diff options
182 files changed, 4860 insertions, 2503 deletions
diff --git a/api/current.xml b/api/current.xml index 374e26f..c43ebac 100644 --- a/api/current.xml +++ b/api/current.xml @@ -6268,17 +6268,6 @@ visibility="public" > </field> -<field name="kraken_resource_pad57" - type="int" - transient="false" - volatile="false" - value="16843464" - static="true" - final="true" - deprecated="not deprecated" - visibility="public" -> -</field> <field name="kraken_resource_pad6" type="int" transient="false" @@ -10129,6 +10118,17 @@ visibility="public" > </field> +<field name="textSelectHandleWindowStyle" + type="int" + transient="false" + volatile="false" + value="16843464" + static="true" + final="true" + deprecated="not deprecated" + visibility="public" +> +</field> <field name="textSize" type="int" transient="false" @@ -15869,6 +15869,28 @@ visibility="public" > </field> +<field name="simple_list_item_activated_1" + type="int" + transient="false" + volatile="false" + value="17367075" + static="true" + final="true" + deprecated="not deprecated" + visibility="public" +> +</field> +<field name="simple_list_item_activated_2" + type="int" + transient="false" + volatile="false" + value="17367076" + static="true" + final="true" + deprecated="not deprecated" + visibility="public" +> +</field> <field name="simple_list_item_checked" type="int" transient="false" @@ -22618,7 +22640,7 @@ </implements> <implements name="android.view.KeyEvent.Callback"> </implements> -<implements name="android.view.LayoutInflater.Factory"> +<implements name="android.view.LayoutInflater.Factory2"> </implements> <implements name="android.view.View.OnCreateContextMenuListener"> </implements> @@ -22751,6 +22773,23 @@ <parameter name="ev" type="android.view.MotionEvent"> </parameter> </method> +<method name="dump" + return="void" + abstract="false" + native="false" + synchronized="false" + static="false" + final="false" + deprecated="not deprecated" + visibility="public" +> +<parameter name="fd" type="java.io.FileDescriptor"> +</parameter> +<parameter name="writer" type="java.io.PrintWriter"> +</parameter> +<parameter name="args" type="java.lang.String[]"> +</parameter> +</method> <method name="findFragmentById" return="android.app.Fragment" abstract="false" @@ -23456,6 +23495,25 @@ <parameter name="attrs" type="android.util.AttributeSet"> </parameter> </method> +<method name="onCreateView" + return="android.view.View" + abstract="false" + native="false" + synchronized="false" + static="false" + final="false" + deprecated="not deprecated" + visibility="public" +> +<parameter name="parent" type="android.view.View"> +</parameter> +<parameter name="name" type="java.lang.String"> +</parameter> +<parameter name="context" type="android.content.Context"> +</parameter> +<parameter name="attrs" type="android.util.AttributeSet"> +</parameter> +</method> <method name="onDestroy" return="void" abstract="false" @@ -28720,6 +28778,25 @@ visibility="public" > </constructor> +<method name="dump" + return="void" + abstract="false" + native="false" + synchronized="false" + static="false" + final="false" + deprecated="not deprecated" + visibility="public" +> +<parameter name="prefix" type="java.lang.String"> +</parameter> +<parameter name="fd" type="java.io.FileDescriptor"> +</parameter> +<parameter name="writer" type="java.io.PrintWriter"> +</parameter> +<parameter name="args" type="java.lang.String[]"> +</parameter> +</method> <method name="equals" return="boolean" abstract="false" @@ -28908,6 +28985,17 @@ visibility="public" > </method> +<method name="isInLayout" + return="boolean" + abstract="false" + native="false" + synchronized="false" + static="false" + final="true" + deprecated="not deprecated" + visibility="public" +> +</method> <method name="isResumed" return="boolean" abstract="false" @@ -29514,6 +29602,25 @@ visibility="public" > </method> +<method name="dump" + return="void" + abstract="true" + native="false" + synchronized="false" + static="false" + final="false" + deprecated="not deprecated" + visibility="public" +> +<parameter name="prefix" type="java.lang.String"> +</parameter> +<parameter name="fd" type="java.io.FileDescriptor"> +</parameter> +<parameter name="writer" type="java.io.PrintWriter"> +</parameter> +<parameter name="args" type="java.lang.String[]"> +</parameter> +</method> <method name="findFragmentById" return="android.app.Fragment" abstract="true" @@ -46477,6 +46584,21 @@ <parameter name="cursor" type="android.database.Cursor"> </parameter> </method> +<method name="registerContentObserver" + return="void" + abstract="false" + native="false" + synchronized="false" + static="false" + final="false" + deprecated="not deprecated" + visibility="public" +> +<parameter name="cursor" type="android.database.Cursor"> +</parameter> +<parameter name="observer" type="android.database.ContentObserver"> +</parameter> +</method> <method name="setProjection" return="void" abstract="false" @@ -87108,11 +87230,11 @@ visibility="public" > </field> -<field name="FOCUS_MODE_CONTINUOUS" +<field name="FOCUS_MODE_CONTINUOUS_VIDEO" type="java.lang.String" transient="false" volatile="false" - value=""continuous"" + value=""continuous-video"" static="true" final="true" deprecated="not deprecated" @@ -92719,8 +92841,8 @@ <exception name="IOException" type="java.io.IOException"> </exception> </method> -<method name="isImplemented" - return="java.lang.Boolean" +<method name="isPresent" + return="boolean" abstract="false" native="false" synchronized="false" @@ -92731,75 +92853,6 @@ > </method> </class> -<class name="GeocoderParams" - extends="java.lang.Object" - abstract="false" - static="false" - final="false" - deprecated="not deprecated" - visibility="public" -> -<implements name="android.os.Parcelable"> -</implements> -<method name="describeContents" - return="int" - abstract="false" - native="false" - synchronized="false" - static="false" - final="false" - deprecated="not deprecated" - visibility="public" -> -</method> -<method name="getClientPackage" - return="java.lang.String" - abstract="false" - native="false" - synchronized="false" - static="false" - final="false" - deprecated="not deprecated" - visibility="public" -> -</method> -<method name="getLocale" - return="java.util.Locale" - abstract="false" - native="false" - synchronized="false" - static="false" - final="false" - deprecated="not deprecated" - visibility="public" -> -</method> -<method name="writeToParcel" - return="void" - abstract="false" - native="false" - synchronized="false" - static="false" - final="false" - deprecated="not deprecated" - visibility="public" -> -<parameter name="parcel" type="android.os.Parcel"> -</parameter> -<parameter name="flags" type="int"> -</parameter> -</method> -<field name="CREATOR" - type="android.os.Parcelable.Creator" - transient="false" - volatile="false" - static="true" - final="true" - deprecated="not deprecated" - visibility="public" -> -</field> -</class> <class name="GpsSatellite" extends="java.lang.Object" abstract="false" @@ -94391,396 +94444,6 @@ </field> </class> </package> -<package name="android.location.provider" -> -<class name="GeocodeProvider" - extends="java.lang.Object" - abstract="true" - static="false" - final="false" - deprecated="not deprecated" - visibility="public" -> -<constructor name="GeocodeProvider" - type="android.location.provider.GeocodeProvider" - static="false" - final="false" - deprecated="not deprecated" - visibility="public" -> -</constructor> -<method name="getBinder" - return="android.os.IBinder" - abstract="false" - native="false" - synchronized="false" - static="false" - final="false" - deprecated="not deprecated" - visibility="public" -> -</method> -<method name="onGetFromLocation" - return="java.lang.String" - abstract="true" - native="false" - synchronized="false" - static="false" - final="false" - deprecated="not deprecated" - visibility="public" -> -<parameter name="latitude" type="double"> -</parameter> -<parameter name="longitude" type="double"> -</parameter> -<parameter name="maxResults" type="int"> -</parameter> -<parameter name="params" type="android.location.GeocoderParams"> -</parameter> -<parameter name="addrs" type="java.util.List<android.location.Address>"> -</parameter> -</method> -<method name="onGetFromLocationName" - return="java.lang.String" - abstract="true" - native="false" - synchronized="false" - static="false" - final="false" - deprecated="not deprecated" - visibility="public" -> -<parameter name="locationName" type="java.lang.String"> -</parameter> -<parameter name="lowerLeftLatitude" type="double"> -</parameter> -<parameter name="lowerLeftLongitude" type="double"> -</parameter> -<parameter name="upperRightLatitude" type="double"> -</parameter> -<parameter name="upperRightLongitude" type="double"> -</parameter> -<parameter name="maxResults" type="int"> -</parameter> -<parameter name="params" type="android.location.GeocoderParams"> -</parameter> -<parameter name="addrs" type="java.util.List<android.location.Address>"> -</parameter> -</method> -</class> -<class name="LocationProvider" - extends="java.lang.Object" - abstract="true" - static="false" - final="false" - deprecated="not deprecated" - visibility="public" -> -<constructor name="LocationProvider" - type="android.location.provider.LocationProvider" - static="false" - final="false" - deprecated="not deprecated" - visibility="public" -> -</constructor> -<method name="getBinder" - return="android.os.IBinder" - abstract="false" - native="false" - synchronized="false" - static="false" - final="false" - deprecated="not deprecated" - visibility="public" -> -</method> -<method name="onAddListener" - return="void" - abstract="true" - native="false" - synchronized="false" - static="false" - final="false" - deprecated="not deprecated" - visibility="public" -> -<parameter name="uid" type="int"> -</parameter> -<parameter name="ws" type="android.os.WorkSource"> -</parameter> -</method> -<method name="onDisable" - return="void" - abstract="true" - native="false" - synchronized="false" - static="false" - final="false" - deprecated="not deprecated" - visibility="public" -> -</method> -<method name="onEnable" - return="void" - abstract="true" - native="false" - synchronized="false" - static="false" - final="false" - deprecated="not deprecated" - visibility="public" -> -</method> -<method name="onEnableLocationTracking" - return="void" - abstract="true" - native="false" - synchronized="false" - static="false" - final="false" - deprecated="not deprecated" - visibility="public" -> -<parameter name="enable" type="boolean"> -</parameter> -</method> -<method name="onGetAccuracy" - return="int" - abstract="true" - native="false" - synchronized="false" - static="false" - final="false" - deprecated="not deprecated" - visibility="public" -> -</method> -<method name="onGetInternalState" - return="java.lang.String" - abstract="true" - native="false" - synchronized="false" - static="false" - final="false" - deprecated="not deprecated" - visibility="public" -> -</method> -<method name="onGetPowerRequirement" - return="int" - abstract="true" - native="false" - synchronized="false" - static="false" - final="false" - deprecated="not deprecated" - visibility="public" -> -</method> -<method name="onGetStatus" - return="int" - abstract="true" - native="false" - synchronized="false" - static="false" - final="false" - deprecated="not deprecated" - visibility="public" -> -<parameter name="extras" type="android.os.Bundle"> -</parameter> -</method> -<method name="onGetStatusUpdateTime" - return="long" - abstract="true" - native="false" - synchronized="false" - static="false" - final="false" - deprecated="not deprecated" - visibility="public" -> -</method> -<method name="onHasMonetaryCost" - return="boolean" - abstract="true" - native="false" - synchronized="false" - static="false" - final="false" - deprecated="not deprecated" - visibility="public" -> -</method> -<method name="onMeetsCriteria" - return="boolean" - abstract="true" - native="false" - synchronized="false" - static="false" - final="false" - deprecated="not deprecated" - visibility="public" -> -<parameter name="criteria" type="android.location.Criteria"> -</parameter> -</method> -<method name="onRemoveListener" - return="void" - abstract="true" - native="false" - synchronized="false" - static="false" - final="false" - deprecated="not deprecated" - visibility="public" -> -<parameter name="uid" type="int"> -</parameter> -<parameter name="ws" type="android.os.WorkSource"> -</parameter> -</method> -<method name="onRequiresCell" - return="boolean" - abstract="true" - native="false" - synchronized="false" - static="false" - final="false" - deprecated="not deprecated" - visibility="public" -> -</method> -<method name="onRequiresNetwork" - return="boolean" - abstract="true" - native="false" - synchronized="false" - static="false" - final="false" - deprecated="not deprecated" - visibility="public" -> -</method> -<method name="onRequiresSatellite" - return="boolean" - abstract="true" - native="false" - synchronized="false" - static="false" - final="false" - deprecated="not deprecated" - visibility="public" -> -</method> -<method name="onSendExtraCommand" - return="boolean" - abstract="true" - native="false" - synchronized="false" - static="false" - final="false" - deprecated="not deprecated" - visibility="public" -> -<parameter name="command" type="java.lang.String"> -</parameter> -<parameter name="extras" type="android.os.Bundle"> -</parameter> -</method> -<method name="onSetMinTime" - return="void" - abstract="true" - native="false" - synchronized="false" - static="false" - final="false" - deprecated="not deprecated" - visibility="public" -> -<parameter name="minTime" type="long"> -</parameter> -<parameter name="ws" type="android.os.WorkSource"> -</parameter> -</method> -<method name="onSupportsAltitude" - return="boolean" - abstract="true" - native="false" - synchronized="false" - static="false" - final="false" - deprecated="not deprecated" - visibility="public" -> -</method> -<method name="onSupportsBearing" - return="boolean" - abstract="true" - native="false" - synchronized="false" - static="false" - final="false" - deprecated="not deprecated" - visibility="public" -> -</method> -<method name="onSupportsSpeed" - return="boolean" - abstract="true" - native="false" - synchronized="false" - static="false" - final="false" - deprecated="not deprecated" - visibility="public" -> -</method> -<method name="onUpdateLocation" - return="void" - abstract="true" - native="false" - synchronized="false" - static="false" - final="false" - deprecated="not deprecated" - visibility="public" -> -<parameter name="location" type="android.location.Location"> -</parameter> -</method> -<method name="onUpdateNetworkState" - return="void" - abstract="true" - native="false" - synchronized="false" - static="false" - final="false" - deprecated="not deprecated" - visibility="public" -> -<parameter name="state" type="int"> -</parameter> -<parameter name="info" type="android.net.NetworkInfo"> -</parameter> -</method> -<method name="reportLocation" - return="void" - abstract="false" - native="false" - synchronized="false" - static="false" - final="false" - deprecated="not deprecated" - visibility="public" -> -<parameter name="location" type="android.location.Location"> -</parameter> -</method> -</class> -</package> <package name="android.media" > <class name="AsyncPlayer" @@ -95370,6 +95033,39 @@ <parameter name="value" type="short"> </parameter> </method> +<field name="ACTION_CLOSE_AUDIO_EFFECT_CONTROL_SESSION" + type="java.lang.String" + transient="false" + volatile="false" + value=""android.media.action.CLOSE_AUDIO_EFFECT_CONTROL_SESSION"" + static="true" + final="true" + deprecated="not deprecated" + visibility="public" +> +</field> +<field name="ACTION_DISPLAY_AUDIO_EFFECT_CONTROL_PANEL" + type="java.lang.String" + transient="false" + volatile="false" + value=""android.media.action.DISPLAY_AUDIO_EFFECT_CONTROL_PANEL"" + static="true" + final="true" + deprecated="not deprecated" + visibility="public" +> +</field> +<field name="ACTION_OPEN_AUDIO_EFFECT_CONTROL_SESSION" + type="java.lang.String" + transient="false" + volatile="false" + value=""android.media.action.OPEN_AUDIO_EFFECT_CONTROL_SESSION"" + static="true" + final="true" + deprecated="not deprecated" + visibility="public" +> +</field> <field name="ALREADY_EXISTS" type="int" transient="false" @@ -95381,6 +95077,50 @@ visibility="public" > </field> +<field name="CONTENT_TYPE_GAME" + type="int" + transient="false" + volatile="false" + value="2" + static="true" + final="true" + deprecated="not deprecated" + visibility="public" +> +</field> +<field name="CONTENT_TYPE_MOVIE" + type="int" + transient="false" + volatile="false" + value="1" + static="true" + final="true" + deprecated="not deprecated" + visibility="public" +> +</field> +<field name="CONTENT_TYPE_MUSIC" + type="int" + transient="false" + volatile="false" + value="0" + static="true" + final="true" + deprecated="not deprecated" + visibility="public" +> +</field> +<field name="CONTENT_TYPE_VOICE" + type="int" + transient="false" + volatile="false" + value="3" + static="true" + final="true" + deprecated="not deprecated" + visibility="public" +> +</field> <field name="EFFECT_AUXILIARY" type="java.lang.String" transient="false" @@ -95529,6 +95269,39 @@ visibility="public" > </field> +<field name="EXTRA_AUDIO_SESSION" + type="java.lang.String" + transient="false" + volatile="false" + value=""android.media.extra.AUDIO_SESSION"" + static="true" + final="true" + deprecated="not deprecated" + visibility="public" +> +</field> +<field name="EXTRA_CONTENT_TYPE" + type="java.lang.String" + transient="false" + volatile="false" + value=""android.media.extra.CONTENT_TYPE"" + static="true" + final="true" + deprecated="not deprecated" + visibility="public" +> +</field> +<field name="EXTRA_PACKAGE_NAME" + type="java.lang.String" + transient="false" + volatile="false" + value=""android.media.extra.PACKAGE_NAME"" + static="true" + final="true" + deprecated="not deprecated" + visibility="public" +> +</field> <field name="NATIVE_EVENT_CONTROL_STATUS" type="int" transient="false" @@ -106737,6 +106510,17 @@ visibility="public" > </field> +<field name="ERROR_FILE_ALREADY_EXISTS" + type="int" + transient="false" + volatile="false" + value="1009" + static="true" + final="true" + deprecated="not deprecated" + visibility="public" +> +</field> <field name="ERROR_FILE_ERROR" type="int" transient="false" @@ -107011,6 +106795,19 @@ <parameter name="value" type="java.lang.String"> </parameter> </method> +<method name="setShowRunningNotification" + return="android.net.DownloadManager.Request" + abstract="false" + native="false" + synchronized="false" + static="false" + final="false" + deprecated="not deprecated" + visibility="public" +> +<parameter name="show" type="boolean"> +</parameter> +</method> <method name="setTitle" return="android.net.DownloadManager.Request" abstract="false" @@ -157486,6 +157283,17 @@ visibility="public" > </field> +<field name="AUTO_TIME_ZONE" + type="java.lang.String" + transient="false" + volatile="false" + value=""auto_time_zone"" + static="true" + final="true" + deprecated="not deprecated" + visibility="public" +> +</field> <field name="BLUETOOTH_DISCOVERABILITY" type="java.lang.String" transient="false" @@ -178798,19 +178606,6 @@ <parameter name="event" type="android.view.MotionEvent"> </parameter> </method> -<method name="setCursorController" - return="void" - abstract="false" - native="false" - synchronized="false" - static="false" - final="false" - deprecated="not deprecated" - visibility="public" -> -<parameter name="cursorController" type="android.widget.TextView.CursorController"> -</parameter> -</method> </class> <class name="BaseKeyListener" extends="android.text.method.MetaKeyKeyListener" @@ -193506,6 +193301,17 @@ visibility="public" > </method> +<method name="getFactory2" + return="android.view.LayoutInflater.Factory2" + abstract="false" + native="false" + synchronized="false" + static="false" + final="true" + deprecated="not deprecated" + visibility="public" +> +</method> <method name="getFilter" return="android.view.LayoutInflater.Filter" abstract="false" @@ -193598,6 +193404,25 @@ <exception name="ClassNotFoundException" type="java.lang.ClassNotFoundException"> </exception> </method> +<method name="onCreateView" + return="android.view.View" + abstract="false" + native="false" + synchronized="false" + static="false" + final="false" + deprecated="not deprecated" + visibility="protected" +> +<parameter name="parent" type="android.view.View"> +</parameter> +<parameter name="name" type="java.lang.String"> +</parameter> +<parameter name="attrs" type="android.util.AttributeSet"> +</parameter> +<exception name="ClassNotFoundException" type="java.lang.ClassNotFoundException"> +</exception> +</method> <method name="setFactory" return="void" abstract="false" @@ -193611,6 +193436,19 @@ <parameter name="factory" type="android.view.LayoutInflater.Factory"> </parameter> </method> +<method name="setFactory2" + return="void" + abstract="false" + native="false" + synchronized="false" + static="false" + final="false" + deprecated="not deprecated" + visibility="public" +> +<parameter name="factory" type="android.view.LayoutInflater.Factory2"> +</parameter> +</method> <method name="setFilter" return="void" abstract="false" @@ -193650,6 +193488,35 @@ </parameter> </method> </interface> +<interface name="LayoutInflater.Factory2" + abstract="true" + static="true" + final="false" + deprecated="not deprecated" + visibility="public" +> +<implements name="android.view.LayoutInflater.Factory"> +</implements> +<method name="onCreateView" + return="android.view.View" + abstract="true" + native="false" + synchronized="false" + static="false" + final="false" + deprecated="not deprecated" + visibility="public" +> +<parameter name="parent" type="android.view.View"> +</parameter> +<parameter name="name" type="java.lang.String"> +</parameter> +<parameter name="context" type="android.content.Context"> +</parameter> +<parameter name="attrs" type="android.util.AttributeSet"> +</parameter> +</method> +</interface> <interface name="LayoutInflater.Filter" abstract="true" static="true" @@ -233604,6 +233471,21 @@ <parameter name="extras" type="android.os.Bundle"> </parameter> </method> +<method name="setOnClickFillInIntent" + return="void" + abstract="false" + native="false" + synchronized="false" + static="false" + final="false" + deprecated="not deprecated" + visibility="public" +> +<parameter name="viewId" type="int"> +</parameter> +<parameter name="fillInIntent" type="android.content.Intent"> +</parameter> +</method> <method name="setOnClickPendingIntent" return="void" abstract="false" @@ -239565,121 +239447,6 @@ > </method> </class> -<interface name="TextView.CursorController" - abstract="true" - static="true" - final="false" - deprecated="not deprecated" - visibility="public" -> -<method name="draw" - return="void" - abstract="true" - native="false" - synchronized="false" - static="false" - final="false" - deprecated="not deprecated" - visibility="public" -> -<parameter name="canvas" type="android.graphics.Canvas"> -</parameter> -</method> -<method name="getOffsetX" - return="float" - abstract="true" - native="false" - synchronized="false" - static="false" - final="false" - deprecated="not deprecated" - visibility="public" -> -</method> -<method name="getOffsetY" - return="float" - abstract="true" - native="false" - synchronized="false" - static="false" - final="false" - deprecated="not deprecated" - visibility="public" -> -</method> -<method name="hide" - return="void" - abstract="true" - native="false" - synchronized="false" - static="false" - final="false" - deprecated="not deprecated" - visibility="public" -> -</method> -<method name="isShowing" - return="boolean" - abstract="true" - native="false" - synchronized="false" - static="false" - final="false" - deprecated="not deprecated" - visibility="public" -> -</method> -<method name="onTouchEvent" - return="boolean" - abstract="true" - native="false" - synchronized="false" - static="false" - final="false" - deprecated="not deprecated" - visibility="public" -> -<parameter name="event" type="android.view.MotionEvent"> -</parameter> -</method> -<method name="show" - return="void" - abstract="true" - native="false" - synchronized="false" - static="false" - final="false" - deprecated="not deprecated" - visibility="public" -> -</method> -<method name="updatePosition" - return="void" - abstract="true" - native="false" - synchronized="false" - static="false" - final="false" - deprecated="not deprecated" - visibility="public" -> -<parameter name="x" type="int"> -</parameter> -<parameter name="y" type="int"> -</parameter> -</method> -<field name="FADE_OUT_DURATION" - type="int" - transient="false" - volatile="false" - value="400" - static="true" - final="true" - deprecated="not deprecated" - visibility="public" -> -</field> -</interface> <interface name="TextView.OnEditorActionListener" abstract="true" static="true" diff --git a/cmds/stagefright/record.cpp b/cmds/stagefright/record.cpp index c424281..b718299 100644 --- a/cmds/stagefright/record.cpp +++ b/cmds/stagefright/record.cpp @@ -36,24 +36,30 @@ static const int32_t kFramerate = 24; // fps static const int32_t kIFramesIntervalSec = 1; static const int32_t kVideoBitRate = 512 * 1024; static const int32_t kAudioBitRate = 12200; -static const int32_t kColorFormat = OMX_COLOR_FormatYUV420SemiPlanar; static const int64_t kDurationUs = 10000000LL; // 10 seconds #if 1 class DummySource : public MediaSource { public: - DummySource(int width, int height) + DummySource(int width, int height, int colorFormat) : mWidth(width), mHeight(height), + mColorFormat(colorFormat), mSize((width * height * 3) / 2) { mGroup.add_buffer(new MediaBuffer(mSize)); + + // Check the color format to make sure + // that the buffer size mSize it set correctly above. + CHECK(colorFormat == OMX_COLOR_FormatYUV420SemiPlanar || + colorFormat == OMX_COLOR_FormatYUV420Planar); } virtual sp<MetaData> getFormat() { sp<MetaData> meta = new MetaData; meta->setInt32(kKeyWidth, mWidth); meta->setInt32(kKeyHeight, mHeight); + meta->setInt32(kKeyColorFormat, mColorFormat); meta->setCString(kKeyMIMEType, MEDIA_MIMETYPE_VIDEO_RAW); return meta; @@ -100,6 +106,7 @@ protected: private: MediaBufferGroup mGroup; int mWidth, mHeight; + int mColorFormat; size_t mSize; int64_t mNumFramesOutput;; @@ -139,20 +146,47 @@ sp<MediaSource> createSource(const char *filename) { return source; } +enum { + kYUV420SP = 0, + kYUV420P = 1, +}; + +// returns -1 if mapping of the given color is unsuccessful +// returns an omx color enum value otherwise +static int translateColorToOmxEnumValue(int color) { + switch (color) { + case kYUV420SP: + return OMX_COLOR_FormatYUV420SemiPlanar; + case kYUV420P: + return OMX_COLOR_FormatYUV420Planar; + default: + fprintf(stderr, "Unsupported color: %d\n", color); + return -1; + } +} + int main(int argc, char **argv) { android::ProcessState::self()->startThreadPool(); DataSource::RegisterDefaultSniffers(); #if 1 - if (argc != 2) { - fprintf(stderr, "usage: %s filename\n", argv[0]); + if (argc != 3) { + fprintf(stderr, "usage: %s <filename> <input_color_format>\n", argv[0]); + fprintf(stderr, " <input_color_format>: 0 (YUV420SP) or 1 (YUV420P)\n"); return 1; } + int colorFormat = translateColorToOmxEnumValue(atoi(argv[2])); + if (colorFormat == -1) { + fprintf(stderr, "input color format must be 0 (YUV420SP) or 1 (YUV420P)\n"); + return 1; + } OMXClient client; CHECK_EQ(client.connect(), OK); + status_t err = OK; + #if 0 sp<MediaSource> source = createSource(argv[1]); @@ -173,7 +207,7 @@ int main(int argc, char **argv) { #else int width = 720; int height = 480; - sp<MediaSource> decoder = new DummySource(width, height); + sp<MediaSource> decoder = new DummySource(width, height, colorFormat); #endif sp<MetaData> enc_meta = new MetaData; @@ -187,7 +221,7 @@ int main(int argc, char **argv) { enc_meta->setInt32(kKeyStride, width); enc_meta->setInt32(kKeySliceHeight, height); enc_meta->setInt32(kKeyIFramesInterval, kIFramesIntervalSec); - enc_meta->setInt32(kKeyColorFormat, kColorFormat); + enc_meta->setInt32(kKeyColorFormat, colorFormat); sp<MediaSource> encoder = OMXCodec::Create( @@ -197,14 +231,14 @@ int main(int argc, char **argv) { sp<MPEG4Writer> writer = new MPEG4Writer("/sdcard/output.mp4"); writer->addSource(encoder); writer->setMaxFileDuration(kDurationUs); - writer->start(); + CHECK_EQ(OK, writer->start()); while (!writer->reachedEOS()) { fprintf(stderr, "."); usleep(100000); } - writer->stop(); + err = writer->stop(); #else - encoder->start(); + CHECK_EQ(OK, encoder->start()); MediaBuffer *buffer; while (encoder->read(&buffer) == OK) { @@ -222,7 +256,7 @@ int main(int argc, char **argv) { buffer = NULL; } - encoder->stop(); + err = encoder->stop(); #endif printf("$\n"); @@ -247,12 +281,16 @@ int main(int argc, char **argv) { buffer = NULL; } - source->stop(); + err = source->stop(); delete source; source = NULL; #endif + if (err != OK && err != ERROR_END_OF_STREAM) { + fprintf(stderr, "record failed: %d\n", err); + return 1; + } return 0; } #else diff --git a/core/java/android/app/Activity.java b/core/java/android/app/Activity.java index 2e8d682..ee49d97 100644 --- a/core/java/android/app/Activity.java +++ b/core/java/android/app/Activity.java @@ -74,6 +74,8 @@ import android.view.accessibility.AccessibilityEvent; import android.widget.AdapterView; import android.widget.FrameLayout; +import java.io.FileDescriptor; +import java.io.PrintWriter; import java.util.ArrayList; import java.util.HashMap; @@ -605,7 +607,7 @@ import java.util.HashMap; * or finished. */ public class Activity extends ContextThemeWrapper - implements LayoutInflater.Factory, + implements LayoutInflater.Factory2, Window.Callback, KeyEvent.Callback, OnCreateContextMenuListener, ComponentCallbacks { private static final String TAG = "Activity"; @@ -1488,7 +1490,9 @@ public class Activity extends ContextThemeWrapper * <li> The function will be called between {@link #onStop} and * {@link #onDestroy}. * <li> A new instance of the activity will <em>always</em> be immediately - * created after this one's {@link #onDestroy()} is called. + * created after this one's {@link #onDestroy()} is called. In particular, + * <em>no</em> messages will be dispatched during this time (when the returned + * object does not have an activity to be associated with). * <li> The object you return here will <em>always</em> be available from * the {@link #getLastNonConfigurationInstance()} method of the following * activity instance as described there. @@ -1501,6 +1505,15 @@ public class Activity extends ContextThemeWrapper * may change based on the configuration, including any data loaded from * resources such as strings, layouts, or drawables. * + * <p>The guarantee of no message handling during the switch to the next + * activity simplifies use with active objects. For example if your retained + * state is an {@link android.os.AsyncTask} you are guaranteed that its + * call back functions (like {@link android.os.AsyncTask#onPostExecute}) will + * not be called from the call here until you execute the next instance's + * {@link #onCreate(Bundle)}. (Note however that there is of course no such + * guarantee for {@link android.os.AsyncTask#doInBackground} since that is + * running in a separate thread.) + * * @return Return any Object holding the desired state to propagate to the * next activity instance. */ @@ -4019,15 +4032,30 @@ public class Activity extends ContextThemeWrapper * Standard implementation of * {@link android.view.LayoutInflater.Factory#onCreateView} used when * inflating with the LayoutInflater returned by {@link #getSystemService}. + * This implementation does nothing and is for + * pre-{@link android.os.Build.VERSION_CODES#HONEYCOMB} apps. Newer apps + * should use {@link #onCreateView(View, String, Context, AttributeSet)}. + * + * @see android.view.LayoutInflater#createView + * @see android.view.Window#getLayoutInflater + */ + public View onCreateView(String name, Context context, AttributeSet attrs) { + return null; + } + + /** + * Standard implementation of + * {@link android.view.LayoutInflater.Factory2#onCreateView(View, String, Context, AttributeSet)} + * used when inflating with the LayoutInflater returned by {@link #getSystemService}. * This implementation handles <fragment> tags to embed fragments inside * of the activity. * * @see android.view.LayoutInflater#createView * @see android.view.Window#getLayoutInflater */ - public View onCreateView(String name, Context context, AttributeSet attrs) { + public View onCreateView(View parent, String name, Context context, AttributeSet attrs) { if (!"fragment".equals(name)) { - return null; + return onCreateView(name, context, attrs); } String fname = attrs.getAttributeValue(null, "class"); @@ -4036,42 +4064,70 @@ public class Activity extends ContextThemeWrapper if (fname == null) { fname = a.getString(com.android.internal.R.styleable.Fragment_name); } - int id = a.getResourceId(com.android.internal.R.styleable.Fragment_id, 0); + int id = a.getResourceId(com.android.internal.R.styleable.Fragment_id, View.NO_ID); String tag = a.getString(com.android.internal.R.styleable.Fragment_tag); a.recycle(); - if (id == 0) { + int containerId = parent != null ? parent.getId() : 0; + if (containerId == View.NO_ID && id == View.NO_ID && tag == null) { throw new IllegalArgumentException(attrs.getPositionDescription() - + ": Must specify unique android:id for " + fname); + + ": Must specify unique android:id, android:tag, or have a parent with an id for " + fname); } - + // If we restored from a previous state, we may already have // instantiated this fragment from the state and should use // that instance instead of making a new one. - Fragment fragment = mFragments.findFragmentById(id); + Fragment fragment = id != View.NO_ID ? mFragments.findFragmentById(id) : null; + if (fragment == null && tag != null) { + fragment = mFragments.findFragmentByTag(tag); + } + if (fragment == null && containerId != View.NO_ID) { + fragment = mFragments.findFragmentById(containerId); + } + if (FragmentManagerImpl.DEBUG) Log.v(TAG, "onCreateView: id=0x" + Integer.toHexString(id) + " fname=" + fname + " existing=" + fragment); if (fragment == null) { fragment = Fragment.instantiate(this, fname); fragment.mFromLayout = true; - fragment.mFragmentId = id; + fragment.mFragmentId = id != 0 ? id : containerId; + fragment.mContainerId = containerId; fragment.mTag = tag; + fragment.mInLayout = true; fragment.mImmediateActivity = this; fragment.mFragmentManager = mFragments; + fragment.onInflate(attrs, fragment.mSavedFragmentState); + mFragments.addFragment(fragment, true); + + } else if (fragment.mInLayout) { + // A fragment already exists and it is not one we restored from + // previous state. + throw new IllegalArgumentException(attrs.getPositionDescription() + + ": Duplicate id 0x" + Integer.toHexString(id) + + ", tag " + tag + ", or parent id 0x" + Integer.toHexString(containerId) + + " with another fragment for " + fname); + } else { + // This fragment was retained from a previous instance; get it + // going now. + fragment.mInLayout = true; + fragment.mImmediateActivity = this; // If this fragment is newly instantiated (either right now, or // from last saved state), then give it the attributes to // initialize itself. if (!fragment.mRetaining) { fragment.onInflate(attrs, fragment.mSavedFragmentState); } - mFragments.addFragment(fragment, true); + mFragments.moveToState(fragment); } + if (fragment.mView == null) { throw new IllegalStateException("Fragment " + fname + " did not create a view."); } - fragment.mView.setId(id); + if (id != 0) { + fragment.mView.setId(id); + } if (fragment.mView.getTag() == null) { fragment.mView.setTag(tag); } @@ -4079,6 +4135,19 @@ public class Activity extends ContextThemeWrapper } /** + * Print the Activity's state into the given stream. This gets invoked if + * you run "adb shell dumpsys activity <youractivityname>". + * + * @param fd The raw file descriptor that the dump is being sent to. + * @param writer The PrintWriter to which you should dump your state. This will be + * closed for you after you return. + * @param args additional arguments to the dump request. + */ + public void dump(FileDescriptor fd, PrintWriter writer, String[] args) { + mFragments.dump("", fd, writer, args); + } + + /** * Bit indicating that this activity is "immersive" and should not be * interrupted by notifications if possible. * @@ -4166,7 +4235,7 @@ public class Activity extends ContextThemeWrapper mWindow = PolicyManager.makeNewWindow(this); mWindow.setCallback(this); - mWindow.getLayoutInflater().setFactory(this); + mWindow.getLayoutInflater().setFactory2(this); if (info.softInputMode != WindowManager.LayoutParams.SOFT_INPUT_STATE_UNSPECIFIED) { mWindow.setSoftInputMode(info.softInputMode); } diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java index c0e2987..3f74904 100644 --- a/core/java/android/app/ActivityThread.java +++ b/core/java/android/app/ActivityThread.java @@ -335,9 +335,9 @@ public final class ActivityThread { } } - private static final class DumpServiceInfo { + private static final class DumpComponentInfo { FileDescriptor fd; - IBinder service; + IBinder token; String[] args; boolean dumped; } @@ -370,7 +370,8 @@ public final class ActivityThread { private static final String HEAP_COLUMN = "%17s %8s %8s %8s %8s"; private static final String ONE_COUNT_COLUMN = "%17s %8d"; private static final String TWO_COUNT_COLUMNS = "%17s %8d %17s %8d"; - private static final String DB_INFO_FORMAT = " %4d %6d %8d %14s %s"; + private static final String TWO_COUNT_COLUMNS_DB = "%20s %8d %20s %8d"; + private static final String DB_INFO_FORMAT = " %8s %8s %14s %14s %s"; // Formatting for checkin service - update version if row format changes private static final int ACTIVITY_THREAD_CHECKIN_VERSION = 1; @@ -591,9 +592,9 @@ public final class ActivityThread { } public void dumpService(FileDescriptor fd, IBinder servicetoken, String[] args) { - DumpServiceInfo data = new DumpServiceInfo(); + DumpComponentInfo data = new DumpComponentInfo(); data.fd = fd; - data.service = servicetoken; + data.token = servicetoken; data.args = args; data.dumped = false; queueOrSendMessage(H.DUMP_SERVICE, data); @@ -663,6 +664,25 @@ public final class ActivityThread { public void scheduleCrash(String msg) { queueOrSendMessage(H.SCHEDULE_CRASH, msg); } + + public void dumpActivity(FileDescriptor fd, IBinder activitytoken, String[] args) { + DumpComponentInfo data = new DumpComponentInfo(); + data.fd = fd; + data.token = activitytoken; + data.args = args; + data.dumped = false; + queueOrSendMessage(H.DUMP_ACTIVITY, data); + synchronized (data) { + while (!data.dumped) { + try { + data.wait(); + } catch (InterruptedException e) { + // no need to do anything here, we will keep waiting until + // dumped is set + } + } + } + } @Override protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) { @@ -820,20 +840,23 @@ public final class ActivityThread { // SQLite mem info pw.println(" "); pw.println(" SQL"); - printRow(pw, TWO_COUNT_COLUMNS, "heap:", sqliteAllocated, "memoryUsed:", + printRow(pw, TWO_COUNT_COLUMNS_DB, "heap:", sqliteAllocated, "MEMORY_USED:", stats.memoryUsed / 1024); - printRow(pw, TWO_COUNT_COLUMNS, "pageCacheOverflo:", stats.pageCacheOverflo / 1024, - "largestMemAlloc:", stats.largestMemAlloc / 1024); + printRow(pw, TWO_COUNT_COLUMNS_DB, "PAGECACHE_OVERFLOW:", + stats.pageCacheOverflo / 1024, "MALLOC_SIZE:", stats.largestMemAlloc / 1024); pw.println(" "); int N = stats.dbStats.size(); if (N > 0) { pw.println(" DATABASES"); - printRow(pw, " %4s %6s %8s %14s %s", "pgsz", "dbsz", "lkaside", "cache", - "Dbname"); + printRow(pw, " %8s %8s %14s %14s %s", "pgsz", "dbsz", "Lookaside(b)", "cache", + "Dbname"); for (int i = 0; i < N; i++) { DbStats dbStats = stats.dbStats.get(i); - printRow(pw, DB_INFO_FORMAT, dbStats.pageSize, dbStats.dbSize, - dbStats.lookaside, dbStats.cache, dbStats.dbName); + printRow(pw, DB_INFO_FORMAT, + (dbStats.pageSize > 0) ? String.valueOf(dbStats.pageSize) : " ", + (dbStats.dbSize > 0) ? String.valueOf(dbStats.dbSize) : " ", + (dbStats.lookaside > 0) ? String.valueOf(dbStats.lookaside) : " ", + dbStats.cache, dbStats.dbName); } } @@ -888,6 +911,7 @@ public final class ActivityThread { public static final int DISPATCH_PACKAGE_BROADCAST = 133; public static final int SCHEDULE_CRASH = 134; public static final int DUMP_HEAP = 135; + public static final int DUMP_ACTIVITY = 136; String codeToString(int code) { if (localLOGV) { switch (code) { @@ -927,6 +951,7 @@ public final class ActivityThread { case DISPATCH_PACKAGE_BROADCAST: return "DISPATCH_PACKAGE_BROADCAST"; case SCHEDULE_CRASH: return "SCHEDULE_CRASH"; case DUMP_HEAP: return "DUMP_HEAP"; + case DUMP_ACTIVITY: return "DUMP_ACTIVITY"; } } return "(unknown)"; @@ -1021,7 +1046,7 @@ public final class ActivityThread { scheduleGcIdler(); break; case DUMP_SERVICE: - handleDumpService((DumpServiceInfo)msg.obj); + handleDumpService((DumpComponentInfo)msg.obj); break; case LOW_MEMORY: handleLowMemory(); @@ -1055,6 +1080,9 @@ public final class ActivityThread { case DUMP_HEAP: handleDumpHeap(msg.arg1 != 0, (DumpHeapData)msg.obj); break; + case DUMP_ACTIVITY: + handleDumpActivity((DumpComponentInfo)msg.obj); + break; } } @@ -2020,9 +2048,9 @@ public final class ActivityThread { } } - private void handleDumpService(DumpServiceInfo info) { + private void handleDumpService(DumpComponentInfo info) { try { - Service s = mServices.get(info.service); + Service s = mServices.get(info.token); if (s != null) { PrintWriter pw = new PrintWriter(new FileOutputStream(info.fd)); s.dump(info.fd, pw, info.args); @@ -2036,6 +2064,22 @@ public final class ActivityThread { } } + private void handleDumpActivity(DumpComponentInfo info) { + try { + ActivityClientRecord r = mActivities.get(info.token); + if (r != null && r.activity != null) { + PrintWriter pw = new PrintWriter(new FileOutputStream(info.fd)); + r.activity.dump(info.fd, pw, info.args); + pw.close(); + } + } finally { + synchronized (info) { + info.dumped = true; + info.notifyAll(); + } + } + } + private final void handleServiceArgs(ServiceArgsData data) { Service s = mServices.get(data.token); if (s != null) { diff --git a/core/java/android/app/ApplicationThreadNative.java b/core/java/android/app/ApplicationThreadNative.java index dc2145f..95689fc 100644 --- a/core/java/android/app/ApplicationThreadNative.java +++ b/core/java/android/app/ApplicationThreadNative.java @@ -414,6 +414,21 @@ public abstract class ApplicationThreadNative extends Binder dumpHeap(managed, path, fd); return true; } + + case DUMP_ACTIVITY_TRANSACTION: { + data.enforceInterface(IApplicationThread.descriptor); + ParcelFileDescriptor fd = data.readFileDescriptor(); + final IBinder activity = data.readStrongBinder(); + final String[] args = data.readStringArray(); + if (fd != null) { + dumpActivity(fd.getFileDescriptor(), activity, args); + try { + fd.close(); + } catch (IOException e) { + } + } + return true; + } } return super.onTransact(code, data, reply, flags); @@ -857,5 +872,16 @@ class ApplicationThreadProxy implements IApplicationThread { IBinder.FLAG_ONEWAY); data.recycle(); } + + public void dumpActivity(FileDescriptor fd, IBinder token, String[] args) + throws RemoteException { + Parcel data = Parcel.obtain(); + data.writeInterfaceToken(IApplicationThread.descriptor); + data.writeFileDescriptor(fd); + data.writeStrongBinder(token); + data.writeStringArray(args); + mRemote.transact(DUMP_ACTIVITY_TRANSACTION, data, null, 0); + data.recycle(); + } } diff --git a/core/java/android/app/Fragment.java b/core/java/android/app/Fragment.java index 1cbed79..12bf7e5 100644 --- a/core/java/android/app/Fragment.java +++ b/core/java/android/app/Fragment.java @@ -38,6 +38,8 @@ import android.view.ContextMenu.ContextMenuInfo; import android.view.View.OnCreateContextMenuListener; import android.widget.AdapterView; +import java.io.FileDescriptor; +import java.io.PrintWriter; import java.util.HashMap; final class FragmentState implements Parcelable { @@ -207,7 +209,7 @@ final class FragmentState implements Parcelable { * * <p>An activity's layout XML can include <code><fragment></code> tags * to embed fragment instances inside of the layout. For example, here is - * a simply layout that embeds one fragment:</p> + * a simple layout that embeds one fragment:</p> * * {@sample development/samples/ApiDemos/res/layout/fragment_layout.xml layout} * @@ -251,6 +253,33 @@ final class FragmentState implements Parcelable { * details activity will finish of it finds itself running in a configuration * where the details can be shown inline. * + * <p>When a configuration change causes the activity hosting these fragments + * to restart, its new instance may use a different layout that doesn't + * include the same fragments as the previous layout. In this case all of + * the previous fragments will still be instantiated and running in the new + * instance; however, any that are no longer associated with a <fragment> + * tag in the view hierarchy will not have their content view created and will + * return false from {@link #isInLayout}. + * + * <p>The attributes of the <fragment> tag are used to control the + * LayoutParams provider when attaching the fragment's view to the parent + * container. They can alse be parsed by the fragment in {@link #onInflate} + * as parameters. + * + * <p>The fragment being instantiated must have some kind of unique identifier + * so that it can be re-associated with a previous instance if the parent + * activity needs to be destroyed and recreated. This can be provided these + * ways: + * + * <ul> + * <li>If nothing is explicitly supplied, the view ID of the container will + * be used. + * <li><code>android:tag</code> can be used in <fragment> to provide + * a specific tag name for the fragment. + * <li><code>android:id</code> can be used in <fragment> to provide + * a specific identifier for the fragment. + * </ul> + * * <a name="BackStack"></a> * <h3>Back Stack</h3> * @@ -316,6 +345,9 @@ public class Fragment implements ComponentCallbacks, OnCreateContextMenuListener // Set to true if this fragment was instantiated from a layout file. boolean mFromLayout; + // Set to true when the view has actually been inflated in its layout. + boolean mInLayout; + // Number of active back stack entries this fragment is in. int mBackStackNesting; @@ -585,7 +617,7 @@ public class Fragment implements ComponentCallbacks, OnCreateContextMenuListener /** * Return the FragmentManager for interacting with fragments associated * with this fragment's activity. Note that this will be non-null slightly - * before {@link #getActivity()}, in the time from when the fragment is + * before {@link #getActivity()}, during the time from when the fragment is * placed in a {@link FragmentTransaction} until it is committed and * attached to its activity. */ @@ -601,6 +633,17 @@ public class Fragment implements ComponentCallbacks, OnCreateContextMenuListener } /** + * Return true if the layout is included as part of an activity view + * hierarchy via the <fragment> tag. This will always be true when + * fragments are created through the <fragment> tag, <em>except</em> + * in the case where an old fragment is restored from a previous state and + * it does not appear in the layout of the current state. + */ + final public boolean isInLayout() { + return mInLayout; + } + + /** * Return true if the fragment is in the resumed state. This is true * for the duration of {@link #onResume()} and {@link #onPause()} as well. */ @@ -1075,6 +1118,76 @@ public class Fragment implements ComponentCallbacks, OnCreateContextMenuListener return false; } + /** + * Print the Fragments's state into the given stream. + * + * @param prefix Text to print at the front of each line. + * @param fd The raw file descriptor that the dump is being sent to. + * @param writer The PrintWriter to which you should dump your state. This will be + * closed for you after you return. + * @param args additional arguments to the dump request. + */ + public void dump(String prefix, FileDescriptor fd, PrintWriter writer, String[] args) { + writer.print(prefix); writer.print("mFragmentId="); writer.print(mFragmentId); + writer.print(" mContainerId="); writer.print(mContainerId); + writer.print(" mTag="); writer.println(mTag); + writer.print(prefix); writer.print("mState="); writer.print(mState); + writer.print(" mIndex="); writer.print(mIndex); + writer.print(" mWho="); writer.print(mWho); + writer.print(" mBackStackNesting="); writer.println(mBackStackNesting); + writer.print(prefix); writer.print("mAdded="); writer.print(mAdded); + writer.print(" mResumed="); writer.print(mResumed); + writer.print(" mFromLayout="); writer.print(mFromLayout); + writer.print(" mInLayout="); writer.println(mInLayout); + writer.print(prefix); writer.print("mHidden="); writer.print(mHidden); + writer.print(" mRetainInstance="); writer.print(mRetainInstance); + writer.print(" mRetaining="); writer.print(mRetaining); + writer.print(" mHasMenu="); writer.println(mHasMenu); + if (mFragmentManager != null) { + writer.print(prefix); writer.print("mFragmentManager="); + writer.println(mFragmentManager); + } + if (mImmediateActivity != null) { + writer.print(prefix); writer.print("mImmediateActivity="); + writer.println(mImmediateActivity); + } + if (mActivity != null) { + writer.print(prefix); writer.print("mActivity="); + writer.println(mActivity); + } + if (mArguments != null) { + writer.print(prefix); writer.print("mArguments="); writer.println(mArguments); + } + if (mSavedFragmentState != null) { + writer.print(prefix); writer.print("mSavedFragmentState="); + writer.println(mSavedFragmentState); + } + if (mSavedViewState != null) { + writer.print(prefix); writer.print("mSavedViewState="); + writer.println(mSavedViewState); + } + if (mTarget != null) { + writer.print(prefix); writer.print("mTarget="); writer.print(mTarget); + writer.print(" mTargetRequestCode="); + writer.println(mTargetRequestCode); + } + if (mNextAnim != 0) { + writer.print(prefix); writer.print("mNextAnim="); writer.println(mNextAnim); + } + if (mContainer != null) { + writer.print(prefix); writer.print("mContainer="); writer.println(mContainer); + } + if (mView != null) { + writer.print(prefix); writer.print("mView="); writer.println(mView); + } + if (mLoaderManager != null) { + writer.print(prefix); writer.print("mLoaderManager="); writer.print(mLoaderManager); + writer.print(" mStarted="); writer.print(mStarted); + writer.print(" mCheckedForLoaderManager="); + writer.println(mCheckedForLoaderManager); + } + } + void performStop() { onStop(); if (mStarted) { diff --git a/core/java/android/app/FragmentBreadCrumbs.java b/core/java/android/app/FragmentBreadCrumbs.java index 0d39d0b..22e0747 100644 --- a/core/java/android/app/FragmentBreadCrumbs.java +++ b/core/java/android/app/FragmentBreadCrumbs.java @@ -16,6 +16,7 @@ package android.app; +import android.app.FragmentManager.BackStackEntry; import android.content.Context; import android.util.AttributeSet; import android.view.LayoutInflater; @@ -139,14 +140,14 @@ public class FragmentBreadCrumbs extends ViewGroup FragmentManager fm = mActivity.getFragmentManager(); int numEntries = fm.countBackStackEntries(); int numViews = mContainer.getChildCount(); - for (int i=mTopEntry != null ? -1 : 0; i<numEntries; i++) { - FragmentManager.BackStackEntry bse = i == -1 ? mTopEntry : fm.getBackStackEntry(i); - int viewI = mTopEntry != null ? i+1 : i; + for (int i = mTopEntry != null ? -1 : 0; i < numEntries; i++) { + BackStackEntry bse = i == -1 ? mTopEntry : fm.getBackStackEntry(i); + int viewI = mTopEntry != null ? i + 1 : i; if (viewI < numViews) { View v = mContainer.getChildAt(viewI); Object tag = v.getTag(); if (tag != bse) { - for (int j=viewI; j<numViews; j++) { + for (int j = viewI; j < numViews; j++) { mContainer.removeViewAt(viewI); } numViews = viewI; @@ -163,13 +164,24 @@ public class FragmentBreadCrumbs extends ViewGroup text.setCompoundDrawables(null, null, null, null); } mContainer.addView(item); + item.setOnClickListener(mOnClickListener); } } - int viewI = mTopEntry != null ? numEntries+1 : numEntries; + int viewI = mTopEntry != null ? numEntries + 1 : numEntries; numViews = mContainer.getChildCount(); while (numViews > viewI) { mContainer.removeViewAt(numViews-1); numViews--; } } + + private OnClickListener mOnClickListener = new OnClickListener() { + public void onClick(View v) { + if (v.getTag() instanceof BackStackEntry) { + BackStackEntry bse = (BackStackEntry) v.getTag(); + mActivity.getFragmentManager().popBackStack(bse.getId(), + bse == mTopEntry? FragmentManager.POP_BACK_STACK_INCLUSIVE : 0); + } + } + }; } diff --git a/core/java/android/app/FragmentManager.java b/core/java/android/app/FragmentManager.java index 9f95824..da7ba6f 100644 --- a/core/java/android/app/FragmentManager.java +++ b/core/java/android/app/FragmentManager.java @@ -32,6 +32,8 @@ import android.view.MenuItem; import android.view.View; import android.view.ViewGroup; +import java.io.FileDescriptor; +import java.io.PrintWriter; import java.util.ArrayList; /** @@ -190,6 +192,16 @@ public interface FragmentManager { * the given reference. */ public Fragment getFragment(Bundle bundle, String key); + + /** + * Print the FragmentManager's state into the given stream. + * + * @param prefix Text to print at the front of each line. + * @param fd The raw file descriptor that the dump is being sent to. + * @param writer A PrintWriter to which the dump is to be set. + * @param args additional arguments to the dump request. + */ + public void dump(String prefix, FileDescriptor fd, PrintWriter writer, String[] args); } final class FragmentManagerState implements Parcelable { @@ -270,18 +282,23 @@ final class FragmentManagerImpl implements FragmentManager { execPendingActions(); } }; + + @Override public FragmentTransaction openTransaction() { return new BackStackRecord(this); } + @Override public boolean popBackStack() { return popBackStackState(mActivity.mHandler, null, -1, 0); } + @Override public boolean popBackStack(String name, int flags) { return popBackStackState(mActivity.mHandler, name, -1, flags); } + @Override public boolean popBackStack(int id, int flags) { if (id < 0) { throw new IllegalArgumentException("Bad id: " + id); @@ -289,14 +306,17 @@ final class FragmentManagerImpl implements FragmentManager { return popBackStackState(mActivity.mHandler, null, id, flags); } + @Override public int countBackStackEntries() { return mBackStack != null ? mBackStack.size() : 0; } + @Override public BackStackEntry getBackStackEntry(int index) { return mBackStack.get(index); } + @Override public void addOnBackStackChangedListener(OnBackStackChangedListener listener) { if (mBackStackChangeListeners == null) { mBackStackChangeListeners = new ArrayList<OnBackStackChangedListener>(); @@ -304,12 +324,14 @@ final class FragmentManagerImpl implements FragmentManager { mBackStackChangeListeners.add(listener); } + @Override public void removeOnBackStackChangedListener(OnBackStackChangedListener listener) { if (mBackStackChangeListeners != null) { mBackStackChangeListeners.remove(listener); } } + @Override public void putFragment(Bundle bundle, String key, Fragment fragment) { if (fragment.mIndex < 0) { throw new IllegalStateException("Fragment " + fragment @@ -318,6 +340,7 @@ final class FragmentManagerImpl implements FragmentManager { bundle.putInt(key, fragment.mIndex); } + @Override public Fragment getFragment(Bundle bundle, String key) { int index = bundle.getInt(key, -1); if (index == -1) { @@ -335,6 +358,51 @@ final class FragmentManagerImpl implements FragmentManager { return f; } + @Override + public void dump(String prefix, FileDescriptor fd, PrintWriter writer, String[] args) { + if (mActive == null || mActive.size() <= 0) { + return; + } + + writer.print(prefix); writer.println("Active Fragments:"); + + String innerPrefix = prefix + " "; + + int N = mActive.size(); + for (int i=0; i<N; i++) { + Fragment f = mActive.get(i); + if (f != null) { + writer.print(prefix); writer.print(" #"); writer.print(i); + writer.print(": "); writer.println(f.toString()); + f.dump(innerPrefix, fd, writer, args); + } + } + + if (mAdded != null) { + N = mAdded.size(); + if (N > 0) { + writer.print(prefix); writer.println("Added Fragments:"); + for (int i=0; i<N; i++) { + Fragment f = mAdded.get(i); + writer.print(prefix); writer.print(" #"); writer.print(i); + writer.print(": "); writer.println(f.toString()); + } + } + } + + if (mBackStack != null) { + N = mBackStack.size(); + if (N > 0) { + writer.print(prefix); writer.println("Back Stack:"); + for (int i=0; i<N; i++) { + BackStackRecord bs = mBackStack.get(i); + writer.print(prefix); writer.print(" #"); writer.print(i); + writer.print(": "); writer.println(bs.toString()); + } + } + } + } + Animator loadAnimator(Fragment fragment, int transit, boolean enter, int transitionStyle) { Animator animObj = fragment.onCreateAnimator(transit, enter, @@ -436,7 +504,7 @@ final class FragmentManagerImpl implements FragmentManager { if (f.mContainerId != 0) { container = (ViewGroup)mActivity.findViewById(f.mContainerId); if (container == null) { - throw new IllegalArgumentException("New view found for id 0x" + throw new IllegalArgumentException("No view found for id 0x" + Integer.toHexString(f.mContainerId) + " for fragment " + f); } @@ -519,7 +587,7 @@ final class FragmentManagerImpl implements FragmentManager { if (f.mView != null) { // Need to save the current view state if not // done already. - if (!mActivity.isFinishing() && f.mSavedFragmentState == null) { + if (!mActivity.isFinishing() && f.mSavedViewState == null) { saveFragmentViewState(f); } } @@ -581,6 +649,10 @@ final class FragmentManagerImpl implements FragmentManager { f.mState = newState; } + void moveToState(Fragment f) { + moveToState(f, mCurState, 0, 0); + } + void moveToState(int newState, boolean always) { moveToState(newState, 0, 0, always); } @@ -655,7 +727,7 @@ final class FragmentManagerImpl implements FragmentManager { mNeedMenuInvalidate = true; } if (moveToStateNow) { - moveToState(fragment, mCurState, 0, 0); + moveToState(fragment); } } @@ -1010,37 +1082,42 @@ final class FragmentManagerImpl implements FragmentManager { FragmentState fs = new FragmentState(f); active[i] = fs; - if (mStateBundle == null) { - mStateBundle = new Bundle(); - } - f.onSaveInstanceState(mStateBundle); - if (!mStateBundle.isEmpty()) { - fs.mSavedFragmentState = mStateBundle; - mStateBundle = null; - } - - if (f.mView != null) { - saveFragmentViewState(f); - if (f.mSavedViewState != null) { + if (f.mState > Fragment.INITIALIZING && fs.mSavedFragmentState == null) { + if (mStateBundle == null) { + mStateBundle = new Bundle(); + } + f.onSaveInstanceState(mStateBundle); + if (!mStateBundle.isEmpty()) { + fs.mSavedFragmentState = mStateBundle; + mStateBundle = null; + } + + if (f.mView != null) { + saveFragmentViewState(f); + if (f.mSavedViewState != null) { + if (fs.mSavedFragmentState == null) { + fs.mSavedFragmentState = new Bundle(); + } + fs.mSavedFragmentState.putSparseParcelableArray( + FragmentManagerImpl.VIEW_STATE_TAG, f.mSavedViewState); + } + } + + if (f.mTarget != null) { if (fs.mSavedFragmentState == null) { fs.mSavedFragmentState = new Bundle(); } - fs.mSavedFragmentState.putSparseParcelableArray( - FragmentManagerImpl.VIEW_STATE_TAG, f.mSavedViewState); + putFragment(fs.mSavedFragmentState, + FragmentManagerImpl.TARGET_STATE_TAG, f.mTarget); + if (f.mTargetRequestCode != 0) { + fs.mSavedFragmentState.putInt( + FragmentManagerImpl.TARGET_REQUEST_CODE_STATE_TAG, + f.mTargetRequestCode); + } } - } - if (f.mTarget != null) { - if (fs.mSavedFragmentState == null) { - fs.mSavedFragmentState = new Bundle(); - } - putFragment(fs.mSavedFragmentState, - FragmentManagerImpl.TARGET_STATE_TAG, f.mTarget); - if (f.mTargetRequestCode != 0) { - fs.mSavedFragmentState.putInt( - FragmentManagerImpl.TARGET_REQUEST_CODE_STATE_TAG, - f.mTargetRequestCode); - } + } else { + fs.mSavedFragmentState = f.mSavedFragmentState; } if (DEBUG) Log.v(TAG, "Saved state of " + f + ": " @@ -1057,13 +1134,15 @@ final class FragmentManagerImpl implements FragmentManager { BackStackState[] backStack = null; // Build list of currently added fragments. - N = mAdded.size(); - if (N > 0) { - added = new int[N]; - for (int i=0; i<N; i++) { - added[i] = mAdded.get(i).mIndex; - if (DEBUG) Log.v(TAG, "saveAllState: adding fragment #" + i - + ": " + mAdded.get(i)); + if (mAdded != null) { + N = mAdded.size(); + if (N > 0) { + added = new int[N]; + for (int i=0; i<N; i++) { + added[i] = mAdded.get(i).mIndex; + if (DEBUG) Log.v(TAG, "saveAllState: adding fragment #" + i + + ": " + mAdded.get(i)); + } } } @@ -1104,6 +1183,7 @@ final class FragmentManagerImpl implements FragmentManager { fs.mInstance = f; f.mSavedViewState = null; f.mBackStackNesting = 0; + f.mInLayout = false; f.mAdded = false; if (fs.mSavedFragmentState != null) { f.mSavedViewState = fs.mSavedFragmentState.getSparseParcelableArray( diff --git a/core/java/android/app/IApplicationThread.java b/core/java/android/app/IApplicationThread.java index 039bcb9..1f8a7c58 100644 --- a/core/java/android/app/IApplicationThread.java +++ b/core/java/android/app/IApplicationThread.java @@ -105,7 +105,9 @@ public interface IApplicationThread extends IInterface { static final int EXTERNAL_STORAGE_UNAVAILABLE = 1; void dispatchPackageBroadcast(int cmd, String[] packages) throws RemoteException; void scheduleCrash(String msg) throws RemoteException; - + void dumpActivity(FileDescriptor fd, IBinder servicetoken, String[] args) + throws RemoteException; + String descriptor = "android.app.IApplicationThread"; int SCHEDULE_PAUSE_ACTIVITY_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION; @@ -143,4 +145,5 @@ public interface IApplicationThread extends IInterface { int DISPATCH_PACKAGE_BROADCAST_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+33; int SCHEDULE_CRASH_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+34; int DUMP_HEAP_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+35; + int DUMP_ACTIVITY_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+36; } diff --git a/core/java/android/app/backup/package.html b/core/java/android/app/backup/package.html index ae29994..e140349 100644 --- a/core/java/android/app/backup/package.html +++ b/core/java/android/app/backup/package.html @@ -3,6 +3,9 @@ <p>Contains the backup and restore functionality available to applications. If a user wipes the data on their device or upgrades to a new Android-powered device, all applications that have enabled backup will restore the user's previous data.</p> + +<p>For a detailed guide to using the backup APIs, see the <a +href="{@docRoot}guide/topics/data/backup.html">Data Backup</a> developer guide.</p> {@more} <p>All backup and restore operations are controlled by the {@link @@ -22,8 +25,5 @@ employing backup helpers such as {@link android.app.backup.SharedPreferencesBack <li>Restore the data saved to remote storage</li> </ul> -<p>For a detailed guide to using the backup APIs, see the <a -href="{@docRoot}guide/topics/data/backup.html">Data Backup</a> developer guide.</p> - </BODY> </HTML> diff --git a/core/java/android/content/CursorLoader.java b/core/java/android/content/CursorLoader.java index 42599ed..7776874 100644 --- a/core/java/android/content/CursorLoader.java +++ b/core/java/android/content/CursorLoader.java @@ -16,6 +16,7 @@ package android.content; +import android.database.ContentObserver; import android.database.Cursor; import android.net.Uri; @@ -37,14 +38,22 @@ public class CursorLoader extends AsyncTaskLoader<Cursor> { public Cursor loadInBackground() { Cursor cursor = getContext().getContentResolver().query(mUri, mProjection, mSelection, mSelectionArgs, mSortOrder); - // Ensure the cursor window is filled if (cursor != null) { + // Ensure the cursor window is filled cursor.getCount(); - cursor.registerContentObserver(mObserver); + registerContentObserver(cursor, mObserver); } return cursor; } + /** + * Registers an observer to get notifications from the content provider + * when the cursor needs to be refreshed. + */ + public void registerContentObserver(Cursor cursor, ContentObserver observer) { + cursor.registerContentObserver(mObserver); + } + /* Runs on the UI thread */ @Override public void deliverResult(Cursor cursor) { diff --git a/core/java/android/database/sqlite/DatabaseConnectionPool.java b/core/java/android/database/sqlite/DatabaseConnectionPool.java index 54b0605..4f5c4e6 100644 --- a/core/java/android/database/sqlite/DatabaseConnectionPool.java +++ b/core/java/android/database/sqlite/DatabaseConnectionPool.java @@ -16,6 +16,7 @@ package android.database.sqlite; +import android.content.res.Resources; import android.os.SystemClock; import android.util.Log; @@ -31,13 +32,9 @@ import java.util.Random; private static final String TAG = "DatabaseConnectionPool"; - /** The default connection pool size. It is set based on the amount of memory the device has. - * TODO: set this with 'a system call' which returns the amount of memory the device has - */ - private static final int DEFAULT_CONNECTION_POOL_SIZE = 1; - - /** the pool size set for this {@link SQLiteDatabase} */ - private volatile int mMaxPoolSize = DEFAULT_CONNECTION_POOL_SIZE; + /** The default connection pool size. */ + private volatile int mMaxPoolSize = + Resources.getSystem().getInteger(com.android.internal.R.integer.db_connection_pool_size); /** The connection pool objects are stored in this member. * TODO: revisit this data struct as the number of pooled connections increase beyond diff --git a/core/java/android/database/sqlite/SQLiteClosable.java b/core/java/android/database/sqlite/SQLiteClosable.java index a5e612b..96e6f22 100644 --- a/core/java/android/database/sqlite/SQLiteClosable.java +++ b/core/java/android/database/sqlite/SQLiteClosable.java @@ -23,12 +23,13 @@ import android.database.CursorWindow; */ public abstract class SQLiteClosable { private int mReferenceCount = 1; + private Object mLock = new Object(); // STOPSHIP remove this line protected abstract void onAllReferencesReleased(); protected void onAllReferencesReleasedFromContainer() {} public void acquireReference() { - synchronized(this) { + synchronized(mLock) { // STOPSHIP change 'mLock' to 'this' checkRefCount(); if (mReferenceCount <= 0) { throw new IllegalStateException( @@ -39,7 +40,7 @@ public abstract class SQLiteClosable { } public void releaseReference() { - synchronized(this) { + synchronized(mLock) { // STOPSHIP change 'mLock' to 'this' checkRefCount(); mReferenceCount--; if (mReferenceCount == 0) { @@ -49,7 +50,7 @@ public abstract class SQLiteClosable { } public void releaseReferenceFromContainer() { - synchronized(this) { + synchronized(mLock) { // STOPSHIP change 'mLock' to 'this' checkRefCount(); mReferenceCount--; if (mReferenceCount == 0) { diff --git a/core/java/android/hardware/Camera.java b/core/java/android/hardware/Camera.java index 26600f3..0d8228c 100644 --- a/core/java/android/hardware/Camera.java +++ b/core/java/android/hardware/Camera.java @@ -1182,14 +1182,17 @@ public class Camera { public static final String FOCUS_MODE_EDOF = "edof"; /** - * Continuous auto focus mode. The camera continuously tries to focus. - * This is ideal for shooting video or shooting photo of moving object. - * Auto focus starts when the parameter is set. Applications should not - * call {@link #autoFocus(AutoFocusCallback)} in this mode. To stop - * continuous focus, applications should change the focus mode to other - * modes. - */ - public static final String FOCUS_MODE_CONTINUOUS = "continuous"; + * Continuous auto focus mode intended for video recording. The camera + * continuously tries to focus. This is ideal for shooting video. + * Applications still can call {@link + * #takePicture(Camera.ShutterCallback, Camera.PictureCallback, + * Camera.PictureCallback)} in this mode but the subject may not be in + * focus. Auto focus starts when the parameter is set. Applications + * should not call {@link #autoFocus(AutoFocusCallback)} in this mode. + * To stop continuous focus, applications should change the focus mode + * to other modes. + */ + public static final String FOCUS_MODE_CONTINUOUS_VIDEO = "continuous-video"; // Indices for focus distance array. /** @@ -2023,7 +2026,7 @@ public class Camera { * @see #FOCUS_MODE_MACRO * @see #FOCUS_MODE_FIXED * @see #FOCUS_MODE_EDOF - * @see #FOCUS_MODE_CONTINUOUS + * @see #FOCUS_MODE_CONTINUOUS_VIDEO */ public String getFocusMode() { return get(KEY_FOCUS_MODE); @@ -2225,8 +2228,8 @@ public class Camera { * #autoFocus(AutoFocusCallback)}, {@link #cancelAutoFocus}, or {@link * #startPreview()}. Applications can call {@link #getParameters()} * and this method anytime to get the latest focus distances. If the - * focus mode is FOCUS_MODE_CONTINUOUS, focus distances may change from - * time to time. + * focus mode is FOCUS_MODE_CONTINUOUS_VIDEO, focus distances may change + * from time to time. * * This method is intended to estimate the distance between the camera * and the subject. After autofocus, the subject distance may be within diff --git a/core/java/android/net/DownloadManager.java b/core/java/android/net/DownloadManager.java index 00c1aac..fc5ebb3 100644 --- a/core/java/android/net/DownloadManager.java +++ b/core/java/android/net/DownloadManager.java @@ -25,7 +25,6 @@ import android.os.ParcelFileDescriptor; import android.provider.BaseColumns; import android.provider.Downloads; -import java.io.File; import java.io.FileNotFoundException; import java.util.ArrayList; import java.util.Arrays; @@ -195,6 +194,12 @@ public class DownloadManager { public final static int ERROR_CANNOT_RESUME = 1008; /** + * Value of {@link #COLUMN_ERROR_CODE} when the requested destination file already exists (the + * download manager will not overwrite an existing file). + */ + public final static int ERROR_FILE_ALREADY_EXISTS = 1009; + + /** * Broadcast intent action sent by the download manager when a download completes. */ public final static String ACTION_DOWNLOAD_COMPLETE = "android.intent.action.DOWNLOAD_COMPLETE"; @@ -235,10 +240,11 @@ public class DownloadManager { Downloads.COLUMN_URI, Downloads.COLUMN_MIME_TYPE, Downloads.COLUMN_TOTAL_BYTES, - Downloads._DATA, Downloads.COLUMN_STATUS, Downloads.COLUMN_CURRENT_BYTES, Downloads.COLUMN_LAST_MODIFICATION, + Downloads.COLUMN_DESTINATION, + Downloads.Impl.COLUMN_FILE_NAME_HINT, }; private static final Set<String> LONG_COLUMNS = new HashSet<String>( @@ -359,7 +365,6 @@ public class DownloadManager { * * @param show whether the download manager should show a notification for this download. * @return this object - * @hide */ public Request setShowRunningNotification(boolean show) { mShowNotification = show; @@ -820,15 +825,10 @@ public class DownloadManager { } private String getLocalUri() { - String localUri = getUnderlyingString(Downloads.Impl._DATA); - if (localUri == null) { - return null; - } - long destinationType = getUnderlyingLong(Downloads.Impl.COLUMN_DESTINATION); if (destinationType == Downloads.Impl.DESTINATION_FILE_URI) { - // return file URI for external download - return Uri.fromFile(new File(localUri)).toString(); + // return client-provided file URI for external download + return getUnderlyingString(Downloads.Impl.COLUMN_FILE_NAME_HINT); } // return content URI for cache download @@ -894,6 +894,9 @@ public class DownloadManager { case Downloads.Impl.STATUS_CANNOT_RESUME: return ERROR_CANNOT_RESUME; + case Downloads.Impl.STATUS_FILE_ALREADY_EXISTS_ERROR: + return ERROR_FILE_ALREADY_EXISTS; + default: return ERROR_UNKNOWN; } diff --git a/core/java/android/net/LinkCapabilities.aidl b/core/java/android/net/LinkCapabilities.aidl index 5f47baf..df72599 100644 --- a/core/java/android/net/LinkCapabilities.aidl +++ b/core/java/android/net/LinkCapabilities.aidl @@ -1,7 +1,6 @@ /* ** -** Copyright (C) 2009 Qualcomm Innovation Center, Inc. All Rights Reserved. -** Copyright (C) 2009 The Android Open Source Project +** Copyright (C) 2010 The Android Open Source Project ** ** Licensed under the Apache License, Version 2.0 (the "License"); ** you may not use this file except in compliance with the License. diff --git a/core/java/android/net/LinkCapabilities.java b/core/java/android/net/LinkCapabilities.java index d10a759..eb9166f 100644 --- a/core/java/android/net/LinkCapabilities.java +++ b/core/java/android/net/LinkCapabilities.java @@ -146,7 +146,7 @@ public class LinkCapabilities implements Parcelable { // code these to match /** Default Role */ - public static final String DEFAULT = "0"; + public static final String DEFAULT = "default"; /** Bulk down load */ public static final String BULK_DOWNLOAD = "bulk.download"; /** Bulk upload */ diff --git a/core/java/android/net/LinkProperties.aidl b/core/java/android/net/LinkProperties.aidl index 73c7988..9cd06d5 100644 --- a/core/java/android/net/LinkProperties.aidl +++ b/core/java/android/net/LinkProperties.aidl @@ -1,7 +1,6 @@ /* ** -** Copyright (C) 2009 Qualcomm Innovation Center, Inc. All Rights Reserved. -** Copyright (C) 2009 The Android Open Source Project +** Copyright (C) 2010 The Android Open Source Project ** ** Licensed under the Apache License, Version 2.0 (the "License"); ** you may not use this file except in compliance with the License. diff --git a/core/java/android/net/LinkProperties.java b/core/java/android/net/LinkProperties.java index 24aebfc..f411eac 100644 --- a/core/java/android/net/LinkProperties.java +++ b/core/java/android/net/LinkProperties.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2008 The Android Open Source Project + * Copyright (C) 2010 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/core/java/android/net/LinkSocket.java b/core/java/android/net/LinkSocket.java index d416ed0..5aa6451 100644 --- a/core/java/android/net/LinkSocket.java +++ b/core/java/android/net/LinkSocket.java @@ -197,6 +197,17 @@ public class LinkSocket extends Socket { /** * Connect a duplicate socket socket to the same remote host address and port + * as the original with a timeout parameter. + * @param timeout the timeout value in milliseconds or 0 for infinite timeout + * @throws IOException if the socket is already connected or an error occurs + * while connecting + */ + public void connect(int timeout) throws IOException { + if (DBG) log("connect(timeout) EX"); + } + + /** + * Connect a duplicate socket socket to the same remote host address and port * as the original. * @throws IOException if the socket is already connected or an error occurs * while connecting @@ -237,9 +248,9 @@ public class LinkSocket extends Socket { */ @Override @Deprecated - public void bind(SocketAddress localAddr) throws IOException { + public void bind(SocketAddress localAddr) throws UnsupportedOperationException { if (DBG) log("bind(localAddr) EX throws IOException"); - throw new IOException("bind is deprecated for LinkSocket"); + throw new UnsupportedOperationException("bind is deprecated for LinkSocket"); } /** diff --git a/core/java/android/net/LinkSocketNotifier.java b/core/java/android/net/LinkSocketNotifier.java index 183c767..28e2834 100644 --- a/core/java/android/net/LinkSocketNotifier.java +++ b/core/java/android/net/LinkSocketNotifier.java @@ -84,5 +84,5 @@ public interface LinkSocketNotifier { * Get notified of every capability change * check for LinkSockets on that Link that are interested in that Capability - call them */ - public void onCapabilityChanged(LinkSocket socket, LinkCapabilities changedCapabilities); + public void onCapabilitiesChanged(LinkSocket socket, LinkCapabilities changedCapabilities); } diff --git a/core/java/android/net/LocalSocket.java b/core/java/android/net/LocalSocket.java index 4039a69..3ee8a80 100644 --- a/core/java/android/net/LocalSocket.java +++ b/core/java/android/net/LocalSocket.java @@ -70,8 +70,11 @@ public class LocalSocket { if (!implCreated) { synchronized (this) { if (!implCreated) { - implCreated = true; - impl.create(true); + try { + impl.create(true); + } finally { + implCreated = true; + } } } } diff --git a/core/java/android/net/ProxyProperties.java b/core/java/android/net/ProxyProperties.java index fb59fed..140b71f 100644 --- a/core/java/android/net/ProxyProperties.java +++ b/core/java/android/net/ProxyProperties.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2007 The Android Open Source Project + * Copyright (C) 2010 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/core/java/android/os/BatteryStats.java b/core/java/android/os/BatteryStats.java index 1e88c56..ba8014f 100644 --- a/core/java/android/os/BatteryStats.java +++ b/core/java/android/os/BatteryStats.java @@ -397,7 +397,7 @@ public abstract class BatteryStats implements Parcelable { } } - public final class HistoryItem implements Parcelable { + public final static class HistoryItem implements Parcelable { public HistoryItem next; public long time; @@ -482,6 +482,18 @@ public abstract class BatteryStats implements Parcelable { dest.writeInt(states); } + public void setTo(HistoryItem o) { + time = o.time; + cmd = o.cmd; + batteryLevel = o.batteryLevel; + batteryStatus = o.batteryStatus; + batteryHealth = o.batteryHealth; + batteryPlugType = o.batteryPlugType; + batteryTemperature = o.batteryTemperature; + batteryVoltage = o.batteryVoltage; + states = o.states; + } + public void setTo(long time, byte cmd, HistoryItem o) { this.time = time; this.cmd = cmd; @@ -526,6 +538,10 @@ public abstract class BatteryStats implements Parcelable { } } + public abstract boolean startIteratingHistoryLocked(); + + public abstract boolean getNextHistoryLocked(HistoryItem out); + /** * Return the current history of battery state changes. */ @@ -1688,8 +1704,8 @@ public abstract class BatteryStats implements Parcelable { */ @SuppressWarnings("unused") public void dumpLocked(PrintWriter pw) { - HistoryItem rec = getHistory(); - if (rec != null) { + final HistoryItem rec = new HistoryItem(); + if (startIteratingHistoryLocked()) { pw.println("Battery History:"); long now = getHistoryBaseTime() + SystemClock.elapsedRealtime(); int oldState = 0; @@ -1698,7 +1714,7 @@ public abstract class BatteryStats implements Parcelable { int oldPlug = -1; int oldTemp = -1; int oldVolt = -1; - while (rec != null) { + while (getNextHistoryLocked(rec)) { pw.print(" "); TimeUtils.formatDuration(rec.time-now, pw, TimeUtils.HUNDRED_DAY_FIELD_LEN); pw.print(" "); @@ -1803,7 +1819,6 @@ public abstract class BatteryStats implements Parcelable { pw.println(); } oldState = rec.states; - rec = rec.next; } pw.println(""); } diff --git a/core/java/android/os/MessageQueue.java b/core/java/android/os/MessageQueue.java index e89f7c2..be5b685 100644 --- a/core/java/android/os/MessageQueue.java +++ b/core/java/android/os/MessageQueue.java @@ -33,6 +33,7 @@ import java.util.ArrayList; public class MessageQueue { Message mMessages; private final ArrayList<IdleHandler> mIdleHandlers = new ArrayList<IdleHandler>(); + private IdleHandler[] mPendingIdleHandlers; private boolean mQuiting = false; boolean mQuitAllowed = true; @@ -105,91 +106,75 @@ public class MessageQueue { } final Message next() { - boolean tryIdle = true; - // when we start out, we'll just touch the input pipes and then go from there - int timeToNextEventMillis = 0; + int pendingIdleHandlerCount = -1; // -1 only during first iteration + int nextPollTimeoutMillis = 0; - while (true) { - long now; - Object[] idlers = null; - - boolean dispatched = nativePollOnce(timeToNextEventMillis); + for (;;) { + if (nextPollTimeoutMillis != 0) { + Binder.flushPendingCommands(); + } + nativePollOnce(nextPollTimeoutMillis); - // Try to retrieve the next message, returning if found. synchronized (this) { - now = SystemClock.uptimeMillis(); - Message msg = pullNextLocked(now); + // Try to retrieve the next message. Return if found. + final long now = SystemClock.uptimeMillis(); + final Message msg = mMessages; if (msg != null) { - msg.markInUse(); - return msg; + final long when = msg.when; + if (now >= when) { + mMessages = msg.next; + if (Config.LOGV) Log.v("MessageQueue", "Returning message: " + msg); + msg.markInUse(); + return msg; + } else { + nextPollTimeoutMillis = (int) Math.min(when - now, Integer.MAX_VALUE); + } + } else { + nextPollTimeoutMillis = -1; + } + + // If first time, then get the number of idlers to run. + if (pendingIdleHandlerCount < 0) { + pendingIdleHandlerCount = mIdleHandlers.size(); } - - if (tryIdle && mIdleHandlers.size() > 0) { - idlers = mIdleHandlers.toArray(); + if (pendingIdleHandlerCount == 0) { + // No idle handlers to run. Loop and wait some more. + continue; } - } - - // There was no message so we are going to wait... but first, - // if there are any idle handlers let them know. - boolean didIdle = false; - if (idlers != null) { - for (Object idler : idlers) { - boolean keep = false; - try { - didIdle = true; - keep = ((IdleHandler)idler).queueIdle(); - } catch (Throwable t) { - Log.wtf("MessageQueue", "IdleHandler threw exception", t); - } - if (!keep) { - synchronized (this) { - mIdleHandlers.remove(idler); - } - } + if (mPendingIdleHandlers == null) { + mPendingIdleHandlers = new IdleHandler[Math.max(pendingIdleHandlerCount, 4)]; } - } - - // While calling an idle handler, a new message could have been - // delivered... so go back and look again for a pending message. - if (didIdle) { - tryIdle = false; - continue; + mPendingIdleHandlers = mIdleHandlers.toArray(mPendingIdleHandlers); } - synchronized (this) { - // No messages, nobody to tell about it... time to wait! - if (mMessages != null) { - long longTimeToNextEventMillis = mMessages.when - now; - - if (longTimeToNextEventMillis > 0) { - Binder.flushPendingCommands(); - timeToNextEventMillis = (int) Math.min(longTimeToNextEventMillis, - Integer.MAX_VALUE); - } else { - timeToNextEventMillis = 0; + // Run the idle handlers. + // We only ever reach this code block during the first iteration. + for (int i = 0; i < pendingIdleHandlerCount; i++) { + final IdleHandler idler = mPendingIdleHandlers[i]; + mPendingIdleHandlers[i] = null; // release the reference to the handler + + boolean keep = false; + try { + keep = idler.queueIdle(); + } catch (Throwable t) { + Log.wtf("MessageQueue", "IdleHandler threw exception", t); + } + + if (!keep) { + synchronized (this) { + mIdleHandlers.remove(idler); } - } else { - Binder.flushPendingCommands(); - timeToNextEventMillis = -1; } } - // loop to the while(true) and do the appropriate nativeWait(when) - } - } - final Message pullNextLocked(long now) { - Message msg = mMessages; - if (msg != null) { - if (now >= msg.when) { - mMessages = msg.next; - if (Config.LOGV) Log.v( - "MessageQueue", "Returning message: " + msg); - return msg; - } - } + // Reset the idle handler count to 0 so we do not run them again. + pendingIdleHandlerCount = 0; - return null; + // While calling an idle handler, a new message could have been delivered + // so go back and look again for a pending message without waiting. + nextPollTimeoutMillis = 0; + } } final boolean enqueueMessage(Message msg, long when) { diff --git a/core/java/android/os/RecoverySystem.java b/core/java/android/os/RecoverySystem.java index 5fea6fe..e56e257 100644 --- a/core/java/android/os/RecoverySystem.java +++ b/core/java/android/os/RecoverySystem.java @@ -307,8 +307,10 @@ public class RecoverySystem { * Requires the {@link android.Manifest.permission#REBOOT} permission. * * @param context the Context to use - * @param packageFile the update package to install. Currently - * must be on the /cache or /data partitions. + * @param packageFile the update package to install. Must be on + * a partition mountable by recovery. (The set of partitions + * known to recovery may vary from device to device. Generally, + * /cache and /data are safe.) * * @throws IOException if writing the recovery command file * fails, or if the reboot itself fails. @@ -316,15 +318,6 @@ public class RecoverySystem { public static void installPackage(Context context, File packageFile) throws IOException { String filename = packageFile.getCanonicalPath(); - - if (filename.startsWith("/cache/")) { - filename = "CACHE:" + filename.substring(7); - } else if (filename.startsWith("/data/")) { - filename = "DATA:" + filename.substring(6); - } else { - throw new IllegalArgumentException( - "Must start with /cache or /data: " + filename); - } Log.w(TAG, "!!! REBOOTING TO INSTALL " + filename + " !!!"); String arg = "--update_package=" + filename; bootCommand(context, arg); diff --git a/core/java/android/provider/Downloads.java b/core/java/android/provider/Downloads.java index 74c7372..1e358c9 100644 --- a/core/java/android/provider/Downloads.java +++ b/core/java/android/provider/Downloads.java @@ -895,6 +895,14 @@ public final class Downloads { */ public static final String COLUMN_IS_VISIBLE_IN_DOWNLOADS_UI = "is_visible_in_downloads_ui"; + /** + * If true, the user has confirmed that this download can proceed over the mobile network + * even though it exceeds the recommended maximum size. + * <P>Type: BOOLEAN</P> + */ + public static final String COLUMN_BYPASS_RECOMMENDED_SIZE_LIMIT = + "bypass_recommended_size_limit"; + /* * Lists the destinations that an application can specify for a download. */ @@ -1077,7 +1085,12 @@ public final class Downloads { /** * The lowest-valued error status that is not an actual HTTP status code. */ - public static final int MIN_ARTIFICIAL_ERROR_STATUS = 489; + public static final int MIN_ARTIFICIAL_ERROR_STATUS = 488; + + /** + * The requested destination file already exists. + */ + public static final int STATUS_FILE_ALREADY_EXISTS_ERROR = 488; /** * Some possibly transient error occurred, but we can't resume the download. diff --git a/core/java/android/provider/Mtp.java b/core/java/android/provider/Mtp.java index e25dbad..de161e7 100644 --- a/core/java/android/provider/Mtp.java +++ b/core/java/android/provider/Mtp.java @@ -75,7 +75,7 @@ public final class Mtp return Uri.parse(CONTENT_AUTHORITY_DEVICE_SLASH + deviceID + "/storage"); } - public static Uri getContentUri(int deviceID, int storageID) { + public static Uri getContentUri(int deviceID, long storageID) { return Uri.parse(CONTENT_AUTHORITY_DEVICE_SLASH + deviceID + "/storage/" + storageID); } @@ -97,17 +97,17 @@ public final class Mtp */ public static final class Object implements BaseColumns { - public static Uri getContentUri(int deviceID, int objectID) { + public static Uri getContentUri(int deviceID, long objectID) { return Uri.parse(CONTENT_AUTHORITY_DEVICE_SLASH + deviceID + "/object/" + objectID); } - public static Uri getContentUriForObjectChildren(int deviceID, int objectID) { + public static Uri getContentUriForObjectChildren(int deviceID, long objectID) { return Uri.parse(CONTENT_AUTHORITY_DEVICE_SLASH + deviceID + "/object/" + objectID + "/child"); } - public static Uri getContentUriForStorageChildren(int deviceID, int storageID) { + public static Uri getContentUriForStorageChildren(int deviceID, long storageID) { return Uri.parse(CONTENT_AUTHORITY_DEVICE_SLASH + deviceID + "/storage/" + storageID + "/child"); } @@ -147,7 +147,7 @@ public final class Mtp * or any of the valid MTP object formats as defined in the MTP specification. * <P>Type: INTEGER</P> */ - public static final String THUMB_FORMAT = "format"; + public static final String THUMB_FORMAT = "thumb_format"; /** * The size of the object's thumbnail in bytes. diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java index 5b4aedb..51dc6ae 100644 --- a/core/java/android/provider/Settings.java +++ b/core/java/android/provider/Settings.java @@ -1494,6 +1494,12 @@ public final class Settings { public static final String AUTO_TIME = "auto_time"; /** + * Value to specify if the user prefers the time zone + * to be automatically fetched from the network (NITZ). 1=yes, 0=no + */ + public static final String AUTO_TIME_ZONE = "auto_time_zone"; + + /** * Display times as 12 or 24 hours * 12 * 24 @@ -1775,6 +1781,7 @@ public final class Settings { TEXT_AUTO_PUNCTUATE, TEXT_SHOW_PASSWORD, AUTO_TIME, + AUTO_TIME_ZONE, TIME_12_24, DATE_FORMAT, ACCELEROMETER_ROTATION, @@ -3530,6 +3537,15 @@ public final class Settings { "download_manager_max_bytes_over_mobile"; /** + * The recommended maximum size, in bytes, of a download that the download manager should + * transfer over a non-wifi connection. Over this size, the use will be warned, but will + * have the option to start the download over the mobile connection anyway. + * @hide + */ + public static final String DOWNLOAD_RECOMMENDED_MAX_BYTES_OVER_MOBILE = + "download_manager_recommended_max_bytes_over_mobile"; + + /** * ms during which to consume extra events related to Inet connection condition * after a transtion to fully-connected * @hide diff --git a/core/java/android/text/method/ArrowKeyMovementMethod.java b/core/java/android/text/method/ArrowKeyMovementMethod.java index 0408673..733b535 100644 --- a/core/java/android/text/method/ArrowKeyMovementMethod.java +++ b/core/java/android/text/method/ArrowKeyMovementMethod.java @@ -314,6 +314,8 @@ public class ArrowKeyMovementMethod implements MovementMethod { * {@link MotionEvent#ACTION_CANCEL} event), the controller is reset to null. * * @param cursorController A cursor controller implementation + * + * @hide */ public void setCursorController(CursorController cursorController) { mCursorController = cursorController; diff --git a/core/java/android/util/Base64InputStream.java b/core/java/android/util/Base64InputStream.java index da3911d..e9dac24 100644 --- a/core/java/android/util/Base64InputStream.java +++ b/core/java/android/util/Base64InputStream.java @@ -112,7 +112,7 @@ public class Base64InputStream extends FilterInputStream { if (outputStart >= outputEnd) { return -1; } else { - return coder.output[outputStart++]; + return coder.output[outputStart++] & 0xff; } } diff --git a/core/java/android/view/LayoutInflater.java b/core/java/android/view/LayoutInflater.java index 458274f..d24af52 100644 --- a/core/java/android/view/LayoutInflater.java +++ b/core/java/android/view/LayoutInflater.java @@ -67,6 +67,7 @@ public abstract class LayoutInflater { // these are optional, set by the caller private boolean mFactorySet; private Factory mFactory; + private Factory2 mFactory2; private Filter mFilter; private final Object[] mConstructorArgs = new Object[2]; @@ -122,12 +123,33 @@ public abstract class LayoutInflater { public View onCreateView(String name, Context context, AttributeSet attrs); } - private static class FactoryMerger implements Factory { + public interface Factory2 extends Factory { + /** + * Version of {@link #onCreateView(String, Context, AttributeSet)} + * that also supplies the parent that the view created view will be + * placed in. + * + * @param parent The parent that the created view will be placed + * in; <em>note that this may be null</em>. + * @param name Tag name to be inflated. + * @param context The context the view is being created in. + * @param attrs Inflation attributes as specified in XML file. + * + * @return View Newly created view. Return null for the default + * behavior. + */ + public View onCreateView(View parent, String name, Context context, AttributeSet attrs); + } + + private static class FactoryMerger implements Factory2 { private final Factory mF1, mF2; + private final Factory2 mF12, mF22; - FactoryMerger(Factory f1, Factory f2) { + FactoryMerger(Factory f1, Factory2 f12, Factory f2, Factory2 f22) { mF1 = f1; mF2 = f2; + mF12 = f12; + mF22 = f22; } public View onCreateView(String name, Context context, AttributeSet attrs) { @@ -135,6 +157,14 @@ public abstract class LayoutInflater { if (v != null) return v; return mF2.onCreateView(name, context, attrs); } + + public View onCreateView(View parent, String name, Context context, AttributeSet attrs) { + View v = mF12 != null ? mF12.onCreateView(parent, name, context, attrs) + : mF1.onCreateView(name, context, attrs); + if (v != null) return v; + return mF22 != null ? mF22.onCreateView(parent, name, context, attrs) + : mF2.onCreateView(name, context, attrs); + } } /** @@ -162,6 +192,7 @@ public abstract class LayoutInflater { protected LayoutInflater(LayoutInflater original, Context newContext) { mContext = newContext; mFactory = original.mFactory; + mFactory2 = original.mFactory2; mFilter = original.mFilter; } @@ -200,7 +231,7 @@ public abstract class LayoutInflater { } /** - * Return the current factory (or null). This is called on each element + * Return the current {@link Factory} (or null). This is called on each element * name. If the factory returns a View, add that to the hierarchy. If it * returns null, proceed to call onCreateView(name). */ @@ -209,6 +240,17 @@ public abstract class LayoutInflater { } /** + * Return the current {@link Factory2}. Returns null if no factory is set + * or the set factory does not implement the {@link Factory2} interface. + * This is called on each element + * name. If the factory returns a View, add that to the hierarchy. If it + * returns null, proceed to call onCreateView(name). + */ + public final Factory2 getFactory2() { + return mFactory2; + } + + /** * Attach a custom Factory interface for creating views while using * this LayoutInflater. This must not be null, and can only be set once; * after setting, you can not change the factory. This is @@ -234,7 +276,26 @@ public abstract class LayoutInflater { if (mFactory == null) { mFactory = factory; } else { - mFactory = new FactoryMerger(factory, mFactory); + mFactory = new FactoryMerger(factory, null, mFactory, mFactory2); + } + } + + /** + * Like {@link #setFactory}, but allows you to set a {@link Factory2} + * interface. + */ + public void setFactory2(Factory2 factory) { + if (mFactorySet) { + throw new IllegalStateException("A factory has already been set on this LayoutInflater"); + } + if (factory == null) { + throw new NullPointerException("Given factory can not be null"); + } + mFactorySet = true; + if (mFactory == null) { + mFactory = mFactory2 = factory; + } else { + mFactory = new FactoryMerger(factory, factory, mFactory, mFactory2); } } @@ -384,7 +445,7 @@ public abstract class LayoutInflater { rInflate(parser, root, attrs, false); } else { // Temp is the root view that was found in the xml - View temp = createViewFromTag(name, attrs); + View temp = createViewFromTag(root, name, attrs); ViewGroup.LayoutParams params = null; @@ -557,10 +618,27 @@ public abstract class LayoutInflater { return createView(name, "android.view.", attrs); } + /** + * Version of {@link #onCreateView(String, AttributeSet)} that also + * takes the future parent of the view being constructure. The default + * implementation simply calls {@link #onCreateView(String, AttributeSet)}. + * + * @param parent The future parent of the returned view. <em>Note that + * this may be null.</em> + * @param name The fully qualified class name of the View to be create. + * @param attrs An AttributeSet of attributes to apply to the View. + * + * @return View The View created. + */ + protected View onCreateView(View parent, String name, AttributeSet attrs) + throws ClassNotFoundException { + return onCreateView(name, attrs); + } + /* * default visibility so the BridgeInflater can override it. */ - View createViewFromTag(String name, AttributeSet attrs) { + View createViewFromTag(View parent, String name, AttributeSet attrs) { if (name.equals("view")) { name = attrs.getAttributeValue(null, "class"); } @@ -568,12 +646,14 @@ public abstract class LayoutInflater { if (DEBUG) System.out.println("******** Creating view: " + name); try { - View view = (mFactory == null) ? null : mFactory.onCreateView(name, - mContext, attrs); + View view; + if (mFactory2 != null) view = mFactory2.onCreateView(parent, name, mContext, attrs); + else if (mFactory != null) view = mFactory.onCreateView(name, mContext, attrs); + else view = null; if (view == null) { if (-1 == name.indexOf('.')) { - view = onCreateView(name, attrs); + view = onCreateView(parent, name, attrs); } else { view = createView(name, null, attrs); } @@ -628,7 +708,7 @@ public abstract class LayoutInflater { } else if (TAG_MERGE.equals(name)) { throw new InflateException("<merge /> must be the root element"); } else { - final View view = createViewFromTag(name, attrs); + final View view = createViewFromTag(parent, name, attrs); final ViewGroup viewGroup = (ViewGroup) parent; final ViewGroup.LayoutParams params = viewGroup.generateLayoutParams(attrs); rInflate(parser, view, attrs, true); @@ -689,7 +769,7 @@ public abstract class LayoutInflater { // Inflate all children. rInflate(childParser, parent, childAttrs, false); } else { - final View view = createViewFromTag(childName, childAttrs); + final View view = createViewFromTag(parent, childName, childAttrs); final ViewGroup group = (ViewGroup) parent; // We try to load the layout params set in the <include /> tag. If diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java index 97d58d2..3d5aff7 100644 --- a/core/java/android/view/View.java +++ b/core/java/android/view/View.java @@ -1613,12 +1613,6 @@ public class View implements Drawable.Callback, KeyEvent.Callback, Accessibility private static final int AWAKEN_SCROLL_BARS_ON_ATTACH = 0x08000000; /** - * Indicates that this view has a visible/touchable overlay. - * @hide - */ - static final int HAS_OVERLAY = 0x10000000; - - /** * Indicates that pivotX or pivotY were explicitly set and we should not assume the center * for transform operations * @@ -3040,57 +3034,6 @@ public class View implements Drawable.Callback, KeyEvent.Callback, Accessibility resetPressedState(); } - /** - * Enable or disable drawing overlays after a full drawing pass. This enables a view to - * draw on a topmost overlay layer after normal drawing completes and get right of first - * refusal for touch events in the window. - * - * <em>Warning:</em> Views that use this feature should take care to disable/enable overlay - * appropriately when they are attached/detached from their window. All overlays should be - * disabled when detached. - * - * @param enabled true if overlay drawing should be enabled for this view, false otherwise - * - * @see #onDrawOverlay(Canvas) - * - * @hide - */ - protected void setOverlayEnabled(boolean enabled) { - final boolean oldValue = (mPrivateFlags & HAS_OVERLAY) == HAS_OVERLAY; - mPrivateFlags = (mPrivateFlags & ~HAS_OVERLAY) | (enabled ? HAS_OVERLAY : 0); - if (enabled != oldValue) { - final ViewParent parent = getParent(); - if (parent != null) { - try { - parent.childOverlayStateChanged(this); - } catch (AbstractMethodError e) { - Log.e(VIEW_LOG_TAG, "Could not propagate hasOverlay state", e); - } - } - } - } - - /** - * @return true if this View has an overlay enabled. - * - * @see #setOverlayEnabled(boolean) - * @see #onDrawOverlay(Canvas) - * - * @hide - */ - public boolean isOverlayEnabled() { - return (mPrivateFlags & HAS_OVERLAY) == HAS_OVERLAY; - } - - /** - * Override this method to draw on an overlay layer above all other views in the window - * after the standard drawing pass is complete. This allows a view to draw outside its - * normal boundaries. - * @hide - */ - public void onDrawOverlay(Canvas canvas) { - } - private void resetPressedState() { if ((mViewFlags & ENABLED_MASK) == DISABLED) { return; diff --git a/core/java/android/view/ViewGroup.java b/core/java/android/view/ViewGroup.java index 3db4857..2b92e87 100644 --- a/core/java/android/view/ViewGroup.java +++ b/core/java/android/view/ViewGroup.java @@ -245,11 +245,6 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager protected static final int FLAG_DISALLOW_INTERCEPT = 0x80000; /** - * When set, at least one child of this ViewGroup will return true from hasOverlay. - */ - private static final int FLAG_CHILD_HAS_OVERLAY = 0x100000; - - /** * When set, this ViewGroup will split MotionEvents to multiple child Views when appropriate. */ private static final int FLAG_SPLIT_MOTION_EVENTS = 0x200000; @@ -910,33 +905,6 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager final View[] children = mChildren; final int count = mChildrenCount; - // Check for children with overlays first. They don't rely on hit rects to determine - // if they can accept a new touch event. - if ((mGroupFlags & FLAG_CHILD_HAS_OVERLAY) == FLAG_CHILD_HAS_OVERLAY) { - for (int i = count - 1; i >= 0; i--) { - final View child = children[i]; - // Don't let children respond to events as an overlay during an animation. - if ((child.mViewFlags & VISIBILITY_MASK) == VISIBLE - && child.getAnimation() == null - && child.isOverlayEnabled()) { - // offset the event to the view's coordinate system - final float xc = scrolledXFloat - child.mLeft; - final float yc = scrolledYFloat - child.mTop; - ev.setLocation(xc, yc); - child.mPrivateFlags &= ~CANCEL_NEXT_UP_EVENT; - if (child.dispatchTouchEvent(ev)) { - // Event handled, we have a target now. - mMotionTarget = child; - return true; - } - // The event didn't get handled, try the next view. - // Don't reset the event's location, it's not - // necessary here. - } - } - } - - // Now check views normally. for (int i = count - 1; i >= 0; i--) { final View child = children[i]; if ((child.mViewFlags & VISIBILITY_MASK) == VISIBLE @@ -2774,8 +2742,6 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager if (clearChildFocus != null) { clearChildFocus(clearChildFocus); } - - mGroupFlags &= ~FLAG_CHILD_HAS_OVERLAY; } /** @@ -3024,8 +2990,7 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager final int left = mLeft; final int top = mTop; - if ((mGroupFlags & FLAG_CHILD_HAS_OVERLAY) == FLAG_CHILD_HAS_OVERLAY || - dirty.intersect(0, 0, mRight - left, mBottom - top) || + if (dirty.intersect(0, 0, mRight - left, mBottom - top) || (mPrivateFlags & DRAW_ANIMATION) == DRAW_ANIMATION) { mPrivateFlags &= ~DRAWING_CACHE_VALID; @@ -4013,69 +3978,6 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager } /** - * Called when a child's overlay state changes between enabled/disabled. - * @param child Child view whose state has changed or null - * @hide - */ - public void childOverlayStateChanged(View child) { - boolean childHasOverlay = false; - if (child != null) { - childHasOverlay = child.isOverlayEnabled(); - } else { - final int childCount = getChildCount(); - for (int i = 0; i < childCount; i++) { - if (childHasOverlay |= getChildAt(i).isOverlayEnabled()) { - break; - } - } - } - - final boolean hasChildWithOverlay = childHasOverlay || - (mGroupFlags & FLAG_CHILD_HAS_OVERLAY) == FLAG_CHILD_HAS_OVERLAY; - - final boolean oldValue = isOverlayEnabled(); - mGroupFlags = (mGroupFlags & ~FLAG_CHILD_HAS_OVERLAY) | - (hasChildWithOverlay ? FLAG_CHILD_HAS_OVERLAY : 0); - if (isOverlayEnabled() != oldValue) { - final ViewParent parent = getParent(); - if (parent != null) { - try { - parent.childOverlayStateChanged(this); - } catch (AbstractMethodError e) { - Log.e("ViewGroup", "Could not propagate hasOverlay state", e); - } - } - } - } - - /** - * @hide - */ - public boolean isOverlayEnabled() { - return super.isOverlayEnabled() || - ((mGroupFlags & FLAG_CHILD_HAS_OVERLAY) == FLAG_CHILD_HAS_OVERLAY); - } - - /** - * @hide - */ - @Override - public void onDrawOverlay(Canvas canvas) { - if ((mGroupFlags & FLAG_CHILD_HAS_OVERLAY) == FLAG_CHILD_HAS_OVERLAY) { - final int childCount = getChildCount(); - for (int i = 0; i < childCount; i++) { - final View child = getChildAt(i); - if (child.isOverlayEnabled()) { - canvas.translate(child.mLeft - child.mScrollX, child.mTop - child.mScrollY); - child.onDrawOverlay(canvas); - canvas.translate(-(child.mLeft - child.mScrollX), - -(child.mTop - child.mScrollY)); - } - } - } - } - - /** * LayoutParams are used by views to tell their parents how they want to be * laid out. See * {@link android.R.styleable#ViewGroup_Layout ViewGroup Layout Attributes} diff --git a/core/java/android/view/ViewParent.java b/core/java/android/view/ViewParent.java index d2907da..d7d4c3f 100644 --- a/core/java/android/view/ViewParent.java +++ b/core/java/android/view/ViewParent.java @@ -222,11 +222,4 @@ public interface ViewParent { */ public boolean requestChildRectangleOnScreen(View child, Rect rectangle, boolean immediate); - - /** - * Called when a child view's overlay state changes between enabled/disabled. - * @param child Child view whose state changed or null. - * @hide - */ - public void childOverlayStateChanged(View child); } diff --git a/core/java/android/view/ViewRoot.java b/core/java/android/view/ViewRoot.java index cb9f84d..e71b5b6 100644 --- a/core/java/android/view/ViewRoot.java +++ b/core/java/android/view/ViewRoot.java @@ -206,8 +206,6 @@ public final class ViewRoot extends Handler implements ViewParent, View.AttachIn AudioManager mAudioManager; private final int mDensity; - - private boolean mHasOverlay; public static IWindowSession getWindowSession(Looper mainLooper) { synchronized (mStaticInit) { @@ -1359,9 +1357,6 @@ public final class ViewRoot extends Handler implements ViewParent, View.AttachIn canvas.setScreenDensity(scalingRequired ? DisplayMetrics.DENSITY_DEVICE : 0); mView.draw(canvas); - if (mHasOverlay) { - mView.onDrawOverlay(canvas); - } } finally { mAttachInfo.mIgnoreDirtyState = false; } @@ -2744,19 +2739,6 @@ public final class ViewRoot extends Handler implements ViewParent, View.AttachIn return scrollToRectOrFocus(rectangle, immediate); } - /** - * @hide - */ - public void childOverlayStateChanged(View child) { - final boolean oldState = mHasOverlay; - mHasOverlay = child.isOverlayEnabled(); - // Invalidate the whole thing when we change overlay states just in case - // something left chunks of data drawn someplace it shouldn't have. - if (mHasOverlay != oldState) { - child.invalidate(); - } - } - class TakenSurfaceHolder extends BaseSurfaceHolder { @Override public boolean onAllowLockCanvas() { diff --git a/core/java/android/webkit/WebSettings.java b/core/java/android/webkit/WebSettings.java index 122c268..63fc008 100644 --- a/core/java/android/webkit/WebSettings.java +++ b/core/java/android/webkit/WebSettings.java @@ -19,6 +19,7 @@ package android.webkit; import android.content.Context; import android.content.SharedPreferences; import android.content.pm.PackageManager; +import android.content.res.Resources; import android.os.Build; import android.os.Handler; import android.os.Message; @@ -326,7 +327,9 @@ public class WebSettings { // Detect tablet device for fixed viewport mode. final DisplayMetrics metrics = context.getResources().getDisplayMetrics(); final int landscapeWidth = Math.max(metrics.widthPixels, metrics.heightPixels); - mUseFixedViewport = (metrics.density == 1.0f && landscapeWidth >= 800); + final int minTabletWidth = context.getResources().getDimensionPixelSize( + com.android.internal.R.dimen.min_xlarge_screen_width); + mUseFixedViewport = (metrics.density == 1.0f && landscapeWidth >= minTabletWidth); mMaxFixedViewportWidth = (int) (landscapeWidth * 1.25); if (sLockForLocaleSettings == null) { diff --git a/core/java/android/webkit/WebView.java b/core/java/android/webkit/WebView.java index c62894c..127eae2 100644 --- a/core/java/android/webkit/WebView.java +++ b/core/java/android/webkit/WebView.java @@ -1941,7 +1941,7 @@ public class WebView extends AbsoluteLayout public void clearView() { mContentWidth = 0; mContentHeight = 0; - nativeSetBaseLayer(0); + if (mNativeClass != 0) nativeSetBaseLayer(0); mWebViewCore.sendMessage(EventHub.CLEAR_CONTENT); } diff --git a/core/java/android/webkit/WebViewCore.java b/core/java/android/webkit/WebViewCore.java index acea163..bb43690 100644 --- a/core/java/android/webkit/WebViewCore.java +++ b/core/java/android/webkit/WebViewCore.java @@ -1829,9 +1829,11 @@ final class WebViewCore { draw.mViewState = mInitialViewState; if (mViewportWidth == -1 && mSettings.getUseFixedViewport() && mSettings.getUseWideViewPort()) { + final int fixedViewportMargin = mContext.getResources().getDimensionPixelSize( + com.android.internal.R.dimen.fixed_viewport_margin); // Use website's initial preferred width as the fixed viewport width. mViewportWidth = Math.min(mSettings.getMaxFixedViewportWidth(), - draw.mMinPrefWidth); + draw.mMinPrefWidth + 2 * fixedViewportMargin); draw.mViewState.mViewportWidth = mViewportWidth; } mInitialViewState = null; diff --git a/core/java/android/webkit/ZoomManager.java b/core/java/android/webkit/ZoomManager.java index 0d704a0..2096fc4 100644 --- a/core/java/android/webkit/ZoomManager.java +++ b/core/java/android/webkit/ZoomManager.java @@ -58,9 +58,9 @@ class ZoomManager { /* * For large screen devices, the defaultScale usually set to 1.0 and * equal to the overview scale, to differentiate the zoom level for double tapping, - * a minimum reading level scale is used. + * a default reading level scale is used. */ - private static final float MIN_READING_LEVEL_SCALE = 1.5f; + private static final float DEFAULT_READING_LEVEL_SCALE = 1.5f; /* * The scale factors that determine the upper and lower bounds for the @@ -258,7 +258,15 @@ class ZoomManager { } public final float getReadingLevelScale() { - return Math.max(mDefaultScale, MIN_READING_LEVEL_SCALE); + // The reading scale is at least 0.5f apart from the overview scale. + final float MIN_SCALE_DIFF = 0.5f; + final float zoomOverviewScale = getZoomOverviewScale(); + if (zoomOverviewScale > DEFAULT_READING_LEVEL_SCALE) { + return Math.min(DEFAULT_READING_LEVEL_SCALE, + zoomOverviewScale - MIN_SCALE_DIFF); + } + return Math.max(zoomOverviewScale + MIN_SCALE_DIFF, + DEFAULT_READING_LEVEL_SCALE); } public final float getInvDefaultScale() { diff --git a/core/java/android/widget/PopupWindow.java b/core/java/android/widget/PopupWindow.java index 4a3e2a9..71f4f03 100644 --- a/core/java/android/widget/PopupWindow.java +++ b/core/java/android/widget/PopupWindow.java @@ -176,6 +176,7 @@ public class PopupWindow { attrs, com.android.internal.R.styleable.PopupWindow, defStyleAttr, defStyleRes); mBackground = a.getDrawable(R.styleable.PopupWindow_popupBackground); + mAnimationStyle = a.getResourceId(R.styleable.PopupWindow_windowAnimationStyle, -1); // If this is a StateListDrawable, try to find and store the drawable to be // used when the drop-down is placed above its anchor view, and the one to be diff --git a/core/java/android/widget/RemoteViews.java b/core/java/android/widget/RemoteViews.java index 5645101..945ffeb 100644 --- a/core/java/android/widget/RemoteViews.java +++ b/core/java/android/widget/RemoteViews.java @@ -156,6 +156,93 @@ public class RemoteViews implements Parcelable, Filter { } } + private class SetOnClickFillInIntent extends Action { + public SetOnClickFillInIntent(int id, Intent fillInIntent) { + this.viewId = id; + this.fillInIntent = fillInIntent; + } + + public SetOnClickFillInIntent(Parcel parcel) { + viewId = parcel.readInt(); + fillInIntent = Intent.CREATOR.createFromParcel(parcel); + } + + public void writeToParcel(Parcel dest, int flags) { + dest.writeInt(TAG); + dest.writeInt(viewId); + fillInIntent.writeToParcel(dest, 0 /* no flags */); + } + + @Override + public void apply(View root) { + final View target = root.findViewById(viewId); + + if (!mIsWidgetCollectionChild) { + Log.e("RemoteViews", "The method setOnClickFillInIntent is available " + + "only from RemoteViewsFactory (ie. on collection items)."); + return; + } + + if (target != null && fillInIntent != null) { + OnClickListener listener = new OnClickListener() { + public void onClick(View v) { + // Insure that this view is a child of an AdapterView + View parent = (View) v.getParent(); + while (!(parent instanceof AdapterView<?>) + && !(parent instanceof AppWidgetHostView)) { + parent = (View) parent.getParent(); + } + + if (parent instanceof AppWidgetHostView) { + // Somehow they've managed to get this far without having + // and AdapterView as a parent. + Log.e("RemoteViews", "Collection item doesn't have AdapterView parent"); + return; + } + + // Insure that a template pending intent has been set on an ancestor + if (!(parent.getTag() instanceof PendingIntent)) { + Log.e("RemoteViews", "Attempting setOnClickFillInIntent without" + + " calling setPendingIntentTemplate on parent."); + return; + } + + PendingIntent pendingIntent = (PendingIntent) parent.getTag(); + + final float appScale = v.getContext().getResources() + .getCompatibilityInfo().applicationScale; + final int[] pos = new int[2]; + v.getLocationOnScreen(pos); + + final Rect rect = new Rect(); + rect.left = (int) (pos[0] * appScale + 0.5f); + rect.top = (int) (pos[1] * appScale + 0.5f); + rect.right = (int) ((pos[0] + v.getWidth()) * appScale + 0.5f); + rect.bottom = (int) ((pos[1] + v.getHeight()) * appScale + 0.5f); + + fillInIntent.setSourceBounds(rect); + try { + // TODO: Unregister this handler if PendingIntent.FLAG_ONE_SHOT? + v.getContext().startIntentSender( + pendingIntent.getIntentSender(), fillInIntent, + Intent.FLAG_ACTIVITY_NEW_TASK, + Intent.FLAG_ACTIVITY_NEW_TASK, 0); + } catch (IntentSender.SendIntentException e) { + android.util.Log.e(LOG_TAG, "Cannot send pending intent: ", e); + } + } + + }; + target.setOnClickListener(listener); + } + } + + int viewId; + Intent fillInIntent; + + public final static int TAG = 9; + } + private class SetOnClickExtras extends Action { public SetOnClickExtras(int id, Bundle extras) { this.viewId = id; @@ -273,7 +360,7 @@ public class RemoteViews implements Parcelable, Filter { target.setTag(pendingIntentTemplate); } else { Log.e("RemoteViews", "Cannot setPendingIntentTemplate on a view which is not" + - "an AdapterView."); + "an AdapterView (id: " + viewId + ")"); return; } } @@ -313,7 +400,8 @@ public class RemoteViews implements Parcelable, Filter { // If the view is an AdapterView, setting a PendingIntent on click doesn't make much // sense, do they mean to set a PendingIntent template for the AdapterView's children? if (mIsWidgetCollectionChild) { - Log.e("RemoteViews", "Cannot setOnClickPendingIntent for collection item."); + Log.e("RemoteViews", "Cannot setOnClickPendingIntent for collection item " + + "(id: " + viewId + ")"); // TODO: return; We'll let this slide until apps are up to date. } @@ -824,6 +912,9 @@ public class RemoteViews implements Parcelable, Filter { case SetPendingIntentTemplate.TAG: mActions.add(new SetPendingIntentTemplate(parcel)); break; + case SetOnClickFillInIntent.TAG: + mActions.add(new SetOnClickFillInIntent(parcel)); + break; default: throw new ActionException("Tag " + tag + " not found"); } @@ -1020,6 +1111,11 @@ public class RemoteViews implements Parcelable, Filter { * {@link android.view.View#setOnClickListener(android.view.View.OnClickListener)} * to launch the provided {@link PendingIntent}. * + * When setting the on-click action of items within collections (eg. {@link ListView}, + * {@link StackView} etc.), this method will not work. Instead, use {@link + * RemoteViews#setPendingIntentTemplate(int, PendingIntent) in conjunction with + * RemoteViews#setOnClickFillInIntent(int, Intent). + * * @param viewId The id of the view that will trigger the {@link PendingIntent} when clicked * @param pendingIntent The {@link PendingIntent} to send when user clicks */ @@ -1028,10 +1124,11 @@ public class RemoteViews implements Parcelable, Filter { } /** - * When using collections (eg. ListView, StackView etc.) in widgets, it is very costly - * to set PendingIntents on the individual items, and is hence not permitted. Instead - * a single PendingIntent template can be set on the collection, and individual items can - * differentiate their click behavior using {@link RemoteViews#setOnClickExtras(int, Bundle)}. + * When using collections (eg. {@link ListView}, {@link StackView} etc.) in widgets, it is very + * costly to set PendingIntents on the individual items, and is hence not permitted. Instead + * this method should be used to set a single PendingIntent template on the collection, and + * individual items can differentiate their on-click behavior using + * {@link RemoteViews#setOnClickFillInIntent(int, Intent)}. * * @param viewId The id of the collection who's children will use this PendingIntent template * when clicked @@ -1043,13 +1140,9 @@ public class RemoteViews implements Parcelable, Filter { } /** - * When using collections (eg. ListView, StackView etc.) in widgets, it is very costly - * to set PendingIntents on the individual items, and is hence not permitted. Instead - * a single PendingIntent template can be set on the collection, see {@link - * RemoteViews#setPendingIntentTemplate(int, PendingIntent)}, and the items click - * behaviour can be distinguished by setting extras. + * Being deprecated. See {@link RemoteViews#setOnClickFillInIntent(int, Intent)}. * - * @param viewId The id of the + * @param viewId * @param extras */ public void setOnClickExtras(int viewId, Bundle extras) { @@ -1057,6 +1150,29 @@ public class RemoteViews implements Parcelable, Filter { } /** + * When using collections (eg. {@link ListView}, {@link StackView} etc.) in widgets, it is very + * costly to set PendingIntents on the individual items, and is hence not permitted. Instead + * a single PendingIntent template can be set on the collection, see {@link + * RemoteViews#setPendingIntentTemplate(int, PendingIntent)}, and the individual on-click + * action of a given item can be distinguished by setting a fillInIntent on that item. The + * fillInIntent is then combined with the PendingIntent template in order to determine the final + * intent which will be executed when the item is clicked. This works as follows: any fields + * which are left blank in the PendingIntent template, but are provided by the fillInIntent + * will be overwritten, and the resulting PendingIntent will be used. + * + * + * of the PendingIntent template will then be filled in with the associated fields that are + * set in fillInIntent. See {@link Intent#fillIn(Intent, int)} for more details. + * + * @param viewId The id of the view on which to set the fillInIntent + * @param fillInIntent The intent which will be combined with the parent's PendingIntent + * in order to determine the on-click behavior of the view specified by viewId + */ + public void setOnClickFillInIntent(int viewId, Intent fillInIntent) { + addAction(new SetOnClickFillInIntent(viewId, fillInIntent)); + } + + /** * @hide * Equivalent to calling a combination of {@link Drawable#setAlpha(int)}, * {@link Drawable#setColorFilter(int, android.graphics.PorterDuff.Mode)}, diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java index 3e5ddfc..d49b4d7 100644 --- a/core/java/android/widget/TextView.java +++ b/core/java/android/widget/TextView.java @@ -96,7 +96,6 @@ import android.view.Menu; import android.view.MenuItem; import android.view.MotionEvent; import android.view.View; -import android.view.ViewConfiguration; import android.view.ViewDebug; import android.view.ViewGroup.LayoutParams; import android.view.ViewRoot; @@ -199,6 +198,9 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener private static final int PRIORITY = 100; private int mCurrentAlpha = 255; + + private final int[] mTempCoords = new int[2]; + private ColorStateList mTextColor; private int mCurTextColor; private ColorStateList mHintTextColor; @@ -3779,8 +3781,6 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener showError(); mShowErrorAfterAttach = false; } - - updateOverlay(); } @Override @@ -3798,8 +3798,6 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener if (mError != null) { hideError(); } - - setOverlayEnabled(false); } @Override @@ -4169,19 +4167,6 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener canvas.restore(); } - /** - * @hide - */ - @Override - public void onDrawOverlay(Canvas canvas) { - if (mInsertionPointCursorController != null) { - mInsertionPointCursorController.draw(canvas); - } - if (mSelectionModifierCursorController != null) { - mSelectionModifierCursorController.draw(canvas); - } - } - @Override public void getFocusedRect(Rect r) { if (mLayout == null) { @@ -6768,31 +6753,17 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener public boolean onTouchEvent(MotionEvent event) { final int action = event.getActionMasked(); if (action == MotionEvent.ACTION_DOWN) { - // Check to see if we're testing for our anchor overlay. - boolean handled = false; - final float x = event.getX(); - final float y = event.getY(); - if (x < 0 || x >= mRight - mLeft || y < 0 || y >= mBottom - mTop) { - if (mInsertionPointCursorController != null) { - handled |= mInsertionPointCursorController.onTouchEvent(event); - } - if (mSelectionModifierCursorController != null) { - handled |= mSelectionModifierCursorController.onTouchEvent(event); - } - - if (!handled) { - return false; - } + if (mInsertionPointCursorController != null) { + mInsertionPointCursorController.onTouchEvent(event); + } + if (mSelectionModifierCursorController != null) { + mSelectionModifierCursorController.onTouchEvent(event); } // Reset this state; it will be re-set if super.onTouchEvent // causes focus to move to the view. mTouchFocusSelected = false; mScrolled = false; - - if (handled) { - return true; - } } final boolean superResult = super.onTouchEvent(event); @@ -6808,7 +6779,6 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener } if ((mMovement != null || onCheckIsTextEditor()) && mText instanceof Spannable && mLayout != null) { - if (mInsertionPointCursorController != null) { mInsertionPointCursorController.onTouchEvent(event); } @@ -6822,11 +6792,22 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener int oldSelStart = getSelectionStart(); int oldSelEnd = getSelectionEnd(); + final int oldScrollX = mScrollX; + final int oldScrollY = mScrollY; + if (mMovement != null) { handled |= mMovement.onTouchEvent(this, (Spannable) mText, event); } if (isTextEditable()) { + if (mScrollX != oldScrollX || mScrollY != oldScrollY) { + // Hide insertion anchor while scrolling. Leave selection. + hideInsertionPointCursorController(); + if (mSelectionModifierCursorController != null && + mSelectionModifierCursorController.isShowing()) { + mSelectionModifierCursorController.updatePosition(); + } + } if (action == MotionEvent.ACTION_UP && isFocused() && !mScrolled) { InputMethodManager imm = (InputMethodManager) getContext().getSystemService(Context.INPUT_METHOD_SERVICE); @@ -7705,22 +7686,13 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener } } - private void updateOverlay() { - boolean enableOverlay = false; - if (mSelectionModifierCursorController != null) { - enableOverlay |= mSelectionModifierCursorController.isShowing(); - } - if (mInsertionPointCursorController != null) { - enableOverlay |= mInsertionPointCursorController.isShowing(); - } - setOverlayEnabled(enableOverlay); - } - /** * A CursorController instance can be used to control a cursor in the text. * * It can be passed to an {@link ArrowKeyMovementMethod} which can intercepts events * and send them to this object instead of the cursor. + * + * @hide */ public interface CursorController { /* Cursor fade-out animation duration, in milliseconds. */ @@ -7748,6 +7720,8 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener */ public void updatePosition(int x, int y); + public void updatePosition(); + /** * The controller and the cursor's positions can be link by a fixed offset, * computed when the controller is touched, and then maintained as it moves @@ -7766,154 +7740,192 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener * @param event The touch event */ public boolean onTouchEvent(MotionEvent event); - - /** - * Draws a visual representation of the controller on the canvas. - * - * Called at the end of {@link #draw(Canvas)}, in the content coordinates system. - * @param canvas The Canvas used by this TextView. - */ - public void draw(Canvas canvas); } - private class Handle { - Drawable mDrawable; - // Vertical extension of the touch region - int mTopExtension, mBottomExtension; - // Position of the virtual finger position on screen - int mHotSpotVerticalPosition; + private class HandleView extends View { + private boolean mPositionOnTop = false; + private Drawable mDrawable; + private PopupWindow mContainer; + private int mPositionX; + private int mPositionY; + private CursorController mController; + private boolean mIsDragging; - Handle(Drawable drawable) { - mDrawable = drawable; + public HandleView(CursorController controller, Drawable handle) { + super(TextView.this.mContext); + mController = controller; + mDrawable = handle; + mContainer = new PopupWindow(TextView.this.mContext, null, + com.android.internal.R.attr.textSelectHandleWindowStyle); } - void positionAtCursor(final int offset, boolean bottom) { - final int drawableWidth = mDrawable.getIntrinsicWidth(); - final int drawableHeight = mDrawable.getIntrinsicHeight(); - final int line = mLayout.getLineForOffset(offset); - final int lineTop = mLayout.getLineTop(line); - final int lineBottom = mLayout.getLineBottom(line); + @Override + public void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { + setMeasuredDimension(mDrawable.getIntrinsicWidth(), + mDrawable.getIntrinsicHeight()); + } - mHotSpotVerticalPosition = lineTop; + public void show() { + if (!isPositionInBounds()) { + hide(); + return; + } + mContainer.setContentView(this); + final int[] coords = mTempCoords; + TextView.this.getLocationOnScreen(coords); + coords[0] += mPositionX; + coords[1] += mPositionY; + mContainer.showAtLocation(TextView.this, 0, coords[0], coords[1]); + } - final Rect bounds = sCursorControllerTempRect; - bounds.left = (int) (mLayout.getPrimaryHorizontal(offset) - drawableWidth / 2.0) - + mScrollX; - bounds.top = (bottom ? lineBottom : lineTop) + mScrollY; + public void hide() { + mIsDragging = false; + mContainer.dismiss(); + } - mTopExtension = bottom ? 0 : drawableHeight / 2; - mBottomExtension = 0; //drawableHeight / 4; + public boolean isShowing() { + return mContainer.isShowing(); + } + + private boolean isPositionInBounds() { + final int extendedPaddingTop = getExtendedPaddingTop(); + final int extendedPaddingBottom = getExtendedPaddingBottom(); + final int compoundPaddingLeft = getCompoundPaddingLeft(); + final int compoundPaddingRight = getCompoundPaddingRight(); + + final TextView hostView = TextView.this; + final int right = hostView.mRight; + final int left = hostView.mLeft; + final int bottom = hostView.mBottom; + final int top = hostView.mTop; + + final int clipLeft = left + compoundPaddingLeft; + final int clipTop = top + extendedPaddingTop; + final int clipRight = right - compoundPaddingRight; + final int clipBottom = bottom - extendedPaddingBottom; + + final int handleWidth = mDrawable.getIntrinsicWidth(); + return mPositionX >= clipLeft - handleWidth * 0.75f && + mPositionX <= clipRight + handleWidth * 0.25f && + mPositionY >= clipTop && mPositionY <= clipBottom; + } + + private void moveTo(int x, int y) { + mPositionX = x - TextView.this.mScrollX; + mPositionY = y - TextView.this.mScrollY; + if (isPositionInBounds()) { + if (mContainer.isShowing()){ + final int[] coords = mTempCoords; + TextView.this.getLocationOnScreen(coords); + coords[0] += mPositionX; + coords[1] += mPositionY; + mContainer.update(coords[0], coords[1], mRight - mLeft, mBottom - mTop); + } else { + show(); + } + } else { + hide(); + } + } - // Extend touch region up when editing the last line of text (or a single line) so that - // it is easier to grab. - if (line == mLayout.getLineCount() - 1) { - mTopExtension = (lineBottom - lineTop) - drawableHeight / 2; + @Override + public void onDraw(Canvas c) { + mDrawable.setBounds(0, 0, mRight - mLeft, mBottom - mTop); + if (mPositionOnTop) { + c.save(); + c.rotate(180, (mRight - mLeft) / 2, (mBottom - mTop) / 2); + mDrawable.draw(c); + c.restore(); + } else { + mDrawable.draw(c); } + } - bounds.right = bounds.left + drawableWidth; - bounds.bottom = bounds.top + drawableHeight; + @Override + public boolean onTouchEvent(MotionEvent ev) { + switch (ev.getActionMasked()) { + case MotionEvent.ACTION_DOWN: + mIsDragging = true; + break; - convertFromViewportToContentCoordinates(bounds); - invalidate(); - mDrawable.setBounds(bounds); - invalidate(); - } + case MotionEvent.ACTION_MOVE: + final float rawX = ev.getRawX(); + final float rawY = ev.getRawY(); + final int[] coords = mTempCoords; + TextView.this.getLocationOnScreen(coords); + final int x = (int) (rawX - coords[0] + 0.5f); + final int y = (int) (rawY - coords[1] + 0.5f); + mController.updatePosition(x, y); + break; - boolean hasFingerOn(float x, float y) { - // Simulate a 'fat finger' to ease grabbing of the controller. - // Expands according to controller image size instead of using dip distance. - // Assumes controller imager has a sensible size, proportionnal to screen density. - final int drawableWidth = mDrawable.getIntrinsicWidth(); - final Rect fingerRect = sCursorControllerTempRect; - fingerRect.set((int) (x - drawableWidth / 2.0), - (int) (y - mBottomExtension), - (int) (x + drawableWidth / 2.0), - (int) (y + mTopExtension)); - fingerRect.offset(mScrollX, mScrollY); - return Rect.intersects(mDrawable.getBounds(), fingerRect); + case MotionEvent.ACTION_UP: + case MotionEvent.ACTION_CANCEL: + mIsDragging = false; + } + return true; } - void invalidate() { - final Rect bounds = mDrawable.getBounds(); - TextView.this.invalidate(bounds.left, bounds.top, - bounds.right, bounds.bottom); + public boolean isDragging() { + return mIsDragging; } - void postInvalidate() { - final Rect bounds = mDrawable.getBounds(); - TextView.this.postInvalidate(bounds.left, bounds.top, - bounds.right, bounds.bottom); - } + void positionAtCursor(final int offset, boolean bottom) { + final int width = mDrawable.getIntrinsicWidth(); + final int height = mDrawable.getIntrinsicHeight(); + final int line = mLayout.getLineForOffset(offset); + final int lineTop = mLayout.getLineTop(line); + final int lineBottom = mLayout.getLineBottom(line); + + final Rect bounds = sCursorControllerTempRect; + bounds.left = (int) (mLayout.getPrimaryHorizontal(offset) - width / 2.0) + + TextView.this.mScrollX; + bounds.top = (bottom ? lineBottom : lineTop) + TextView.this.mScrollY; - void postInvalidateDelayed(long delay) { - final Rect bounds = mDrawable.getBounds(); - TextView.this.postInvalidateDelayed(delay, bounds.left, bounds.top, - bounds.right, bounds.bottom); + bounds.right = bounds.left + width; + bounds.bottom = bounds.top + height; + + convertFromViewportToContentCoordinates(bounds); + moveTo(bounds.left, bounds.top); } } class InsertionPointCursorController implements CursorController { - private static final int DELAY_BEFORE_FADE_OUT = 2100; + private static final int DELAY_BEFORE_FADE_OUT = 4100; - // Whether or not the cursor control is currently visible - private boolean mIsVisible = false; - // Starting time of the fade timer - private long mFadeOutTimerStart; // The cursor controller image - private final Handle mHandle; - // Used to detect a tap (vs drag) on the controller - private long mOnDownTimerStart; + private final HandleView mHandle; // Offset between finger hot point on cursor controller and actual cursor private float mOffsetX, mOffsetY; + private final Runnable mHider = new Runnable() { + public void run() { + hide(); + } + }; + InsertionPointCursorController() { Resources res = mContext.getResources(); - mHandle = new Handle(res.getDrawable(mTextSelectHandleRes)); + mHandle = new HandleView(this, res.getDrawable(mTextSelectHandleRes)); } public void show() { - updateDrawablePosition(); - // Has to be done after updateDrawablePosition, so that previous position invalidate - // in only done if necessary. - mIsVisible = true; - updateOverlay(); + updatePosition(); + mHandle.show(); + hideDelayed(DELAY_BEFORE_FADE_OUT); } public void hide() { - if (mIsVisible) { - long time = System.currentTimeMillis(); - // Start fading out, only if not already in progress - if (time - mFadeOutTimerStart < DELAY_BEFORE_FADE_OUT) { - mFadeOutTimerStart = time - DELAY_BEFORE_FADE_OUT; - mHandle.postInvalidate(); - } - } + mHandle.hide(); + TextView.this.removeCallbacks(mHider); } - public boolean isShowing() { - return mIsVisible; + private void hideDelayed(int msec) { + TextView.this.removeCallbacks(mHider); + TextView.this.postDelayed(mHider, msec); } - public void draw(Canvas canvas) { - if (mIsVisible) { - int time = (int) (System.currentTimeMillis() - mFadeOutTimerStart); - if (time <= DELAY_BEFORE_FADE_OUT) { - mHandle.postInvalidateDelayed(DELAY_BEFORE_FADE_OUT - time); - } else { - time -= DELAY_BEFORE_FADE_OUT; - if (time <= FADE_OUT_DURATION) { - final int alpha = (int) - ((255.0 * (FADE_OUT_DURATION - time)) / FADE_OUT_DURATION); - mHandle.mDrawable.setAlpha(alpha); - mHandle.postInvalidateDelayed(30); - } else { - mHandle.mDrawable.setAlpha(0); - mIsVisible = false; - updateOverlay(); - } - } - mHandle.mDrawable.draw(canvas); - } + public boolean isShowing() { + return mHandle.isShowing(); } public void updatePosition(int x, int y) { @@ -7922,81 +7934,22 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener if (offset != previousOffset) { Selection.setSelection((Spannable) mText, offset); - updateDrawablePosition(); + updatePosition(); } + hideDelayed(DELAY_BEFORE_FADE_OUT); } - private void updateDrawablePosition() { - if (mIsVisible) { - // Clear previous cursor controller before bounds are updated - mHandle.postInvalidate(); - } - + public void updatePosition() { final int offset = getSelectionStart(); if (offset < 0) { // Should never happen, safety check. Log.w(LOG_TAG, "Update cursor controller position called with no cursor"); - mIsVisible = false; - updateOverlay(); + hide(); return; } mHandle.positionAtCursor(offset, true); - - mFadeOutTimerStart = System.currentTimeMillis(); - mHandle.mDrawable.setAlpha(255); - } - - public boolean onTouchEvent(MotionEvent event) { - if (isFocused() && isTextEditable() && mIsVisible) { - switch (event.getActionMasked()) { - case MotionEvent.ACTION_DOWN : { - final float x = event.getX(); - final float y = event.getY(); - - if (mHandle.hasFingerOn(x, y)) { - show(); - - if (mMovement instanceof ArrowKeyMovementMethod) { - ((ArrowKeyMovementMethod)mMovement).setCursorController(this); - } - - if (mParent != null) { - // Prevent possible scrollView parent from scrolling, so that - // we can use auto-scrolling. - mParent.requestDisallowInterceptTouchEvent(true); - } - - final Rect bounds = mHandle.mDrawable.getBounds(); - mOffsetX = (bounds.left + bounds.right) / 2.0f - x; - mOffsetY = mHandle.mHotSpotVerticalPosition - y; - - mOffsetX += viewportToContentHorizontalOffset(); - mOffsetY += viewportToContentVerticalOffset(); - - mOnDownTimerStart = event.getEventTime(); - return true; - } - return false; - } - - case MotionEvent.ACTION_UP : { - int time = (int) (event.getEventTime() - mOnDownTimerStart); - - if (time <= ViewConfiguration.getTapTimeout()) { - // A tap on the controller (not a drag) will move the cursor - int offset = getOffset((int) event.getX(), (int) event.getY()); - Selection.setSelection((Spannable) mText, offset); - - // Modified by cancelLongPress and prevents the cursor from changing - mScrolled = false; - } - break; - } - } - } - return false; } public float getOffsetX() { @@ -8006,88 +7959,59 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener public float getOffsetY() { return mOffsetY; } + + public boolean onTouchEvent(MotionEvent ev) { + return false; + } } class SelectionModifierCursorController implements CursorController { - // Whether or not the selection controls are currently visible - private boolean mIsVisible = false; - // Whether that start or the end of selection controller is dragged - private boolean mStartIsDragged = false; - // Starting time of the fade timer - private long mFadeOutTimerStart; // The cursor controller images - private final Handle mStartHandle, mEndHandle; + private HandleView mStartHandle, mEndHandle; // Offset between finger hot point on active cursor controller and actual cursor private float mOffsetX, mOffsetY; // The offsets of that last touch down event. Remembered to start selection there. private int mMinTouchOffset, mMaxTouchOffset; + // Whether selection anchors are active + private boolean mIsShowing; SelectionModifierCursorController() { Resources res = mContext.getResources(); - mStartHandle = new Handle(res.getDrawable(mTextSelectHandleLeftRes)); - mEndHandle = new Handle(res.getDrawable(mTextSelectHandleRightRes)); + mStartHandle = new HandleView(this, res.getDrawable(mTextSelectHandleLeftRes)); + mEndHandle = new HandleView(this, res.getDrawable(mTextSelectHandleRightRes)); } public void show() { - updateDrawablesPositions(); - // Has to be done after updateDrawablePositions, so that previous position invalidate - // in only done if necessary. - mIsVisible = true; - updateOverlay(); - mFadeOutTimerStart = -1; + mIsShowing = true; + updatePosition(); + mStartHandle.show(); + mEndHandle.show(); hideInsertionPointCursorController(); } public void hide() { - if (mIsVisible && (mFadeOutTimerStart < 0)) { - mFadeOutTimerStart = System.currentTimeMillis(); - mStartHandle.postInvalidate(); - mEndHandle.postInvalidate(); - } + mStartHandle.hide(); + mEndHandle.hide(); + mIsShowing = false; } public boolean isShowing() { - return mIsVisible; + return mIsShowing; } public void cancelFadeOutAnimation() { - mIsVisible = false; - updateOverlay(); - mStartHandle.postInvalidate(); - mEndHandle.postInvalidate(); - } - - public void draw(Canvas canvas) { - if (mIsVisible) { - if (mFadeOutTimerStart >= 0) { - int time = (int) (System.currentTimeMillis() - mFadeOutTimerStart); - if (time <= FADE_OUT_DURATION) { - final int alpha = 255 * (FADE_OUT_DURATION - time) / FADE_OUT_DURATION; - mStartHandle.mDrawable.setAlpha(alpha); - mEndHandle.mDrawable.setAlpha(alpha); - mStartHandle.postInvalidateDelayed(30); - mEndHandle.postInvalidateDelayed(30); - } else { - mStartHandle.mDrawable.setAlpha(0); - mEndHandle.mDrawable.setAlpha(0); - mIsVisible = false; - updateOverlay(); - } - } - mStartHandle.mDrawable.draw(canvas); - mEndHandle.mDrawable.draw(canvas); - } + hide(); } public void updatePosition(int x, int y) { int selectionStart = getSelectionStart(); int selectionEnd = getSelectionEnd(); - final int previousOffset = mStartIsDragged ? selectionStart : selectionEnd; + final int previousOffset = mStartHandle.isDragging() ? selectionStart : selectionEnd; int offset = getHysteresisOffset(x, y, previousOffset); // Handle the case where start and end are swapped, making sure start <= end - if (mStartIsDragged) { + if (mStartHandle.isDragging()) { if (offset <= selectionEnd) { if (selectionStart == offset) { return; // no change, no need to redraw; @@ -8096,7 +8020,9 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener } else { selectionStart = selectionEnd; selectionEnd = offset; - mStartIsDragged = false; + HandleView temp = mStartHandle; + mStartHandle = mEndHandle; + mEndHandle = temp; } } else { if (offset >= selectionStart) { @@ -8107,43 +8033,35 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener } else { selectionEnd = selectionStart; selectionStart = offset; - mStartIsDragged = true; + HandleView temp = mStartHandle; + mStartHandle = mEndHandle; + mEndHandle = temp; } } Selection.setSelection((Spannable) mText, selectionStart, selectionEnd); - updateDrawablesPositions(); + updatePosition(); } - private void updateDrawablesPositions() { - if (mIsVisible) { - // Clear previous cursor controller before bounds are updated - mStartHandle.postInvalidate(); - mEndHandle.postInvalidate(); - } - + public void updatePosition() { final int selectionStart = getSelectionStart(); final int selectionEnd = getSelectionEnd(); if ((selectionStart < 0) || (selectionEnd < 0)) { // Should never happen, safety check. Log.w(LOG_TAG, "Update selection controller position called with no cursor"); - mIsVisible = false; - updateOverlay(); + hide(); return; } - boolean oneLineSelection = - mLayout.getLineForOffset(selectionStart) == mLayout.getLineForOffset(selectionEnd); + boolean oneLineSelection = mLayout.getLineForOffset(selectionStart) == + mLayout.getLineForOffset(selectionEnd); mStartHandle.positionAtCursor(selectionStart, oneLineSelection); mEndHandle.positionAtCursor(selectionEnd, true); - - mStartHandle.mDrawable.setAlpha(255); - mEndHandle.mDrawable.setAlpha(255); } public boolean onTouchEvent(MotionEvent event) { - if (isTextEditable()) { + if (isFocused() && isTextEditable()) { switch (event.getActionMasked()) { case MotionEvent.ACTION_DOWN: final int x = (int) event.getX(); @@ -8152,34 +8070,6 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener // Remember finger down position, to be able to start selection from there mMinTouchOffset = mMaxTouchOffset = mLastTouchOffset = getOffset(x, y); - if (mIsVisible) { - if (mMovement instanceof ArrowKeyMovementMethod) { - boolean isOnStart = mStartHandle.hasFingerOn(x, y); - boolean isOnEnd = mEndHandle.hasFingerOn(x, y); - if (isOnStart || isOnEnd) { - if (mParent != null) { - // Prevent possible scrollView parent from scrolling, so - // that we can use auto-scrolling. - mParent.requestDisallowInterceptTouchEvent(true); - } - - // In case both controllers are under finger (very small - // selection region), arbitrarily pick end controller. - mStartIsDragged = !isOnEnd; - final Handle draggedHandle = - mStartIsDragged ? mStartHandle : mEndHandle; - final Rect bounds = draggedHandle.mDrawable.getBounds(); - mOffsetX = (bounds.left + bounds.right) / 2.0f - x; - mOffsetY = draggedHandle.mHotSpotVerticalPosition - y; - - mOffsetX += viewportToContentHorizontalOffset(); - mOffsetY += viewportToContentVerticalOffset(); - - ((ArrowKeyMovementMethod)mMovement).setCursorController(this); - return true; - } - } - } break; case MotionEvent.ACTION_POINTER_DOWN: @@ -8230,7 +8120,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener * @return true iff this controller is currently used to move the selection start. */ public boolean isSelectionStartDragged() { - return mIsVisible && mStartIsDragged; + return mStartHandle.isDragging(); } } diff --git a/core/java/com/android/internal/os/BatteryStatsImpl.java b/core/java/com/android/internal/os/BatteryStatsImpl.java index 0508df6..4e61ddf 100644 --- a/core/java/com/android/internal/os/BatteryStatsImpl.java +++ b/core/java/com/android/internal/os/BatteryStatsImpl.java @@ -51,6 +51,7 @@ import java.util.HashMap; import java.util.Iterator; import java.util.Map; import java.util.concurrent.atomic.AtomicInteger; +import java.util.concurrent.locks.ReentrantLock; /** * All information we are collecting about things that can happen that impact @@ -3836,6 +3837,22 @@ public final class BatteryStatsImpl extends BatteryStats { } } + private HistoryItem mHistoryIterator; + + public boolean startIteratingHistoryLocked() { + return (mHistoryIterator = mHistory) != null; + } + + public boolean getNextHistoryLocked(HistoryItem out) { + HistoryItem cur = mHistoryIterator; + if (cur == null) { + return false; + } + out.setTo(cur); + mHistoryIterator = cur.next; + return true; + } + @Override public HistoryItem getHistory() { return mHistory; @@ -3962,7 +3979,7 @@ public final class BatteryStatsImpl extends BatteryStats { } if (doWrite || (mLastWriteTime + (60 * 1000)) < mSecRealtime) { if (mFile != null) { - writeLocked(); + writeAsyncLocked(); } } } @@ -4358,11 +4375,22 @@ public final class BatteryStatsImpl extends BatteryStats { } public void shutdownLocked() { - writeLocked(); + writeSyncLocked(); mShuttingDown = true; } - public void writeLocked() { + Parcel mPendingWrite = null; + final ReentrantLock mWriteLock = new ReentrantLock(); + + public void writeAsyncLocked() { + writeLocked(false); + } + + public void writeSyncLocked() { + writeLocked(true); + } + + void writeLocked(boolean sync) { if (mFile == null) { Slog.w("BatteryStats", "writeLocked: no file associated with this instance"); return; @@ -4372,23 +4400,51 @@ public final class BatteryStatsImpl extends BatteryStats { return; } + Parcel out = Parcel.obtain(); + writeSummaryToParcel(out); + mLastWriteTime = SystemClock.elapsedRealtime(); + + if (mPendingWrite != null) { + mPendingWrite.recycle(); + } + mPendingWrite = out; + + if (sync) { + commitPendingDataToDisk(); + } else { + Thread thr = new Thread("BatteryStats-Write") { + @Override + public void run() { + Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND); + commitPendingDataToDisk(); + } + }; + thr.start(); + } + } + + public void commitPendingDataToDisk() { + Parcel next; + synchronized (this) { + next = mPendingWrite; + mPendingWrite = null; + + mWriteLock.lock(); + } + try { FileOutputStream stream = new FileOutputStream(mFile.chooseForWrite()); - Parcel out = Parcel.obtain(); - writeSummaryToParcel(out); - stream.write(out.marshall()); - out.recycle(); - + stream.write(next.marshall()); stream.flush(); stream.close(); mFile.commit(); - - mLastWriteTime = SystemClock.elapsedRealtime(); - return; } catch (IOException e) { Slog.w("BatteryStats", "Error writing battery statistics", e); + mFile.rollback(); + } finally { + next.recycle(); + mWriteLock.unlock(); } - mFile.rollback(); } static byte[] readFully(FileInputStream stream) throws java.io.IOException { diff --git a/core/jni/android/graphics/Shader.cpp b/core/jni/android/graphics/Shader.cpp index 9202429..ee44747 100644 --- a/core/jni/android/graphics/Shader.cpp +++ b/core/jni/android/graphics/Shader.cpp @@ -226,10 +226,8 @@ static SkShader* LinearGradient_create2(JNIEnv* env, jobject o, /////////////////////////////////////////////////////////////////////////////////////////////// -static SkShader* RadialGradient_create1(JNIEnv* env, jobject, - float x, float y, float radius, - jintArray colorArray, jfloatArray posArray, int tileMode) -{ +static SkShader* RadialGradient_create1(JNIEnv* env, jobject, float x, float y, float radius, + jintArray colorArray, jfloatArray posArray, int tileMode) { SkPoint center; center.set(SkFloatToScalar(x), SkFloatToScalar(y)); @@ -259,10 +257,8 @@ static SkShader* RadialGradient_create1(JNIEnv* env, jobject, return shader; } -static SkShader* RadialGradient_create2(JNIEnv* env, jobject, - float x, float y, float radius, - int color0, int color1, int tileMode) -{ +static SkShader* RadialGradient_create2(JNIEnv* env, jobject, float x, float y, float radius, + int color0, int color1, int tileMode) { SkPoint center; center.set(SkFloatToScalar(x), SkFloatToScalar(y)); @@ -276,11 +272,65 @@ static SkShader* RadialGradient_create2(JNIEnv* env, jobject, return s; } +static SkiaShader* RadialGradient_postCreate1(JNIEnv* env, jobject o, SkShader* shader, + float x, float y, float radius, jintArray colorArray, jfloatArray posArray, int tileMode) { +#ifdef USE_OPENGL_RENDERER + size_t count = env->GetArrayLength(colorArray); + const jint* colorValues = env->GetIntArrayElements(colorArray, NULL); + + jfloat* storedPositions = new jfloat[count]; + uint32_t* storedColors = new uint32_t[count]; + for (size_t i = 0; i < count; i++) { + storedColors[i] = static_cast<uint32_t>(colorValues[i]); + } + + if (posArray) { + AutoJavaFloatArray autoPos(env, posArray, count); + const float* posValues = autoPos.ptr(); + for (size_t i = 0; i < count; i++) { + storedPositions[i] = posValues[i]; + } + } else { + storedPositions[0] = 0.0f; + storedPositions[1] = 1.0f; + } + + SkiaShader* skiaShader = new SkiaCircularGradientShader(x, y, radius, storedColors, + storedPositions, count, shader, (SkShader::TileMode) tileMode, NULL, + (shader->getFlags() & SkShader::kOpaqueAlpha_Flag) == 0); + + env->ReleaseIntArrayElements(colorArray, const_cast<jint*>(colorValues), JNI_ABORT); + return skiaShader; +#else + return NULL; +#endif +} + +static SkiaShader* RadialGradient_postCreate2(JNIEnv* env, jobject o, SkShader* shader, + float x, float y, float radius, int color0, int color1, int tileMode) { +#ifdef USE_OPENGL_RENDERER + float* storedPositions = new float[2]; + storedPositions[0] = 0.0f; + storedPositions[1] = 1.0f; + + uint32_t* storedColors = new uint32_t[2]; + storedColors[0] = static_cast<uint32_t>(color0); + storedColors[1] = static_cast<uint32_t>(color1); + + SkiaShader* skiaShader = new SkiaCircularGradientShader(x, y, radius, storedColors, + storedPositions, 2, shader, (SkShader::TileMode) tileMode, NULL, + (shader->getFlags() & SkShader::kOpaqueAlpha_Flag) == 0); + + return skiaShader; +#else + return NULL; +#endif +} + /////////////////////////////////////////////////////////////////////////////// static SkShader* SweepGradient_create1(JNIEnv* env, jobject, float x, float y, - jintArray jcolors, jfloatArray jpositions) -{ + jintArray jcolors, jfloatArray jpositions) { size_t count = env->GetArrayLength(jcolors); const jint* colors = env->GetIntArrayElements(jcolors, NULL); @@ -307,8 +357,7 @@ static SkShader* SweepGradient_create1(JNIEnv* env, jobject, float x, float y, } static SkShader* SweepGradient_create2(JNIEnv* env, jobject, float x, float y, - int color0, int color1) -{ + int color0, int color1) { SkColor colors[2]; colors[0] = color0; colors[1] = color1; @@ -318,6 +367,59 @@ static SkShader* SweepGradient_create2(JNIEnv* env, jobject, float x, float y, return s; } +static SkiaShader* SweepGradient_postCreate1(JNIEnv* env, jobject o, SkShader* shader, + float x, float y, jintArray colorArray, jfloatArray posArray) { +#ifdef USE_OPENGL_RENDERER + size_t count = env->GetArrayLength(colorArray); + const jint* colorValues = env->GetIntArrayElements(colorArray, NULL); + + jfloat* storedPositions = new jfloat[count]; + uint32_t* storedColors = new uint32_t[count]; + for (size_t i = 0; i < count; i++) { + storedColors[i] = static_cast<uint32_t>(colorValues[i]); + } + + if (posArray) { + AutoJavaFloatArray autoPos(env, posArray, count); + const float* posValues = autoPos.ptr(); + for (size_t i = 0; i < count; i++) { + storedPositions[i] = posValues[i]; + } + } else { + storedPositions[0] = 0.0f; + storedPositions[1] = 1.0f; + } + + SkiaShader* skiaShader = new SkiaSweepGradientShader(x, y, storedColors, storedPositions, count, + shader, NULL, (shader->getFlags() & SkShader::kOpaqueAlpha_Flag) == 0); + + env->ReleaseIntArrayElements(colorArray, const_cast<jint*>(colorValues), JNI_ABORT); + return skiaShader; +#else + return NULL; +#endif +} + +static SkiaShader* SweepGradient_postCreate2(JNIEnv* env, jobject o, SkShader* shader, + float x, float y, int color0, int color1) { +#ifdef USE_OPENGL_RENDERER + float* storedPositions = new float[2]; + storedPositions[0] = 0.0f; + storedPositions[1] = 1.0f; + + uint32_t* storedColors = new uint32_t[2]; + storedColors[0] = static_cast<uint32_t>(color0); + storedColors[1] = static_cast<uint32_t>(color1); + + SkiaShader* skiaShader = new SkiaSweepGradientShader(x, y, storedColors, storedPositions, 2, + shader, NULL, (shader->getFlags() & SkShader::kOpaqueAlpha_Flag) == 0); + + return skiaShader; +#else + return NULL; +#endif +} + /////////////////////////////////////////////////////////////////////////////////////////////// static SkShader* ComposeShader_create1(JNIEnv* env, jobject o, @@ -384,20 +486,24 @@ static JNINativeMethod gLinearGradientMethods[] = { }; static JNINativeMethod gRadialGradientMethods[] = { - {"nativeCreate1", "(FFF[I[FI)I", (void*)RadialGradient_create1 }, - {"nativeCreate2", "(FFFIII)I", (void*)RadialGradient_create2 } + { "nativeCreate1", "(FFF[I[FI)I", (void*)RadialGradient_create1 }, + { "nativeCreate2", "(FFFIII)I", (void*)RadialGradient_create2 }, + { "nativePostCreate1", "(IFFF[I[FI)I", (void*)RadialGradient_postCreate1 }, + { "nativePostCreate2", "(IFFFIII)I", (void*)RadialGradient_postCreate2 } }; static JNINativeMethod gSweepGradientMethods[] = { - {"nativeCreate1", "(FF[I[F)I", (void*)SweepGradient_create1 }, - {"nativeCreate2", "(FFII)I", (void*)SweepGradient_create2 } + { "nativeCreate1", "(FF[I[F)I", (void*)SweepGradient_create1 }, + { "nativeCreate2", "(FFII)I", (void*)SweepGradient_create2 }, + { "nativePostCreate1", "(IFF[I[F)I", (void*)SweepGradient_postCreate1 }, + { "nativePostCreate2", "(IFFII)I", (void*)SweepGradient_postCreate2 } }; static JNINativeMethod gComposeShaderMethods[] = { - {"nativeCreate1", "(III)I", (void*)ComposeShader_create1 }, - {"nativeCreate2", "(III)I", (void*)ComposeShader_create2 }, - {"nativePostCreate1", "(IIII)I", (void*)ComposeShader_postCreate1 }, - {"nativePostCreate2", "(IIII)I", (void*)ComposeShader_postCreate2 } + { "nativeCreate1", "(III)I", (void*)ComposeShader_create1 }, + { "nativeCreate2", "(III)I", (void*)ComposeShader_create2 }, + { "nativePostCreate1", "(IIII)I", (void*)ComposeShader_postCreate1 }, + { "nativePostCreate2", "(IIII)I", (void*)ComposeShader_postCreate2 } }; #include <android_runtime/AndroidRuntime.h> diff --git a/core/res/res/drawable-mdpi/overscroll_edge.png b/core/res/res/drawable-mdpi/overscroll_edge.png Binary files differnew file mode 100644 index 0000000..22f4ef8 --- /dev/null +++ b/core/res/res/drawable-mdpi/overscroll_edge.png diff --git a/core/res/res/drawable-mdpi/overscroll_glow.png b/core/res/res/drawable-mdpi/overscroll_glow.png Binary files differnew file mode 100644 index 0000000..761fb74 --- /dev/null +++ b/core/res/res/drawable-mdpi/overscroll_glow.png diff --git a/core/res/res/layout/simple_list_item_2.xml b/core/res/res/layout/simple_list_item_2.xml index 5eab54e..c87922c 100644 --- a/core/res/res/layout/simple_list_item_2.xml +++ b/core/res/res/layout/simple_list_item_2.xml @@ -15,8 +15,6 @@ --> <TwoLineListItem xmlns:android="http://schemas.android.com/apk/res/android" - android:paddingTop="2dip" - android:paddingBottom="2dip" android:layout_width="match_parent" android:layout_height="wrap_content" android:minHeight="?android:attr/listPreferredItemHeight" diff --git a/core/res/res/layout/simple_list_item_activated_1.xml b/core/res/res/layout/simple_list_item_activated_1.xml new file mode 100644 index 0000000..8416df2 --- /dev/null +++ b/core/res/res/layout/simple_list_item_activated_1.xml @@ -0,0 +1,25 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- Copyright (C) 2010 The Android Open Source Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +--> + +<TextView xmlns:android="http://schemas.android.com/apk/res/android" + android:id="@android:id/text1" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:textAppearance="?android:attr/textAppearanceLarge" + android:gravity="center_vertical" + android:background="?android:attr/activatedBackgroundIndicator" + android:minHeight="?android:attr/listPreferredItemHeight" +/> diff --git a/core/res/res/layout/simple_list_item_activated_2.xml b/core/res/res/layout/simple_list_item_activated_2.xml new file mode 100644 index 0000000..2ffbf02 --- /dev/null +++ b/core/res/res/layout/simple_list_item_activated_2.xml @@ -0,0 +1,43 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- Copyright (C) 2010 The Android Open Source Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +--> + +<TwoLineListItem xmlns:android="http://schemas.android.com/apk/res/android" + android:paddingTop="2dip" + android:paddingBottom="2dip" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:background="?android:attr/activatedBackgroundIndicator" + android:minHeight="?android:attr/listPreferredItemHeight" + android:mode="twoLine" +> + + <TextView android:id="@android:id/text1" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:layout_marginLeft="6dip" + android:layout_marginTop="6dip" + android:textAppearance="?android:attr/textAppearanceLarge" + /> + + <TextView android:id="@android:id/text2" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:layout_below="@android:id/text1" + android:layout_alignLeft="@android:id/text1" + android:textAppearance="?android:attr/textAppearanceSmall" + /> + +</TwoLineListItem> diff --git a/core/res/res/values/attrs.xml b/core/res/res/values/attrs.xml index 779a33f..19b76ab 100755 --- a/core/res/res/values/attrs.xml +++ b/core/res/res/values/attrs.xml @@ -466,6 +466,9 @@ <attr name="quickContactBadgeStyleSmallWindowMedium" format="reference" /> <!-- Default quickcontact badge style with large quickcontact window. --> <attr name="quickContactBadgeStyleSmallWindowLarge" format="reference" /> + <!-- Reference to a style that will be used for the window containing a text + selection anchor. --> + <attr name="textSelectHandleWindowStyle" format="reference" /> <!-- Default ListPopupWindow style. --> <attr name="listPopupWindowStyle" format="reference" /> <!-- Default PopupMenu style. --> @@ -2355,6 +2358,7 @@ </declare-styleable> <declare-styleable name="PopupWindow"> <attr name="popupBackground" format="reference|color" /> + <attr name="windowAnimationStyle" /> </declare-styleable> <declare-styleable name="ViewAnimator"> <!-- Identifier for the animation to use when a view is shown. --> diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml index ff37d05..b4e1fcb 100644 --- a/core/res/res/values/config.xml +++ b/core/res/res/values/config.xml @@ -416,4 +416,8 @@ <!-- Enables SIP on WIFI only --> <bool name="config_sip_wifi_only">false</bool> + + <!-- Number of database connections opened and managed by framework layer + to handle queries on each database. --> + <integer name="db_connection_pool_size">1</integer> </resources> diff --git a/core/res/res/values/dimens.xml b/core/res/res/values/dimens.xml index d3aa2d4..171bb45 100644 --- a/core/res/res/values/dimens.xml +++ b/core/res/res/values/dimens.xml @@ -43,6 +43,10 @@ <dimen name="fastscroll_thumb_width">64dp</dimen> <!-- Height of the fastscroll thumb --> <dimen name="fastscroll_thumb_height">52dp</dimen> + <!-- Min width for a tablet device --> + <dimen name="min_xlarge_screen_width">800dp</dimen> + <!-- Fixed viewport margin for website content width change --> + <dimen name="fixed_viewport_margin">7dp</dimen> <!-- Default height of a key in the password keyboard for alpha --> <dimen name="password_keyboard_key_height_alpha">56dip</dimen> <!-- Default height of a key in the password keyboard for numeric --> diff --git a/core/res/res/values/public.xml b/core/res/res/values/public.xml index 6f53677..cdeb899 100644 --- a/core/res/res/values/public.xml +++ b/core/res/res/values/public.xml @@ -1255,6 +1255,7 @@ <public type="attr" name="textSelectHandleLeft" id="0x010102c5" /> <public type="attr" name="textSelectHandleRight" id="0x010102c6" /> <public type="attr" name="textSelectHandle" id="0x010102c7" /> + <public type="attr" name="textSelectHandleWindowStyle" id="0x010102c8" /> <public-padding type="attr" name="kraken_resource_pad" end="0x01010300" /> @@ -1376,6 +1377,16 @@ <!-- A simple ListView item layout which can contain text and support (single or multiple) item selection. --> <public type="layout" name="simple_selectable_list_item" /> + <!-- A version of {@link #simple_list_item_1} that is able to change its + background state to indicate when it is activated (that is checked by + a ListView). --> + <public type="layout" name="simple_list_item_activated_1" /> + + <!-- A version of {@link #simple_list_item_2} that is able to change its + background state to indicate when it is activated (that is checked by + a ListView). --> + <public type="layout" name="simple_list_item_activated_2" /> + <public type="style" name="Theme.WithActionBar" /> <public type="style" name="Widget.Spinner.DropDown" /> <public type="style" name="Widget.ActionButton" /> diff --git a/core/res/res/values/styles.xml b/core/res/res/values/styles.xml index e8343f1..c37bb66 100644 --- a/core/res/res/values/styles.xml +++ b/core/res/res/values/styles.xml @@ -881,6 +881,17 @@ <item name="android:background">@android:drawable/bottom_bar</item> </style> + <!-- Style for the small popup windows that contain text selection anchors. --> + <style name="Widget.TextSelectHandle"> + <item name="android:windowAnimationStyle">@android:style/Animation.TextSelectHandle</item> + </style> + + <!-- Style for animating text selection handles. --> + <style name="Animation.TextSelectHandle"> + <item name="windowEnterAnimation">@android:anim/fade_in</item> + <item name="windowExitAnimation">@android:anim/fade_out</item> + </style> + <style name="Widget.ActionBar"> <item name="android:background">@android:drawable/action_bar_background</item> <item name="android:displayOptions">useLogo</item> diff --git a/core/res/res/values/themes.xml b/core/res/res/values/themes.xml index fd39179..9425fc4 100644 --- a/core/res/res/values/themes.xml +++ b/core/res/res/values/themes.xml @@ -156,6 +156,7 @@ <item name="textSelectHandleLeft">@android:drawable/text_select_handle_middle</item> <item name="textSelectHandleRight">@android:drawable/text_select_handle_middle</item> <item name="textSelectHandle">@android:drawable/text_select_handle_middle</item> + <item name="textSelectHandleWindowStyle">@android:style/Widget.TextSelectHandle</item> <!-- Widget styles --> <item name="absListViewStyle">@android:style/Widget.AbsListView</item> diff --git a/core/tests/coretests/AndroidManifest.xml b/core/tests/coretests/AndroidManifest.xml index e449ddb..b1e38ee 100644 --- a/core/tests/coretests/AndroidManifest.xml +++ b/core/tests/coretests/AndroidManifest.xml @@ -35,6 +35,7 @@ android:label="@string/permlab_testDenied" android:description="@string/permdesc_testDenied" /> + <uses-permission android:name="android.permission.ACCESS_CACHE_FILESYSTEM" /> <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" /> <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" /> <uses-permission android:name="android.permission.ACCESS_WIFI_STATE" /> diff --git a/core/tests/coretests/src/android/net/DownloadManagerBaseTest.java b/core/tests/coretests/src/android/net/DownloadManagerBaseTest.java index ee0f5f1..a7ec7d5 100644 --- a/core/tests/coretests/src/android/net/DownloadManagerBaseTest.java +++ b/core/tests/coretests/src/android/net/DownloadManagerBaseTest.java @@ -27,6 +27,7 @@ import android.net.NetworkInfo; import android.net.DownloadManager.Query; import android.net.DownloadManager.Request; import android.net.wifi.WifiManager; +import android.os.Bundle; import android.os.Environment; import android.os.ParcelFileDescriptor; import android.os.SystemClock; @@ -43,9 +44,12 @@ import java.io.FileOutputStream; import java.io.IOException; import java.net.URL; import java.util.concurrent.TimeoutException; +import java.util.Collections; +import java.util.HashSet; import java.util.Iterator; import java.util.List; import java.util.Random; +import java.util.Set; import java.util.Vector; import junit.framework.AssertionFailedError; @@ -67,6 +71,7 @@ public class DownloadManagerBaseTest extends InstrumentationTestCase { protected static final String LOG_TAG = "android.net.DownloadManagerBaseTest"; protected static final int HTTP_OK = 200; + protected static final int HTTP_REDIRECT = 307; protected static final int HTTP_PARTIAL_CONTENT = 206; protected static final int HTTP_NOT_FOUND = 404; protected static final int HTTP_SERVICE_UNAVAILABLE = 503; @@ -119,6 +124,7 @@ public class DownloadManagerBaseTest extends InstrumentationTestCase { public static class MultipleDownloadsCompletedReceiver extends BroadcastReceiver { private volatile int mNumDownloadsCompleted = 0; + private Set<Long> downloadIds = Collections.synchronizedSet(new HashSet<Long>()); /** * {@inheritDoc} @@ -129,6 +135,8 @@ public class DownloadManagerBaseTest extends InstrumentationTestCase { ++mNumDownloadsCompleted; Log.i(LOG_TAG, "MultipleDownloadsCompletedReceiver got intent: " + intent.getAction() + " --> total count: " + mNumDownloadsCompleted); + Bundle extras = intent.getExtras(); + downloadIds.add(new Long(extras.getLong(DownloadManager.EXTRA_DOWNLOAD_ID))); } } @@ -142,6 +150,18 @@ public class DownloadManagerBaseTest extends InstrumentationTestCase { public int numDownloadsCompleted() { return mNumDownloadsCompleted; } + + /** + * Gets the list of download IDs. + * @return A Set<Long> with the ids of the completed downloads. + */ + public Set<Long> getDownloadIds() { + synchronized(downloadIds) { + Set<Long> returnIds = new HashSet<Long>(downloadIds); + return returnIds; + } + } + } public static class WiFiChangedReceiver extends BroadcastReceiver { @@ -196,6 +216,17 @@ public class DownloadManagerBaseTest extends InstrumentationTestCase { } /** + * Helper to enqueue a response from the MockWebServer with no body. + * + * @param status The HTTP status code to return for this response + * @return Returns the mock web server response that was queued (which can be modified) + */ + protected MockResponse enqueueResponse(int status) { + return doEnqueueResponse(status); + + } + + /** * Helper to enqueue a response from the MockWebServer. * * @param status The HTTP status code to return for this response diff --git a/core/tests/coretests/src/android/net/DownloadManagerIntegrationTest.java b/core/tests/coretests/src/android/net/DownloadManagerIntegrationTest.java index be3cbf7..a61f02d 100644 --- a/core/tests/coretests/src/android/net/DownloadManagerIntegrationTest.java +++ b/core/tests/coretests/src/android/net/DownloadManagerIntegrationTest.java @@ -21,6 +21,7 @@ import android.content.Context; import android.content.Intent; import android.content.IntentFilter; import android.database.Cursor; +import android.net.DownloadManager; import android.net.DownloadManager.Query; import android.net.DownloadManager.Request; import android.net.DownloadManagerBaseTest.DataType; @@ -28,6 +29,7 @@ import android.net.DownloadManagerBaseTest.MultipleDownloadsCompletedReceiver; import android.net.wifi.WifiManager; import android.os.Environment; import android.os.ParcelFileDescriptor; +import android.os.StatFs; import android.os.SystemClock; import android.test.InstrumentationTestCase; import android.test.suitebuilder.annotation.LargeTest; @@ -36,10 +38,13 @@ import android.test.suitebuilder.annotation.SmallTest; import android.util.Log; import java.io.File; +import java.io.FileOutputStream; import java.io.FileWriter; import java.io.IOException; import java.net.URL; +import java.util.Iterator; import java.util.Random; +import java.util.Set; import junit.framework.AssertionFailedError; @@ -51,8 +56,11 @@ import coretestutils.http.MockWebServer; */ public class DownloadManagerIntegrationTest extends DownloadManagerBaseTest { - private static String LOG_TAG = "android.net.DownloadManagerIntegrationTest"; - private static String PROHIBITED_DIRECTORY = "/system"; + private final static String LOG_TAG = "android.net.DownloadManagerIntegrationTest"; + private final static String PROHIBITED_DIRECTORY = + Environment.getRootDirectory().getAbsolutePath(); + private final static String CACHE_DIR = + Environment.getDownloadCacheDirectory().getAbsolutePath(); protected MultipleDownloadsCompletedReceiver mReceiver = null; /** @@ -74,25 +82,48 @@ public class DownloadManagerIntegrationTest extends DownloadManagerBaseTest { public void tearDown() throws Exception { super.tearDown(); setWiFiStateOn(true); + removeAllCurrentDownloads(); if (mReceiver != null) { mContext.unregisterReceiver(mReceiver); mReceiver = null; - removeAllCurrentDownloads(); } } /** * Helper that does the actual basic download verification. */ - protected void doBasicDownload(byte[] blobData) throws Exception { + protected long doBasicDownload(byte[] blobData) throws Exception { long dlRequest = doStandardEnqueue(blobData); // wait for the download to complete waitForDownloadOrTimeout(dlRequest); - verifyAndCleanupSingleFileDownload(dlRequest, blobData); assertEquals(1, mReceiver.numDownloadsCompleted()); + return dlRequest; + } + + /** + * Verifies a particular error code was received from a download + * + * @param uri The uri to enqueue to the DownloadManager + * @param error The error code expected + * @throws an Exception if the test fails + */ + @LargeTest + public void doErrorTest(Uri uri, int error) throws Exception { + Request request = new Request(uri); + request.setTitle(DEFAULT_FILENAME); + + long dlRequest = mDownloadManager.enqueue(request); + waitForDownloadOrTimeout(dlRequest); + + Cursor cursor = getCursor(dlRequest); + try { + verifyInt(cursor, DownloadManager.COLUMN_ERROR_CODE, error); + } finally { + cursor.close(); + } } /** @@ -103,7 +134,8 @@ public class DownloadManagerIntegrationTest extends DownloadManagerBaseTest { int fileSize = 500 * 1024; // 500k byte[] blobData = generateData(fileSize, DataType.BINARY); - doBasicDownload(blobData); + long dlRequest = doBasicDownload(blobData); + verifyAndCleanupSingleFileDownload(dlRequest, blobData); } /** @@ -114,7 +146,8 @@ public class DownloadManagerIntegrationTest extends DownloadManagerBaseTest { int fileSize = 300000; byte[] blobData = generateData(fileSize, DataType.TEXT); - doBasicDownload(blobData); + long dlRequest = doBasicDownload(blobData); + verifyAndCleanupSingleFileDownload(dlRequest, blobData); } /** @@ -348,34 +381,209 @@ public class DownloadManagerIntegrationTest extends DownloadManagerBaseTest { } /** - * Tests trying to download two large files (50M bytes, followed by 60M bytes) + * Tests downloading a file to cache when there isn't enough space in the cache to hold the + * entire file. */ @LargeTest - public void testInsufficientSpaceSingleFiles() throws Exception { - long fileSize1 = 50000000L; - long fileSize2 = 60000000L; - File largeFile1 = createFileOnSD(null, fileSize1, DataType.TEXT, null); - File largeFile2 = createFileOnSD(null, fileSize2, DataType.TEXT, null); + public void testDownloadToCache_whenFull() throws Exception { + int DOWNLOAD_FILE_SIZE = 500000; + + StatFs fs = new StatFs(CACHE_DIR); + Log.i(LOG_TAG, "getAvailableBlocks: " + fs.getAvailableBlocks()); + Log.i(LOG_TAG, "getBlockSize: " + fs.getBlockSize()); + + int blockSize = fs.getBlockSize(); + int availableBlocks = fs.getAvailableBlocks(); + int availableBytes = blockSize * availableBlocks; + File outFile = null; try { - long dlRequest = doStandardEnqueue(largeFile1); - waitForDownloadOrTimeout(dlRequest); - ParcelFileDescriptor pfd = mDownloadManager.openDownloadedFile(dlRequest); - verifyFileContents(pfd, largeFile1); - verifyFileSize(pfd, largeFile1.length()); + // fill cache to ensure we don't have enough space - take half the size of the + // download size, and leave that much freespace left on the cache partition + if (DOWNLOAD_FILE_SIZE <= availableBytes) { + int writeSizeBytes = availableBytes - (DOWNLOAD_FILE_SIZE / 2); + + int writeSizeBlocks = writeSizeBytes / blockSize; + int remainderSizeBlocks = availableBlocks - writeSizeBlocks; + + FileOutputStream fo = null; + try { + outFile = File.createTempFile("DM_TEST", null, new File(CACHE_DIR)); + Log.v(LOG_TAG, "writing " + writeSizeBlocks + " blocks to file " + + outFile.getAbsolutePath()); + + fo = new FileOutputStream(outFile); + + byte[] buffer = new byte[blockSize]; + while (fs.getAvailableBlocks() >= remainderSizeBlocks) { + fo.write(buffer); + fs.restat(CACHE_DIR); + } + } catch (IOException e) { + Log.e(LOG_TAG, "error filling file: ", e); + throw e; + } finally { + if (fo != null) { + fo.close(); + } + } + } - dlRequest = doStandardEnqueue(largeFile2); - waitForDownloadOrTimeout(dlRequest); - Cursor cursor = getCursor(dlRequest); - try { - verifyInt(cursor, DownloadManager.COLUMN_ERROR_CODE, - DownloadManager.ERROR_INSUFFICIENT_SPACE); - } finally { - cursor.close(); + assertTrue(DOWNLOAD_FILE_SIZE > (fs.getAvailableBlocks() * blockSize)); + byte[] blobData = generateData(DOWNLOAD_FILE_SIZE, DataType.TEXT); + long dlRequest = doBasicDownload(blobData); + verifyAndCleanupSingleFileDownload(dlRequest, blobData); + + } finally { + if (outFile != null) { + outFile.delete(); } + } + } + + /** + * Tests that files are not deleted when DOWNLOAD_CACHE_NON_PURGEABLE is set, even if we've + * run out of space. + */ + @LargeTest + public void testDownloadCacheNonPurgeable() throws Exception { + int fileSize = 10000000; + byte[] blobData = generateData(fileSize, DataType.BINARY); + long dlRequest = -1; + + // Fill up the cache partition until there's not enough room for another download. + // Note that we need to initiate a download first, then check for the available space. This + // is b/c there could be some files that are still left in the cache that can (and will be) + // cleared out, but not until DM gets a request for a download and reclaims that + // space first. + boolean spaceAvailable = true; + while (spaceAvailable) { + dlRequest = doStandardEnqueue(blobData); + waitForDownloadOrTimeout(dlRequest); + + // Check if we've filled up the cache yet + StatFs fs = new StatFs(CACHE_DIR); + Log.i(LOG_TAG, "getAvailableBlocks: " + fs.getAvailableBlocks()); + Log.i(LOG_TAG, "getBlockSize: " + fs.getBlockSize()); + int availableBytes = fs.getBlockSize() * fs.getAvailableBlocks(); + spaceAvailable = (availableBytes > fileSize) ? true : false; + } + + // Now add one more download (should not fit in the space left over) + dlRequest = doStandardEnqueue(blobData); + waitForDownloadOrTimeout(dlRequest); + + // For the last download we should have failed b/c there is not enough space left in cache + Cursor cursor = getCursor(dlRequest); + try { + verifyInt(cursor, DownloadManager.COLUMN_ERROR_CODE, + DownloadManager.ERROR_INSUFFICIENT_SPACE); + } finally { + cursor.close(); + } + } + + /** + * Tests that we get the correct download ID from the download notification. + */ + @LargeTest + public void testGetDownloadIdOnNotification() throws Exception { + byte[] blobData = generateData(3000, DataType.TEXT); // file size = 3000 bytes + + MockResponse response = enqueueResponse(HTTP_OK, blobData); + long dlRequest = doCommonStandardEnqueue(); + waitForDownloadOrTimeout(dlRequest); + + Set<Long> ids = mReceiver.getDownloadIds(); + assertEquals(1, ids.size()); + Iterator<Long> it = ids.iterator(); + assertEquals("Download ID received from notification does not match initial id!", + dlRequest, it.next().longValue()); + } + + /** + * Tests the download failure error after too many redirects (>5). + */ + @LargeTest + public void testErrorTooManyRedirects() throws Exception { + Uri uri = getServerUri(DEFAULT_FILENAME); + + // force 6 redirects + for (int i = 0; i < 6; ++i) { + MockResponse response = enqueueResponse(HTTP_REDIRECT); + response.addHeader("Location", uri.toString()); + } + doErrorTest(uri, DownloadManager.ERROR_TOO_MANY_REDIRECTS); + } + + /** + * Tests the download failure error from an unhandled HTTP status code + */ + @LargeTest + public void testErrorUnhandledHttpCode() throws Exception { + Uri uri = getServerUri(DEFAULT_FILENAME); + MockResponse response = enqueueResponse(HTTP_PARTIAL_CONTENT); + + doErrorTest(uri, DownloadManager.ERROR_UNHANDLED_HTTP_CODE); + } + + /** + * Tests the download failure error from an unhandled HTTP status code + */ + @LargeTest + public void testErrorHttpDataError_invalidRedirect() throws Exception { + Uri uri = getServerUri(DEFAULT_FILENAME); + MockResponse response = enqueueResponse(HTTP_REDIRECT); + response.addHeader("Location", "://blah.blah.blah.com"); + + doErrorTest(uri, DownloadManager.ERROR_HTTP_DATA_ERROR); + } + + /** + * Tests that we can remove a download from the download manager. + */ + @LargeTest + public void testRemoveDownload() throws Exception { + int fileSize = 100 * 1024; // 100k + byte[] blobData = generateData(fileSize, DataType.BINARY); + + long dlRequest = doBasicDownload(blobData); + Cursor cursor = mDownloadManager.query(new Query().setFilterById(dlRequest)); + try { + assertEquals("The count of downloads with this ID is not 1!", 1, cursor.getCount()); + mDownloadManager.remove(dlRequest); + cursor.requery(); + assertEquals("The count of downloads with this ID is not 0!", 0, cursor.getCount()); + } finally { + cursor.close(); + } + } + + /** + * Tests that we can set the title of a download. + */ + @LargeTest + public void testSetTitle() throws Exception { + int fileSize = 50 * 1024; // 50k + byte[] blobData = generateData(fileSize, DataType.BINARY); + MockResponse response = enqueueResponse(HTTP_OK, blobData); + + // An arbitrary unicode string title + final String title = "\u00a5123;\"\u0152\u017d \u054b \u0a07 \ucce0 \u6820\u03a8\u5c34" + + "\uf4ad\u0da9\uc0c5\uc1a8 \uf4c5 \uf4aa\u0023\'"; + + Uri uri = getServerUri(DEFAULT_FILENAME); + Request request = new Request(uri); + request.setTitle(title); + + long dlRequest = mDownloadManager.enqueue(request); + waitForDownloadOrTimeout(dlRequest); + + Cursor cursor = getCursor(dlRequest); + try { + verifyString(cursor, DownloadManager.COLUMN_TITLE, title); } finally { - largeFile1.delete(); - largeFile2.delete(); + cursor.close(); } } } diff --git a/core/tests/coretests/src/android/util/Base64Test.java b/core/tests/coretests/src/android/util/Base64Test.java index 0f5b090..53368d4 100644 --- a/core/tests/coretests/src/android/util/Base64Test.java +++ b/core/tests/coretests/src/android/util/Base64Test.java @@ -16,6 +16,9 @@ package android.util; +import java.io.IOException; +import java.io.InputStream; +import java.util.Arrays; import junit.framework.TestCase; import java.io.ByteArrayInputStream; @@ -404,6 +407,14 @@ public class Base64Test extends TestCase { } } + /** http://b/3026478 */ + public void testSingleByteReads() throws IOException { + InputStream in = new Base64InputStream( + new ByteArrayInputStream("/v8=".getBytes()), Base64.DEFAULT); + assertEquals(254, in.read()); + assertEquals(255, in.read()); + } + /** * Tests that Base64OutputStream produces exactly the same results * as calling Base64.encode/.decode on an in-memory array. diff --git a/core/tests/hosttests/src/android/content/pm/PackageManagerHostTestUtils.java b/core/tests/hosttests/src/android/content/pm/PackageManagerHostTestUtils.java index 0f7351a..c698e99 100644 --- a/core/tests/hosttests/src/android/content/pm/PackageManagerHostTestUtils.java +++ b/core/tests/hosttests/src/android/content/pm/PackageManagerHostTestUtils.java @@ -601,7 +601,7 @@ public class PackageManagerHostTestUtils extends Assert { mTestRunErrorMessage = errorMessage; } - public void testRunStarted(int testCount) { + public void testRunStarted(String runName, int testCount) { // ignore } diff --git a/core/tests/hosttests/src/android/net/DownloadManagerHostTests.java b/core/tests/hosttests/src/android/net/DownloadManagerHostTests.java index cfabb6c..a94555c 100644 --- a/core/tests/hosttests/src/android/net/DownloadManagerHostTests.java +++ b/core/tests/hosttests/src/android/net/DownloadManagerHostTests.java @@ -46,8 +46,10 @@ public class DownloadManagerHostTests extends DeviceTestCase { private static final String EXTERNAL_DOWNLOAD_URI_KEY = "external_download_uri"; // Note: External environment variable ANDROID_TEST_EXTERNAL_URI must be set to point to the // external URI under which the files downloaded by the tests can be found. Note that the Uri - // must be accessible by the device during a test run. - private static String EXTERNAL_DOWNLOAD_URI_VALUE = null; + // must be accessible by the device during a test run. Correspondingly, + // ANDROID_TEST_EXTERNAL_LARGE_URI should point to the external URI of the folder containing + // large files. + private static String externalDownloadUriValue = null; Hashtable<String, String> mExtraParams = null; @@ -61,8 +63,8 @@ public class DownloadManagerHostTests extends DeviceTestCase { // ensure apk path has been set before test is run assertNotNull(getTestAppPath()); mPMUtils = new PackageManagerHostTestUtils(getDevice()); - EXTERNAL_DOWNLOAD_URI_VALUE = System.getenv("ANDROID_TEST_EXTERNAL_URI"); - assertNotNull(EXTERNAL_DOWNLOAD_URI_VALUE); + externalDownloadUriValue = System.getenv("ANDROID_TEST_EXTERNAL_URI"); + assertNotNull(externalDownloadUriValue); mExtraParams = getExtraParams(); } @@ -71,7 +73,7 @@ public class DownloadManagerHostTests extends DeviceTestCase { */ protected Hashtable<String, String> getExtraParams() { Hashtable<String, String> extraParams = new Hashtable<String, String>(); - extraParams.put(EXTERNAL_DOWNLOAD_URI_KEY, EXTERNAL_DOWNLOAD_URI_VALUE); + extraParams.put(EXTERNAL_DOWNLOAD_URI_KEY, externalDownloadUriValue); return extraParams; } @@ -190,4 +192,19 @@ public class DownloadManagerHostTests extends DeviceTestCase { DOWNLOAD_TEST_RUNNER_NAME, mExtraParams); assertTrue(testPassed); } + + /** + * Spawns a device-based function to test 15 concurrent downloads of 5,000,000-byte files + * + * @throws Exception if the test failed at any point + */ + public void testDownloadMultipleSimultaneously() throws Exception { + mPMUtils.installAppAndVerifyExistsOnDevice(String.format("%s%s%s", getTestAppPath(), + File.separator, FILE_DOWNLOAD_APK), FILE_DOWNLOAD_PKG, true); + + boolean testPassed = mPMUtils.runDeviceTestsDidAllTestsPass(FILE_DOWNLOAD_PKG, + FILE_DOWNLOAD_CLASS, "runDownloadMultipleSimultaneously", + DOWNLOAD_TEST_RUNNER_NAME, mExtraParams); + assertTrue(testPassed); + } } diff --git a/core/tests/hosttests/test-apps/DownloadManagerTestApp/src/com/android/frameworks/DownloadManagerTestApp.java b/core/tests/hosttests/test-apps/DownloadManagerTestApp/src/com/android/frameworks/DownloadManagerTestApp.java index ef81353..0293ded 100644 --- a/core/tests/hosttests/test-apps/DownloadManagerTestApp/src/com/android/frameworks/DownloadManagerTestApp.java +++ b/core/tests/hosttests/test-apps/DownloadManagerTestApp/src/com/android/frameworks/DownloadManagerTestApp.java @@ -35,6 +35,7 @@ import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.FileWriter; +import java.util.HashSet; import coretestutils.http.MockResponse; import coretestutils.http.MockWebServer; @@ -55,8 +56,13 @@ public class DownloadManagerTestApp extends DownloadManagerBaseTest { protected static String DOWNLOAD_10MB_FILENAME = "External10mb.apk"; protected static long DOWNLOAD_10MB_FILESIZE = 10258741; + private static final String FILE_CONCURRENT_DOWNLOAD_FILE_PREFIX = "file"; + private static final String FILE_CONCURRENT_DOWNLOAD_FILE_EXTENSION = ".bin"; + protected static long CONCURRENT_DOWNLOAD_FILESIZE = 1000000; + // Values to be obtained from TestRunner private String externalDownloadUriValue = null; + private String externalLargeDownloadUriValue = null; /** * {@inheritDoc } @@ -65,12 +71,24 @@ public class DownloadManagerTestApp extends DownloadManagerBaseTest { public void setUp() throws Exception { super.setUp(); DownloadManagerTestRunner mRunner = (DownloadManagerTestRunner)getInstrumentation(); - externalDownloadUriValue = mRunner.externalDownloadUriValue; + externalDownloadUriValue = normalizeUri(mRunner.externalDownloadUriValue); assertNotNull(externalDownloadUriValue); - if (!externalDownloadUriValue.endsWith("/")) { - externalDownloadUriValue += "/"; + externalLargeDownloadUriValue = normalizeUri(mRunner.externalDownloadUriValue); + assertNotNull(externalLargeDownloadUriValue); + } + + /** + * Normalizes a uri to ensure it ends with a "/" + * + * @param uri The uri to normalize (or null) + * @return The normalized uri, or null if null was passed in + */ + public String normalizeUri(String uri) { + if (uri != null && !uri.endsWith("/")) { + uri += "/"; } + return uri; } /** @@ -460,4 +478,37 @@ public class DownloadManagerTestApp extends DownloadManagerBaseTest { downloadedFile.delete(); } } + + /** + * Tests 15 concurrent downloads of 1,000,000-byte files. + * + * @throws Exception if test failed + */ + public void runDownloadMultipleSimultaneously() throws Exception { + final int TOTAL_DOWNLOADS = 15; + HashSet<Long> downloadIds = new HashSet<Long>(TOTAL_DOWNLOADS); + MultipleDownloadsCompletedReceiver receiver = registerNewMultipleDownloadsReceiver(); + + // Make sure there are no pending downloads currently going on + removeAllCurrentDownloads(); + + try { + for (int i = 0; i < TOTAL_DOWNLOADS; ++i) { + long dlRequest = -1; + String filename = FILE_CONCURRENT_DOWNLOAD_FILE_PREFIX + i + + FILE_CONCURRENT_DOWNLOAD_FILE_EXTENSION; + Uri remoteUri = getExternalFileUri(filename); + Request request = new Request(remoteUri); + request.setTitle(filename); + dlRequest = mDownloadManager.enqueue(request); + assertTrue(dlRequest != -1); + downloadIds.add(dlRequest); + } + + waitForDownloadsOrTimeout(DEFAULT_WAIT_POLL_TIME, 15 * 60 * 2000); // wait 15 mins max + assertEquals(TOTAL_DOWNLOADS, receiver.numDownloadsCompleted()); + } finally { + removeAllCurrentDownloads(); + } + } } diff --git a/core/tests/hosttests/test-apps/DownloadManagerTestApp/src/com/android/frameworks/DownloadManagerTestRunner.java b/core/tests/hosttests/test-apps/DownloadManagerTestApp/src/com/android/frameworks/DownloadManagerTestRunner.java index 0f16619..27bf7e1 100644 --- a/core/tests/hosttests/test-apps/DownloadManagerTestApp/src/com/android/frameworks/DownloadManagerTestRunner.java +++ b/core/tests/hosttests/test-apps/DownloadManagerTestApp/src/com/android/frameworks/DownloadManagerTestRunner.java @@ -30,7 +30,7 @@ import junit.framework.TestSuite; * * To run the download manager tests: * - * adb shell am instrument -e external_download_1mb_uri <uri> external_download_500k_uri <uri> \ + * adb shell am instrument -e external_download_uri <uri> external_large_download_uri <uri> \ * -w com.android.frameworks.downloadmanagertests/.DownloadManagerTestRunner */ diff --git a/data/fonts/MTLc3m.ttf b/data/fonts/MTLc3m.ttf Binary files differnew file mode 100644 index 0000000..3cc5c96 --- /dev/null +++ b/data/fonts/MTLc3m.ttf diff --git a/data/fonts/MTLmr3m.ttf b/data/fonts/MTLmr3m.ttf Binary files differnew file mode 100644 index 0000000..05b9093 --- /dev/null +++ b/data/fonts/MTLmr3m.ttf diff --git a/graphics/java/android/graphics/RadialGradient.java b/graphics/java/android/graphics/RadialGradient.java index b4e902d..897762c 100644 --- a/graphics/java/android/graphics/RadialGradient.java +++ b/graphics/java/android/graphics/RadialGradient.java @@ -40,6 +40,8 @@ public class RadialGradient extends Shader { throw new IllegalArgumentException("color and position arrays must be of equal length"); } native_instance = nativeCreate1(x, y, radius, colors, positions, tile.nativeInt); + native_shader = nativePostCreate1(native_instance, x, y, radius, colors, positions, + tile.nativeInt); } /** Create a shader that draws a radial gradient given the center and radius. @@ -56,11 +58,18 @@ public class RadialGradient extends Shader { throw new IllegalArgumentException("radius must be > 0"); } native_instance = nativeCreate2(x, y, radius, color0, color1, tile.nativeInt); + native_shader = nativePostCreate2(native_instance, x, y, radius, color0, color1, + tile.nativeInt); } private static native int nativeCreate1(float x, float y, float radius, - int colors[], float positions[], int tileMode); + int colors[], float positions[], int tileMode); private static native int nativeCreate2(float x, float y, float radius, - int color0, int color1, int tileMode); + int color0, int color1, int tileMode); + + private static native int nativePostCreate1(int native_shader, float x, float y, float radius, + int colors[], float positions[], int tileMode); + private static native int nativePostCreate2(int native_shader, float x, float y, float radius, + int color0, int color1, int tileMode); } diff --git a/graphics/java/android/graphics/Shader.java b/graphics/java/android/graphics/Shader.java index b397662..0400b5c 100644 --- a/graphics/java/android/graphics/Shader.java +++ b/graphics/java/android/graphics/Shader.java @@ -71,7 +71,8 @@ public class Shader { * @param localM The shader's new local matrix, or null to specify identity */ public void setLocalMatrix(Matrix localM) { - nativeSetLocalMatrix(native_instance, native_shader, localM.native_instance); + nativeSetLocalMatrix(native_instance, native_shader, + localM == null ? 0 : localM.native_instance); } protected void finalize() throws Throwable { diff --git a/graphics/java/android/graphics/SweepGradient.java b/graphics/java/android/graphics/SweepGradient.java index 7456993..2afdd4d 100644 --- a/graphics/java/android/graphics/SweepGradient.java +++ b/graphics/java/android/graphics/SweepGradient.java @@ -42,6 +42,7 @@ public class SweepGradient extends Shader { "color and position arrays must be of equal length"); } native_instance = nativeCreate1(cx, cy, colors, positions); + native_shader = nativePostCreate1(native_instance, cx, cy, colors, positions); } /** @@ -54,11 +55,15 @@ public class SweepGradient extends Shader { */ public SweepGradient(float cx, float cy, int color0, int color1) { native_instance = nativeCreate2(cx, cy, color0, color1); + native_shader = nativePostCreate2(native_instance, cx, cy, color0, color1); } - private static native int nativeCreate1(float x, float y, - int colors[], float positions[]); - private static native int nativeCreate2(float x, float y, - int color0, int color1); + private static native int nativeCreate1(float x, float y, int colors[], float positions[]); + private static native int nativeCreate2(float x, float y, int color0, int color1); + + private static native int nativePostCreate1(int native_shader, float cx, float cy, + int[] colors, float[] positions); + private static native int nativePostCreate2(int native_shader, float cx, float cy, + int color0, int color1); } diff --git a/graphics/java/android/renderscript/BaseObj.java b/graphics/java/android/renderscript/BaseObj.java index 3198e3f..715e3fb 100644 --- a/graphics/java/android/renderscript/BaseObj.java +++ b/graphics/java/android/renderscript/BaseObj.java @@ -32,6 +32,9 @@ class BaseObj { } public int getID() { + if (mDestroyed) { + throw new IllegalStateException("using a destroyed object."); + } return mID; } diff --git a/graphics/java/android/renderscript/RenderScript.java b/graphics/java/android/renderscript/RenderScript.java index 1312036..159e070 100644 --- a/graphics/java/android/renderscript/RenderScript.java +++ b/graphics/java/android/renderscript/RenderScript.java @@ -358,6 +358,10 @@ public class RenderScript { synchronized void nScriptSetVarF(int id, int slot, float val) { rsnScriptSetVarF(mContext, id, slot, val); } + native void rsnScriptSetVarD(int con, int id, int slot, double val); + synchronized void nScriptSetVarD(int id, int slot, double val) { + rsnScriptSetVarD(mContext, id, slot, val); + } native void rsnScriptSetVarV(int con, int id, int slot, byte[] val); synchronized void nScriptSetVarV(int id, int slot, byte[] val) { rsnScriptSetVarV(mContext, id, slot, val); diff --git a/graphics/java/android/renderscript/Script.java b/graphics/java/android/renderscript/Script.java index 19c444c..8772c4c 100644 --- a/graphics/java/android/renderscript/Script.java +++ b/graphics/java/android/renderscript/Script.java @@ -72,6 +72,10 @@ public class Script extends BaseObj { mRS.nScriptSetVarF(mID, index, v); } + public void setVar(int index, double v) { + mRS.nScriptSetVarD(mID, index, v); + } + public void setVar(int index, int v) { mRS.nScriptSetVarI(mID, index, v); } diff --git a/graphics/jni/android_renderscript_RenderScript.cpp b/graphics/jni/android_renderscript_RenderScript.cpp index f386537..ee2080e 100644 --- a/graphics/jni/android_renderscript_RenderScript.cpp +++ b/graphics/jni/android_renderscript_RenderScript.cpp @@ -791,11 +791,18 @@ nScriptSetVarI(JNIEnv *_env, jobject _this, RsContext con, jint script, jint slo static void nScriptSetVarF(JNIEnv *_env, jobject _this, RsContext con, jint script, jint slot, float val) { - LOG_API("nScriptSetVarI, con(%p), s(%p), slot(%i), val(%f)", con, (void *)script, slot, val); + LOG_API("nScriptSetVarF, con(%p), s(%p), slot(%i), val(%f)", con, (void *)script, slot, val); rsScriptSetVarF(con, (RsScript)script, slot, val); } static void +nScriptSetVarD(JNIEnv *_env, jobject _this, RsContext con, jint script, jint slot, double val) +{ + LOG_API("nScriptSetVarD, con(%p), s(%p), slot(%i), val(%lf)", con, (void *)script, slot, val); + rsScriptSetVarD(con, (RsScript)script, slot, val); +} + +static void nScriptSetVarV(JNIEnv *_env, jobject _this, RsContext con, jint script, jint slot, jbyteArray data) { LOG_API("nScriptSetVarV, con(%p), s(%p), slot(%i)", con, (void *)script, slot); @@ -1281,6 +1288,7 @@ static JNINativeMethod methods[] = { {"rsnScriptInvokeV", "(III[B)V", (void*)nScriptInvokeV }, {"rsnScriptSetVarI", "(IIII)V", (void*)nScriptSetVarI }, {"rsnScriptSetVarF", "(IIIF)V", (void*)nScriptSetVarF }, +{"rsnScriptSetVarD", "(IIID)V", (void*)nScriptSetVarD }, {"rsnScriptSetVarV", "(III[B)V", (void*)nScriptSetVarV }, {"rsnScriptCBegin", "(I)V", (void*)nScriptCBegin }, diff --git a/include/camera/CameraParameters.h b/include/camera/CameraParameters.h index 72d5756..705b101 100644 --- a/include/camera/CameraParameters.h +++ b/include/camera/CameraParameters.h @@ -383,12 +383,14 @@ public: // continuously. Applications should not call // CameraHardwareInterface.autoFocus in this mode. static const char FOCUS_MODE_EDOF[]; - // Continuous auto focus mode. The camera continuously tries to focus. This - // is ideal for shooting video or shooting photo of moving object. Auto - // focus starts when the parameter is set. Applications should not call - // CameraHardwareInterface.autoFocus in this mode. To stop continuous - // focus, applications should change the focus mode to other modes. - static const char FOCUS_MODE_CONTINUOUS[]; + // Continuous auto focus mode intended for video recording. The camera + // continuously tries to focus. This is ideal for shooting video. + // Applications still can call CameraHardwareInterface.takePicture in this + // mode but the subject may not be in focus. Auto focus starts when the + // parameter is set. Applications should not call + // CameraHardwareInterface.autoFocus in this mode. To stop continuous focus, + // applications should change the focus mode to other modes. + static const char FOCUS_MODE_CONTINUOUS_VIDEO[]; private: DefaultKeyedVector<String8,String8> mMap; diff --git a/include/media/stagefright/foundation/ADebug.h b/include/media/stagefright/foundation/ADebug.h index 0f986a0..69021d8 100644 --- a/include/media/stagefright/foundation/ADebug.h +++ b/include/media/stagefright/foundation/ADebug.h @@ -22,45 +22,18 @@ #include <media/stagefright/foundation/ABase.h> #include <media/stagefright/foundation/AString.h> +#include <utils/Log.h> namespace android { -enum LogType { - VERBOSE, - INFO, - WARNING, - ERROR, - FATAL, -}; - -struct Logger { - Logger(LogType type); - virtual ~Logger(); - - template<class T> Logger &operator<<(const T &x) { - mMessage.append(x); - - return *this; - } - -private: - android::AString mMessage; - LogType mLogType; - - DISALLOW_EVIL_CONSTRUCTORS(Logger); -}; - -const char *LeafName(const char *s); - -#undef LOG -#define LOG(type) Logger(type) << LeafName(__FILE__) << ":" << __LINE__ << " " +#define LITERAL_TO_STRING_INTERNAL(x) #x +#define LITERAL_TO_STRING(x) LITERAL_TO_STRING_INTERNAL(x) #define CHECK(condition) \ - do { \ - if (!(condition)) { \ - LOG(FATAL) << "CHECK(" #condition ") failed."; \ - } \ - } while (false) + LOG_ALWAYS_FATAL_IF( \ + !(condition), \ + __FILE__ ":" LITERAL_TO_STRING(__LINE__) \ + " CHECK(" #condition ") failed.") #define MAKE_COMPARATOR(suffix,op) \ template<class A, class B> \ @@ -85,8 +58,10 @@ MAKE_COMPARATOR(GT,>) do { \ AString ___res = Compare_##suffix(x, y); \ if (!___res.empty()) { \ - LOG(FATAL) << "CHECK_" #suffix "(" #x "," #y ") failed: " \ - << ___res; \ + LOG_ALWAYS_FATAL( \ + __FILE__ ":" LITERAL_TO_STRING(__LINE__) \ + " CHECK_" #suffix "( " #x "," #y ") failed: %s", \ + ___res.c_str()); \ } \ } while (false) @@ -97,7 +72,7 @@ MAKE_COMPARATOR(GT,>) #define CHECK_GE(x,y) CHECK_OP(x,y,GE,>=) #define CHECK_GT(x,y) CHECK_OP(x,y,GT,>) -#define TRESPASS() LOG(FATAL) << "Should not be here." +#define TRESPASS() LOG_ALWAYS_FATAL("Should not be here.") } // namespace android diff --git a/include/utils/Looper.h b/include/utils/Looper.h index 7d90866..3f00b78 100644 --- a/include/utils/Looper.h +++ b/include/utils/Looper.h @@ -205,6 +205,7 @@ private: int pollInner(int timeoutMillis); + static void initTLSKey(); static void threadDestructor(void *st); }; diff --git a/libs/camera/CameraParameters.cpp b/libs/camera/CameraParameters.cpp index 887b12c..af58f77 100644 --- a/libs/camera/CameraParameters.cpp +++ b/libs/camera/CameraParameters.cpp @@ -142,7 +142,7 @@ const char CameraParameters::FOCUS_MODE_INFINITY[] = "infinity"; const char CameraParameters::FOCUS_MODE_MACRO[] = "macro"; const char CameraParameters::FOCUS_MODE_FIXED[] = "fixed"; const char CameraParameters::FOCUS_MODE_EDOF[] = "edof"; -const char CameraParameters::FOCUS_MODE_CONTINUOUS[] = "continuous"; +const char CameraParameters::FOCUS_MODE_CONTINUOUS_VIDEO[] = "continuous-video"; CameraParameters::CameraParameters() : mMap() diff --git a/libs/hwui/GradientCache.cpp b/libs/hwui/GradientCache.cpp index 9957370..97f4cb4 100644 --- a/libs/hwui/GradientCache.cpp +++ b/libs/hwui/GradientCache.cpp @@ -116,7 +116,7 @@ void GradientCache::clear() { mCache.clear(); } -Texture* GradientCache::addLinearGradient(SkShader* shader, float* bounds, uint32_t* colors, +Texture* GradientCache::addLinearGradient(SkShader* shader, uint32_t* colors, float* positions, int count, SkShader::TileMode tileMode) { SkBitmap bitmap; bitmap.setConfig(SkBitmap::kARGB_8888_Config, 1024, 1); diff --git a/libs/hwui/GradientCache.h b/libs/hwui/GradientCache.h index 51a8c01..c829fd4 100644 --- a/libs/hwui/GradientCache.h +++ b/libs/hwui/GradientCache.h @@ -46,8 +46,8 @@ public: * Adds a new linear gradient to the cache. The generated texture is * returned. */ - Texture* addLinearGradient(SkShader* shader, float* bounds, uint32_t* colors, - float* positions, int count, SkShader::TileMode tileMode); + Texture* addLinearGradient(SkShader* shader, uint32_t* colors, float* positions, + int count, SkShader::TileMode tileMode = SkShader::kClamp_TileMode); /** * Returns the texture associated with the specified shader. */ diff --git a/libs/hwui/Matrix.cpp b/libs/hwui/Matrix.cpp index 264ad3d..c698b5a 100644 --- a/libs/hwui/Matrix.cpp +++ b/libs/hwui/Matrix.cpp @@ -144,6 +144,12 @@ float Matrix4::getTranslateY() { return data[kTranslateY]; } +void Matrix4::multiply(float v) { + for (int i = 0; i < 16; i++) { + data[i] *= v; + } +} + void Matrix4::loadTranslate(float x, float y, float z) { loadIdentity(); data[kTranslateX] = x; diff --git a/libs/hwui/Matrix.h b/libs/hwui/Matrix.h index c247a67..0608efe 100644 --- a/libs/hwui/Matrix.h +++ b/libs/hwui/Matrix.h @@ -83,6 +83,8 @@ public: load(u); } + void multiply(float v); + void translate(float x, float y, float z) { Matrix4 u; u.loadTranslate(x, y, z); diff --git a/libs/hwui/ProgramCache.cpp b/libs/hwui/ProgramCache.cpp index becbc22..3e9412c 100644 --- a/libs/hwui/ProgramCache.cpp +++ b/libs/hwui/ProgramCache.cpp @@ -33,11 +33,21 @@ const char* gVS_Header_Attributes_TexCoords = "attribute vec2 texCoords;\n"; const char* gVS_Header_Uniforms = "uniform mat4 transform;\n"; -const char* gVS_Header_Uniforms_HasGradient = +const char* gVS_Header_Uniforms_HasGradient[3] = { + // Linear "uniform float gradientLength;\n" "uniform vec2 gradient;\n" "uniform vec2 gradientStart;\n" - "uniform mat4 screenSpace;\n"; + "uniform mat4 screenSpace;\n", + // Circular + "uniform vec2 gradientStart;\n" + "uniform mat4 gradientMatrix;\n" + "uniform mat4 screenSpace;\n", + // Sweep + "uniform vec2 gradientStart;\n" + "uniform mat4 gradientMatrix;\n" + "uniform mat4 screenSpace;\n" +}; const char* gVS_Header_Uniforms_HasBitmap = "uniform mat4 textureTransform;\n" "uniform vec2 textureDimension;\n"; @@ -45,15 +55,29 @@ const char* gVS_Header_Varyings_HasTexture = "varying vec2 outTexCoords;\n"; const char* gVS_Header_Varyings_HasBitmap = "varying vec2 outBitmapTexCoords;\n"; -const char* gVS_Header_Varyings_HasGradient = - "varying float index;\n"; +const char* gVS_Header_Varyings_HasGradient[3] = { + // Linear + "varying float index;\n", + // Circular + "varying vec2 circular;\n", + // Sweep + "varying vec2 sweep;\n" +}; const char* gVS_Main = "\nvoid main(void) {\n"; const char* gVS_Main_OutTexCoords = " outTexCoords = texCoords;\n"; -const char* gVS_Main_OutGradientIndex = +const char* gVS_Main_OutGradient[3] = { + // Linear + " vec4 location = screenSpace * position;\n" + " index = dot(location.xy - gradientStart, gradient) * gradientLength;\n", + // Circular " vec4 location = screenSpace * position;\n" - " index = dot(location.xy - gradientStart, gradient) * gradientLength;\n"; + " circular = (gradientMatrix * vec4(location.xy - gradientStart, 0.0, 0.0)).xy;\n", + // Sweep + " vec4 location = screenSpace * position;\n" + " sweep = (gradientMatrix * vec4(location.xy - gradientStart, 0.0, 0.0)).xy;\n" +}; const char* gVS_Main_OutBitmapTexCoords = " vec4 bitmapCoords = textureTransform * position;\n" " outBitmapTexCoords = bitmapCoords.xy * textureDimension;\n"; @@ -74,8 +98,15 @@ const char* gFS_Uniforms_Color = "uniform vec4 color;\n"; const char* gFS_Uniforms_TextureSampler = "uniform sampler2D sampler;\n"; -const char* gFS_Uniforms_GradientSampler = - "uniform sampler2D gradientSampler;\n"; +const char* gFS_Uniforms_GradientSampler[3] = { + // Linear + "uniform sampler2D gradientSampler;\n", + // Circular + "uniform float gradientRadius;\n" + "uniform sampler2D gradientSampler;\n", + // Sweep + "uniform sampler2D gradientSampler;\n" +}; const char* gFS_Uniforms_BitmapSampler = "uniform sampler2D bitmapSampler;\n"; const char* gFS_Uniforms_ColorOp[4] = { @@ -99,8 +130,16 @@ const char* gFS_Main_FetchTexture = " fragColor = color * texture2D(sampler, outTexCoords);\n"; const char* gFS_Main_FetchA8Texture = " fragColor = color * texture2D(sampler, outTexCoords).a;\n"; -const char* gFS_Main_FetchGradient = - " vec4 gradientColor = texture2D(gradientSampler, vec2(index, 0.5));\n"; +const char* gFS_Main_FetchGradient[3] = { + // Linear + " vec4 gradientColor = texture2D(gradientSampler, vec2(index, 0.5));\n", + // Circular + " float index = length(circular) * gradientRadius;\n" + " vec4 gradientColor = texture2D(gradientSampler, vec2(index, 0.5));\n", + // Sweep + " float index = atan(sweep.y, sweep.x) * 0.15915494309; // inv(2 * PI)\n" + " vec4 gradientColor = texture2D(gradientSampler, vec2(index - floor(index), 0.5));\n" +}; const char* gFS_Main_FetchBitmap = " vec4 bitmapColor = texture2D(bitmapSampler, outBitmapTexCoords);\n"; const char* gFS_Main_FetchBitmapNpot = @@ -217,7 +256,7 @@ Program* ProgramCache::get(const ProgramDescription& description) { ssize_t index = mCache.indexOfKey(key); Program* program = NULL; if (index < 0) { - PROGRAM_LOGD("Could not find program with key 0x%x", key); + description.log("Could not find program"); program = generateProgram(description, key); mCache.add(key, program); } else { @@ -247,7 +286,7 @@ String8 ProgramCache::generateVertexShader(const ProgramDescription& description // Uniforms shader.append(gVS_Header_Uniforms); if (description.hasGradient) { - shader.append(gVS_Header_Uniforms_HasGradient); + shader.append(gVS_Header_Uniforms_HasGradient[description.gradientType]); } if (description.hasBitmap) { shader.append(gVS_Header_Uniforms_HasBitmap); @@ -257,7 +296,7 @@ String8 ProgramCache::generateVertexShader(const ProgramDescription& description shader.append(gVS_Header_Varyings_HasTexture); } if (description.hasGradient) { - shader.append(gVS_Header_Varyings_HasGradient); + shader.append(gVS_Header_Varyings_HasGradient[description.gradientType]); } if (description.hasBitmap) { shader.append(gVS_Header_Varyings_HasBitmap); @@ -269,7 +308,7 @@ String8 ProgramCache::generateVertexShader(const ProgramDescription& description shader.append(gVS_Main_OutTexCoords); } if (description.hasGradient) { - shader.append(gVS_Main_OutGradientIndex); + shader.append(gVS_Main_OutGradient[description.gradientType]); } if (description.hasBitmap) { shader.append(gVS_Main_OutBitmapTexCoords); @@ -301,7 +340,7 @@ String8 ProgramCache::generateFragmentShader(const ProgramDescription& descripti shader.append(gVS_Header_Varyings_HasTexture); } if (description.hasGradient) { - shader.append(gVS_Header_Varyings_HasGradient); + shader.append(gVS_Header_Varyings_HasGradient[description.gradientType]); } if (description.hasBitmap) { shader.append(gVS_Header_Varyings_HasBitmap); @@ -314,7 +353,7 @@ String8 ProgramCache::generateFragmentShader(const ProgramDescription& descripti shader.append(gFS_Uniforms_TextureSampler); } if (description.hasGradient) { - shader.append(gFS_Uniforms_GradientSampler); + shader.append(gFS_Uniforms_GradientSampler[description.gradientType]); } if (description.hasBitmap) { shader.append(gFS_Uniforms_BitmapSampler); @@ -348,7 +387,7 @@ String8 ProgramCache::generateFragmentShader(const ProgramDescription& descripti shader.append(gFS_Main_FetchColor); } if (description.hasGradient) { - shader.append(gFS_Main_FetchGradient); + shader.append(gFS_Main_FetchGradient[description.gradientType]); } if (description.hasBitmap) { if (!description.isBitmapNpot) { diff --git a/libs/hwui/ProgramCache.h b/libs/hwui/ProgramCache.h index 0a17052..4fa8011 100644 --- a/libs/hwui/ProgramCache.h +++ b/libs/hwui/ProgramCache.h @@ -44,9 +44,6 @@ namespace uirenderer { #define PROGRAM_LOGD(...) #endif -/* - * IMPORTANT: All 32 bits are used, switch to a long. - */ #define PROGRAM_KEY_TEXTURE 0x1 #define PROGRAM_KEY_A8_TEXTURE 0x2 #define PROGRAM_KEY_BITMAP 0x4 @@ -70,14 +67,13 @@ namespace uirenderer { #define PROGRAM_BITMAP_WRAPS_SHIFT 9 #define PROGRAM_BITMAP_WRAPT_SHIFT 11 +#define PROGRAM_GRADIENT_TYPE_SHIFT 33 + /////////////////////////////////////////////////////////////////////////////// // Types /////////////////////////////////////////////////////////////////////////////// -/* - * IMPORTANT: All 32 bits are used, switch to a long. - */ -typedef uint32_t programid; +typedef uint64_t programid; /////////////////////////////////////////////////////////////////////////////// // Cache @@ -96,9 +92,16 @@ struct ProgramDescription { kColorBlend }; + enum Gradient { + kGradientLinear, + kGradientCircular, + kGradientSweep + }; + ProgramDescription(): hasTexture(false), hasAlpha8Texture(false), hasBitmap(false), isBitmapNpot(false), hasGradient(false), + gradientType(kGradientLinear), shadersMode(SkXfermode::kClear_Mode), isBitmapFirst(false), bitmapWrapS(GL_CLAMP_TO_EDGE), bitmapWrapT(GL_CLAMP_TO_EDGE), colorOp(kColorNone), colorMode(SkXfermode::kClear_Mode), @@ -112,8 +115,12 @@ struct ProgramDescription { // Shaders bool hasBitmap; bool isBitmapNpot; + bool hasGradient; + Gradient gradientType; + SkXfermode::Mode shadersMode; + bool isBitmapFirst; GLenum bitmapWrapS; GLenum bitmapWrapT; @@ -152,7 +159,8 @@ struct ProgramDescription { } } if (hasGradient) key |= PROGRAM_KEY_GRADIENT; - if (isBitmapFirst) key |= PROGRAM_KEY_BITMAP_FIRST; + key |= programid(gradientType) << PROGRAM_GRADIENT_TYPE_SHIFT; + if (isBitmapFirst) key |= PROGRAM_KEY_BITMAP_FIRST; if (hasBitmap && hasGradient) { key |= (shadersMode & PROGRAM_MAX_XFERMODE) << PROGRAM_XFERMODE_SHADER_SHIFT; } @@ -174,6 +182,12 @@ struct ProgramDescription { if (swapSrcDst) key |= PROGRAM_KEY_SWAP_SRC_DST; return key; } + + void log(const char* message) const { + programid k = key(); + PROGRAM_LOGD("%s (key = 0x%.8x%.8x)", message, uint32_t(k >> 32), + uint32_t(k & 0xffffffff)); + } }; // struct ProgramDescription /** diff --git a/libs/hwui/SkiaShader.cpp b/libs/hwui/SkiaShader.cpp index 946cc4b..9e1f6c2 100644 --- a/libs/hwui/SkiaShader.cpp +++ b/libs/hwui/SkiaShader.cpp @@ -164,6 +164,7 @@ SkiaLinearGradientShader::~SkiaLinearGradientShader() { void SkiaLinearGradientShader::describe(ProgramDescription& description, const Extensions& extensions) { description.hasGradient = true; + description.gradientType = ProgramDescription::kGradientLinear; } void SkiaLinearGradientShader::setupProgram(Program* program, const mat4& modelView, @@ -173,8 +174,7 @@ void SkiaLinearGradientShader::setupProgram(Program* program, const mat4& modelV Texture* texture = mGradientCache->get(mKey); if (!texture) { - texture = mGradientCache->addLinearGradient(mKey, mBounds, mColors, mPositions, - mCount, mTileX); + texture = mGradientCache->addLinearGradient(mKey, mColors, mPositions, mCount, mTileX); } Rect start(mBounds[0], mBounds[1], mBounds[2], mBounds[3]); @@ -209,6 +209,101 @@ void SkiaLinearGradientShader::updateTransforms(Program* program, const mat4& mo } /////////////////////////////////////////////////////////////////////////////// +// Circular gradient shader +/////////////////////////////////////////////////////////////////////////////// + +SkiaCircularGradientShader::SkiaCircularGradientShader(float x, float y, float radius, + uint32_t* colors, float* positions, int count, SkShader* key, SkShader::TileMode tileMode, + SkMatrix* matrix, bool blend): + SkiaSweepGradientShader(kCircularGradient, x, y, colors, positions, count, key, + tileMode, matrix, blend), + mRadius(radius) { +} + +void SkiaCircularGradientShader::describe(ProgramDescription& description, + const Extensions& extensions) { + description.hasGradient = true; + description.gradientType = ProgramDescription::kGradientCircular; +} + +void SkiaCircularGradientShader::setupProgram(Program* program, const mat4& modelView, + const Snapshot& snapshot, GLuint* textureUnit) { + SkiaSweepGradientShader::setupProgram(program, modelView, snapshot, textureUnit); + glUniform1f(program->getUniform("gradientRadius"), 1.0f / mRadius); +} + +/////////////////////////////////////////////////////////////////////////////// +// Sweep gradient shader +/////////////////////////////////////////////////////////////////////////////// + +SkiaSweepGradientShader::SkiaSweepGradientShader(float x, float y, uint32_t* colors, + float* positions, int count, SkShader* key, SkMatrix* matrix, bool blend): + SkiaShader(kSweepGradient, key, SkShader::kClamp_TileMode, + SkShader::kClamp_TileMode, matrix, blend), + mX(x), mY(y), mColors(colors), mPositions(positions), mCount(count) { +} + +SkiaSweepGradientShader::SkiaSweepGradientShader(Type type, float x, float y, uint32_t* colors, + float* positions, int count, SkShader* key, SkShader::TileMode tileMode, + SkMatrix* matrix, bool blend): + SkiaShader(type, key, tileMode, tileMode, matrix, blend), + mX(x), mY(y), mColors(colors), mPositions(positions), mCount(count) { +} + +SkiaSweepGradientShader::~SkiaSweepGradientShader() { + delete[] mColors; + delete[] mPositions; +} + +void SkiaSweepGradientShader::describe(ProgramDescription& description, + const Extensions& extensions) { + description.hasGradient = true; + description.gradientType = ProgramDescription::kGradientSweep; +} + +void SkiaSweepGradientShader::setupProgram(Program* program, const mat4& modelView, + const Snapshot& snapshot, GLuint* textureUnit) { + GLuint textureSlot = (*textureUnit)++; + glActiveTexture(gTextureUnitsMap[textureSlot]); + + Texture* texture = mGradientCache->get(mKey); + if (!texture) { + texture = mGradientCache->addLinearGradient(mKey, mColors, mPositions, mCount); + } + + float left = mX; + float top = mY; + + mat4 shaderMatrix; + if (mMatrix) { + shaderMatrix.load(*mMatrix); + shaderMatrix.mapPoint(left, top); + } + + mat4 copy(shaderMatrix); + shaderMatrix.loadInverse(copy); + + snapshot.transform->mapPoint(left, top); + + mat4 screenSpace(*snapshot.transform); + screenSpace.multiply(modelView); + + // Uniforms + bindTexture(texture->id, gTileModes[mTileX], gTileModes[mTileY], textureSlot); + glUniform1i(program->getUniform("gradientSampler"), textureSlot); + glUniformMatrix4fv(program->getUniform("gradientMatrix"), 1, GL_FALSE, &shaderMatrix.data[0]); + glUniform2f(program->getUniform("gradientStart"), left, top); + glUniformMatrix4fv(program->getUniform("screenSpace"), 1, GL_FALSE, &screenSpace.data[0]); +} + +void SkiaSweepGradientShader::updateTransforms(Program* program, const mat4& modelView, + const Snapshot& snapshot) { + mat4 screenSpace(*snapshot.transform); + screenSpace.multiply(modelView); + glUniformMatrix4fv(program->getUniform("screenSpace"), 1, GL_FALSE, &screenSpace.data[0]); +} + +/////////////////////////////////////////////////////////////////////////////// // Compose shader /////////////////////////////////////////////////////////////////////////////// diff --git a/libs/hwui/SkiaShader.h b/libs/hwui/SkiaShader.h index cc94ae6..0023c46 100644 --- a/libs/hwui/SkiaShader.h +++ b/libs/hwui/SkiaShader.h @@ -145,6 +145,44 @@ private: }; // struct SkiaLinearGradientShader /** + * A shader that draws a sweep gradient. + */ +struct SkiaSweepGradientShader: public SkiaShader { + SkiaSweepGradientShader(float x, float y, uint32_t* colors, float* positions, int count, + SkShader* key, SkMatrix* matrix, bool blend); + ~SkiaSweepGradientShader(); + + virtual void describe(ProgramDescription& description, const Extensions& extensions); + virtual void setupProgram(Program* program, const mat4& modelView, const Snapshot& snapshot, + GLuint* textureUnit); + void updateTransforms(Program* program, const mat4& modelView, const Snapshot& snapshot); + +protected: + SkiaSweepGradientShader(Type type, float x, float y, uint32_t* colors, float* positions, + int count, SkShader* key, SkShader::TileMode tileMode, SkMatrix* matrix, bool blend); + + float mX, mY; + uint32_t* mColors; + float* mPositions; + int mCount; +}; // struct SkiaSweepGradientShader + +/** + * A shader that draws a circular gradient. + */ +struct SkiaCircularGradientShader: public SkiaSweepGradientShader { + SkiaCircularGradientShader(float x, float y, float radius, uint32_t* colors, float* positions, + int count, SkShader* key,SkShader::TileMode tileMode, SkMatrix* matrix, bool blend); + + void describe(ProgramDescription& description, const Extensions& extensions); + void setupProgram(Program* program, const mat4& modelView, const Snapshot& snapshot, + GLuint* textureUnit); + +private: + float mRadius; +}; // struct SkiaCircularGradientShader + +/** * A shader that draws two shaders, composited with an xfermode. */ struct SkiaComposeShader: public SkiaShader { diff --git a/libs/rs/java/tests/src/com/android/rs/test/RSTestCore.java b/libs/rs/java/tests/src/com/android/rs/test/RSTestCore.java index 6645372..cf9c6be 100644 --- a/libs/rs/java/tests/src/com/android/rs/test/RSTestCore.java +++ b/libs/rs/java/tests/src/com/android/rs/test/RSTestCore.java @@ -38,33 +38,21 @@ public class RSTestCore { return true; } - //private ScriptC_Fountain mScript; + private boolean rs_primitives_test() { + ScriptC_primitives s = new ScriptC_primitives(mRS, mRes, R.raw.primitives, true); + s.invoke_rs_primitives_test(0, 0); + return true; + } + public void init(RenderScriptGL rs, Resources res, int width, int height) { mRS = rs; mRes = res; mRootScript = new ScriptC_test_root(mRS, mRes, R.raw.test_root, true); + rs_primitives_test(); fp_mad(); - - /* - ProgramFragment.Builder pfb = new ProgramFragment.Builder(rs); - pfb.setVaryingColor(true); - rs.contextBindProgramFragment(pfb.create()); - - ScriptField_Point points = new ScriptField_Point(mRS, PART_COUNT); - - Mesh.AllocationBuilder smb = new Mesh.AllocationBuilder(mRS); - smb.addVertexAllocation(points.getAllocation()); - smb.addIndexType(Primitive.POINT); - Mesh sm = smb.create(); - - mScript = new ScriptC_Fountain(mRS, mRes, R.raw.fountain, true); - mScript.set_partMesh(sm); - mScript.bind_point(points); - mRS.contextBindRootScript(mScript); - */ } public void newTouchPosition(float x, float y, float pressure, int id) { diff --git a/libs/rs/java/tests/src/com/android/rs/test/primitives.rs b/libs/rs/java/tests/src/com/android/rs/test/primitives.rs new file mode 100644 index 0000000..39bd2c4 --- /dev/null +++ b/libs/rs/java/tests/src/com/android/rs/test/primitives.rs @@ -0,0 +1,44 @@ +#include "shared.rsh" + +#pragma rs export_func(rs_primitives_test) + +// Testing primitive types +#pragma rs export_var(floatTest) +#pragma rs export_var(doubleTest) +static float floatTest = 1.99f; +static double doubleTest = 2.05; +static char charTest = -8; +static short shortTest = -16; +static int intTest = -32; +static uchar ucharTest = 8; +static ushort ushortTest = 16; +static uint uintTest = 32; + +static void test_primitive_types(uint32_t index) { + bool failed = false; + start(); + + _RS_ASSERT(floatTest == 1.99f); + _RS_ASSERT(doubleTest == 2.05); + _RS_ASSERT(charTest == -8); + _RS_ASSERT(shortTest == -16); + _RS_ASSERT(intTest == -32); + _RS_ASSERT(ucharTest == 8); + _RS_ASSERT(ushortTest == 16); + _RS_ASSERT(uintTest == 32); + + float time = end(index); + if (failed) { + rsDebug("test_primitives FAILED ", time); + } + else { + rsDebug("test_primitives PASSED ", time); + } +} + + +void rs_primitives_test(uint32_t index, int test_num) { + test_primitive_types(index); +} + + diff --git a/libs/rs/java/tests/src/com/android/rs/test/shared.rsh b/libs/rs/java/tests/src/com/android/rs/test/shared.rsh index 1773e47..8c3e5f4 100644 --- a/libs/rs/java/tests/src/com/android/rs/test/shared.rsh +++ b/libs/rs/java/tests/src/com/android/rs/test/shared.rsh @@ -23,3 +23,13 @@ static float end(uint32_t idx) { return ((float)t) / 1000.f; } +#define _RS_ASSERT(b) \ +do { \ + rsDebug("Checking " #b, ((int) (b))); \ + if (!(b)) { \ + failed = true; \ + rsDebug(#b " FAILED", 0); \ + } \ +\ +} while (0) + diff --git a/libs/rs/rs.spec b/libs/rs/rs.spec index c7fb2af..31d70c7 100644 --- a/libs/rs/rs.spec +++ b/libs/rs/rs.spec @@ -338,6 +338,12 @@ ScriptSetVarF { param float value } +ScriptSetVarD { + param RsScript s + param uint32_t slot + param double value + } + ScriptSetVarV { param RsScript s param uint32_t slot diff --git a/libs/rs/rsScript.cpp b/libs/rs/rsScript.cpp index fc22fc3..43bb09e 100644 --- a/libs/rs/rsScript.cpp +++ b/libs/rs/rsScript.cpp @@ -101,6 +101,12 @@ void rsi_ScriptSetVarF(Context *rsc, RsScript vs, uint32_t slot, float value) s->setVar(slot, &value, sizeof(value)); } +void rsi_ScriptSetVarD(Context *rsc, RsScript vs, uint32_t slot, double value) +{ + Script *s = static_cast<Script *>(vs); + s->setVar(slot, &value, sizeof(value)); +} + void rsi_ScriptSetVarV(Context *rsc, RsScript vs, uint32_t slot, const void *data, uint32_t len) { const float *fp = (const float *)data; diff --git a/libs/utils/Looper.cpp b/libs/utils/Looper.cpp index b46279e..d2dd6eb 100644 --- a/libs/utils/Looper.cpp +++ b/libs/utils/Looper.cpp @@ -24,16 +24,15 @@ namespace android { -static pthread_mutex_t gTLSMutex = PTHREAD_MUTEX_INITIALIZER; -static bool gHaveTLS = false; -static pthread_key_t gTLS = 0; - // Hint for number of file descriptors to be associated with the epoll instance. static const int EPOLL_SIZE_HINT = 8; // Maximum number of file descriptors for which to retrieve poll events each iteration. static const int EPOLL_MAX_EVENTS = 16; +static pthread_once_t gTLSOnce = PTHREAD_ONCE_INIT; +static pthread_key_t gTLSKey = 0; + Looper::Looper(bool allowNonCallbacks) : mAllowNonCallbacks(allowNonCallbacks), mResponseIndex(0) { @@ -56,6 +55,7 @@ Looper::Looper(bool allowNonCallbacks) : errno); struct epoll_event eventItem; + memset(& eventItem, 0, sizeof(epoll_event)); // zero out unused members of data field union eventItem.events = EPOLLIN; eventItem.data.fd = mWakeReadPipeFd; result = epoll_ctl(mEpollFd, EPOLL_CTL_ADD, mWakeReadPipeFd, & eventItem); @@ -69,6 +69,11 @@ Looper::~Looper() { close(mEpollFd); } +void Looper::initTLSKey() { + int result = pthread_key_create(& gTLSKey, threadDestructor); + LOG_ALWAYS_FATAL_IF(result != 0, "Could not allocate TLS key."); +} + void Looper::threadDestructor(void *st) { Looper* const self = static_cast<Looper*>(st); if (self != NULL) { @@ -83,7 +88,7 @@ void Looper::setForThread(const sp<Looper>& looper) { looper->incStrong((void*)threadDestructor); } - pthread_setspecific(gTLS, looper.get()); + pthread_setspecific(gTLSKey, looper.get()); if (old != NULL) { old->decStrong((void*)threadDestructor); @@ -91,17 +96,10 @@ void Looper::setForThread(const sp<Looper>& looper) { } sp<Looper> Looper::getForThread() { - if (!gHaveTLS) { - pthread_mutex_lock(&gTLSMutex); - if (pthread_key_create(&gTLS, threadDestructor) != 0) { - pthread_mutex_unlock(&gTLSMutex); - return NULL; - } - gHaveTLS = true; - pthread_mutex_unlock(&gTLSMutex); - } + int result = pthread_once(& gTLSOnce, initTLSKey); + LOG_ALWAYS_FATAL_IF(result != 0, "pthread_once failed"); - return (Looper*)pthread_getspecific(gTLS); + return (Looper*)pthread_getspecific(gTLSKey); } sp<Looper> Looper::prepare(int opts) { @@ -331,6 +329,7 @@ int Looper::addFd(int fd, int ident, int events, ALooper_callbackFunc callback, request.data = data; struct epoll_event eventItem; + memset(& eventItem, 0, sizeof(epoll_event)); // zero out unused members of data field union eventItem.events = epollEvents; eventItem.data.fd = fd; diff --git a/location/java/android/location/Geocoder.java b/location/java/android/location/Geocoder.java index 546bb9d..ac7eb8b 100644 --- a/location/java/android/location/Geocoder.java +++ b/location/java/android/location/Geocoder.java @@ -41,7 +41,7 @@ import java.util.List; * The Geocoder class requires a backend service that is not included in * the core android framework. The Geocoder query methods will return an * empty list if there no backend service in the platform. Use the - * isImplemented() method to determine whether a Geocoder implementation + * isPresent() method to determine whether a Geocoder implementation * exists. */ public final class Geocoder { @@ -56,13 +56,13 @@ public final class Geocoder { * connectivity may still cause these methods to return null or * empty lists. */ - public static Boolean isImplemented() { + public static boolean isPresent() { IBinder b = ServiceManager.getService(Context.LOCATION_SERVICE); ILocationManager lm = ILocationManager.Stub.asInterface(b); try { - return lm.geocoderIsImplemented(); + return lm.geocoderIsPresent(); } catch (RemoteException e) { - Log.e(TAG, "isImplemented: got RemoteException", e); + Log.e(TAG, "isPresent: got RemoteException", e); return false; } } diff --git a/location/java/android/location/GeocoderParams.java b/location/java/android/location/GeocoderParams.java index 8b8e63b..174fe3e 100644 --- a/location/java/android/location/GeocoderParams.java +++ b/location/java/android/location/GeocoderParams.java @@ -29,6 +29,8 @@ import java.util.Locale; * as well as the Geocoder client's package name for geocoder server * logging. This information is kept in a separate class to allow for * future expansion of the IGeocodeProvider interface. + * + * @hide */ public class GeocoderParams implements Parcelable { private Locale mLocale; diff --git a/location/java/android/location/ILocationManager.aidl b/location/java/android/location/ILocationManager.aidl index 32d4b27..2255bf2 100644 --- a/location/java/android/location/ILocationManager.aidl +++ b/location/java/android/location/ILocationManager.aidl @@ -67,7 +67,7 @@ interface ILocationManager // it need not be shared with other providers. void reportLocation(in Location location, boolean passive); - boolean geocoderIsImplemented(); + boolean geocoderIsPresent(); String getFromLocation(double latitude, double longitude, int maxResults, in GeocoderParams params, out List<Address> addrs); String getFromLocationName(String locationName, diff --git a/location/java/android/location/provider/GeocodeProvider.java b/location/java/android/location/provider/GeocodeProvider.java index 9a58763..493c631 100644 --- a/location/java/android/location/provider/GeocodeProvider.java +++ b/location/java/android/location/provider/GeocodeProvider.java @@ -29,6 +29,8 @@ import java.util.List; * outside of the core android platform. * Geocode providers can be implemented as services and return the result of * {@link GeocodeProvider#getBinder()} in its getBinder() method. + * + * @hide */ public abstract class GeocodeProvider { diff --git a/location/java/android/location/provider/LocationProvider.java b/location/java/android/location/provider/LocationProvider.java index 95b4425..14dea14 100644 --- a/location/java/android/location/provider/LocationProvider.java +++ b/location/java/android/location/provider/LocationProvider.java @@ -34,6 +34,8 @@ import android.util.Log; * outside of the core android platform. * Location providers can be implemented as services and return the result of * {@link LocationProvider#getBinder()} in its getBinder() method. + * + * @hide */ public abstract class LocationProvider { diff --git a/media/java/android/media/AudioEffect.java b/media/java/android/media/AudioEffect.java index ae67114..ed7601e 100644 --- a/media/java/android/media/AudioEffect.java +++ b/media/java/android/media/AudioEffect.java @@ -847,39 +847,40 @@ public class AudioEffect { // ------------------------------------------------------------------------- /** - * This intent launches an audio effect control panel UI. The goal of this intent is to enable - * separate implementations of music/media player applications and audio effect control - * application or services. This will allow platform vendors to offer more advanced control - * options for standard effects or control for platform specific effects. + * Intent to launch an audio effect control panel UI. + * <p>The goal of this intent is to enable separate implementations of music/media player + * applications and audio effect control application or services. + * This will allow platform vendors to offer more advanced control options for standard effects + * or control for platform specific effects. * <p>The intent carries a number of extras used by the player application to communicate * necessary pieces of information to the control panel application. * <p>The calling application must use the * {@link android.app.Activity#startActivityForResult(Intent, int)} method to launch the * control panel so that its package name is indicated and used by the control panel * application to keep track of changes for this particular application. - * <p>The android.media.EXTRA_AUDIO_SESSION extra will indicate an audio session to which the + * <p>The {@link #EXTRA_AUDIO_SESSION} extra will indicate an audio session to which the * audio effects should be applied. If no audio session is specified, either one of the * follownig will happen: - * - If an audio session was previously opened by the calling application with + * <p>- If an audio session was previously opened by the calling application with * {@link #ACTION_OPEN_AUDIO_EFFECT_CONTROL_SESSION} intent, the effect changes will * be applied to that session. - * - If no audio session is opened, the changes will be stored in the package specific storage - * area and applied whenever a new audio session is opened by this application. - * <p>The android.media.EXTRA_CONTENT_TYPE extra will help the control panel application + * <p>- If no audio session is opened, the changes will be stored in the package specific + * storage area and applied whenever a new audio session is opened by this application. + * <p>The {@link #EXTRA_CONTENT_TYPE} extra will help the control panel application * customize both the UI layout and the default audio effect settings if none are already * stored for the calling application. - * {@hide} pending API council approval */ @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION) public static final String ACTION_DISPLAY_AUDIO_EFFECT_CONTROL_PANEL = "android.media.action.DISPLAY_AUDIO_EFFECT_CONTROL_PANEL"; /** - * This intent indicates to the effect control application or service that a new audio session - * is opened and requires audio effects to be applied. This is different from - * {@link #ACTION_DISPLAY_AUDIO_EFFECT_CONTROL_PANEL} in that no UI should be displayed in - * this case. Music player applications can broadcast this intent before starting playback - * to make sure that any audio effect settings previously selected by the user are applied. + * Intent to signal to the effect control application or service that a new audio session + * is opened and requires audio effects to be applied. + * <p>This is different from {@link #ACTION_DISPLAY_AUDIO_EFFECT_CONTROL_PANEL} in that no + * UI should be displayed in this case. Music player applications can broadcast this intent + * before starting playback to make sure that any audio effect settings previously selected + * by the user are applied. * <p>The effect control application receiving this intent will look for previously stored * settings for the calling application, create all required audio effects and apply the * effect settings to the specified audio session. @@ -888,48 +889,50 @@ public class AudioEffect { * <p>If no stored settings are found for the calling application, default settings for the * content type indicated by {@link #EXTRA_CONTENT_TYPE} will be applied. The default settings * for a given content type are platform specific. - * {@hide} pending API council approval */ @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) public static final String ACTION_OPEN_AUDIO_EFFECT_CONTROL_SESSION = "android.media.action.OPEN_AUDIO_EFFECT_CONTROL_SESSION"; /** - * This intent indicates to the effect control application or service that an audio session + * Intent to signal to the effect control application or service that an audio session * is closed and that effects should not be applied anymore. - * <p>The effect control application receiving this intent will delete all effects on this - * session and store current settings in package specific storage. + * <p>The effect control application receiving this intent will delete all effects on + * this session and store current settings in package specific storage. * <p>The calling package name is indicated by the {@link #EXTRA_PACKAGE_NAME} extra and the * audio session ID by the {@link #EXTRA_AUDIO_SESSION} extra. Both extras are mandatory. * <p>It is good practice for applications to broadcast this intent when music playback stops * and/or when exiting to free system resources consumed by audio effect engines. - * {@hide} pending API council approval */ @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) public static final String ACTION_CLOSE_AUDIO_EFFECT_CONTROL_SESSION = "android.media.action.CLOSE_AUDIO_EFFECT_CONTROL_SESSION"; /** - * This extra indicates the ID of the audio session the effects should be applied to. + * Contains the ID of the audio session the effects should be applied to. + * <p>This extra is for use with {@link #ACTION_DISPLAY_AUDIO_EFFECT_CONTROL_PANEL}, + * {@link #ACTION_OPEN_AUDIO_EFFECT_CONTROL_SESSION} and + * {@link #ACTION_CLOSE_AUDIO_EFFECT_CONTROL_SESSION} intents. * <p>The extra value is of type int and is the audio session ID. - * @see android.media.MediaPlayer#setAudioSessionId(int) for details on audio sessions. - * {@hide} pending API council approval + * + * @see android.media.MediaPlayer#setAudioSessionId(int) */ public static final String EXTRA_AUDIO_SESSION = "android.media.extra.AUDIO_SESSION"; /** - * This extra indicates the package name of the calling application for - * {@link #ACTION_OPEN_AUDIO_EFFECT_CONTROL_SESSION} and + * Contains the package name of the calling application. + * <p>This extra is for use with {@link #ACTION_OPEN_AUDIO_EFFECT_CONTROL_SESSION} and * {@link #ACTION_CLOSE_AUDIO_EFFECT_CONTROL_SESSION} intents. * <p>The extra value is a string containing the full package name. - * {@hide} pending API council approval */ public static final String EXTRA_PACKAGE_NAME = "android.media.extra.PACKAGE_NAME"; /** - * This extra indicates which type of content is played by the application. This information is - * used by the effect control application to customize UI and default effect settings. - * The content type is one of the following: + * Indicates which type of content is played by the application. + * <p>This extra is for use with {@link #ACTION_DISPLAY_AUDIO_EFFECT_CONTROL_PANEL} and + * {@link #ACTION_OPEN_AUDIO_EFFECT_CONTROL_SESSION} intents. + * <p>This information is used by the effect control application to customize UI and select + * appropriate default effect settings. The content type is one of the following: * <ul> * <li>{@link #CONTENT_TYPE_MUSIC}</li> * <li>{@link #CONTENT_TYPE_MOVIE}</li> @@ -937,28 +940,23 @@ public class AudioEffect { * <li>{@link #CONTENT_TYPE_VOICE}</li> * </ul> * If omitted, the content type defaults to {@link #CONTENT_TYPE_MUSIC}. - * {@hide} pending API council approval */ public static final String EXTRA_CONTENT_TYPE = "android.media.extra.CONTENT_TYPE"; /** * Value for {@link #EXTRA_CONTENT_TYPE} when the type of content played is music - * {@hide} pending API council approval */ public static final int CONTENT_TYPE_MUSIC = 0; /** - * Value for {@link #EXTRA_CONTENT_TYPE} when the type of content played is video of movie - * {@hide} pending API council approval + * Value for {@link #EXTRA_CONTENT_TYPE} when the type of content played is video or movie */ public static final int CONTENT_TYPE_MOVIE = 1; /** * Value for {@link #EXTRA_CONTENT_TYPE} when the type of content played is game audio - * {@hide} pending API council approval */ public static final int CONTENT_TYPE_GAME = 2; /** * Value for {@link #EXTRA_CONTENT_TYPE} when the type of content played is voice audio - * {@hide} pending API council approval */ public static final int CONTENT_TYPE_VOICE = 3; diff --git a/media/java/android/media/MtpClient.java b/media/java/android/media/MtpClient.java index f7c0ce2..98da1f6 100644 --- a/media/java/android/media/MtpClient.java +++ b/media/java/android/media/MtpClient.java @@ -57,20 +57,20 @@ public class MtpClient { native_stop(); } - public boolean deleteObject(int deviceID, int objectID) { + public boolean deleteObject(int deviceID, long objectID) { return native_delete_object(deviceID, objectID); } - public int getParent(int deviceID, int objectID) { + public long getParent(int deviceID, long objectID) { return native_get_parent(deviceID, objectID); } - public int getStorageID(int deviceID, int objectID) { + public long getStorageID(int deviceID, long objectID) { return native_get_storage_id(deviceID, objectID); } // create a file descriptor for reading the contents of an object over MTP - public ParcelFileDescriptor openFile(int deviceID, int objectID) { + public ParcelFileDescriptor openFile(int deviceID, long objectID) { return native_open_file(deviceID, objectID); } @@ -101,8 +101,8 @@ public class MtpClient { private native final void native_finalize(); private native boolean native_start(); private native void native_stop(); - private native boolean native_delete_object(int deviceID, int objectID); - private native int native_get_parent(int deviceID, int objectID); - private native int native_get_storage_id(int deviceID, int objectID); - private native ParcelFileDescriptor native_open_file(int deviceID, int objectID); + private native boolean native_delete_object(int deviceID, long objectID); + private native long native_get_parent(int deviceID, long objectID); + private native long native_get_storage_id(int deviceID, long objectID); + private native ParcelFileDescriptor native_open_file(int deviceID, long objectID); } diff --git a/media/java/android/media/MtpCursor.java b/media/java/android/media/MtpCursor.java index d4142d8..b9dd03e 100644 --- a/media/java/android/media/MtpCursor.java +++ b/media/java/android/media/MtpCursor.java @@ -43,8 +43,8 @@ public final class MtpCursor extends AbstractWindowedCursor { private int mQueryType; private int mDeviceID; - private int mStorageID; - private int mQbjectID; + private long mStorageID; + private long mQbjectID; /** The names of the columns in the projection */ private String[] mColumns; @@ -54,7 +54,7 @@ public final class MtpCursor extends AbstractWindowedCursor { private final MtpClient mClient; - public MtpCursor(MtpClient client, int queryType, int deviceID, int storageID, int objectID, + public MtpCursor(MtpClient client, int queryType, int deviceID, long storageID, long objectID, String[] projection) { mClient = client; @@ -220,7 +220,7 @@ public final class MtpCursor extends AbstractWindowedCursor { private int mNativeContext; private native final void native_setup(MtpClient client, int queryType, - int deviceID, int storageID, int objectID, int[] columns); + int deviceID, long storageID, long objectID, int[] columns); private native final void native_finalize(); private native void native_wait_for_event(); private native int native_fill_window(CursorWindow window, int startPos); diff --git a/media/java/android/media/Visualizer.java b/media/java/android/media/Visualizer.java index 453fc04..33222ff 100755 --- a/media/java/android/media/Visualizer.java +++ b/media/java/android/media/Visualizer.java @@ -218,13 +218,16 @@ public class Visualizer { public int setEnabled(boolean enabled) throws IllegalStateException { synchronized (mStateLock) { - if ((enabled && mState != STATE_INITIALIZED) || - (!enabled && mState != STATE_ENABLED)) { + if (mState == STATE_UNINITIALIZED) { throw(new IllegalStateException("setEnabled() called in wrong state: "+mState)); } - int status = native_setEnabled(enabled); - if (status == SUCCESS) { - mState = enabled ? STATE_ENABLED : STATE_INITIALIZED; + int status = SUCCESS; + if ((enabled && (mState == STATE_INITIALIZED)) || + (!enabled && (mState == STATE_ENABLED))) { + status = native_setEnabled(enabled); + if (status == SUCCESS) { + mState = enabled ? STATE_ENABLED : STATE_INITIALIZED; + } } return status; } diff --git a/media/java/android/media/videoeditor/Transition.java b/media/java/android/media/videoeditor/Transition.java index e4bc9a4..eb71285 100755 --- a/media/java/android/media/videoeditor/Transition.java +++ b/media/java/android/media/videoeditor/Transition.java @@ -34,6 +34,7 @@ import java.io.File; */
public abstract class Transition {
// The transition behavior
+ private static final int BEHAVIOR_MIN_VALUE = 0;
/** The transition starts slowly and speed up */
public static final int BEHAVIOR_SPEED_UP = 0;
/** The transition start fast and speed down */
@@ -45,6 +46,8 @@ public abstract class Transition { /** The transition starts slowly and ends slowly with a fast middle */
public static final int BEHAVIOR_MIDDLE_FAST = 4;
+ private static final int BEHAVIOR_MAX_VALUE = 4;
+
// The unique id of the transition
private final String mUniqueId;
@@ -84,6 +87,9 @@ public abstract class Transition { */
protected Transition(String transitionId, MediaItem afterMediaItem, MediaItem beforeMediaItem,
long durationMs, int behavior) {
+ if (behavior < BEHAVIOR_MIN_VALUE || behavior > BEHAVIOR_MAX_VALUE) {
+ throw new IllegalArgumentException("Invalid behavior: " + behavior);
+ }
mUniqueId = transitionId;
mAfterMediaItem = afterMediaItem;
mBeforeMediaItem = beforeMediaItem;
diff --git a/media/java/android/media/videoeditor/TransitionEndCurtainClosing.java b/media/java/android/media/videoeditor/TransitionEndCurtainClosing.java index 0bf4ff2..b1c6bb5 100644 --- a/media/java/android/media/videoeditor/TransitionEndCurtainClosing.java +++ b/media/java/android/media/videoeditor/TransitionEndCurtainClosing.java @@ -28,7 +28,7 @@ public class TransitionEndCurtainClosing extends Transition { */
@SuppressWarnings("unused")
private TransitionEndCurtainClosing() {
- this(null, null, 0);
+ this(null, null, 0, BEHAVIOR_LINEAR);
}
/**
@@ -38,10 +38,11 @@ public class TransitionEndCurtainClosing extends Transition { * @param afterMediaItem The transition is applied to the end of this
* media item
* @param durationMs duration of the transition in milliseconds
+ * @param behavior The transition behavior
*/
public TransitionEndCurtainClosing(String transitionId, MediaItem afterMediaItem,
- long duration) {
- super(transitionId, afterMediaItem, null, duration, Transition.BEHAVIOR_LINEAR);
+ long duration, int behavior) {
+ super(transitionId, afterMediaItem, null, duration, behavior);
}
/*
diff --git a/media/java/android/media/videoeditor/TransitionEndFadeToBlack.java b/media/java/android/media/videoeditor/TransitionEndFadeToBlack.java index 752532c..5f913fc 100755 --- a/media/java/android/media/videoeditor/TransitionEndFadeToBlack.java +++ b/media/java/android/media/videoeditor/TransitionEndFadeToBlack.java @@ -28,7 +28,7 @@ public class TransitionEndFadeToBlack extends Transition { */
@SuppressWarnings("unused")
private TransitionEndFadeToBlack() {
- this(null, null, 0);
+ this(null, null, 0, BEHAVIOR_LINEAR);
}
/**
@@ -38,9 +38,11 @@ public class TransitionEndFadeToBlack extends Transition { * @param afterMediaItem The transition is applied to the end of this
* media item
* @param durationMs duration of the transition in milliseconds
+ * @param behavior The transition behavior
*/
- public TransitionEndFadeToBlack(String transitionId, MediaItem afterMediaItem, long duration) {
- super(transitionId, afterMediaItem, null, duration, Transition.BEHAVIOR_LINEAR);
+ public TransitionEndFadeToBlack(String transitionId, MediaItem afterMediaItem, long duration,
+ int behavior) {
+ super(transitionId, afterMediaItem, null, duration, behavior);
}
/*
diff --git a/media/java/android/media/videoeditor/TransitionStartCurtainOpening.java b/media/java/android/media/videoeditor/TransitionStartCurtainOpening.java index 5f03e0e..b787b32 100755 --- a/media/java/android/media/videoeditor/TransitionStartCurtainOpening.java +++ b/media/java/android/media/videoeditor/TransitionStartCurtainOpening.java @@ -30,7 +30,7 @@ public class TransitionStartCurtainOpening extends Transition { */
@SuppressWarnings("unused")
private TransitionStartCurtainOpening() {
- this(null, null, 0);
+ this(null, null, 0, Transition.BEHAVIOR_LINEAR);
}
/**
@@ -40,11 +40,11 @@ public class TransitionStartCurtainOpening extends Transition { * @param beforeMediaItem The transition is applied to the beginning of
* this media item
* @param durationMs The duration of the transition in milliseconds
+ * @param behavior The transition behavior
*/
public TransitionStartCurtainOpening(String transitionId, MediaItem beforeMediaItem,
- long durationMs) {
- super(transitionId, null, beforeMediaItem, durationMs,
- Transition.BEHAVIOR_LINEAR);
+ long durationMs, int behavior) {
+ super(transitionId, null, beforeMediaItem, durationMs, behavior);
}
/*
diff --git a/media/java/android/media/videoeditor/TransitionStartFadeFromBlack.java b/media/java/android/media/videoeditor/TransitionStartFadeFromBlack.java index 08fd8bf..be993a5 100644 --- a/media/java/android/media/videoeditor/TransitionStartFadeFromBlack.java +++ b/media/java/android/media/videoeditor/TransitionStartFadeFromBlack.java @@ -28,7 +28,7 @@ public class TransitionStartFadeFromBlack extends Transition { */
@SuppressWarnings("unused")
private TransitionStartFadeFromBlack() {
- this(null, null, 0);
+ this(null, null, 0, Transition.BEHAVIOR_LINEAR);
}
/**
@@ -38,11 +38,11 @@ public class TransitionStartFadeFromBlack extends Transition { * @param beforeMediaItem The transition is applied to the beginning of
* this media item
* @param durationMs The duration of the transition in milliseconds
+ * @param behavior The transition behavior
*/
public TransitionStartFadeFromBlack(String transitionId, MediaItem beforeMediaItem,
- long durationMs) {
- super(transitionId, null, beforeMediaItem, durationMs,
- Transition.BEHAVIOR_LINEAR);
+ long durationMs, int behavior) {
+ super(transitionId, null, beforeMediaItem, durationMs, behavior);
}
/*
diff --git a/media/java/android/media/videoeditor/VideoEditorTestImpl.java b/media/java/android/media/videoeditor/VideoEditorTestImpl.java index e8cc776..14e2658 100644 --- a/media/java/android/media/videoeditor/VideoEditorTestImpl.java +++ b/media/java/android/media/videoeditor/VideoEditorTestImpl.java @@ -35,8 +35,7 @@ import android.util.Xml; import android.view.SurfaceHolder; /** - * The VideoEditor implementation - * {@hide} + * The VideoEditor implementation {@hide} */ public class VideoEditorTestImpl implements VideoEditor { // Logging @@ -49,6 +48,8 @@ public class VideoEditorTestImpl implements VideoEditor { private static final String TAG_PROJECT = "project"; private static final String TAG_MEDIA_ITEMS = "media_items"; private static final String TAG_MEDIA_ITEM = "media_item"; + private static final String TAG_BEGIN_TRANSITION = "begin_transition"; + private static final String TAG_END_TRANSITION = "end_transition"; private static final String ATTR_ID = "id"; private static final String ATTR_FILENAME = "filename"; private static final String ATTR_AUDIO_WAVEFORM_FILENAME = "wavefoem"; @@ -59,8 +60,14 @@ public class VideoEditorTestImpl implements VideoEditor { private static final String ATTR_BEGIN_TIME = "start_time"; private static final String ATTR_END_TIME = "end_time"; private static final String ATTR_VOLUME = "volume"; - - private static long mDurationMs; + private static final String ATTR_BEHAVIOR = "behavior"; + private static final String ATTR_DIRECTION = "direction"; + private static final String ATTR_BLENDING = "blending"; + private static final String ATTR_INVERT = "invert"; + private static final String ATTR_MASK = "mask"; + + // Instance variables + private long mDurationMs; private final String mProjectPath; private final List<MediaItem> mMediaItems = new ArrayList<MediaItem>(); private final List<AudioTrack> mAudioTracks = new ArrayList<AudioTrack>(); @@ -74,6 +81,8 @@ public class VideoEditorTestImpl implements VideoEditor { private class PreviewThread extends Thread { // Instance variables private final static long FRAME_DURATION = 33; + + // Instance variables private final PreviewProgressListener mListener; private final int mCallbackAfterFrameCount; private final long mFromMs, mToMs; @@ -85,10 +94,12 @@ public class VideoEditorTestImpl implements VideoEditor { * * @param fromMs Start preview at this position * @param toMs The time (relative to the timeline) at which the preview - * will stop. Use -1 to play to the end of the timeline - * @param callbackAfterFrameCount The listener interface should be invoked - * after the number of frames specified by this parameter. - * @param loop true if the preview should be looped once it reaches the end + * will stop. Use -1 to play to the end of the timeline + * @param callbackAfterFrameCount The listener interface should be + * invoked after the number of frames specified by this + * parameter. + * @param loop true if the preview should be looped once it reaches the + * end * @param listener The listener */ public PreviewThread(long fromMs, long toMs, boolean loop, int callbackAfterFrameCount, @@ -217,7 +228,15 @@ public class VideoEditorTestImpl implements VideoEditor { throw new IllegalArgumentException("Media item already exists: " + mediaItem.getId()); } + // Invalidate the end transition if necessary + final int mediaItemsCount = mMediaItems.size(); + if ( mediaItemsCount > 0) { + removeTransitionAfter(mediaItemsCount - 1); + } + + // Add the new media item mMediaItems.add(mediaItem); + computeTimelineDuration(); } @@ -235,9 +254,8 @@ public class VideoEditorTestImpl implements VideoEditor { if (afterMediaItemId == null) { if (mMediaItems.size() > 0) { - final MediaItem mi = mMediaItems.get(0); // Invalidate the transition at the beginning of the timeline - removeTransitionBefore(mi); + removeTransitionBefore(0); } mMediaItems.add(0, mediaItem); computeTimelineDuration(); @@ -247,9 +265,9 @@ public class VideoEditorTestImpl implements VideoEditor { final MediaItem mi = mMediaItems.get(i); if (mi.getId().equals(afterMediaItemId)) { // Invalidate the transition at this position - removeTransitionAfter(mi); + removeTransitionAfter(i); // Insert the new media item - mMediaItems.add(i+1, mediaItem); + mMediaItems.add(i + 1, mediaItem); computeTimelineDuration(); return; } @@ -273,9 +291,9 @@ public class VideoEditorTestImpl implements VideoEditor { if (afterMediaItemId == null) { if (mMediaItems.size() > 0) { - final MediaItem mi = mMediaItems.get(0); // Invalidate adjacent transitions at the insertion point - removeTransitionBefore(mi); + removeTransitionBefore(0); + // Insert the media item at the new position mMediaItems.add(0, moveMediaItem); computeTimelineDuration(); @@ -288,9 +306,9 @@ public class VideoEditorTestImpl implements VideoEditor { final MediaItem mi = mMediaItems.get(i); if (mi.getId().equals(afterMediaItemId)) { // Invalidate adjacent transitions at the insertion point - removeTransitionAfter(mi); + removeTransitionAfter(i); // Insert the media item at the new position - mMediaItems.add(i+1, moveMediaItem); + mMediaItems.add(i + 1, moveMediaItem); computeTimelineDuration(); return; } @@ -359,28 +377,27 @@ public class VideoEditorTestImpl implements VideoEditor { * {@inheritDoc} */ public synchronized void addTransition(Transition transition) { - // If a transition already exists at the specified position then - // invalidate it. - final Iterator<Transition> it = mTransitions.iterator(); - while (it.hasNext()) { - final Transition t = it.next(); - if (t.getAfterMediaItem() == transition.getAfterMediaItem() - || t.getBeforeMediaItem() == transition.getBeforeMediaItem()) { - it.remove(); - t.invalidate(); - break; - } - } - mTransitions.add(transition); - // Cross reference the transitions + final MediaItem beforeMediaItem = transition.getBeforeMediaItem(); final MediaItem afterMediaItem = transition.getAfterMediaItem(); + + // Cross reference the transitions if (afterMediaItem != null) { + // If a transition already exists at the specified position then + // invalidate it. + if (afterMediaItem.getEndTransition() != null) { + afterMediaItem.getEndTransition().invalidate(); + } afterMediaItem.setEndTransition(transition); } - final MediaItem beforeMediaItem = transition.getBeforeMediaItem(); + if (beforeMediaItem != null) { + // If a transition already exists at the specified position then + // invalidate it. + if (beforeMediaItem.getBeginTransition() != null) { + beforeMediaItem.getBeginTransition().invalidate(); + } beforeMediaItem.setBeginTransition(transition); } computeTimelineDuration(); @@ -460,7 +477,7 @@ public class VideoEditorTestImpl implements VideoEditor { for (int i = 0; i < audioTrackCount; i++) { AudioTrack at = mAudioTracks.get(i); if (at.getId().equals(afterAudioTrackId)) { - mAudioTracks.add(i+1, audioTrack); + mAudioTracks.add(i + 1, audioTrack); return; } } @@ -526,24 +543,67 @@ public class VideoEditorTestImpl implements VideoEditor { serializer.startTag("", TAG_PROJECT); serializer.attribute("", ATTR_ASPECT_RATIO, Integer.toString(mAspectRatio)); + boolean firstMediaItem = true; serializer.startTag("", TAG_MEDIA_ITEMS); for (MediaItem mediaItem : mMediaItems) { serializer.startTag("", TAG_MEDIA_ITEM); serializer.attribute("", ATTR_ID, mediaItem.getId()); serializer.attribute("", ATTR_TYPE, mediaItem.getClass().getSimpleName()); serializer.attribute("", ATTR_FILENAME, mediaItem.getFilename()); - serializer.attribute("", ATTR_RENDERING_MODE, Integer.toString(mediaItem.getRenderingMode())); + serializer.attribute("", ATTR_RENDERING_MODE, Integer.toString(mediaItem + .getRenderingMode())); if (mediaItem instanceof MediaVideoItem) { final MediaVideoItem mvi = (MediaVideoItem)mediaItem; - serializer.attribute("", ATTR_BEGIN_TIME, Long.toString(mvi.getBoundaryBeginTime())); + serializer + .attribute("", ATTR_BEGIN_TIME, Long.toString(mvi.getBoundaryBeginTime())); serializer.attribute("", ATTR_END_TIME, Long.toString(mvi.getBoundaryEndTime())); serializer.attribute("", ATTR_VOLUME, Integer.toString(mvi.getVolume())); if (mvi.getAudioWaveformFilename() != null) { - serializer.attribute("", ATTR_AUDIO_WAVEFORM_FILENAME, mvi.getAudioWaveformFilename()); + serializer.attribute("", ATTR_AUDIO_WAVEFORM_FILENAME, mvi + .getAudioWaveformFilename()); } } else if (mediaItem instanceof MediaImageItem) { serializer.attribute("", ATTR_DURATION, Long.toString(mediaItem.getDuration())); } + + if (firstMediaItem) { + firstMediaItem = false; + final Transition beginTransition = mediaItem.getBeginTransition(); + if (beginTransition != null) { + serializer.startTag("", TAG_BEGIN_TRANSITION); + serializer.attribute("", ATTR_ID, beginTransition.getId()); + serializer.attribute("", ATTR_TYPE, beginTransition.getClass() + .getSimpleName()); + serializer.attribute("", ATTR_DURATION, Long.toString(beginTransition + .getDuration())); + serializer.attribute("", ATTR_BEHAVIOR, Integer.toString(beginTransition + .getBehavior())); + serializer.endTag("", TAG_BEGIN_TRANSITION); + } + } + + final Transition endTransition = mediaItem.getEndTransition(); + if (endTransition != null) { + serializer.startTag("", TAG_END_TRANSITION); + serializer.attribute("", ATTR_ID, endTransition.getId()); + serializer.attribute("", ATTR_TYPE, endTransition.getClass().getSimpleName()); + serializer.attribute("", ATTR_DURATION, Long.toString(endTransition + .getDuration())); + serializer.attribute("", ATTR_BEHAVIOR, Integer.toString(endTransition + .getBehavior())); + if (endTransition instanceof TransitionSliding) { + serializer.attribute("", ATTR_DIRECTION, Integer + .toString(((TransitionSliding)endTransition).getDirection())); + } else if (endTransition instanceof TransitionAlpha) { + TransitionAlpha ta = (TransitionAlpha)endTransition; + serializer.attribute("", ATTR_BLENDING, Integer.toString(ta + .getBlendingPercent())); + serializer.attribute("", ATTR_INVERT, Boolean.toString(ta.isInvert())); + serializer.attribute("", ATTR_MASK, ta.getMaskFilename()); + } + serializer.endTag("", TAG_END_TRANSITION); + } + serializer.endTag("", TAG_MEDIA_ITEM); } serializer.endTag("", TAG_MEDIA_ITEMS); @@ -568,6 +628,8 @@ public class VideoEditorTestImpl implements VideoEditor { parser.setInput(new FileInputStream(file), "UTF-8"); int eventType = parser.getEventType(); String name; + MediaItem currentMediaItem = null; + MediaItem previousMediaItem = null; while (eventType != XmlPullParser.END_DOCUMENT) { switch (eventType) { case XmlPullParser.START_TAG: { @@ -579,27 +641,59 @@ public class VideoEditorTestImpl implements VideoEditor { final String mediaItemId = parser.getAttributeValue("", ATTR_ID); final String type = parser.getAttributeValue("", ATTR_TYPE); final String filename = parser.getAttributeValue("", ATTR_FILENAME); - final int renderingMode = Integer.parseInt(parser.getAttributeValue("", ATTR_RENDERING_MODE)); - final MediaItem mediaItem; + final int renderingMode = Integer.parseInt(parser.getAttributeValue("", + ATTR_RENDERING_MODE)); + if (MediaImageItem.class.getSimpleName().equals(type)) { - final long durationMs = Long.parseLong(parser.getAttributeValue("", ATTR_DURATION)); - mediaItem = new MediaImageItem(mediaItemId, filename, durationMs, - renderingMode); - } else if (MediaVideoItem.class.getSimpleName().equals(type)) { - final String audioWaveformFilename = parser.getAttributeValue("", ATTR_AUDIO_WAVEFORM_FILENAME); - mediaItem = new MediaVideoItem(mediaItemId, filename, renderingMode, audioWaveformFilename); - - final long beginTimeMs = Long.parseLong(parser.getAttributeValue("", ATTR_BEGIN_TIME)); - final long endTimeMs = Long.parseLong(parser.getAttributeValue("", ATTR_END_TIME)); - ((MediaVideoItem)mediaItem).setExtractBoundaries(beginTimeMs, endTimeMs); - - final int volumePercent = Integer.parseInt(parser.getAttributeValue("", ATTR_VOLUME)); - ((MediaVideoItem)mediaItem).setVolume(volumePercent); + final long durationMs = Long.parseLong(parser.getAttributeValue("", + ATTR_DURATION)); + currentMediaItem = new MediaImageItem(mediaItemId, filename, + durationMs, renderingMode); + } else if (MediaVideoItem.class.getSimpleName().equals(type)) { + final String audioWaveformFilename = parser.getAttributeValue("", + ATTR_AUDIO_WAVEFORM_FILENAME); + currentMediaItem = new MediaVideoItem(mediaItemId, filename, + renderingMode, audioWaveformFilename); + + final long beginTimeMs = Long.parseLong(parser.getAttributeValue("", + ATTR_BEGIN_TIME)); + final long endTimeMs = Long.parseLong(parser.getAttributeValue("", + ATTR_END_TIME)); + ((MediaVideoItem)currentMediaItem).setExtractBoundaries(beginTimeMs, + endTimeMs); + + final int volumePercent = Integer.parseInt(parser.getAttributeValue("", + ATTR_VOLUME)); + ((MediaVideoItem)currentMediaItem).setVolume(volumePercent); } else { Log.e(TAG, "Unknown media item type: " + type); - mediaItem = null; + currentMediaItem = null; } - mMediaItems.add(mediaItem); + + if (currentMediaItem != null) { + if (previousMediaItem != null) { + currentMediaItem.setBeginTransition(previousMediaItem + .getEndTransition()); + } + mMediaItems.add(currentMediaItem); + } + } else if (name.equals(TAG_BEGIN_TRANSITION)) { + final Transition transition = parseTransition(parser, currentMediaItem, + null); + currentMediaItem.setBeginTransition(transition); + } else if (name.equals(TAG_END_TRANSITION)) { + final Transition transition = parseTransition(parser, previousMediaItem, + currentMediaItem); + currentMediaItem.setEndTransition(transition); + } + break; + } + + case XmlPullParser.END_TAG: { + name = parser.getName(); + if (name.equals(TAG_MEDIA_ITEM)) { + previousMediaItem = currentMediaItem; + currentMediaItem = null; } break; } @@ -614,6 +708,53 @@ public class VideoEditorTestImpl implements VideoEditor { computeTimelineDuration(); } + /** + * Parse the transition + * + * @param parser The parser + * @param afterMediaItem The transition is at the end of this media item + * @param beforeMediaItem The transition is at the beginning of this media + * item + * @return The transition + */ + private Transition parseTransition(XmlPullParser parser, MediaItem beforeMediaItem, + MediaItem afterMediaItem) { + final String transitionId = parser.getAttributeValue("", ATTR_ID); + final String type = parser.getAttributeValue("", ATTR_TYPE); + final long durationMs = Long.parseLong(parser.getAttributeValue("", ATTR_DURATION)); + final int behavior = Integer.parseInt(parser.getAttributeValue("", ATTR_BEHAVIOR)); + if (TransitionStartCurtainOpening.class.getSimpleName().equals(type)) { + return new TransitionStartCurtainOpening(transitionId, beforeMediaItem, durationMs, + behavior); + } else if (TransitionStartFadeFromBlack.class.getSimpleName().equals(type)) { + return new TransitionStartFadeFromBlack(transitionId, beforeMediaItem, durationMs, + behavior); + } else if (TransitionAlpha.class.getSimpleName().equals(type)) { + final int blending = Integer.parseInt(parser.getAttributeValue("", ATTR_BLENDING)); + final String maskFilename = parser.getAttributeValue("", ATTR_MASK); + final boolean invert = Boolean.getBoolean(parser.getAttributeValue("", ATTR_INVERT)); + return new TransitionAlpha(transitionId, afterMediaItem, beforeMediaItem, durationMs, + behavior, maskFilename, blending, invert); + } else if (TransitionAlpha.class.getSimpleName().equals(type)) { + return new TransitionCrossfade(transitionId, afterMediaItem, beforeMediaItem, + durationMs, behavior); + } else if (TransitionSliding.class.getSimpleName().equals(type)) { + final int direction = Integer.parseInt(parser.getAttributeValue("", ATTR_DIRECTION)); + return new TransitionSliding(transitionId, afterMediaItem, beforeMediaItem, durationMs, + behavior, direction); + } else if (TransitionFadeToBlack.class.getSimpleName().equals(type)) { + return new TransitionFadeToBlack(transitionId, afterMediaItem, beforeMediaItem, + durationMs, behavior); + } else if (TransitionEndCurtainClosing.class.getSimpleName().equals(type)) { + return new TransitionEndCurtainClosing(transitionId, beforeMediaItem, durationMs, + behavior); + } else if (TransitionEndFadeToBlack.class.getSimpleName().equals(type)) { + return new TransitionEndFadeToBlack(transitionId, beforeMediaItem, durationMs, behavior); + } + + return null; + } + public void cancelExport(String filename) { } @@ -632,7 +773,8 @@ public class VideoEditorTestImpl implements VideoEditor { } } - // This is necessary because the user may had called setDuration on MediaImageItems + // This is necessary because the user may had called setDuration on + // MediaImageItems computeTimelineDuration(); } @@ -647,7 +789,8 @@ public class VideoEditorTestImpl implements VideoEditor { * {@inheritDoc} */ public long getDuration() { - // Since MediaImageItem can change duration we need to compute the duration here + // Since MediaImageItem can change duration we need to compute the + // duration here computeTimelineDuration(); return mDurationMs; } @@ -679,9 +822,8 @@ public class VideoEditorTestImpl implements VideoEditor { /* * {@inheritDoc} */ - public synchronized void startPreview(SurfaceHolder surfaceHolder, long fromMs, - long toMs, boolean loop, int callbackAfterFrameCount, - PreviewProgressListener listener) { + public synchronized void startPreview(SurfaceHolder surfaceHolder, long fromMs, long toMs, + boolean loop, int callbackAfterFrameCount, PreviewProgressListener listener) { if (fromMs >= mDurationMs) { return; } @@ -714,7 +856,10 @@ public class VideoEditorTestImpl implements VideoEditor { // Subtract the transition times for (Transition transition : mTransitions) { - if (!(transition instanceof TransitionStartCurtainOpening) && !(transition instanceof TransitionEndFadeToBlack)) { + if (!(transition instanceof TransitionStartCurtainOpening) + && !(transition instanceof TransitionStartFadeFromBlack) + && !(transition instanceof TransitionEndFadeToBlack) + && !(transition instanceof TransitionEndCurtainClosing)) { mDurationMs -= transition.getDuration(); } } @@ -742,9 +887,10 @@ public class VideoEditorTestImpl implements VideoEditor { /** * Remove the transition before this media item * - * @param mediaItem The media item + * @param index The media item index */ - private void removeTransitionBefore(MediaItem mediaItem) { + private void removeTransitionBefore(int index) { + final MediaItem mediaItem = mMediaItems.get(0); final Iterator<Transition> it = mTransitions.iterator(); while (it.hasNext()) { Transition t = it.next(); @@ -752,6 +898,9 @@ public class VideoEditorTestImpl implements VideoEditor { it.remove(); t.invalidate(); mediaItem.setBeginTransition(null); + if (index > 0) { + mMediaItems.get(index - 1).setEndTransition(null); + } break; } } @@ -760,9 +909,10 @@ public class VideoEditorTestImpl implements VideoEditor { /** * Remove the transition after this media item * - * @param mediaItem The media item + * @param index The media item index */ - private void removeTransitionAfter(MediaItem mediaItem) { + private void removeTransitionAfter(int index) { + final MediaItem mediaItem = mMediaItems.get(index); final Iterator<Transition> it = mTransitions.iterator(); while (it.hasNext()) { Transition t = it.next(); @@ -770,6 +920,10 @@ public class VideoEditorTestImpl implements VideoEditor { it.remove(); t.invalidate(); mediaItem.setEndTransition(null); + // Invalidate the reference in the next media item + if (index < mMediaItems.size() - 1) { + mMediaItems.get(index + 1).setBeginTransition(null); + } break; } } diff --git a/media/jni/android_media_MtpClient.cpp b/media/jni/android_media_MtpClient.cpp index 67740bc..d23185b 100644 --- a/media/jni/android_media_MtpClient.cpp +++ b/media/jni/android_media_MtpClient.cpp @@ -161,7 +161,7 @@ android_media_MtpClient_stop(JNIEnv *env, jobject thiz) static jboolean android_media_MtpClient_delete_object(JNIEnv *env, jobject thiz, - jint device_id, jint object_id) + jint device_id, jlong object_id) { #ifdef HAVE_ANDROID_OS MyClient *client = (MyClient *)env->GetIntField(thiz, field_context); @@ -173,9 +173,9 @@ android_media_MtpClient_delete_object(JNIEnv *env, jobject thiz, return NULL; } -static jint +static jlong android_media_MtpClient_get_parent(JNIEnv *env, jobject thiz, - jint device_id, jint object_id) + jint device_id, jlong object_id) { #ifdef HAVE_ANDROID_OS MyClient *client = (MyClient *)env->GetIntField(thiz, field_context); @@ -187,9 +187,9 @@ android_media_MtpClient_get_parent(JNIEnv *env, jobject thiz, return -1; } -static jint +static jlong android_media_MtpClient_get_storage_id(JNIEnv *env, jobject thiz, - jint device_id, jint object_id) + jint device_id, jlong object_id) { #ifdef HAVE_ANDROID_OS MyClient *client = (MyClient *)env->GetIntField(thiz, field_context); @@ -203,7 +203,7 @@ android_media_MtpClient_get_storage_id(JNIEnv *env, jobject thiz, static jobject android_media_MtpClient_open_file(JNIEnv *env, jobject thiz, - jint device_id, jint object_id) + jint device_id, jlong object_id) { #ifdef HAVE_ANDROID_OS MyClient *client = (MyClient *)env->GetIntField(thiz, field_context); @@ -240,10 +240,10 @@ static JNINativeMethod gMethods[] = { {"native_finalize", "()V", (void *)android_media_MtpClient_finalize}, {"native_start", "()Z", (void *)android_media_MtpClient_start}, {"native_stop", "()V", (void *)android_media_MtpClient_stop}, - {"native_delete_object", "(II)Z", (void *)android_media_MtpClient_delete_object}, - {"native_get_parent", "(II)I", (void *)android_media_MtpClient_get_parent}, - {"native_get_storage_id", "(II)I", (void *)android_media_MtpClient_get_storage_id}, - {"native_open_file", "(II)Landroid/os/ParcelFileDescriptor;", + {"native_delete_object", "(IJ)Z", (void *)android_media_MtpClient_delete_object}, + {"native_get_parent", "(IJ)J", (void *)android_media_MtpClient_get_parent}, + {"native_get_storage_id", "(IJ)J", (void *)android_media_MtpClient_get_storage_id}, + {"native_open_file", "(IJ)Landroid/os/ParcelFileDescriptor;", (void *)android_media_MtpClient_open_file}, }; diff --git a/media/jni/android_media_MtpCursor.cpp b/media/jni/android_media_MtpCursor.cpp index 6228b5d..6a65ffd 100644 --- a/media/jni/android_media_MtpCursor.cpp +++ b/media/jni/android_media_MtpCursor.cpp @@ -49,7 +49,7 @@ static bool ExceptionCheck(void* env) static void android_media_MtpCursor_setup(JNIEnv *env, jobject thiz, jobject javaClient, - jint queryType, jint deviceID, jint storageID, jint objectID, jintArray javaColumns) + jint queryType, jint deviceID, jlong storageID, jlong objectID, jintArray javaColumns) { #ifdef HAVE_ANDROID_OS LOGD("android_media_MtpCursor_setup queryType: %d deviceID: %d storageID: %d objectID: %d\n", @@ -104,7 +104,7 @@ android_media_MtpCursor_fill_window(JNIEnv *env, jobject thiz, jobject javaWindo // ---------------------------------------------------------------------------- static JNINativeMethod gMethods[] = { - {"native_setup", "(Landroid/media/MtpClient;IIII[I)V", + {"native_setup", "(Landroid/media/MtpClient;IIJJ[I)V", (void *)android_media_MtpCursor_setup}, {"native_finalize", "()V", (void *)android_media_MtpCursor_finalize}, {"native_fill_window", "(Landroid/database/CursorWindow;I)I", diff --git a/media/libeffects/visualizer/EffectVisualizer.cpp b/media/libeffects/visualizer/EffectVisualizer.cpp index 8ab57c93..03a6bbb 100644 --- a/media/libeffects/visualizer/EffectVisualizer.cpp +++ b/media/libeffects/visualizer/EffectVisualizer.cpp @@ -239,6 +239,24 @@ extern "C" int Visualizer_process( } // all code below assumes stereo 16 bit PCM output and input + + // derive capture scaling factor from peak value in current buffer + // this gives more interesting captures for display. + int32_t shift = 32; + for (size_t i = 0; i < inBuffer->frameCount; i++) { + int32_t smp = inBuffer->s16[i]; + if (smp < 0) smp = -smp; + int32_t clz = __builtin_clz(smp); + if (shift > clz) shift = clz; + } + // never scale by less than 8 to avoid returning unaltered PCM signal. + // add one to combine the division by 2 needed after summing left and right channels below + if (20 > shift) { + shift = (31 - 8 + 1) - shift; + } else { + shift = (3 + 1); + } + uint32_t captIdx; uint32_t inIdx; uint8_t *buf = pContext->mCaptureBuf[pContext->mCurrentBuf]; @@ -246,7 +264,7 @@ extern "C" int Visualizer_process( inIdx < inBuffer->frameCount && captIdx < pContext->mCaptureSize; inIdx++, captIdx++) { int32_t smp = inBuffer->s16[2 * inIdx] + inBuffer->s16[2 * inIdx + 1]; - smp = (smp + (1 << 8)) >> 9; + smp = (smp + (1 << (shift - 1))) >> shift; buf[captIdx] = ((uint8_t)smp)^0x80; } pContext->mCaptureIdx = captIdx; @@ -369,7 +387,7 @@ extern "C" int Visualizer_command(effect_interface_t self, uint32_t cmdCode, uin case VISU_CMD_CAPTURE: - if (pReplyData == NULL || *replySize != (int)pContext->mCaptureSize) { + if (pReplyData == NULL || *replySize != pContext->mCaptureSize) { LOGV("VISU_CMD_CAPTURE() error *replySize %d pContext->mCaptureSize %d", *replySize, pContext->mCaptureSize); return -EINVAL; diff --git a/media/libstagefright/NuCachedSource2.cpp b/media/libstagefright/NuCachedSource2.cpp index 9171aab..3a0fc41 100644 --- a/media/libstagefright/NuCachedSource2.cpp +++ b/media/libstagefright/NuCachedSource2.cpp @@ -132,7 +132,7 @@ size_t PageCache::releaseFromStart(size_t maxBytes) { } void PageCache::copy(size_t from, void *data, size_t size) { - LOG(VERBOSE) << "copy from " << from << " size " << size; + LOGV("copy from %d size %d", from, size); CHECK_LE(from + size, mTotalSize); @@ -228,7 +228,7 @@ void NuCachedSource2::onMessageReceived(const sp<AMessage> &msg) { } void NuCachedSource2::fetchInternal() { - LOG(VERBOSE) << "fetchInternal"; + LOGV("fetchInternal"); CHECK_EQ(mFinalStatus, (status_t)OK); @@ -240,11 +240,11 @@ void NuCachedSource2::fetchInternal() { Mutex::Autolock autoLock(mLock); if (n < 0) { - LOG(ERROR) << "source returned error " << n; + LOGE("source returned error %ld", n); mFinalStatus = n; mCache->releasePage(page); } else if (n == 0) { - LOG(INFO) << "ERROR_END_OF_STREAM"; + LOGI("ERROR_END_OF_STREAM"); mFinalStatus = ERROR_END_OF_STREAM; mCache->releasePage(page); } else { @@ -254,10 +254,10 @@ void NuCachedSource2::fetchInternal() { } void NuCachedSource2::onFetch() { - LOG(VERBOSE) << "onFetch"; + LOGV("onFetch"); if (mFinalStatus != OK) { - LOG(VERBOSE) << "EOS reached, done prefetching for now"; + LOGV("EOS reached, done prefetching for now"); mFetching = false; } @@ -268,7 +268,7 @@ void NuCachedSource2::onFetch() { if (mFetching || keepAlive) { if (keepAlive) { - LOG(INFO) << "Keep alive"; + LOGI("Keep alive"); } fetchInternal(); @@ -276,7 +276,7 @@ void NuCachedSource2::onFetch() { mLastFetchTimeUs = ALooper::GetNowUs(); if (mFetching && mCache->totalSize() >= kHighWaterThreshold) { - LOG(INFO) << "Cache full, done prefetching for now"; + LOGI("Cache full, done prefetching for now"); mFetching = false; } } else { @@ -289,7 +289,7 @@ void NuCachedSource2::onFetch() { } void NuCachedSource2::onRead(const sp<AMessage> &msg) { - LOG(VERBOSE) << "onRead"; + LOGV("onRead"); int64_t offset; CHECK(msg->findInt64("offset", &offset)); @@ -339,14 +339,14 @@ void NuCachedSource2::restartPrefetcherIfNecessary_l() { size_t actualBytes = mCache->releaseFromStart(maxBytes); mCacheOffset += actualBytes; - LOG(INFO) << "restarting prefetcher, totalSize = " << mCache->totalSize(); + LOGI("restarting prefetcher, totalSize = %d", mCache->totalSize()); mFetching = true; } ssize_t NuCachedSource2::readAt(off_t offset, void *data, size_t size) { Mutex::Autolock autoSerializer(mSerializer); - LOG(VERBOSE) << "readAt offset " << offset << " size " << size; + LOGV("readAt offset %ld, size %d", offset, size); Mutex::Autolock autoLock(mLock); @@ -406,7 +406,7 @@ size_t NuCachedSource2::approxDataRemaining_l(bool *eos) { } ssize_t NuCachedSource2::readInternal(off_t offset, void *data, size_t size) { - LOG(VERBOSE) << "readInternal offset " << offset << " size " << size; + LOGV("readInternal offset %ld size %d", offset, size); Mutex::Autolock autoLock(mLock); @@ -442,7 +442,7 @@ ssize_t NuCachedSource2::readInternal(off_t offset, void *data, size_t size) { return size; } - LOG(VERBOSE) << "deferring read"; + LOGV("deferring read"); return -EAGAIN; } @@ -455,7 +455,7 @@ status_t NuCachedSource2::seekInternal_l(off_t offset) { return OK; } - LOG(INFO) << "new range: offset= " << offset; + LOGI("new range: offset= %ld", offset); mCacheOffset = offset; diff --git a/media/libstagefright/OMXCodec.cpp b/media/libstagefright/OMXCodec.cpp index 4e79575..1b2be41 100644 --- a/media/libstagefright/OMXCodec.cpp +++ b/media/libstagefright/OMXCodec.cpp @@ -1821,7 +1821,7 @@ void OMXCodec::onEvent(OMX_EVENTTYPE event, OMX_U32 data1, OMX_U32 data2) { case OMX_EventError: { - LOGE("ERROR(0x%08lx, %ld)", data1, data2); + CODEC_LOGE("ERROR(0x%08lx, %ld)", data1, data2); setState(ERROR); break; diff --git a/media/libstagefright/ThreadedSource.cpp b/media/libstagefright/ThreadedSource.cpp index 5add2a5..38c6e2d 100644 --- a/media/libstagefright/ThreadedSource.cpp +++ b/media/libstagefright/ThreadedSource.cpp @@ -14,6 +14,10 @@ * limitations under the License. */ +#define LOG_TAG "ThreadedSource" +//#define LOG_NDEBUG 0 +#include <utils/Log.h> + #include "include/ThreadedSource.h" #include <media/stagefright/foundation/ADebug.h> diff --git a/media/libstagefright/codecs/aacdec/AACDecoder.cpp b/media/libstagefright/codecs/aacdec/AACDecoder.cpp index c5b51c0..e4ed5e6 100644 --- a/media/libstagefright/codecs/aacdec/AACDecoder.cpp +++ b/media/libstagefright/codecs/aacdec/AACDecoder.cpp @@ -123,6 +123,8 @@ status_t AACDecoder::start(MetaData *params) { mAnchorTimeUs = 0; mNumSamplesOutput = 0; mStarted = true; + mNumDecodedBuffers = 0; + mUpsamplingFactor = 2; return OK; } @@ -207,22 +209,65 @@ status_t AACDecoder::read( Int decoderErr = PVMP4AudioDecodeFrame(mConfig, mDecoderBuf); - // Check on the sampling rate to see whether it is changed. - int32_t sampleRate; - CHECK(mMeta->findInt32(kKeySampleRate, &sampleRate)); - if (mConfig->samplingRate != sampleRate) { - mMeta->setInt32(kKeySampleRate, mConfig->samplingRate); - LOGW("Sample rate was %d, but now is %d", - sampleRate, mConfig->samplingRate); - buffer->release(); - mInputBuffer->release(); - mInputBuffer = NULL; - return INFO_FORMAT_CHANGED; + /* + * AAC+/eAAC+ streams can be signalled in two ways: either explicitly + * or implicitly, according to MPEG4 spec. AAC+/eAAC+ is a dual + * rate system and the sampling rate in the final output is actually + * doubled compared with the core AAC decoder sampling rate. + * + * Explicit signalling is done by explicitly defining SBR audio object + * type in the bitstream. Implicit signalling is done by embedding + * SBR content in AAC extension payload specific to SBR, and hence + * requires an AAC decoder to perform pre-checks on actual audio frames. + * + * Thus, we could not say for sure whether a stream is + * AAC+/eAAC+ until the first data frame is decoded. + */ + if (++mNumDecodedBuffers <= 2) { + LOGV("audio/extended audio object type: %d + %d", + mConfig->audioObjectType, mConfig->extendedAudioObjectType); + LOGV("aac+ upsampling factor: %d desired channels: %d", + mConfig->aacPlusUpsamplingFactor, mConfig->desiredChannels); + + CHECK(mNumDecodedBuffers > 0); + if (mNumDecodedBuffers == 1) { + mUpsamplingFactor = mConfig->aacPlusUpsamplingFactor; + // Check on the sampling rate to see whether it is changed. + int32_t sampleRate; + CHECK(mMeta->findInt32(kKeySampleRate, &sampleRate)); + if (mConfig->samplingRate != sampleRate) { + mMeta->setInt32(kKeySampleRate, mConfig->samplingRate); + LOGW("Sample rate was %d Hz, but now is %d Hz", + sampleRate, mConfig->samplingRate); + buffer->release(); + mInputBuffer->release(); + mInputBuffer = NULL; + return INFO_FORMAT_CHANGED; + } + } else { // mNumDecodedBuffers == 2 + if (mConfig->extendedAudioObjectType == MP4AUDIO_AAC_LC || + mConfig->extendedAudioObjectType == MP4AUDIO_LTP) { + if (mUpsamplingFactor == 2) { + // The stream turns out to be not aacPlus mode anyway + LOGW("Disable AAC+/eAAC+ since extended audio object type is %d", + mConfig->extendedAudioObjectType); + mConfig->aacPlusEnabled = 0; + } + } else { + if (mUpsamplingFactor == 1) { + // aacPlus mode does not buy us anything, but to cause + // 1. CPU load to increase, and + // 2. a half speed of decoding + LOGW("Disable AAC+/eAAC+ since upsampling factor is 1"); + mConfig->aacPlusEnabled = 0; + } + } + } } size_t numOutBytes = mConfig->frameLength * sizeof(int16_t) * mConfig->desiredChannels; - if (mConfig->aacPlusUpsamplingFactor == 2) { + if (mUpsamplingFactor == 2) { if (mConfig->desiredChannels == 1) { memcpy(&mConfig->pOutputBuffer[1024], &mConfig->pOutputBuffer[2048], numOutBytes * 2); } diff --git a/media/libstagefright/codecs/avc/dec/AVCDecoder.cpp b/media/libstagefright/codecs/avc/dec/AVCDecoder.cpp index 7483d60..3c0b736 100644 --- a/media/libstagefright/codecs/avc/dec/AVCDecoder.cpp +++ b/media/libstagefright/codecs/avc/dec/AVCDecoder.cpp @@ -232,6 +232,53 @@ static void findNALFragment( } } +MediaBuffer *AVCDecoder::drainOutputBuffer() { + int32_t index; + int32_t Release; + AVCFrameIO Output; + Output.YCbCr[0] = Output.YCbCr[1] = Output.YCbCr[2] = NULL; + AVCDec_Status status = PVAVCDecGetOutput(mHandle, &index, &Release, &Output); + + if (status != AVCDEC_SUCCESS) { + LOGV("PVAVCDecGetOutput returned error %d", status); + return NULL; + } + + CHECK(index >= 0); + CHECK(index < (int32_t)mFrames.size()); + + MediaBuffer *mbuf = mFrames.editItemAt(index); + + bool skipFrame = false; + + if (mTargetTimeUs >= 0) { + int64_t timeUs; + CHECK(mbuf->meta_data()->findInt64(kKeyTime, &timeUs)); + CHECK(timeUs <= mTargetTimeUs); + + if (timeUs < mTargetTimeUs) { + // We're still waiting for the frame with the matching + // timestamp and we won't return the current one. + skipFrame = true; + + LOGV("skipping frame at %lld us", timeUs); + } else { + LOGV("found target frame at %lld us", timeUs); + + mTargetTimeUs = -1; + } + } + + if (!skipFrame) { + mbuf->set_range(0, mbuf->size()); + mbuf->add_ref(); + + return mbuf; + } + + return new MediaBuffer(0); +} + status_t AVCDecoder::read( MediaBuffer **out, const ReadOptions *options) { *out = NULL; @@ -279,7 +326,8 @@ status_t AVCDecoder::read( seekOptions.clearSeekTo(); if (err != OK) { - return err; + *out = drainOutputBuffer(); + return (*out == NULL) ? err : (status_t)OK; } if (mInputBuffer->range_length() > 0) { @@ -415,51 +463,12 @@ status_t AVCDecoder::read( fragSize); if (res == AVCDEC_PICTURE_OUTPUT_READY) { - int32_t index; - int32_t Release; - AVCFrameIO Output; - Output.YCbCr[0] = Output.YCbCr[1] = Output.YCbCr[2] = NULL; - - AVCDec_Status status = - PVAVCDecGetOutput(mHandle, &index, &Release, &Output); - - if (status != AVCDEC_SUCCESS) { - LOGV("PVAVCDecGetOutput returned error %d", status); + MediaBuffer *mbuf = drainOutputBuffer(); + if (mbuf == NULL) { break; } - CHECK(index >= 0); - CHECK(index < (int32_t)mFrames.size()); - - MediaBuffer *mbuf = mFrames.editItemAt(index); - - bool skipFrame = false; - - if (mTargetTimeUs >= 0) { - int64_t timeUs; - CHECK(mbuf->meta_data()->findInt64(kKeyTime, &timeUs)); - CHECK(timeUs <= mTargetTimeUs); - - if (timeUs < mTargetTimeUs) { - // We're still waiting for the frame with the matching - // timestamp and we won't return the current one. - skipFrame = true; - - LOGV("skipping frame at %lld us", timeUs); - } else { - LOGV("found target frame at %lld us", timeUs); - - mTargetTimeUs = -1; - } - } - - if (!skipFrame) { - *out = mbuf; - (*out)->set_range(0, (*out)->size()); - (*out)->add_ref(); - } else { - *out = new MediaBuffer(0); - } + *out = mbuf; // Do _not_ release input buffer yet. @@ -496,6 +505,7 @@ status_t AVCDecoder::read( case AVC_NALTYPE_AUD: case AVC_NALTYPE_FILL: + case AVC_NALTYPE_EOSEQ: { *out = new MediaBuffer(0); diff --git a/media/libstagefright/foundation/ADebug.cpp b/media/libstagefright/foundation/ADebug.cpp deleted file mode 100644 index 16f8b22..0000000 --- a/media/libstagefright/foundation/ADebug.cpp +++ /dev/null @@ -1,76 +0,0 @@ -/* - * Copyright (C) 2010 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "ADebug.h" - -#include <stdio.h> -#include <stdlib.h> - -#ifdef ANDROID -#include <cutils/log.h> -#endif - -namespace android { - -Logger::Logger(LogType type) - : mLogType(type) { - switch (mLogType) { - case VERBOSE: - mMessage = "V "; - break; - case INFO: - mMessage = "I "; - break; - case WARNING: - mMessage = "W "; - break; - case ERROR: - mMessage = "E "; - break; - case FATAL: - mMessage = "F "; - break; - - default: - break; - } -} - -Logger::~Logger() { - if (mLogType == VERBOSE) { - return; - } - - mMessage.append("\n"); - -#if defined(ANDROID) && 1 - LOG_PRI(ANDROID_LOG_INFO, "ADebug", "%s", mMessage.c_str()); -#else - fprintf(stderr, mMessage.c_str()); - fflush(stderr); -#endif - - if (mLogType == FATAL) { - abort(); - } -} - -const char *LeafName(const char *s) { - const char *lastSlash = strrchr(s, '/'); - return lastSlash != NULL ? lastSlash + 1 : s; -} - -} // namespace android diff --git a/media/libstagefright/foundation/ALooperRoster.cpp b/media/libstagefright/foundation/ALooperRoster.cpp index 65f7593..7683113 100644 --- a/media/libstagefright/foundation/ALooperRoster.cpp +++ b/media/libstagefright/foundation/ALooperRoster.cpp @@ -74,7 +74,7 @@ void ALooperRoster::postMessage( ssize_t index = mHandlers.indexOfKey(msg->target()); if (index < 0) { - LOG(WARNING) << "failed to post message. Target handler not registered."; + LOGW("failed to post message. Target handler not registered."); return; } @@ -83,8 +83,8 @@ void ALooperRoster::postMessage( sp<ALooper> looper = info.mLooper.promote(); if (looper == NULL) { - LOG(WARNING) << "failed to post message. " - "Target handler still registered, but object gone."; + LOGW("failed to post message. " + "Target handler still registered, but object gone."); mHandlers.removeItemsAt(index); return; @@ -102,8 +102,7 @@ void ALooperRoster::deliverMessage(const sp<AMessage> &msg) { ssize_t index = mHandlers.indexOfKey(msg->target()); if (index < 0) { - LOG(WARNING) << "failed to deliver message. " - << "Target handler not registered."; + LOGW("failed to deliver message. Target handler not registered."); return; } @@ -111,8 +110,8 @@ void ALooperRoster::deliverMessage(const sp<AMessage> &msg) { handler = info.mHandler.promote(); if (handler == NULL) { - LOG(WARNING) << "failed to deliver message. " - "Target handler registered, but object gone."; + LOGW("failed to deliver message. " + "Target handler registered, but object gone."); mHandlers.removeItemsAt(index); return; diff --git a/media/libstagefright/foundation/Android.mk b/media/libstagefright/foundation/Android.mk index f6a8a52..ffa7db0 100644 --- a/media/libstagefright/foundation/Android.mk +++ b/media/libstagefright/foundation/Android.mk @@ -5,7 +5,6 @@ LOCAL_SRC_FILES:= \ AAtomizer.cpp \ ABitReader.cpp \ ABuffer.cpp \ - ADebug.cpp \ AHandler.cpp \ ALooper.cpp \ ALooperRoster.cpp \ diff --git a/media/libstagefright/foundation/hexdump.cpp b/media/libstagefright/foundation/hexdump.cpp index 093b587..9f6bf9e 100644 --- a/media/libstagefright/foundation/hexdump.cpp +++ b/media/libstagefright/foundation/hexdump.cpp @@ -14,6 +14,10 @@ * limitations under the License. */ +//#define LOG_NDEBUG 0 +#define LOG_TAG "hexdump" +#include <utils/Log.h> + #include "hexdump.h" #include "ADebug.h" @@ -63,7 +67,7 @@ void hexdump(const void *_data, size_t size) { } } - LOG(INFO) << line; + LOGI("%s", line.c_str()); offset += 16; } diff --git a/media/libstagefright/include/AACDecoder.h b/media/libstagefright/include/AACDecoder.h index 200f93c..886a3b7 100644 --- a/media/libstagefright/include/AACDecoder.h +++ b/media/libstagefright/include/AACDecoder.h @@ -53,6 +53,8 @@ private: int64_t mAnchorTimeUs; int64_t mNumSamplesOutput; status_t mInitCheck; + int64_t mNumDecodedBuffers; + int32_t mUpsamplingFactor; MediaBuffer *mInputBuffer; diff --git a/media/libstagefright/include/AVCDecoder.h b/media/libstagefright/include/AVCDecoder.h index 898c90a..eb3b142 100644 --- a/media/libstagefright/include/AVCDecoder.h +++ b/media/libstagefright/include/AVCDecoder.h @@ -82,6 +82,8 @@ private: void releaseFrames(); + MediaBuffer *drainOutputBuffer(); + AVCDecoder(const AVCDecoder &); AVCDecoder &operator=(const AVCDecoder &); }; diff --git a/media/libstagefright/mpeg2ts/ATSParser.cpp b/media/libstagefright/mpeg2ts/ATSParser.cpp index 72de8d7..9952783 100644 --- a/media/libstagefright/mpeg2ts/ATSParser.cpp +++ b/media/libstagefright/mpeg2ts/ATSParser.cpp @@ -14,6 +14,10 @@ * limitations under the License. */ +//#define LOG_NDEBUG 0 +#define LOG_TAG "ATSParser" +#include <utils/Log.h> + #include "ATSParser.h" #include "AnotherPacketSource.h" @@ -31,6 +35,10 @@ namespace android { +// I want the expression "y" evaluated even if verbose logging is off. +#define MY_LOGV(x, y) \ + do { unsigned tmp = y; LOGV(x, tmp); } while (0) + static const size_t kTSPacketSize = 188; struct ATSParser::Program : public RefBase { @@ -115,36 +123,33 @@ bool ATSParser::Program::parsePID( void ATSParser::Program::parseProgramMap(ABitReader *br) { unsigned table_id = br->getBits(8); - LOG(VERBOSE) << " table_id = " << table_id; + LOGV(" table_id = %u", table_id); CHECK_EQ(table_id, 0x02u); - unsigned section_syntax_indictor = br->getBits(1); - LOG(VERBOSE) << " section_syntax_indictor = " << section_syntax_indictor; - CHECK_EQ(section_syntax_indictor, 1u); + unsigned section_syntax_indicator = br->getBits(1); + LOGV(" section_syntax_indicator = %u", section_syntax_indicator); + CHECK_EQ(section_syntax_indicator, 1u); CHECK_EQ(br->getBits(1), 0u); - LOG(VERBOSE) << " reserved = " << br->getBits(2); + MY_LOGV(" reserved = %u", br->getBits(2)); unsigned section_length = br->getBits(12); - LOG(VERBOSE) << " section_length = " << section_length; + LOGV(" section_length = %u", section_length); CHECK((section_length & 0xc00) == 0); CHECK_LE(section_length, 1021u); - LOG(VERBOSE) << " program_number = " << br->getBits(16); - LOG(VERBOSE) << " reserved = " << br->getBits(2); - LOG(VERBOSE) << " version_number = " << br->getBits(5); - LOG(VERBOSE) << " current_next_indicator = " << br->getBits(1); - LOG(VERBOSE) << " section_number = " << br->getBits(8); - LOG(VERBOSE) << " last_section_number = " << br->getBits(8); - LOG(VERBOSE) << " reserved = " << br->getBits(3); - - LOG(VERBOSE) << " PCR_PID = " - << StringPrintf("0x%04x", br->getBits(13)); - - LOG(VERBOSE) << " reserved = " << br->getBits(4); + MY_LOGV(" program_number = %u", br->getBits(16)); + MY_LOGV(" reserved = %u", br->getBits(2)); + MY_LOGV(" version_number = %u", br->getBits(5)); + MY_LOGV(" current_next_indicator = %u", br->getBits(1)); + MY_LOGV(" section_number = %u", br->getBits(8)); + MY_LOGV(" last_section_number = %u", br->getBits(8)); + MY_LOGV(" reserved = %u", br->getBits(3)); + MY_LOGV(" PCR_PID = 0x%04x", br->getBits(13)); + MY_LOGV(" reserved = %u", br->getBits(4)); unsigned program_info_length = br->getBits(12); - LOG(VERBOSE) << " program_info_length = " << program_info_length; + LOGV(" program_info_length = %u", program_info_length); CHECK((program_info_length & 0xc00) == 0); br->skipBits(program_info_length * 8); // skip descriptors @@ -158,19 +163,17 @@ void ATSParser::Program::parseProgramMap(ABitReader *br) { CHECK_GE(infoBytesRemaining, 5u); unsigned streamType = br->getBits(8); - LOG(VERBOSE) << " stream_type = " - << StringPrintf("0x%02x", streamType); + LOGV(" stream_type = 0x%02x", streamType); - LOG(VERBOSE) << " reserved = " << br->getBits(3); + MY_LOGV(" reserved = %u", br->getBits(3)); unsigned elementaryPID = br->getBits(13); - LOG(VERBOSE) << " elementary_PID = " - << StringPrintf("0x%04x", elementaryPID); + LOGV(" elementary_PID = 0x%04x", elementaryPID); - LOG(VERBOSE) << " reserved = " << br->getBits(4); + MY_LOGV(" reserved = %u", br->getBits(4)); unsigned ES_info_length = br->getBits(12); - LOG(VERBOSE) << " ES_info_length = " << ES_info_length; + LOGV(" ES_info_length = %u", ES_info_length); CHECK((ES_info_length & 0xc00) == 0); CHECK_GE(infoBytesRemaining - 5, ES_info_length); @@ -180,10 +183,10 @@ void ATSParser::Program::parseProgramMap(ABitReader *br) { #else unsigned info_bytes_remaining = ES_info_length; while (info_bytes_remaining >= 2) { - LOG(VERBOSE) << " tag = " << StringPrintf("0x%02x", br->getBits(8)); + MY_LOGV(" tag = 0x%02x", br->getBits(8)); unsigned descLength = br->getBits(8); - LOG(VERBOSE) << " len = " << descLength; + LOGV(" len = %u", descLength); CHECK_GE(info_bytes_remaining, 2 + descLength); @@ -209,7 +212,7 @@ void ATSParser::Program::parseProgramMap(ABitReader *br) { CHECK_EQ(infoBytesRemaining, 0u); - LOG(VERBOSE) << " CRC = " << StringPrintf("0x%08x", br->getBits(32)); + MY_LOGV(" CRC = 0x%08x", br->getBits(32)); } sp<MediaSource> ATSParser::Program::getSource(SourceType type) { @@ -255,7 +258,7 @@ void ATSParser::Stream::parse( } size_t payloadSizeBits = br->numBitsLeft(); - CHECK_EQ(payloadSizeBits % 8, 0u); + CHECK((payloadSizeBits % 8) == 0); CHECK_LE(mBuffer->size() + payloadSizeBits / 8, mBuffer->capacity()); @@ -266,16 +269,15 @@ void ATSParser::Stream::parse( void ATSParser::Stream::parsePES(ABitReader *br) { unsigned packet_startcode_prefix = br->getBits(24); - LOG(VERBOSE) << "packet_startcode_prefix = " - << StringPrintf("0x%08x", packet_startcode_prefix); + LOGV("packet_startcode_prefix = 0x%08x", packet_startcode_prefix); CHECK_EQ(packet_startcode_prefix, 0x000001u); unsigned stream_id = br->getBits(8); - LOG(VERBOSE) << "stream_id = " << StringPrintf("0x%02x", stream_id); + LOGV("stream_id = 0x%02x", stream_id); unsigned PES_packet_length = br->getBits(16); - LOG(VERBOSE) << "PES_packet_length = " << PES_packet_length; + LOGV("PES_packet_length = %u", PES_packet_length); if (stream_id != 0xbc // program_stream_map && stream_id != 0xbe // padding_stream @@ -287,33 +289,32 @@ void ATSParser::Stream::parsePES(ABitReader *br) { && stream_id != 0xf8) { // H.222.1 type E CHECK_EQ(br->getBits(2), 2u); - LOG(VERBOSE) << "PES_scrambling_control = " << br->getBits(2); - LOG(VERBOSE) << "PES_priority = " << br->getBits(1); - LOG(VERBOSE) << "data_alignment_indicator = " << br->getBits(1); - LOG(VERBOSE) << "copyright = " << br->getBits(1); - LOG(VERBOSE) << "original_or_copy = " << br->getBits(1); + MY_LOGV("PES_scrambling_control = %u", br->getBits(2)); + MY_LOGV("PES_priority = %u", br->getBits(1)); + MY_LOGV("data_alignment_indicator = %u", br->getBits(1)); + MY_LOGV("copyright = %u", br->getBits(1)); + MY_LOGV("original_or_copy = %u", br->getBits(1)); unsigned PTS_DTS_flags = br->getBits(2); - LOG(VERBOSE) << "PTS_DTS_flags = " << PTS_DTS_flags; + LOGV("PTS_DTS_flags = %u", PTS_DTS_flags); unsigned ESCR_flag = br->getBits(1); - LOG(VERBOSE) << "ESCR_flag = " << ESCR_flag; + LOGV("ESCR_flag = %u", ESCR_flag); unsigned ES_rate_flag = br->getBits(1); - LOG(VERBOSE) << "ES_rate_flag = " << ES_rate_flag; + LOGV("ES_rate_flag = %u", ES_rate_flag); unsigned DSM_trick_mode_flag = br->getBits(1); - LOG(VERBOSE) << "DSM_trick_mode_flag = " << DSM_trick_mode_flag; + LOGV("DSM_trick_mode_flag = %u", DSM_trick_mode_flag); unsigned additional_copy_info_flag = br->getBits(1); - LOG(VERBOSE) << "additional_copy_info_flag = " - << additional_copy_info_flag; + LOGV("additional_copy_info_flag = %u", additional_copy_info_flag); - LOG(VERBOSE) << "PES_CRC_flag = " << br->getBits(1); - LOG(VERBOSE) << "PES_extension_flag = " << br->getBits(1); + MY_LOGV("PES_CRC_flag = %u", br->getBits(1)); + MY_LOGV("PES_extension_flag = %u", br->getBits(1)); unsigned PES_header_data_length = br->getBits(8); - LOG(VERBOSE) << "PES_header_data_length = " << PES_header_data_length; + LOGV("PES_header_data_length = %u", PES_header_data_length); unsigned optional_bytes_remaining = PES_header_data_length; @@ -331,8 +332,8 @@ void ATSParser::Stream::parsePES(ABitReader *br) { PTS |= br->getBits(15); CHECK_EQ(br->getBits(1), 1u); - LOG(VERBOSE) << "PTS = " << PTS; - // LOG(INFO) << "PTS = " << PTS / 90000.0f << " secs"; + LOGV("PTS = %llu", PTS); + // LOGI("PTS = %.2f secs", PTS / 90000.0f); optional_bytes_remaining -= 5; @@ -348,7 +349,7 @@ void ATSParser::Stream::parsePES(ABitReader *br) { DTS |= br->getBits(15); CHECK_EQ(br->getBits(1), 1u); - LOG(VERBOSE) << "DTS = " << DTS; + LOGV("DTS = %llu", DTS); optional_bytes_remaining -= 5; } @@ -366,8 +367,8 @@ void ATSParser::Stream::parsePES(ABitReader *br) { ESCR |= br->getBits(15); CHECK_EQ(br->getBits(1), 1u); - LOG(VERBOSE) << "ESCR = " << ESCR; - LOG(VERBOSE) << "ESCR_extension = " << br->getBits(9); + LOGV("ESCR = %llu", ESCR); + MY_LOGV("ESCR_extension = %u", br->getBits(9)); CHECK_EQ(br->getBits(1), 1u); @@ -378,7 +379,7 @@ void ATSParser::Stream::parsePES(ABitReader *br) { CHECK_GE(optional_bytes_remaining, 3u); CHECK_EQ(br->getBits(1), 1u); - LOG(VERBOSE) << "ES_rate = " << br->getBits(22); + MY_LOGV("ES_rate = %u", br->getBits(22)); CHECK_EQ(br->getBits(1), 1u); optional_bytes_remaining -= 3; @@ -405,8 +406,7 @@ void ATSParser::Stream::parsePES(ABitReader *br) { size_t payloadSizeBits = br->numBitsLeft(); CHECK((payloadSizeBits % 8) == 0); - LOG(VERBOSE) << "There's " << (payloadSizeBits / 8) - << " bytes of payload."; + LOGV("There's %d bytes of payload.", payloadSizeBits / 8); } } else if (stream_id == 0xbe) { // padding_stream CHECK_NE(PES_packet_length, 0u); @@ -422,9 +422,7 @@ void ATSParser::Stream::flush() { return; } - LOG(VERBOSE) << "flushing stream " - << StringPrintf("0x%04x", mElementaryPID) - << " size = " << mBuffer->size(); + LOGV("flushing stream 0x%04x size = %d", mElementaryPID, mBuffer->size()); ABitReader br(mBuffer->data(), mBuffer->size()); parsePES(&br); @@ -493,7 +491,7 @@ static sp<ABuffer> MakeAVCCodecSpecificData( CHECK(picParamSet != NULL); buffer->setRange(stopOffset, size - stopOffset); - LOG(INFO) << "buffer has " << buffer->size() << " bytes left."; + LOGI("buffer has %d bytes left.", buffer->size()); size_t csdSize = 1 + 3 + 1 + 1 @@ -617,15 +615,15 @@ static sp<ABuffer> FindMPEG2ADTSConfig( CHECK_EQ(br.getBits(2), 0u); br.getBits(1); // protection_absent unsigned profile = br.getBits(2); - LOG(INFO) << "profile = " << profile; + LOGI("profile = %u", profile); CHECK_NE(profile, 3u); unsigned sampling_freq_index = br.getBits(4); br.getBits(1); // private_bit unsigned channel_configuration = br.getBits(3); CHECK_NE(channel_configuration, 0u); - LOG(INFO) << "sampling_freq_index = " << sampling_freq_index; - LOG(INFO) << "channel_configuration = " << channel_configuration; + LOGI("sampling_freq_index = %u", sampling_freq_index); + LOGI("channel_configuration = %u", channel_configuration); CHECK_LE(sampling_freq_index, 11u); static const int32_t kSamplingFreq[] = { @@ -671,8 +669,7 @@ static sp<ABuffer> FindMPEG2ADTSConfig( void ATSParser::Stream::onPayloadData( unsigned PTS_DTS_flags, uint64_t PTS, uint64_t DTS, const uint8_t *data, size_t size) { - LOG(VERBOSE) << "onPayloadData mStreamType=" - << StringPrintf("0x%02x", mStreamType); + LOGV("onPayloadData mStreamType=0x%02x", mStreamType); sp<ABuffer> buffer; @@ -710,8 +707,8 @@ void ATSParser::Stream::onPayloadData( sp<ABuffer> csd = FindMPEG2ADTSConfig(buffer, &sampleRate, &channelCount); - LOG(INFO) << "sampleRate = " << sampleRate; - LOG(INFO) << "channelCount = " << channelCount; + LOGI("sampleRate = %d", sampleRate); + LOGI("channelCount = %d", channelCount); meta->setInt32(kKeySampleRate, sampleRate); meta->setInt32(kKeyChannelCount, channelCount); @@ -719,7 +716,7 @@ void ATSParser::Stream::onPayloadData( meta->setData(kKeyESDS, 0, csd->data(), csd->size()); } - LOG(INFO) << "created source!"; + LOGI("created source!"); mSource = new AnotherPacketSource(meta); // fall through @@ -777,12 +774,7 @@ void ATSParser::Stream::extractAACFrames(const sp<ABuffer> &buffer) { CHECK_LE(scan, buffer->size()); - LOG(VERBOSE) - << "found aac raw data block at [" - << StringPrintf("0x%08x", offset) - << " ; " - << StringPrintf("0x%08x", scan) - << ")"; + LOGV("found aac raw data block at [0x%08x ; 0x%08x)", offset, scan); memmove(&buffer->data()[dstOffset], &buffer->data()[offset], scan - offset); @@ -825,50 +817,48 @@ void ATSParser::feedTSPacket(const void *data, size_t size) { void ATSParser::parseProgramAssociationTable(ABitReader *br) { unsigned table_id = br->getBits(8); - LOG(VERBOSE) << " table_id = " << table_id; + LOGV(" table_id = %u", table_id); CHECK_EQ(table_id, 0x00u); unsigned section_syntax_indictor = br->getBits(1); - LOG(VERBOSE) << " section_syntax_indictor = " << section_syntax_indictor; + LOGV(" section_syntax_indictor = %u", section_syntax_indictor); CHECK_EQ(section_syntax_indictor, 1u); CHECK_EQ(br->getBits(1), 0u); - LOG(VERBOSE) << " reserved = " << br->getBits(2); + MY_LOGV(" reserved = %u", br->getBits(2)); unsigned section_length = br->getBits(12); - LOG(VERBOSE) << " section_length = " << section_length; + LOGV(" section_length = %u", section_length); CHECK((section_length & 0xc00) == 0); - LOG(VERBOSE) << " transport_stream_id = " << br->getBits(16); - LOG(VERBOSE) << " reserved = " << br->getBits(2); - LOG(VERBOSE) << " version_number = " << br->getBits(5); - LOG(VERBOSE) << " current_next_indicator = " << br->getBits(1); - LOG(VERBOSE) << " section_number = " << br->getBits(8); - LOG(VERBOSE) << " last_section_number = " << br->getBits(8); + MY_LOGV(" transport_stream_id = %u", br->getBits(16)); + MY_LOGV(" reserved = %u", br->getBits(2)); + MY_LOGV(" version_number = %u", br->getBits(5)); + MY_LOGV(" current_next_indicator = %u", br->getBits(1)); + MY_LOGV(" section_number = %u", br->getBits(8)); + MY_LOGV(" last_section_number = %u", br->getBits(8)); size_t numProgramBytes = (section_length - 5 /* header */ - 4 /* crc */); CHECK_EQ((numProgramBytes % 4), 0u); for (size_t i = 0; i < numProgramBytes / 4; ++i) { unsigned program_number = br->getBits(16); - LOG(VERBOSE) << " program_number = " << program_number; + LOGV(" program_number = %u", program_number); - LOG(VERBOSE) << " reserved = " << br->getBits(3); + MY_LOGV(" reserved = %u", br->getBits(3)); if (program_number == 0) { - LOG(VERBOSE) << " network_PID = " - << StringPrintf("0x%04x", br->getBits(13)); + MY_LOGV(" network_PID = 0x%04x", br->getBits(13)); } else { unsigned programMapPID = br->getBits(13); - LOG(VERBOSE) << " program_map_PID = " - << StringPrintf("0x%04x", programMapPID); + LOGV(" program_map_PID = 0x%04x", programMapPID); mPrograms.push(new Program(programMapPID)); } } - LOG(VERBOSE) << " CRC = " << StringPrintf("0x%08x", br->getBits(32)); + MY_LOGV(" CRC = 0x%08x", br->getBits(32)); } void ATSParser::parsePID( @@ -893,8 +883,7 @@ void ATSParser::parsePID( } if (!handled) { - LOG(WARNING) << "PID " << StringPrintf("0x%04x", PID) - << " not handled."; + LOGV("PID 0x%04x not handled.", PID); } } @@ -906,28 +895,27 @@ void ATSParser::parseAdaptationField(ABitReader *br) { } void ATSParser::parseTS(ABitReader *br) { - LOG(VERBOSE) << "---"; + LOGV("---"); unsigned sync_byte = br->getBits(8); CHECK_EQ(sync_byte, 0x47u); - LOG(VERBOSE) << "transport_error_indicator = " << br->getBits(1); + MY_LOGV("transport_error_indicator = %u", br->getBits(1)); unsigned payload_unit_start_indicator = br->getBits(1); - LOG(VERBOSE) << "payload_unit_start_indicator = " - << payload_unit_start_indicator; + LOGV("payload_unit_start_indicator = %u", payload_unit_start_indicator); - LOG(VERBOSE) << "transport_priority = " << br->getBits(1); + MY_LOGV("transport_priority = %u", br->getBits(1)); unsigned PID = br->getBits(13); - LOG(VERBOSE) << "PID = " << StringPrintf("0x%04x", PID); + LOGV("PID = 0x%04x", PID); - LOG(VERBOSE) << "transport_scrambling_control = " << br->getBits(2); + MY_LOGV("transport_scrambling_control = %u", br->getBits(2)); unsigned adaptation_field_control = br->getBits(2); - LOG(VERBOSE) << "adaptation_field_control = " << adaptation_field_control; + LOGV("adaptation_field_control = %u", adaptation_field_control); - LOG(VERBOSE) << "continuity_counter = " << br->getBits(4); + MY_LOGV("continuity_counter = %u", br->getBits(4)); if (adaptation_field_control == 2 || adaptation_field_control == 3) { parseAdaptationField(br); diff --git a/media/libstagefright/omx/tests/OMXHarness.cpp b/media/libstagefright/omx/tests/OMXHarness.cpp index fcf506d..4f28855 100644 --- a/media/libstagefright/omx/tests/OMXHarness.cpp +++ b/media/libstagefright/omx/tests/OMXHarness.cpp @@ -286,7 +286,7 @@ status_t Harness::testStateTransitions( return OK; } - sp<MemoryDealer> dealer = new MemoryDealer(8 * 1024 * 1024, "OMXHarness"); + sp<MemoryDealer> dealer = new MemoryDealer(16 * 1024 * 1024, "OMXHarness"); IOMX::node_id node; status_t err = diff --git a/media/libstagefright/rtsp/AAMRAssembler.cpp b/media/libstagefright/rtsp/AAMRAssembler.cpp index 154ba31..b1f6e9a 100644 --- a/media/libstagefright/rtsp/AAMRAssembler.cpp +++ b/media/libstagefright/rtsp/AAMRAssembler.cpp @@ -14,6 +14,10 @@ * limitations under the License. */ +//#define LOG_NDEBUG 0 +#define LOG_TAG "AAMRAssembler" +#include <utils/Log.h> + #include "AAMRAssembler.h" #include "ARTPSource.h" @@ -119,9 +123,7 @@ ARTPAssembler::AssemblyStatus AAMRAssembler::addPacket( mNextExpectedSeqNoValid = true; mNextExpectedSeqNo = (uint32_t)buffer->int32Data(); } else if ((uint32_t)buffer->int32Data() != mNextExpectedSeqNo) { -#if VERBOSE - LOG(VERBOSE) << "Not the sequence number I expected"; -#endif + LOGV("Not the sequence number I expected"); return WRONG_SEQUENCE_NUMBER; } @@ -132,7 +134,7 @@ ARTPAssembler::AssemblyStatus AAMRAssembler::addPacket( queue->erase(queue->begin()); ++mNextExpectedSeqNo; - LOG(VERBOSE) << "AMR packet too short."; + LOGV("AMR packet too short."); return MALFORMED_PACKET; } @@ -150,7 +152,7 @@ ARTPAssembler::AssemblyStatus AAMRAssembler::addPacket( queue->erase(queue->begin()); ++mNextExpectedSeqNo; - LOG(VERBOSE) << "Unable to parse TOC."; + LOGV("Unable to parse TOC."); return MALFORMED_PACKET; } @@ -164,7 +166,7 @@ ARTPAssembler::AssemblyStatus AAMRAssembler::addPacket( queue->erase(queue->begin()); ++mNextExpectedSeqNo; - LOG(VERBOSE) << "Illegal TOC entry."; + LOGV("Illegal TOC entry."); return MALFORMED_PACKET; } @@ -191,7 +193,7 @@ ARTPAssembler::AssemblyStatus AAMRAssembler::addPacket( queue->erase(queue->begin()); ++mNextExpectedSeqNo; - LOG(VERBOSE) << "AMR packet too short."; + LOGV("AMR packet too short."); return MALFORMED_PACKET; } diff --git a/media/libstagefright/rtsp/AAVCAssembler.cpp b/media/libstagefright/rtsp/AAVCAssembler.cpp index 6b1e292..11c6ae7 100644 --- a/media/libstagefright/rtsp/AAVCAssembler.cpp +++ b/media/libstagefright/rtsp/AAVCAssembler.cpp @@ -14,6 +14,10 @@ * limitations under the License. */ +//#define LOG_NDEBUG 0 +#define LOG_TAG "AAVCAssembler" +#include <utils/Log.h> + #include "AAVCAssembler.h" #include "ARTPSource.h" @@ -25,8 +29,6 @@ #include <stdint.h> -#define BE_VERBOSE 0 - namespace android { // static @@ -70,9 +72,7 @@ ARTPAssembler::AssemblyStatus AAVCAssembler::addNALUnit( mNextExpectedSeqNoValid = true; mNextExpectedSeqNo = (uint32_t)buffer->int32Data(); } else if ((uint32_t)buffer->int32Data() != mNextExpectedSeqNo) { -#if BE_VERBOSE - LOG(VERBOSE) << "Not the sequence number I expected"; -#endif + LOGV("Not the sequence number I expected"); return WRONG_SEQUENCE_NUMBER; } @@ -83,7 +83,7 @@ ARTPAssembler::AssemblyStatus AAVCAssembler::addNALUnit( if (size < 1 || (data[0] & 0x80)) { // Corrupt. - LOG(ERROR) << "Ignoring corrupt buffer."; + LOGV("Ignoring corrupt buffer."); queue->erase(queue->begin()); ++mNextExpectedSeqNo; @@ -107,7 +107,7 @@ ARTPAssembler::AssemblyStatus AAVCAssembler::addNALUnit( return success ? OK : MALFORMED_PACKET; } else { - LOG(ERROR) << "Ignoring unsupported buffer (nalType=" << nalType << ")"; + LOGV("Ignoring unsupported buffer (nalType=%d)", nalType); queue->erase(queue->begin()); ++mNextExpectedSeqNo; @@ -117,8 +117,8 @@ ARTPAssembler::AssemblyStatus AAVCAssembler::addNALUnit( } void AAVCAssembler::addSingleNALUnit(const sp<ABuffer> &buffer) { -#if BE_VERBOSE - LOG(VERBOSE) << "addSingleNALUnit of size " << buffer->size(); + LOGV("addSingleNALUnit of size %d", buffer->size()); +#if !LOG_NDEBUG hexdump(buffer->data(), buffer->size()); #endif @@ -138,7 +138,7 @@ bool AAVCAssembler::addSingleTimeAggregationPacket(const sp<ABuffer> &buffer) { size_t size = buffer->size(); if (size < 3) { - LOG(ERROR) << "Discarding too small STAP-A packet."; + LOGV("Discarding too small STAP-A packet."); return false; } @@ -148,7 +148,7 @@ bool AAVCAssembler::addSingleTimeAggregationPacket(const sp<ABuffer> &buffer) { size_t nalSize = (data[0] << 8) | data[1]; if (size < nalSize + 2) { - LOG(ERROR) << "Discarding malformed STAP-A packet."; + LOGV("Discarding malformed STAP-A packet."); return false; } @@ -164,7 +164,7 @@ bool AAVCAssembler::addSingleTimeAggregationPacket(const sp<ABuffer> &buffer) { } if (size != 0) { - LOG(WARNING) << "Unexpected padding at end of STAP-A packet."; + LOGV("Unexpected padding at end of STAP-A packet."); } return true; @@ -184,7 +184,7 @@ ARTPAssembler::AssemblyStatus AAVCAssembler::addFragmentedNALUnit( CHECK((indicator & 0x1f) == 28); if (size < 2) { - LOG(ERROR) << "Ignoring malformed FU buffer (size = " << size << ")"; + LOGV("Ignoring malformed FU buffer (size = %d)", size); queue->erase(queue->begin()); ++mNextExpectedSeqNo; @@ -194,9 +194,7 @@ ARTPAssembler::AssemblyStatus AAVCAssembler::addFragmentedNALUnit( if (!(data[1] & 0x80)) { // Start bit not set on the first buffer. -#if BE_VERBOSE - LOG(ERROR) << "Start bit not set on first buffer"; -#endif + LOGV("Start bit not set on first buffer"); queue->erase(queue->begin()); ++mNextExpectedSeqNo; @@ -214,17 +212,13 @@ ARTPAssembler::AssemblyStatus AAVCAssembler::addFragmentedNALUnit( if (data[1] & 0x40) { // Huh? End bit also set on the first buffer. -#if BE_VERBOSE - LOG(WARNING) << "Grrr. This isn't fragmented at all."; -#endif + LOGV("Grrr. This isn't fragmented at all."); complete = true; } else { List<sp<ABuffer> >::iterator it = ++queue->begin(); while (it != queue->end()) { -#if BE_VERBOSE - LOG(VERBOSE) << "sequence length " << totalCount; -#endif + LOGV("sequence length %d", totalCount); const sp<ABuffer> &buffer = *it; @@ -232,11 +226,8 @@ ARTPAssembler::AssemblyStatus AAVCAssembler::addFragmentedNALUnit( size_t size = buffer->size(); if ((uint32_t)buffer->int32Data() != expectedSeqNo) { -#if BE_VERBOSE - LOG(VERBOSE) << "sequence not complete, expected seqNo " - << expectedSeqNo << ", got " - << (uint32_t)buffer->int32Data(); -#endif + LOGV("sequence not complete, expected seqNo %d, got %d", + expectedSeqNo, (uint32_t)buffer->int32Data()); return WRONG_SEQUENCE_NUMBER; } @@ -245,7 +236,7 @@ ARTPAssembler::AssemblyStatus AAVCAssembler::addFragmentedNALUnit( || data[0] != indicator || (data[1] & 0x1f) != nalType || (data[1] & 0x80)) { - LOG(ERROR) << "Ignoring malformed FU buffer.\n"; + LOGV("Ignoring malformed FU buffer."); // Delete the whole start of the FU. @@ -296,8 +287,8 @@ ARTPAssembler::AssemblyStatus AAVCAssembler::addFragmentedNALUnit( for (size_t i = 0; i < totalCount; ++i) { const sp<ABuffer> &buffer = *it; -#if BE_VERBOSE - LOG(VERBOSE) << "piece #" << (i + 1) << "/" << totalCount; + LOGV("piece #%d/%d", i + 1, totalCount); +#if !LOG_NDEBUG hexdump(buffer->data(), buffer->size()); #endif @@ -311,9 +302,7 @@ ARTPAssembler::AssemblyStatus AAVCAssembler::addFragmentedNALUnit( addSingleNALUnit(unit); -#if BE_VERBOSE - LOG(VERBOSE) << "successfully assembled a NAL unit from fragments."; -#endif + LOGV("successfully assembled a NAL unit from fragments."); return OK; } @@ -321,9 +310,7 @@ ARTPAssembler::AssemblyStatus AAVCAssembler::addFragmentedNALUnit( void AAVCAssembler::submitAccessUnit() { CHECK(!mNALUnits.empty()); -#if BE_VERBOSE - LOG(VERBOSE) << "Access unit complete (" << mNALUnits.size() << " nal units)"; -#endif + LOGV("Access unit complete (%d nal units)", mNALUnits.size()); size_t totalSize = 0; for (List<sp<ABuffer> >::iterator it = mNALUnits.begin(); @@ -373,7 +360,7 @@ ARTPAssembler::AssemblyStatus AAVCAssembler::assembleMore( void AAVCAssembler::packetLost() { CHECK(mNextExpectedSeqNoValid); - LOG(VERBOSE) << "packetLost (expected " << mNextExpectedSeqNo << ")"; + LOGV("packetLost (expected %d)", mNextExpectedSeqNo); ++mNextExpectedSeqNo; diff --git a/media/libstagefright/rtsp/AMPEG4ElementaryAssembler.cpp b/media/libstagefright/rtsp/AMPEG4ElementaryAssembler.cpp index f68a35b..13988cd 100644 --- a/media/libstagefright/rtsp/AMPEG4ElementaryAssembler.cpp +++ b/media/libstagefright/rtsp/AMPEG4ElementaryAssembler.cpp @@ -14,6 +14,10 @@ * limitations under the License. */ +//#define LOG_NDEBUG 0 +#define LOG_TAG "AMPEG4ElementaryAssembler" +#include <utils/Log.h> + #include "AMPEG4ElementaryAssembler.h" #include "ARTPSource.h" @@ -28,8 +32,6 @@ #include <ctype.h> #include <stdint.h> -#define BE_VERBOSE 0 - namespace android { static bool GetAttribute(const char *s, const char *key, AString *value) { @@ -201,9 +203,7 @@ ARTPAssembler::AssemblyStatus AMPEG4ElementaryAssembler::addPacket( mNextExpectedSeqNoValid = true; mNextExpectedSeqNo = (uint32_t)buffer->int32Data(); } else if ((uint32_t)buffer->int32Data() != mNextExpectedSeqNo) { -#if BE_VERBOSE - LOG(VERBOSE) << "Not the sequence number I expected"; -#endif + LOGV("Not the sequence number I expected"); return WRONG_SEQUENCE_NUMBER; } @@ -336,9 +336,7 @@ ARTPAssembler::AssemblyStatus AMPEG4ElementaryAssembler::addPacket( void AMPEG4ElementaryAssembler::submitAccessUnit() { CHECK(!mPackets.empty()); -#if BE_VERBOSE - LOG(VERBOSE) << "Access unit complete (" << mPackets.size() << " nal units)"; -#endif + LOGV("Access unit complete (%d nal units)", mPackets.size()); size_t totalSize = 0; for (List<sp<ABuffer> >::iterator it = mPackets.begin(); @@ -385,7 +383,7 @@ ARTPAssembler::AssemblyStatus AMPEG4ElementaryAssembler::assembleMore( void AMPEG4ElementaryAssembler::packetLost() { CHECK(mNextExpectedSeqNoValid); - LOG(VERBOSE) << "packetLost (expected " << mNextExpectedSeqNo << ")"; + LOGV("packetLost (expected %d)", mNextExpectedSeqNo); ++mNextExpectedSeqNo; diff --git a/media/libstagefright/rtsp/APacketSource.cpp b/media/libstagefright/rtsp/APacketSource.cpp index b3e86eb..78754e6 100644 --- a/media/libstagefright/rtsp/APacketSource.cpp +++ b/media/libstagefright/rtsp/APacketSource.cpp @@ -14,6 +14,10 @@ * limitations under the License. */ +//#define LOG_NDEBUG 0 +#define LOG_TAG "APacketSource" +#include <utils/Log.h> + #include "APacketSource.h" #include "ASessionDescription.h" @@ -188,7 +192,7 @@ static sp<ABuffer> MakeAVCCodecSpecificData( if (i == 0) { FindAVCDimensions(nal, width, height); - LOG(INFO) << "dimensions " << *width << "x" << *height; + LOGI("dimensions %dx%d", *width, *height); } } @@ -412,7 +416,7 @@ static bool ExtractDimensionsFromVOLHeader( *width = video_object_layer_width; *height = video_object_layer_height; - LOG(INFO) << "VOL dimensions = " << *width << "x" << *height; + LOGI("VOL dimensions = %dx%d", *width, *height); return true; } @@ -711,7 +715,7 @@ void APacketSource::updateNormalPlayTime_l(const sp<ABuffer> &buffer) { void APacketSource::queueAccessUnit(const sp<ABuffer> &buffer) { int32_t damaged; if (buffer->meta()->findInt32("damaged", &damaged) && damaged) { - LOG(VERBOSE) << "discarding damaged AU"; + LOGV("discarding damaged AU"); return; } @@ -765,8 +769,9 @@ int64_t APacketSource::getQueueDurationUs(bool *eos) { CHECK(last->meta()->findInt64("timeUs", &lastTimeUs)); if (lastTimeUs < firstTimeUs) { - LOG(ERROR) << "Huh? Time moving backwards? " - << firstTimeUs << " > " << lastTimeUs; + LOGE("Huh? Time moving backwards? %lld > %lld", + firstTimeUs, lastTimeUs); + return 0; } diff --git a/media/libstagefright/rtsp/ARTPConnection.cpp b/media/libstagefright/rtsp/ARTPConnection.cpp index 10c9e02..ded3b24 100644 --- a/media/libstagefright/rtsp/ARTPConnection.cpp +++ b/media/libstagefright/rtsp/ARTPConnection.cpp @@ -14,6 +14,10 @@ * limitations under the License. */ +//#define LOG_NDEBUG 0 +#define LOG_TAG "ARTPConnection" +#include <utils/Log.h> + #include "ARTPConnection.h" #include "ARTPSource.h" @@ -319,7 +323,7 @@ void ARTPConnection::onPollStreams() { } if (buffer->size() > 0) { - LOG(VERBOSE) << "Sending RR..."; + LOGV("Sending RR..."); ssize_t n = sendto( s->mRTCPSocket, buffer->data(), buffer->size(), 0, @@ -356,7 +360,7 @@ status_t ARTPConnection::receive(StreamInfo *s, bool receiveRTP) { buffer->setRange(0, nbytes); - // LOG(INFO) << "received " << buffer->size() << " bytes."; + // LOGI("received %d bytes.", buffer->size()); status_t err; if (receiveRTP) { @@ -521,9 +525,8 @@ status_t ARTPConnection::parseRTCP(StreamInfo *s, const sp<ABuffer> &buffer) { default: { - LOG(WARNING) << "Unknown RTCP packet type " - << (unsigned)data[1] - << " of size " << headerLength; + LOGW("Unknown RTCP packet type %u of size %d", + (unsigned)data[1], headerLength); break; } } @@ -567,10 +570,10 @@ status_t ARTPConnection::parseSR( uint32_t rtpTime = u32at(&data[16]); #if 0 - LOG(INFO) << StringPrintf( - "XXX timeUpdate: ssrc=0x%08x, rtpTime %u == ntpTime %.3f", - id, - rtpTime, (ntpTime >> 32) + (double)(ntpTime & 0xffffffff) / (1ll << 32)); + LOGI("XXX timeUpdate: ssrc=0x%08x, rtpTime %u == ntpTime %.3f", + id, + rtpTime, + (ntpTime >> 32) + (double)(ntpTime & 0xffffffff) / (1ll << 32)); #endif sp<ARTPSource> source = findSource(s, id); diff --git a/media/libstagefright/rtsp/ARTPSession.cpp b/media/libstagefright/rtsp/ARTPSession.cpp index 8ce93b7..39c6619 100644 --- a/media/libstagefright/rtsp/ARTPSession.cpp +++ b/media/libstagefright/rtsp/ARTPSession.cpp @@ -14,6 +14,10 @@ * limitations under the License. */ +//#define LOG_NDEBUG 0 +#define LOG_TAG "ARTPSession" +#include <utils/Log.h> + #include "ARTPSession.h" #include <media/stagefright/foundation/ABuffer.h> @@ -51,24 +55,24 @@ status_t ARTPSession::setup(const sp<ASessionDescription> &desc) { if (!mDesc->findAttribute(i, "c=", &connection)) { // No per-stream connection information, try global fallback. if (!mDesc->findAttribute(0, "c=", &connection)) { - LOG(ERROR) << "Unable to find connection attribtue."; + LOGE("Unable to find connection attribute."); return mInitCheck; } } if (!(connection == "IN IP4 127.0.0.1")) { - LOG(ERROR) << "We only support localhost connections for now."; + LOGE("We only support localhost connections for now."); return mInitCheck; } unsigned port; if (!validateMediaFormat(i, &port) || (port & 1) != 0) { - LOG(ERROR) << "Invalid media format."; + LOGE("Invalid media format."); return mInitCheck; } sp<APacketSource> source = new APacketSource(mDesc, i); if (source->initCheck() != OK) { - LOG(ERROR) << "Unsupported format."; + LOGE("Unsupported format."); return mInitCheck; } @@ -157,9 +161,8 @@ void ARTPSession::onMessageReceived(const sp<AMessage> &msg) { printf("access unit complete size=%d\tntp-time=0x%016llx\n", accessUnit->size(), ntpTime); #else - LOG(INFO) << "access unit complete, " - << "size=" << accessUnit->size() << ", " - << "ntp-time=" << ntpTime; + LOGI("access unit complete, size=%d, ntp-time=%llu", + accessUnit->size(), ntpTime); hexdump(accessUnit->data(), accessUnit->size()); #endif #endif @@ -169,9 +172,8 @@ void ARTPSession::onMessageReceived(const sp<AMessage> &msg) { CHECK(!memcmp("\x00\x00\x00\x01", accessUnit->data(), 4)); unsigned x = accessUnit->data()[4]; - LOG(INFO) << "access unit complete: " - << StringPrintf("nalType=0x%02x, nalRefIdc=0x%02x", - x & 0x1f, (x & 0x60) >> 5); + LOGI("access unit complete: nalType=0x%02x, nalRefIdc=0x%02x", + x & 0x1f, (x & 0x60) >> 5); #endif accessUnit->meta()->setInt64("ntp-time", ntpTime); @@ -181,7 +183,7 @@ void ARTPSession::onMessageReceived(const sp<AMessage> &msg) { int32_t damaged; if (accessUnit->meta()->findInt32("damaged", &damaged) && damaged != 0) { - LOG(INFO) << "ignoring damaged AU"; + LOGI("ignoring damaged AU"); } else #endif { diff --git a/media/libstagefright/rtsp/ARTPSource.cpp b/media/libstagefright/rtsp/ARTPSource.cpp index 9656ba2..2518264 100644 --- a/media/libstagefright/rtsp/ARTPSource.cpp +++ b/media/libstagefright/rtsp/ARTPSource.cpp @@ -14,6 +14,10 @@ * limitations under the License. */ +//#define LOG_NDEBUG 0 +#define LOG_TAG "ARTPSource" +#include <utils/Log.h> + #include "ARTPSource.h" #include "AAMRAssembler.h" @@ -27,8 +31,6 @@ #include <media/stagefright/foundation/ADebug.h> #include <media/stagefright/foundation/AMessage.h> -#define BE_VERBOSE 0 - namespace android { static const uint32_t kSourceID = 0xdeadbeef; @@ -83,14 +85,10 @@ void ARTPSource::processRTPPacket(const sp<ABuffer> &buffer) { && mAssembler != NULL) { mAssembler->onPacketReceived(this); } - - dump(); } void ARTPSource::timeUpdate(uint32_t rtpTime, uint64_t ntpTime) { -#if BE_VERBOSE - LOG(VERBOSE) << "timeUpdate"; -#endif + LOGV("timeUpdate"); mLastNTPTime = ntpTime; mLastNTPTimeUpdateUs = ALooper::GetNowUs(); @@ -173,7 +171,7 @@ bool ARTPSource::queuePacket(const sp<ABuffer> &buffer) { } if (it != mQueue.end() && (uint32_t)(*it)->int32Data() == seqNum) { - LOG(WARNING) << "Discarding duplicate buffer"; + LOGW("Discarding duplicate buffer"); return false; } @@ -182,89 +180,6 @@ bool ARTPSource::queuePacket(const sp<ABuffer> &buffer) { return true; } -void ARTPSource::dump() const { - if ((mNumBuffersReceived % 128) != 0) { - return; - } - -#if 0 - if (mAssembler == NULL) { - char tmp[20]; - sprintf(tmp, "0x%08x", mID); - - int32_t numMissing = 0; - - if (!mQueue.empty()) { - List<sp<ABuffer> >::const_iterator it = mQueue.begin(); - uint32_t expectedSeqNum = (uint32_t)(*it)->int32Data(); - ++expectedSeqNum; - ++it; - - for (; it != mQueue.end(); ++it) { - uint32_t seqNum = (uint32_t)(*it)->int32Data(); - CHECK_GE(seqNum, expectedSeqNum); - - if (seqNum != expectedSeqNum) { - numMissing += seqNum - expectedSeqNum; - expectedSeqNum = seqNum; - } - - ++expectedSeqNum; - } - } - - LOG(VERBOSE) << "[" << tmp << "] Missing " << numMissing - << " / " << (mNumBuffersReceived + numMissing) << " packets. (" - << (100.0 * numMissing / (mNumBuffersReceived + numMissing)) - << " %%)"; - } -#endif - -#if 0 - AString out; - - out.append(tmp); - out.append(" ["); - - List<sp<ABuffer> >::const_iterator it = mQueue.begin(); - while (it != mQueue.end()) { - uint32_t start = (uint32_t)(*it)->int32Data(); - - out.append(start); - - ++it; - uint32_t expected = start + 1; - - while (it != mQueue.end()) { - uint32_t seqNum = (uint32_t)(*it)->int32Data(); - - if (seqNum != expected) { - if (expected > start + 1) { - out.append("-"); - out.append(expected - 1); - } - out.append(", "); - break; - } - - ++it; - ++expected; - } - - if (it == mQueue.end()) { - if (expected > start + 1) { - out.append("-"); - out.append(expected - 1); - } - } - } - - out.append("]"); - - LOG(VERBOSE) << out; -#endif -} - uint64_t ARTPSource::RTP2NTP(uint32_t rtpTime) const { CHECK_EQ(mNumTimes, 2u); @@ -291,7 +206,7 @@ void ARTPSource::addFIR(const sp<ABuffer> &buffer) { mLastFIRRequestUs = nowUs; if (buffer->size() + 20 > buffer->capacity()) { - LOG(WARNING) << "RTCP buffer too small to accomodate FIR."; + LOGW("RTCP buffer too small to accomodate FIR."); return; } @@ -324,12 +239,12 @@ void ARTPSource::addFIR(const sp<ABuffer> &buffer) { buffer->setRange(buffer->offset(), buffer->size() + 20); - LOG(VERBOSE) << "Added FIR request."; + LOGV("Added FIR request."); } void ARTPSource::addReceiverReport(const sp<ABuffer> &buffer) { if (buffer->size() + 32 > buffer->capacity()) { - LOG(WARNING) << "RTCP buffer too small to accomodate RR."; + LOGW("RTCP buffer too small to accomodate RR."); return; } diff --git a/media/libstagefright/rtsp/ARTPSource.h b/media/libstagefright/rtsp/ARTPSource.h index 252d6d6..e62c3f1 100644 --- a/media/libstagefright/rtsp/ARTPSource.h +++ b/media/libstagefright/rtsp/ARTPSource.h @@ -72,7 +72,6 @@ private: uint64_t RTP2NTP(uint32_t rtpTime) const; bool queuePacket(const sp<ABuffer> &buffer); - void dump() const; DISALLOW_EVIL_CONSTRUCTORS(ARTPSource); }; diff --git a/media/libstagefright/rtsp/ARTPWriter.cpp b/media/libstagefright/rtsp/ARTPWriter.cpp index ce1ee0e..155fd96 100644 --- a/media/libstagefright/rtsp/ARTPWriter.cpp +++ b/media/libstagefright/rtsp/ARTPWriter.cpp @@ -1,3 +1,23 @@ +/* + * Copyright (C) 2010 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +//#define LOG_NDEBUG 0 +#define LOG_TAG "ARTPWriter" +#include <utils/Log.h> + #include "ARTPWriter.h" #include <fcntl.h> @@ -249,7 +269,7 @@ void ARTPWriter::onRead(const sp<AMessage> &msg) { status_t err = mSource->read(&mediaBuf); if (err != OK) { - LOG(INFO) << "reached EOS."; + LOGI("reached EOS."); Mutex::Autolock autoLock(mLock); mFlags |= kFlagEOS; @@ -257,7 +277,7 @@ void ARTPWriter::onRead(const sp<AMessage> &msg) { } if (mediaBuf->range_length() > 0) { - LOG(VERBOSE) << "read buffer of size " << mediaBuf->range_length(); + LOGV("read buffer of size %d", mediaBuf->range_length()); if (mMode == H264) { StripStartcode(mediaBuf); @@ -500,7 +520,7 @@ void ARTPWriter::dumpSessionDesc() { sdp.append("a=fmtp:" PT_STR " octed-align\r\n"); } - LOG(INFO) << sdp; + LOGI("%s", sdp.c_str()); } void ARTPWriter::makeH264SPropParamSets(MediaBuffer *buffer) { diff --git a/media/libstagefright/rtsp/ARTSPConnection.cpp b/media/libstagefright/rtsp/ARTSPConnection.cpp index dcff64c..f928c06 100644 --- a/media/libstagefright/rtsp/ARTSPConnection.cpp +++ b/media/libstagefright/rtsp/ARTSPConnection.cpp @@ -14,6 +14,10 @@ * limitations under the License. */ +//#define LOG_NDEBUG 0 +#define LOG_TAG "ARTSPConnection" +#include <utils/Log.h> + #include "ARTSPConnection.h" #include <media/stagefright/foundation/ABuffer.h> @@ -41,7 +45,7 @@ ARTSPConnection::ARTSPConnection() ARTSPConnection::~ARTSPConnection() { if (mSocket >= 0) { - LOG(ERROR) << "Connection is still open, closing the socket."; + LOGE("Connection is still open, closing the socket."); close(mSocket); mSocket = -1; } @@ -184,7 +188,7 @@ void ARTSPConnection::onConnect(const sp<AMessage> &msg) { AString host, path; unsigned port; if (!ParseURL(url.c_str(), &host, &port, &path)) { - LOG(ERROR) << "Malformed rtsp url " << url; + LOGE("Malformed rtsp url %s", url.c_str()); reply->setInt32("result", ERROR_MALFORMED); reply->post(); @@ -195,7 +199,7 @@ void ARTSPConnection::onConnect(const sp<AMessage> &msg) { struct hostent *ent = gethostbyname(host.c_str()); if (ent == NULL) { - LOG(ERROR) << "Unknown host " << host; + LOGE("Unknown host %s", host.c_str()); reply->setInt32("result", -ENOENT); reply->post(); @@ -300,7 +304,7 @@ void ARTSPConnection::onCompleteConnection(const sp<AMessage> &msg) { CHECK_EQ(optionLen, (socklen_t)sizeof(err)); if (err != 0) { - LOG(ERROR) << "err = " << err << " (" << strerror(err) << ")"; + LOGE("err = %d (%s)", err, strerror(err)); reply->setInt32("result", -err); @@ -343,7 +347,7 @@ void ARTSPConnection::onSendRequest(const sp<AMessage> &msg) { request.insert(cseqHeader, i + 2); - LOG(VERBOSE) << request; + LOGV("%s", request.c_str()); size_t numBytesSent = 0; while (numBytesSent < request.size()) { @@ -353,7 +357,7 @@ void ARTSPConnection::onSendRequest(const sp<AMessage> &msg) { if (n == 0) { // Server closed the connection. - LOG(ERROR) << "Server unexpectedly closed the connection."; + LOGE("Server unexpectedly closed the connection."); reply->setInt32("result", ERROR_IO); reply->post(); @@ -363,7 +367,7 @@ void ARTSPConnection::onSendRequest(const sp<AMessage> &msg) { continue; } - LOG(ERROR) << "Error sending rtsp request."; + LOGE("Error sending rtsp request."); reply->setInt32("result", -errno); reply->post(); return; @@ -438,14 +442,14 @@ status_t ARTSPConnection::receive(void *data, size_t size) { ssize_t n = recv(mSocket, (uint8_t *)data + offset, size - offset, 0); if (n == 0) { // Server closed the connection. - LOG(ERROR) << "Server unexpectedly closed the connection."; + LOGE("Server unexpectedly closed the connection."); return ERROR_IO; } else if (n < 0) { if (errno == EINTR) { continue; } - LOG(ERROR) << "Error reading rtsp response."; + LOGE("Error reading rtsp response."); return -errno; } @@ -516,7 +520,7 @@ bool ARTSPConnection::receiveRTSPReponse() { notify->setObject("buffer", buffer); notify->post(); } else { - LOG(WARNING) << "received binary data, but no one cares."; + LOGW("received binary data, but no one cares."); } return true; @@ -525,7 +529,7 @@ bool ARTSPConnection::receiveRTSPReponse() { sp<ARTSPResponse> response = new ARTSPResponse; response->mStatusLine = statusLine; - LOG(INFO) << "status: " << response->mStatusLine; + LOGI("status: %s", response->mStatusLine.c_str()); ssize_t space1 = response->mStatusLine.find(" "); if (space1 < 0) { @@ -555,7 +559,7 @@ bool ARTSPConnection::receiveRTSPReponse() { break; } - LOG(VERBOSE) << "line: " << line; + LOGV("line: %s", line.c_str()); ssize_t colonPos = line.find(":"); if (colonPos < 0) { diff --git a/media/libstagefright/rtsp/ASessionDescription.cpp b/media/libstagefright/rtsp/ASessionDescription.cpp index 4a8cce8..612caff 100644 --- a/media/libstagefright/rtsp/ASessionDescription.cpp +++ b/media/libstagefright/rtsp/ASessionDescription.cpp @@ -14,6 +14,10 @@ * limitations under the License. */ +//#define LOG_NDEBUG 0 +#define LOG_TAG "ASessionDescription" +#include <utils/Log.h> + #include "ASessionDescription.h" #include <media/stagefright/foundation/ADebug.h> @@ -49,7 +53,7 @@ bool ASessionDescription::parse(const void *data, size_t size) { mFormats.push(AString("[root]")); AString desc((const char *)data, size); - LOG(INFO) << desc; + LOGI("%s", desc.c_str()); size_t i = 0; for (;;) { @@ -102,7 +106,7 @@ bool ASessionDescription::parse(const void *data, size_t size) { key.trim(); value.trim(); - LOG(VERBOSE) << "adding '" << key << "' => '" << value << "'"; + LOGV("adding '%s' => '%s'", key.c_str(), value.c_str()); mTracks.editItemAt(mTracks.size() - 1).add(key, value); break; @@ -110,7 +114,8 @@ bool ASessionDescription::parse(const void *data, size_t size) { case 'm': { - LOG(VERBOSE) << "new section '" << AString(line, 2, line.size() - 2) << "'"; + LOGV("new section '%s'", + AString(line, 2, line.size() - 2).c_str()); mTracks.push(Attribs()); mFormats.push(AString(line, 2, line.size() - 2)); @@ -129,7 +134,7 @@ bool ASessionDescription::parse(const void *data, size_t size) { key.trim(); value.trim(); - LOG(VERBOSE) << "adding '" << key << "' => '" << value << "'"; + LOGV("adding '%s' => '%s'", key.c_str(), value.c_str()); mTracks.editItemAt(mTracks.size() - 1).add(key, value); break; diff --git a/media/libstagefright/rtsp/MyHandler.h b/media/libstagefright/rtsp/MyHandler.h index a3864f1..09dc156 100644 --- a/media/libstagefright/rtsp/MyHandler.h +++ b/media/libstagefright/rtsp/MyHandler.h @@ -18,6 +18,10 @@ #define MY_HANDLER_H_ +//#define LOG_NDEBUG 0 +#define LOG_TAG "MyHandler" +#include <utils/Log.h> + #include "APacketSource.h" #include "ARTPConnection.h" #include "ARTSPConnection.h" @@ -137,8 +141,8 @@ struct MyHandler : public AHandler { int32_t result; CHECK(msg->findInt32("result", &result)); - LOG(INFO) << "connection request completed with result " - << result << " (" << strerror(-result) << ")"; + LOGI("connection request completed with result %d (%s)", + result, strerror(-result)); if (result == OK) { AString request; @@ -173,8 +177,8 @@ struct MyHandler : public AHandler { int32_t result; CHECK(msg->findInt32("result", &result)); - LOG(INFO) << "DESCRIBE completed with result " - << result << " (" << strerror(-result) << ")"; + LOGI("DESCRIBE completed with result %d (%s)", + result, strerror(-result)); if (result == OK) { sp<RefBase> obj; @@ -251,8 +255,8 @@ struct MyHandler : public AHandler { int32_t result; CHECK(msg->findInt32("result", &result)); - LOG(INFO) << "SETUP(" << index << ") completed with result " - << result << " (" << strerror(-result) << ")"; + LOGI("SETUP(%d) completed with result %d (%s)", + index, result, strerror(-result)); if (result == OK) { CHECK(track != NULL); @@ -326,8 +330,8 @@ struct MyHandler : public AHandler { int32_t result; CHECK(msg->findInt32("result", &result)); - LOG(INFO) << "PLAY completed with result " - << result << " (" << strerror(-result) << ")"; + LOGI("PLAY completed with result %d (%s)", + result, strerror(-result)); if (result == OK) { sp<RefBase> obj; @@ -404,8 +408,8 @@ struct MyHandler : public AHandler { int32_t result; CHECK(msg->findInt32("result", &result)); - LOG(INFO) << "TEARDOWN completed with result " - << result << " (" << strerror(-result) << ")"; + LOGI("TEARDOWN completed with result %d (%s)", + result, strerror(-result)); sp<AMessage> reply = new AMessage('disc', id()); @@ -431,7 +435,7 @@ struct MyHandler : public AHandler { case 'chek': { if (mNumAccessUnitsReceived == 0) { - LOG(INFO) << "stream ended? aborting."; + LOGI("stream ended? aborting."); (new AMessage('abor', id()))->post(); break; } @@ -461,7 +465,7 @@ struct MyHandler : public AHandler { CHECK(msg->findSize("track-index", &trackIndex)); if (trackIndex >= mTracks.size()) { - LOG(ERROR) << "late packets ignored."; + LOGV("late packets ignored."); break; } @@ -469,7 +473,7 @@ struct MyHandler : public AHandler { int32_t eos; if (msg->findInt32("eos", &eos)) { - LOG(INFO) << "received BYE on track index " << trackIndex; + LOGI("received BYE on track index %d", trackIndex); #if 0 track->mPacketSource->signalEOS(ERROR_END_OF_STREAM); #endif @@ -484,14 +488,13 @@ struct MyHandler : public AHandler { uint32_t seqNum = (uint32_t)accessUnit->int32Data(); if (mSeekPending) { - LOG(INFO) << "we're seeking, dropping stale packet."; + LOGV("we're seeking, dropping stale packet."); break; } if (seqNum < track->mFirstSeqNumInSegment) { - LOG(INFO) << "dropping stale access-unit " - << "(" << seqNum << " < " - << track->mFirstSeqNumInSegment << ")"; + LOGV("dropping stale access-unit (%d < %d)", + seqNum, track->mFirstSeqNumInSegment); break; } @@ -506,10 +509,8 @@ struct MyHandler : public AHandler { if (track->mNewSegment) { track->mNewSegment = false; - LOG(VERBOSE) << "first segment unit ntpTime=" - << StringPrintf("0x%016llx", ntpTime) - << " rtpTime=" << rtpTime - << " seq=" << seqNum; + LOGV("first segment unit ntpTime=0x%016llx rtpTime=%u seq=%d", + ntpTime, rtpTime, seqNum); } if (mFirstAccessUnit) { @@ -535,7 +536,7 @@ struct MyHandler : public AHandler { int32_t damaged; if (accessUnit->meta()->findInt32("damaged", &damaged) && damaged != 0) { - LOG(INFO) << "ignoring damaged AU"; + LOGI("ignoring damaged AU"); } else #endif { @@ -608,8 +609,8 @@ struct MyHandler : public AHandler { int32_t result; CHECK(msg->findInt32("result", &result)); - LOG(INFO) << "PLAY completed with result " - << result << " (" << strerror(-result) << ")"; + LOGI("PLAY completed with result %d (%s)", + result, strerror(-result)); if (result == OK) { sp<RefBase> obj; @@ -622,12 +623,12 @@ struct MyHandler : public AHandler { } else { parsePlayResponse(response); - LOG(INFO) << "seek completed."; + LOGI("seek completed."); } } if (result != OK) { - LOG(ERROR) << "seek failed, aborting."; + LOGE("seek failed, aborting."); (new AMessage('abor', id()))->post(); } @@ -652,11 +653,10 @@ struct MyHandler : public AHandler { { if (!mReceivedFirstRTCPPacket) { if (mTryTCPInterleaving) { - LOG(WARNING) << "Never received any data, disconnecting."; + LOGW("Never received any data, disconnecting."); (new AMessage('abor', id()))->post(); } else { - LOG(WARNING) - << "Never received any data, switching transports."; + LOGW("Never received any data, switching transports."); mTryTCPInterleaving = true; @@ -700,7 +700,7 @@ struct MyHandler : public AHandler { } AString range = response->mHeaders.valueAt(i); - LOG(VERBOSE) << "Range: " << range; + LOGV("Range: %s", range.c_str()); AString val; CHECK(GetAttribute(range.c_str(), "npt", &val)); @@ -724,7 +724,7 @@ struct MyHandler : public AHandler { for (List<AString>::iterator it = streamInfos.begin(); it != streamInfos.end(); ++it) { (*it).trim(); - LOG(VERBOSE) << "streamInfo[" << n << "] = " << *it; + LOGV("streamInfo[%d] = %s", n, (*it).c_str()); CHECK(GetAttribute((*it).c_str(), "url", &val)); @@ -748,8 +748,7 @@ struct MyHandler : public AHandler { uint32_t rtpTime = strtoul(val.c_str(), &end, 10); - LOG(VERBOSE) << "track #" << n - << ": rtpTime=" << rtpTime << " <=> npt=" << npt1; + LOGV("track #%d: rtpTime=%u <=> ntp=%.2f", n, rtpTime, npt1); info->mPacketSource->setNormalPlayTimeMapping( rtpTime, (int64_t)(npt1 * 1E6)); @@ -806,8 +805,7 @@ private: new APacketSource(mSessionDesc, index); if (source->initCheck() != OK) { - LOG(WARNING) << "Unsupported format. Ignoring track #" - << index << "."; + LOGW("Unsupported format. Ignoring track #%d.", index); sp<AMessage> reply = new AMessage('setu', id()); reply->setSize("index", index); @@ -830,7 +828,7 @@ private: info->mFirstSeqNumInSegment = 0; info->mNewSegment = true; - LOG(VERBOSE) << "track #" << mTracks.size() << " URL=" << trackURL; + LOGV("track #%d URL=%s", mTracks.size(), trackURL.c_str()); AString request = "SETUP "; request.append(trackURL); diff --git a/media/libstagefright/rtsp/UDPPusher.cpp b/media/libstagefright/rtsp/UDPPusher.cpp index 28a343f..576b3ca 100644 --- a/media/libstagefright/rtsp/UDPPusher.cpp +++ b/media/libstagefright/rtsp/UDPPusher.cpp @@ -14,6 +14,10 @@ * limitations under the License. */ +//#define LOG_NDEBUG 0 +#define LOG_TAG "UDPPusher" +#include <utils/Log.h> + #include "UDPPusher.h" #include <media/stagefright/foundation/ABuffer.h> @@ -67,7 +71,7 @@ void UDPPusher::start() { bool UDPPusher::onPush() { uint32_t length; if (fread(&length, 1, sizeof(length), mFile) < sizeof(length)) { - LOG(INFO) << "No more data to push."; + LOGI("No more data to push."); return false; } @@ -77,7 +81,7 @@ bool UDPPusher::onPush() { sp<ABuffer> buffer = new ABuffer(length); if (fread(buffer->data(), 1, length, mFile) < length) { - LOG(ERROR) << "File truncated?."; + LOGE("File truncated?."); return false; } @@ -89,7 +93,7 @@ bool UDPPusher::onPush() { uint32_t timeMs; if (fread(&timeMs, 1, sizeof(timeMs), mFile) < sizeof(timeMs)) { - LOG(INFO) << "No more data to push."; + LOGI("No more data to push."); return false; } @@ -109,7 +113,7 @@ void UDPPusher::onMessageReceived(const sp<AMessage> &msg) { case kWhatPush: { if (!onPush() && !(ntohs(mRemoteAddr.sin_port) & 1)) { - LOG(INFO) << "emulating BYE packet"; + LOGI("emulating BYE packet"); sp<ABuffer> buffer = new ABuffer(8); uint8_t *data = buffer->data(); diff --git a/media/libstagefright/rtsp/rtp_test.cpp b/media/libstagefright/rtsp/rtp_test.cpp index cec6c0c..f0cb5a5 100644 --- a/media/libstagefright/rtsp/rtp_test.cpp +++ b/media/libstagefright/rtsp/rtp_test.cpp @@ -14,6 +14,10 @@ * limitations under the License. */ +//#define LOG_NDEBUG 0 +#define LOG_TAG "rtp_test" +#include <utils/Log.h> + #include <binder/ProcessState.h> #include <media/stagefright/foundation/ADebug.h> @@ -200,8 +204,7 @@ int main(int argc, char **argv) { continue; } - LOG(ERROR) << "decoder returned error " - << StringPrintf("0x%08x", err); + LOGE("decoder returned error 0x%08x", err); break; } diff --git a/media/mtp/MtpCursor.cpp b/media/mtp/MtpCursor.cpp index 3ba07cc..8c964b4 100644 --- a/media/mtp/MtpCursor.cpp +++ b/media/mtp/MtpCursor.cpp @@ -371,7 +371,7 @@ bool MtpCursor::fillObject(CursorWindow* window, MtpDevice* device, goto fail; break; default: - LOGE("fillStorage: unknown column %d\n", mColumns[i]); + LOGE("fillObject: unknown column %d\n", mColumns[i]); goto fail; } } diff --git a/media/tests/CameraBrowser/Android.mk b/media/tests/CameraBrowser/Android.mk index 33d2976..1d81129 100644 --- a/media/tests/CameraBrowser/Android.mk +++ b/media/tests/CameraBrowser/Android.mk @@ -1,6 +1,8 @@ LOCAL_PATH:= $(call my-dir) include $(CLEAR_VARS) +LOCAL_MODULE_TAGS := tests + LOCAL_SRC_FILES := $(call all-subdir-java-files) LOCAL_PACKAGE_NAME := CameraBrowser diff --git a/media/tests/CameraBrowser/res/layout/object_info.xml b/media/tests/CameraBrowser/res/layout/object_info.xml index c7fd830..ac210b9 100644 --- a/media/tests/CameraBrowser/res/layout/object_info.xml +++ b/media/tests/CameraBrowser/res/layout/object_info.xml @@ -41,6 +41,16 @@ style="@style/info_value" /> </TableRow> <TableRow> + <TextView android:id="@+id/format_label" + android:text="@string/format_label" + android:layout_gravity="right" + android:layout_marginRight="8dip" + style="@style/info_label" /> + + <TextView android:id="@+id/format" + style="@style/info_value" /> + </TableRow> + <TableRow> <TextView android:id="@+id/thumb_width_label" android:text="@string/thumb_width_label" android:layout_gravity="right" diff --git a/media/tests/CameraBrowser/res/values/strings.xml b/media/tests/CameraBrowser/res/values/strings.xml index 56c5111..cd477f1 100644 --- a/media/tests/CameraBrowser/res/values/strings.xml +++ b/media/tests/CameraBrowser/res/values/strings.xml @@ -20,6 +20,7 @@ <!-- for object info --> <string name="name_label">Name: </string> <string name="size_label">Size: </string> + <string name="format_label">Format: </string> <string name="thumb_width_label">Thumb Width: </string> <string name="thumb_height_label">Thumb Height: </string> <string name="thumb_size_label">Thumb Size: </string> diff --git a/media/tests/CameraBrowser/src/com/android/camerabrowser/ObjectBrowser.java b/media/tests/CameraBrowser/src/com/android/camerabrowser/ObjectBrowser.java index fc9989d..6d34fd4 100644 --- a/media/tests/CameraBrowser/src/com/android/camerabrowser/ObjectBrowser.java +++ b/media/tests/CameraBrowser/src/com/android/camerabrowser/ObjectBrowser.java @@ -44,8 +44,8 @@ public class ObjectBrowser extends ListActivity { private Cursor mCursor; private ObjectCursorAdapter mAdapter; private int mDeviceID; - private int mStorageID; - private int mObjectID; + private long mStorageID; + private long mObjectID; private static final String[] OBJECT_COLUMNS = new String[] { Mtp.Object._ID, Mtp.Object.NAME, Mtp.Object.FORMAT, Mtp.Object.THUMB }; @@ -65,8 +65,8 @@ public class ObjectBrowser extends ListActivity { super.onResume(); mDeviceID = getIntent().getIntExtra("device", 0); - mStorageID = getIntent().getIntExtra("storage", 0); - mObjectID = getIntent().getIntExtra("object", 0); + mStorageID = getIntent().getLongExtra("storage", 0); + mObjectID = getIntent().getLongExtra("object", 0); if (mDeviceID != 0 && mStorageID != 0) { Cursor c; Uri uri; @@ -88,7 +88,7 @@ public class ObjectBrowser extends ListActivity { @Override protected void onListItemClick(ListView l, View v, int position, long id) { - int rowID = (int)mAdapter.getItemId(position); + long rowID = mAdapter.getItemId(position); Cursor c = getContentResolver().query( Mtp.Object.getContentUri(mDeviceID, rowID), OBJECT_COLUMNS, null, null, null); @@ -101,14 +101,14 @@ public class ObjectBrowser extends ListActivity { format = c.getLong(FORMAT_COLUMN); Log.d(TAG, "rowId: " + rowId + " name: " + name + " format: " + format); } - if (format == MtpConstants.FORMAT_JFIF) { - Intent intent = new Intent(this, ObjectViewer.class); + if (format == MtpConstants.FORMAT_ASSOCIATION) { + Intent intent = new Intent(this, ObjectBrowser.class); intent.putExtra("device", mDeviceID); intent.putExtra("storage", mStorageID); - intent.putExtra("object",rowID); + intent.putExtra("object", rowID); startActivity(intent); } else { - Intent intent = new Intent(this, ObjectBrowser.class); + Intent intent = new Intent(this, ObjectViewer.class); intent.putExtra("device", mDeviceID); intent.putExtra("storage", mStorageID); intent.putExtra("object", rowID); diff --git a/media/tests/CameraBrowser/src/com/android/camerabrowser/ObjectViewer.java b/media/tests/CameraBrowser/src/com/android/camerabrowser/ObjectViewer.java index aa49cd8..5899bc1 100644 --- a/media/tests/CameraBrowser/src/com/android/camerabrowser/ObjectViewer.java +++ b/media/tests/CameraBrowser/src/com/android/camerabrowser/ObjectViewer.java @@ -51,8 +51,8 @@ public class ObjectViewer extends Activity { private static final String TAG = "ObjectViewer"; private int mDeviceID; - private int mStorageID; - private int mObjectID; + private long mStorageID; + private long mObjectID; private static final String[] OBJECT_COLUMNS = new String[] { Mtp.Object._ID, @@ -69,6 +69,7 @@ public class ObjectViewer extends Activity { Mtp.Object.DATE_MODIFIED, Mtp.Object.KEYWORDS, Mtp.Object.THUMB, + Mtp.Object.FORMAT, }; @Override @@ -83,8 +84,8 @@ public class ObjectViewer extends Activity { super.onResume(); mDeviceID = getIntent().getIntExtra("device", 0); - mStorageID = getIntent().getIntExtra("storage", 0); - mObjectID = getIntent().getIntExtra("object", 0); + mStorageID = getIntent().getLongExtra("storage", 0); + mObjectID = getIntent().getLongExtra("object", 0); if (mDeviceID != 0 && mObjectID != 0) { Cursor c = getContentResolver().query( @@ -125,6 +126,8 @@ public class ObjectViewer extends Activity { thumbView.setImageBitmap(bitmap); } } + view = (TextView)findViewById(R.id.format); + view.setText(Long.toHexString(c.getLong(14)).toUpperCase()); } } diff --git a/media/tests/CameraBrowser/src/com/android/camerabrowser/StorageBrowser.java b/media/tests/CameraBrowser/src/com/android/camerabrowser/StorageBrowser.java index 6ddf4e7..63e036e 100644 --- a/media/tests/CameraBrowser/src/com/android/camerabrowser/StorageBrowser.java +++ b/media/tests/CameraBrowser/src/com/android/camerabrowser/StorageBrowser.java @@ -70,7 +70,7 @@ public class StorageBrowser extends ListActivity { protected void onListItemClick(ListView l, View v, int position, long id) { Intent intent = new Intent(this, ObjectBrowser.class); intent.putExtra("device", mDeviceID); - intent.putExtra("storage", (int)mAdapter.getItemId(position)); + intent.putExtra("storage", mAdapter.getItemId(position)); startActivity(intent); } } diff --git a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/MediaEnvReverbTest.java b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/MediaEnvReverbTest.java index db0db70..d5538f1 100644 --- a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/MediaEnvReverbTest.java +++ b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/MediaEnvReverbTest.java @@ -414,13 +414,13 @@ public class MediaEnvReverbTest extends ActivityInstrumentationTestCase2<MediaFr EnergyProbe probe = null; AudioEffect vc = null; MediaPlayer mp = null; + AudioEffect rvb = null; AudioManager am = (AudioManager) getActivity().getSystemService(Context.AUDIO_SERVICE); int volume = am.getStreamMaxVolume(AudioManager.STREAM_MUSIC); am.setStreamVolume(AudioManager.STREAM_MUSIC, am.getStreamMaxVolume(AudioManager.STREAM_MUSIC), 0); try { - probe = new EnergyProbe(0); // creating a volume controller on output mix ensures that ro.audio.silent mutes // audio after the effects and not before vc = new AudioEffect( @@ -433,11 +433,24 @@ public class MediaEnvReverbTest extends ActivityInstrumentationTestCase2<MediaFr mp = new MediaPlayer(); mp.setDataSource(MediaNames.SINE_200_1000); mp.setAudioStreamType(AudioManager.STREAM_MUSIC); - getReverb(mp.getAudioSessionId()); - mReverb.setRoomLevel((short)0); - mReverb.setReverbLevel((short)0); - mReverb.setDecayTime(2000); - mReverb.setEnabled(true); + + // create reverb with UUID instead of EnvironmentalReverb constructor otherwise an + // auxiliary reverb will be chosen by the effect framework as we are on session 0 + rvb = new AudioEffect( + AudioEffect.EFFECT_TYPE_NULL, + UUID.fromString("c7a511a0-a3bb-11df-860e-0002a5d5c51b"), + 0, + 0); + + rvb.setParameter(EnvironmentalReverb.PARAM_ROOM_LEVEL, (short)0); + rvb.setParameter(EnvironmentalReverb.PARAM_REVERB_LEVEL, (short)0); + rvb.setParameter(EnvironmentalReverb.PARAM_DECAY_TIME, 2000); + rvb.setEnabled(true); + + // create probe after reverb so that it is chained behind the reverb in the + // effect chain + probe = new EnergyProbe(0); + mp.prepare(); mp.start(); Thread.sleep(1000); @@ -460,13 +473,15 @@ public class MediaEnvReverbTest extends ActivityInstrumentationTestCase2<MediaFr loge(msg, "sleep() interrupted"); } finally { - releaseReverb(); if (mp != null) { mp.release(); } if (vc != null) { vc.release(); } + if (rvb != null) { + rvb.release(); + } if (probe != null) { probe.release(); } diff --git a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/MediaPresetReverbTest.java b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/MediaPresetReverbTest.java index c14319a..fbd8a78 100644 --- a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/MediaPresetReverbTest.java +++ b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/MediaPresetReverbTest.java @@ -257,13 +257,13 @@ public class MediaPresetReverbTest extends ActivityInstrumentationTestCase2<Medi EnergyProbe probe = null; AudioEffect vc = null; MediaPlayer mp = null; + AudioEffect rvb = null; AudioManager am = (AudioManager) getActivity().getSystemService(Context.AUDIO_SERVICE); int volume = am.getStreamMaxVolume(AudioManager.STREAM_MUSIC); am.setStreamVolume(AudioManager.STREAM_MUSIC, am.getStreamMaxVolume(AudioManager.STREAM_MUSIC), 0); try { - probe = new EnergyProbe(0); // creating a volume controller on output mix ensures that ro.audio.silent mutes // audio after the effects and not before vc = new AudioEffect( @@ -279,6 +279,22 @@ public class MediaPresetReverbTest extends ActivityInstrumentationTestCase2<Medi getReverb(mp.getAudioSessionId()); mReverb.setPreset((short)PresetReverb.PRESET_PLATE); mReverb.setEnabled(true); + + // create reverb with UUID instead of PresetReverb constructor otherwise an auxiliary + // reverb will be chosen by the effect framework as we are on session 0 + rvb = new AudioEffect( + AudioEffect.EFFECT_TYPE_NULL, + UUID.fromString("172cdf00-a3bc-11df-a72f-0002a5d5c51b"), + 0, + 0); + + rvb.setParameter(PresetReverb.PARAM_PRESET, PresetReverb.PRESET_PLATE); + rvb.setEnabled(true); + + // create probe after reverb so that it is chained behind the reverb in the + // effect chain + probe = new EnergyProbe(0); + mp.prepare(); mp.start(); Thread.sleep(1000); @@ -308,6 +324,9 @@ public class MediaPresetReverbTest extends ActivityInstrumentationTestCase2<Medi if (vc != null) { vc.release(); } + if (rvb != null) { + rvb.release(); + } if (probe != null) { probe.release(); } diff --git a/opengl/libs/EGL/Loader.cpp b/opengl/libs/EGL/Loader.cpp index 5d6ac26..747c829 100644 --- a/opengl/libs/EGL/Loader.cpp +++ b/opengl/libs/EGL/Loader.cpp @@ -136,30 +136,24 @@ void* Loader::open(EGLNativeDisplayType display, int impl, egl_connection_t* cnx */ void* dso; - char path[PATH_MAX]; int index = int(display); driver_t* hnd = 0; - const char* const format = "/system/lib/egl/lib%s_%s.so"; char const* tag = getTag(index, impl); if (tag) { - snprintf(path, PATH_MAX, format, "GLES", tag); - dso = load_driver(path, cnx, EGL | GLESv1_CM | GLESv2); + dso = load_driver("GLES", tag, cnx, EGL | GLESv1_CM | GLESv2); if (dso) { hnd = new driver_t(dso); } else { // Always load EGL first - snprintf(path, PATH_MAX, format, "EGL", tag); - dso = load_driver(path, cnx, EGL); + dso = load_driver("EGL", tag, cnx, EGL); if (dso) { hnd = new driver_t(dso); // TODO: make this more automated - snprintf(path, PATH_MAX, format, "GLESv1_CM", tag); - hnd->set( load_driver(path, cnx, GLESv1_CM), GLESv1_CM ); + hnd->set( load_driver("GLESv1_CM", tag, cnx, GLESv1_CM), GLESv1_CM ); - snprintf(path, PATH_MAX, format, "GLESv2", tag); - hnd->set( load_driver(path, cnx, GLESv2), GLESv2 ); + hnd->set( load_driver("GLESv2", tag, cnx, GLESv2), GLESv2 ); } } } @@ -222,12 +216,20 @@ void Loader::init_api(void* dso, } } -void *Loader::load_driver(const char* driver_absolute_path, +void *Loader::load_driver(const char* kind, const char *tag, egl_connection_t* cnx, uint32_t mask) { + char driver_absolute_path[PATH_MAX]; + const char* const search1 = "/vendor/lib/egl/lib%s_%s.so"; + const char* const search2 = "/system/lib/egl/lib%s_%s.so"; + + snprintf(driver_absolute_path, PATH_MAX, search1, kind, tag); if (access(driver_absolute_path, R_OK)) { - // this happens often, we don't want to log an error - return 0; + snprintf(driver_absolute_path, PATH_MAX, search2, kind, tag); + if (access(driver_absolute_path, R_OK)) { + // this happens often, we don't want to log an error + return 0; + } } void* dso = dlopen(driver_absolute_path, RTLD_NOW | RTLD_LOCAL); diff --git a/opengl/libs/EGL/Loader.h b/opengl/libs/EGL/Loader.h index 8659b0b..580d6e4 100644 --- a/opengl/libs/EGL/Loader.h +++ b/opengl/libs/EGL/Loader.h @@ -74,7 +74,7 @@ public: private: Loader(); - void *load_driver(const char* driver, egl_connection_t* cnx, uint32_t mask); + void *load_driver(const char* kind, const char *tag, egl_connection_t* cnx, uint32_t mask); static __attribute__((noinline)) void init_api(void* dso, diff --git a/opengl/tests/testLatency/Android.mk b/opengl/tests/testLatency/Android.mk new file mode 100644 index 0000000..96417c7 --- /dev/null +++ b/opengl/tests/testLatency/Android.mk @@ -0,0 +1,20 @@ +######################################################################### +# Test end-to-end latency. +######################################################################### + +TOP_LOCAL_PATH:= $(call my-dir) + +# Build activity + + +LOCAL_PATH:= $(call my-dir) +include $(CLEAR_VARS) + +LOCAL_SDK_VERSION := 8 +LOCAL_MODULE_TAGS := optional + +LOCAL_SRC_FILES := $(call all-subdir-java-files) + +LOCAL_PACKAGE_NAME := TestLatency + +include $(BUILD_PACKAGE) diff --git a/opengl/tests/testLatency/AndroidManifest.xml b/opengl/tests/testLatency/AndroidManifest.xml new file mode 100644 index 0000000..741266e --- /dev/null +++ b/opengl/tests/testLatency/AndroidManifest.xml @@ -0,0 +1,37 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- +/* +** +** Copyright 2009, The Android Open Source Project +** +** Licensed under the Apache License, Version 2.0 (the "License"); +** you may not use this file except in compliance with the License. +** You may obtain a copy of the License at +** +** http://www.apache.org/licenses/LICENSE-2.0 +** +** Unless required by applicable law or agreed to in writing, software +** distributed under the License is distributed on an "AS IS" BASIS, +** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +** See the License for the specific language governing permissions and +** limitations under the License. +*/ +--> + +<manifest xmlns:android="http://schemas.android.com/apk/res/android" + package="com.android.testlatency"> + <uses-sdk android:targetSdkVersion="8" android:minSdkVersion="8" /> + + <application + android:label="@string/testLatency_activity"> + <activity android:name="TestLatencyActivity" + android:theme="@android:style/Theme.NoTitleBar.Fullscreen" + android:launchMode="singleTask" + android:configChanges="orientation|keyboardHidden"> + <intent-filter> + <action android:name="android.intent.action.MAIN" /> + <category android:name="android.intent.category.LAUNCHER" /> + </intent-filter> + </activity> + </application> +</manifest> diff --git a/opengl/tests/testLatency/res/values/strings.xml b/opengl/tests/testLatency/res/values/strings.xml new file mode 100644 index 0000000..0309991 --- /dev/null +++ b/opengl/tests/testLatency/res/values/strings.xml @@ -0,0 +1,29 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- +/* +** +** Copyright 2006, The Android Open Source Project +** +** Licensed under the Apache License, Version 2.0 (the "License"); +** you may not use this file except in compliance with the License. +** You may obtain a copy of the License at +** +** http://www.apache.org/licenses/LICENSE-2.0 +** +** Unless required by applicable law or agreed to in writing, software +** distributed under the License is distributed on an "AS IS" BASIS, +** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +** See the License for the specific language governing permissions and +** limitations under the License. +*/ +--> + +<!-- This file contains resource definitions for displayed strings, allowing + them to be changed based on the locale and options. --> + +<resources> + <!-- Simple strings. --> + <string name="testLatency_activity">TestLatency</string> + +</resources> + diff --git a/opengl/tests/testLatency/src/com/android/testlatency/TestLatencyActivity.java b/opengl/tests/testLatency/src/com/android/testlatency/TestLatencyActivity.java new file mode 100644 index 0000000..ed993cb --- /dev/null +++ b/opengl/tests/testLatency/src/com/android/testlatency/TestLatencyActivity.java @@ -0,0 +1,47 @@ +/* + * Copyright (C) 2007 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.testlatency; + +import android.app.Activity; +import android.os.Bundle; +import android.util.Log; +import android.view.WindowManager; + +import java.io.File; + + +public class TestLatencyActivity extends Activity { + + TestLatencyView mView; + + @Override protected void onCreate(Bundle icicle) { + super.onCreate(icicle); + mView = new TestLatencyView(getApplication()); + setContentView(mView); + mView.setFocusableInTouchMode(true); + } + + @Override protected void onPause() { + super.onPause(); + mView.onPause(); + } + + @Override protected void onResume() { + super.onResume(); + mView.onResume(); + } +} diff --git a/opengl/tests/testLatency/src/com/android/testlatency/TestLatencyView.java b/opengl/tests/testLatency/src/com/android/testlatency/TestLatencyView.java new file mode 100644 index 0000000..d62bf17 --- /dev/null +++ b/opengl/tests/testLatency/src/com/android/testlatency/TestLatencyView.java @@ -0,0 +1,267 @@ +/* + * Copyright (C) 2009 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.testlatency; + +import android.content.Context; +import android.opengl.GLSurfaceView; +import android.util.AttributeSet; +import android.util.Log; +import android.view.KeyEvent; +import android.view.MotionEvent; + +import java.nio.ByteBuffer; +import java.nio.ByteOrder; +import java.nio.FloatBuffer; + +import javax.microedition.khronos.egl.EGL10; +import javax.microedition.khronos.egl.EGLConfig; +import javax.microedition.khronos.egl.EGLContext; +import javax.microedition.khronos.egl.EGLDisplay; +import javax.microedition.khronos.opengles.GL10; + +import android.opengl.GLES20; + +/** + * An implementation of SurfaceView that uses the dedicated surface for + * displaying an OpenGL animation. This allows the animation to run in a + * separate thread, without requiring that it be driven by the update mechanism + * of the view hierarchy. + * + * The application-specific rendering code is delegated to a GLView.Renderer + * instance. + */ +class TestLatencyView extends GLSurfaceView { + private static String TAG = "TestLatencyiew"; + private float mX; + private float mY; + private float mDX; + private float mDY; + private long mT; + private long mDT; + + public TestLatencyView(Context context) { + super(context); + setEGLContextClientVersion(2); + setRenderer(new Renderer()); + } + + @Override + public boolean onTouchEvent(MotionEvent event) { + switch (event.getAction()) { + case MotionEvent.ACTION_MOVE: + float x = event.getX(); + float y = event.getY(); + long t = event.getEventTime(); + synchronized(this) { + mDT = t - mT; + mT = t; + mDX = x - mX; + mX = x; + mDY = y - mY; + mY = y; + } + break; + default: + break; + } + return true; + } + + private class Renderer implements GLSurfaceView.Renderer { + private float mScaleX, mScaleY, mOffsetX, mOffsetY; + private final float MS_PER_FRAME = 1000 / 60; + public Renderer() { + mTriangleVertices = ByteBuffer.allocateDirect(mTriangleVerticesData.length * 4) + .order(ByteOrder.nativeOrder()).asFloatBuffer(); + } + + + public void onDrawFrame(GL10 gl) { + GLES20.glClearColor(0.4f, 0.4f, 0.4f, 1.0f); + GLES20.glClear( GLES20.GL_DEPTH_BUFFER_BIT | GLES20.GL_COLOR_BUFFER_BIT); + GLES20.glUseProgram(mProgram); + checkGlError("glUseProgram"); + + float x, y, dx, dy; + long t, dt; + synchronized(TestLatencyView.this) { + x = mX; + y = mY; + dx = mDX; + dy = mDY; + dt = mDT; + } + + if (dt > 0) { + dx = dx * MS_PER_FRAME / dt; + dy = dy * MS_PER_FRAME / dt; + } + + GLES20.glEnableVertexAttribArray(mvPositionHandle); + checkGlError("glEnableVertexAttribArray"); + GLES20.glEnableVertexAttribArray(mvColorHandle); + checkGlError("glEnableVertexAttribArray"); + for(int step = 0; step < 8; step++) { + float sx = (x + dx * step) * mScaleX + mOffsetX; + float sy = (y + dy * step) * mScaleY + mOffsetY; + int cbase = step * 4; + + for (int i = 0; i < mTriangleVerticesData.length; i += 6) { + mTriangleVerticesData2[i] = sx + mTriangleVerticesData[i]; + mTriangleVerticesData2[i+1] = -sy + mTriangleVerticesData[i+1]; + mTriangleVerticesData2[i+2] = mColors[cbase]; + mTriangleVerticesData2[i+3] = mColors[cbase+1]; + mTriangleVerticesData2[i+4] = mColors[cbase+2]; + mTriangleVerticesData2[i+5] = mColors[cbase+3]; + } + mTriangleVertices.position(0); + mTriangleVertices.put(mTriangleVerticesData2).position(0); + + GLES20.glVertexAttribPointer(mvPositionHandle, 2, GLES20.GL_FLOAT, false, 6*4, mTriangleVertices); + checkGlError("glVertexAttribPointer mvPosition"); + mTriangleVertices.put(mTriangleVerticesData2).position(2); + GLES20.glVertexAttribPointer(mvColorHandle, 4, GLES20.GL_FLOAT, false, 6*4, mTriangleVertices); + checkGlError("glVertexAttribPointer mvColor"); + GLES20.glDrawArrays(GLES20.GL_TRIANGLES, 0, 3); + checkGlError("glDrawArrays"); + } + } + + public void onSurfaceChanged(GL10 gl, int width, int height) { + GLES20.glViewport(0, 0, width, height); + mScaleX = 2.0f / width; + mScaleY = 2.0f / height; + mOffsetX = -1f; + mOffsetY = -1f; + } + + public void onSurfaceCreated(GL10 gl, EGLConfig config) { + mProgram = createProgram(mVertexShader, mFragmentShader); + if (mProgram == 0) { + return; + } + mvPositionHandle = GLES20.glGetAttribLocation(mProgram, "aPosition"); + checkGlError("glGetAttribLocation"); + if (mvPositionHandle == -1) { + throw new RuntimeException("Could not get attrib location for vPosition"); + } + mvColorHandle = GLES20.glGetAttribLocation(mProgram, "aColor"); + checkGlError("glGetAttribLocation"); + if (mvColorHandle == -1) { + throw new RuntimeException("Could not get attrib location for vColor"); + } + } + + private int loadShader(int shaderType, String source) { + int shader = GLES20.glCreateShader(shaderType); + if (shader != 0) { + GLES20.glShaderSource(shader, source); + GLES20.glCompileShader(shader); + int[] compiled = new int[1]; + GLES20.glGetShaderiv(shader, GLES20.GL_COMPILE_STATUS, compiled, 0); + if (compiled[0] == 0) { + Log.e(TAG, "Could not compile shader " + shaderType + ":"); + Log.e(TAG, GLES20.glGetShaderInfoLog(shader)); + GLES20.glDeleteShader(shader); + shader = 0; + } + } + return shader; + } + + private int createProgram(String vertexSource, String fragmentSource) { + int vertexShader = loadShader(GLES20.GL_VERTEX_SHADER, vertexSource); + if (vertexShader == 0) { + return 0; + } + + int pixelShader = loadShader(GLES20.GL_FRAGMENT_SHADER, fragmentSource); + if (pixelShader == 0) { + return 0; + } + + int program = GLES20.glCreateProgram(); + if (program != 0) { + GLES20.glAttachShader(program, vertexShader); + checkGlError("glAttachShader vertexShader"); + GLES20.glAttachShader(program, pixelShader); + checkGlError("glAttachShader pixelShader"); + GLES20.glLinkProgram(program); + int[] linkStatus = new int[1]; + GLES20.glGetProgramiv(program, GLES20.GL_LINK_STATUS, linkStatus, 0); + if (linkStatus[0] != GLES20.GL_TRUE) { + Log.e(TAG, "Could not link program: "); + Log.e(TAG, GLES20.glGetProgramInfoLog(program)); + GLES20.glDeleteProgram(program); + program = 0; + } + } + return program; + } + + private void checkGlError(String op) { + int error; + while ((error = GLES20.glGetError()) != GLES20.GL_NO_ERROR) { + Log.e(TAG, op + ": glError " + error); + throw new RuntimeException(op + ": glError " + error); + } + } + + // X, Y, R G B A + private final float[] mTriangleVerticesData = { + -0.025f, 0.3f, 0.0f, 1.0f, 0.0f, 1.0f, + 0.0f , 0.0f, 0.0f, 1.0f, 0.0f, 1.0f, + 0.025f, 0.3f, 1.0f, 1.0f, 255.0f, 1.0f + }; + + // Color cascade: + private final float[] mColors = { + 0.0f, 0.0f, 0.0f, 1.0f, + 0.5f, 0.0f, 0.0f, 1.0f, + 0.0f, 0.5f, 0.0f, 1.0f, + 0.5f, 0.5f, 0.0f, 1.0f, + + 0.0f, 0.0f, 0.5f, 1.0f, + 1.0f, 0.0f, 0.0f, 1.0f, + 1.0f, 1.0f, 1.0f, 1.0f, + 0.0f, 1.0f, 0.0f, 1.0f + }; + + private float[] mTriangleVerticesData2 = new float[mTriangleVerticesData.length]; + private FloatBuffer mTriangleVertices; + + private final String mVertexShader = "attribute vec4 aPosition;\n" + + "attribute vec4 aColor;\n" + + "varying vec4 vColor;\n" + + "void main() {\n" + + " gl_Position = aPosition;\n" + + " vColor = aColor;\n" + + "}\n"; + + private final String mFragmentShader = "precision mediump float;\n" + + "varying vec4 vColor;\n" + + "void main() {\n" + + " gl_FragColor = vColor;\n" + + "}\n"; + + private int mProgram; + private int mvPositionHandle; + private int mvColorHandle; + + } +} + diff --git a/packages/SettingsProvider/res/values/defaults.xml b/packages/SettingsProvider/res/values/defaults.xml index 43bb26a..3980189 100644 --- a/packages/SettingsProvider/res/values/defaults.xml +++ b/packages/SettingsProvider/res/values/defaults.xml @@ -3,16 +3,16 @@ /** * Copyright (c) 2009, The Android Open Source Project * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and * limitations under the License. */ --> @@ -24,6 +24,7 @@ <string name="def_airplane_mode_radios" translatable="false">cell,bluetooth,wifi</string> <string name="airplane_mode_toggleable_radios" translatable="false">bluetooth,wifi</string> <bool name="def_auto_time">true</bool> + <bool name="def_auto_time_zone">true</bool> <bool name="def_accelerometer_rotation">true</bool> <!-- Default screen brightness, from 0 to 255. 102 is 40%. --> <integer name="def_screen_brightness">102</integer> @@ -31,12 +32,12 @@ <fraction name="def_window_animation_scale">100%</fraction> <fraction name="def_window_transition_scale">100%</fraction> <bool name="def_haptic_feedback">true</bool> - + <bool name="def_bluetooth_on">false</bool> <bool name="def_install_non_market_apps">false</bool> - <!-- Comma-separated list of location providers. + <!-- Comma-separated list of location providers. Network location is off by default because it requires - user opt-in via Setup Wizard or Settings. + user opt-in via Setup Wizard or Settings. --> <string name="def_location_providers_allowed" translatable="false">gps</string> <bool name="assisted_gps_enabled">true</bool> @@ -45,11 +46,11 @@ <bool name="def_usb_mass_storage_enabled">true</bool> <bool name="def_wifi_on">false</bool> <bool name="def_networks_available_notification_on">true</bool> - + <bool name="def_backup_enabled">false</bool> <string name="def_backup_transport" translatable="false">android/com.android.internal.backup.LocalTransport</string> - <!-- Default value for whether or not to pulse the notification LED when there is a + <!-- Default value for whether or not to pulse the notification LED when there is a pending notification --> <bool name="def_notification_pulse">true</bool> diff --git a/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java b/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java index 8eb3fe6..9ac832b 100644 --- a/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java +++ b/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java @@ -16,6 +16,15 @@ package com.android.providers.settings; +import com.android.internal.content.PackageHelper; +import com.android.internal.telephony.RILConstants; +import com.android.internal.util.XmlUtils; +import com.android.internal.widget.LockPatternUtils; +import com.android.internal.widget.LockPatternView; + +import org.xmlpull.v1.XmlPullParser; +import org.xmlpull.v1.XmlPullParserException; + import android.content.ComponentName; import android.content.ContentValues; import android.content.Context; @@ -36,14 +45,6 @@ import android.provider.Settings.Secure; import android.text.TextUtils; import android.util.Log; -import com.android.internal.content.PackageHelper; -import com.android.internal.telephony.RILConstants; -import com.android.internal.util.XmlUtils; -import com.android.internal.widget.LockPatternUtils; -import com.android.internal.widget.LockPatternView; -import org.xmlpull.v1.XmlPullParser; -import org.xmlpull.v1.XmlPullParserException; - import java.io.IOException; import java.util.HashSet; import java.util.List; @@ -60,7 +61,7 @@ public class DatabaseHelper extends SQLiteOpenHelper { // database gets upgraded properly. At a minimum, please confirm that 'upgradeVersion' // is properly propagated through your change. Not doing so will result in a loss of user // settings. - private static final int DATABASE_VERSION = 58; + private static final int DATABASE_VERSION = 59; private Context mContext; @@ -757,6 +758,23 @@ public class DatabaseHelper extends SQLiteOpenHelper { upgradeVersion = 58; } + if (upgradeVersion == 58) { + /* Add default for new Auto Time Zone */ + db.beginTransaction(); + SQLiteStatement stmt = null; + try { + stmt = db.compileStatement("INSERT INTO secure(name,value)" + + " VALUES(?,?);"); + loadBooleanSetting(stmt, Settings.System.AUTO_TIME_ZONE, + R.bool.def_auto_time_zone); // Sync timezone to NITZ + db.setTransactionSuccessful(); + } finally { + db.endTransaction(); + if (stmt != null) stmt.close(); + } + upgradeVersion = 59; + } + // *** Remember to update DATABASE_VERSION above! if (upgradeVersion != currentVersion) { @@ -1067,7 +1085,10 @@ public class DatabaseHelper extends SQLiteOpenHelper { loadBooleanSetting(stmt, Settings.System.AUTO_TIME, R.bool.def_auto_time); // Sync time to NITZ - + + loadBooleanSetting(stmt, Settings.System.AUTO_TIME_ZONE, + R.bool.def_auto_time_zone); // Sync timezone to NITZ + loadIntegerSetting(stmt, Settings.System.SCREEN_BRIGHTNESS, R.integer.def_screen_brightness); diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarPolicy.java b/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarPolicy.java index 7ccf210..0fc092e 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarPolicy.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarPolicy.java @@ -711,21 +711,20 @@ public class StatusBarPolicy { ConnectivityManager.EXTRA_NETWORK_INFO)); int connectionStatus = intent.getIntExtra(ConnectivityManager.EXTRA_INET_CONDITION, 0); Slog.d(TAG, "got CONNECTIVITY_ACTION - info=" + info + ", status = " + connectionStatus); - if (info.isConnected() == false) return; + + int inetCondition = (connectionStatus > INET_CONDITION_THRESHOLD ? 1 : 0); switch (info.getType()) { case ConnectivityManager.TYPE_MOBILE: - if (info.isConnected()) { - updateDataNetType(info.getSubtype(), connectionStatus); - updateDataIcon(); - updateSignalStrength(); // apply any change in connectionStatus - } + mInetCondition = inetCondition; + updateDataNetType(info.getSubtype()); + updateDataIcon(); + updateSignalStrength(); // apply any change in connectionStatus break; case ConnectivityManager.TYPE_WIFI: + mInetCondition = inetCondition; if (info.isConnected()) { mIsWifiConnected = true; - mInetCondition = - (connectionStatus > INET_CONDITION_THRESHOLD ? 1 : 0); int iconId; if (mLastWifiSignalLevel == -1) { iconId = sWifiSignalImages[mInetCondition][0]; @@ -738,7 +737,6 @@ public class StatusBarPolicy { } else { mLastWifiSignalLevel = -1; mIsWifiConnected = false; - mInetCondition = 0; int iconId = sWifiSignalImages[0][0]; mService.setIcon("wifi", iconId, 0); @@ -777,9 +775,8 @@ public class StatusBarPolicy { @Override public void onDataConnectionStateChanged(int state, int networkType) { mDataState = state; - updateDataNetType(networkType, 0); + updateDataNetType(networkType); updateDataIcon(); - updateSignalStrength(); // apply the change in connection status } @Override @@ -940,8 +937,7 @@ public class StatusBarPolicy { return (levelEvdoDbm < levelEvdoSnr) ? levelEvdoDbm : levelEvdoSnr; } - private final void updateDataNetType(int net, int inetCondition) { - mInetCondition = (inetCondition > INET_CONDITION_THRESHOLD ? 1 : 0); + private final void updateDataNetType(int net) { switch (net) { case TelephonyManager.NETWORK_TYPE_EDGE: mDataIconList = sDataNetType_e[mInetCondition]; diff --git a/packages/SystemUI/src/com/android/systemui/usb/UsbStorageActivity.java b/packages/SystemUI/src/com/android/systemui/usb/UsbStorageActivity.java index 55d31ec..29df28e 100644 --- a/packages/SystemUI/src/com/android/systemui/usb/UsbStorageActivity.java +++ b/packages/SystemUI/src/com/android/systemui/usb/UsbStorageActivity.java @@ -30,6 +30,7 @@ import android.content.DialogInterface.OnCancelListener; import android.content.pm.ApplicationInfo; import android.content.pm.PackageManager; import android.content.pm.PackageManager.NameNotFoundException; +import android.hardware.Usb; import android.os.Bundle; import android.os.Environment; import android.os.Handler; @@ -70,11 +71,11 @@ public class UsbStorageActivity extends Activity static final boolean localLOGV = false; /** Used to detect when the USB cable is unplugged, so we can call finish() */ - private BroadcastReceiver mBatteryReceiver = new BroadcastReceiver() { + private BroadcastReceiver mUsbStateReceiver = new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { - if (intent.getAction() == Intent.ACTION_BATTERY_CHANGED) { - handleBatteryChanged(intent); + if (intent.getAction().equals(Usb.ACTION_USB_STATE)) { + handleUsbStateChanged(intent); } } }; @@ -139,7 +140,7 @@ public class UsbStorageActivity extends Activity super.onResume(); mStorageManager.registerListener(mStorageListener); - registerReceiver(mBatteryReceiver, new IntentFilter(Intent.ACTION_BATTERY_CHANGED)); + registerReceiver(mUsbStateReceiver, new IntentFilter(Usb.ACTION_USB_STATE)); try { switchDisplay(mStorageManager.isUsbMassStorageEnabled()); } catch (Exception ex) { @@ -151,15 +152,15 @@ public class UsbStorageActivity extends Activity protected void onPause() { super.onPause(); - unregisterReceiver(mBatteryReceiver); + unregisterReceiver(mUsbStateReceiver); if (mStorageManager == null && mStorageListener != null) { mStorageManager.unregisterListener(mStorageListener); } } - private void handleBatteryChanged(Intent intent) { - int pluggedType = intent.getIntExtra("plugged", 0); - if (pluggedType == 0) { + private void handleUsbStateChanged(Intent intent) { + boolean connected = intent.getExtras().getBoolean(Usb.USB_CONNECTED); + if (!connected) { // It was disconnected from the plug, so finish finish(); } diff --git a/services/java/com/android/server/ConnectivityService.java b/services/java/com/android/server/ConnectivityService.java index 315bb87..aae3cff 100644 --- a/services/java/com/android/server/ConnectivityService.java +++ b/services/java/com/android/server/ConnectivityService.java @@ -58,6 +58,7 @@ import java.net.InetAddress; import java.net.UnknownHostException; import java.util.ArrayList; import java.util.Collection; +import java.util.GregorianCalendar; import java.util.List; import java.net.InetAddress; import java.net.UnknownHostException; @@ -129,6 +130,10 @@ public class ConnectivityService extends IConnectivityManager.Stub { private InetAddress mDefaultDns; + // used in DBG mode to track inet condition reports + private static final int INET_CONDITION_LOG_MAX_SIZE = 15; + private ArrayList mInetLog; + private static class NetworkAttributes { /** * Class for holding settings read from resources. @@ -339,6 +344,9 @@ public class ConnectivityService extends IConnectivityManager.Stub { mTethering.getTetherableBluetoothRegexs().length != 0) && mTethering.getUpstreamIfaceRegexs().length != 0); + if (DBG) { + mInetLog = new ArrayList(); + } } @@ -1005,11 +1013,19 @@ public class ConnectivityService extends IConnectivityManager.Stub { newNet = tryFailover(prevNetType); if (newNet != null) { NetworkInfo switchTo = newNet.getNetworkInfo(); + if (!switchTo.isConnected()) { + // if the other net is connected they've already reset this and perhaps even gotten + // a positive report we don't want to overwrite, but if not we need to clear this now + // to turn our cellular sig strength white + mDefaultInetConditionPublished = 0; + } intent.putExtra(ConnectivityManager.EXTRA_OTHER_NETWORK_INFO, switchTo); } else { + mDefaultInetConditionPublished = 0; // we're not connected anymore intent.putExtra(ConnectivityManager.EXTRA_NO_CONNECTIVITY, true); } } + intent.putExtra(ConnectivityManager.EXTRA_INET_CONDITION, mDefaultInetConditionPublished); // do this before we broadcast the change handleConnectivityChange(prevNetType); @@ -1168,12 +1184,20 @@ public class ConnectivityService extends IConnectivityManager.Stub { newNet = tryFailover(info.getType()); if (newNet != null) { NetworkInfo switchTo = newNet.getNetworkInfo(); + if (!switchTo.isConnected()) { + // if the other net is connected they've already reset this and perhaps even gotten + // a positive report we don't want to overwrite, but if not we need to clear this now + // to turn our cellular sig strength white + mDefaultInetConditionPublished = 0; + } intent.putExtra(ConnectivityManager.EXTRA_OTHER_NETWORK_INFO, switchTo); } else { + mDefaultInetConditionPublished = 0; intent.putExtra(ConnectivityManager.EXTRA_NO_CONNECTIVITY, true); } } + intent.putExtra(ConnectivityManager.EXTRA_INET_CONDITION, mDefaultInetConditionPublished); sendStickyBroadcast(intent); /* * If the failover network is already connected, then immediately send @@ -1598,6 +1622,14 @@ public class ConnectivityService extends IConnectivityManager.Stub { pw.println(); mTethering.dump(fd, pw, args); + + if (mInetLog != null) { + pw.println(); + pw.println("Inet condition reports:"); + for(int i = 0; i < mInetLog.size(); i++) { + pw.println(mInetLog.get(i)); + } + } } // must be stateless - things change under us. @@ -1874,6 +1906,17 @@ public class ConnectivityService extends IConnectivityManager.Stub { android.Manifest.permission.STATUS_BAR, "ConnectivityService"); + if (DBG) { + int pid = getCallingPid(); + int uid = getCallingUid(); + String s = pid + "(" + uid + ") reports inet is " + + (percentage > 50 ? "connected" : "disconnected") + " (" + percentage + ") on " + + "network Type " + networkType + " at " + GregorianCalendar.getInstance().getTime(); + mInetLog.add(s); + while(mInetLog.size() > INET_CONDITION_LOG_MAX_SIZE) { + mInetLog.remove(0); + } + } mHandler.sendMessage(mHandler.obtainMessage( NetworkStateTracker.EVENT_INET_CONDITION_CHANGE, networkType, percentage)); } diff --git a/services/java/com/android/server/InputManager.java b/services/java/com/android/server/InputManager.java index 024aec5..29ca9a4 100644 --- a/services/java/com/android/server/InputManager.java +++ b/services/java/com/android/server/InputManager.java @@ -53,10 +53,6 @@ public class InputManager { private final Context mContext; private final WindowManagerService mWindowManagerService; - private int mTouchScreenConfig; - private int mKeyboardConfig; - private int mNavigationConfig; - private static native void nativeInit(Callbacks callbacks); private static native void nativeStart(); private static native void nativeSetDisplaySize(int displayId, int width, int height); @@ -79,6 +75,7 @@ public class InputManager { private static native void nativeSetInputDispatchMode(boolean enabled, boolean frozen); private static native void nativeSetFocusedApplication(InputApplication application); private static native InputDevice nativeGetInputDevice(int deviceId); + private static native void nativeGetInputConfiguration(Configuration configuration); private static native int[] nativeGetInputDeviceIds(); private static native String nativeDump(); @@ -114,10 +111,6 @@ public class InputManager { this.mCallbacks = new Callbacks(); - mTouchScreenConfig = Configuration.TOUCHSCREEN_NOTOUCH; - mKeyboardConfig = Configuration.KEYBOARD_NOKEYS; - mNavigationConfig = Configuration.NAVIGATION_NONAV; - init(); } @@ -154,9 +147,7 @@ public class InputManager { throw new IllegalArgumentException("config must not be null."); } - config.touchscreen = mTouchScreenConfig; - config.keyboard = mKeyboardConfig; - config.navigation = mNavigationConfig; + nativeGetInputConfiguration(config); } /** @@ -367,12 +358,7 @@ public class InputManager { } @SuppressWarnings("unused") - public void notifyConfigurationChanged(long whenNanos, - int touchScreenConfig, int keyboardConfig, int navigationConfig) { - mTouchScreenConfig = touchScreenConfig; - mKeyboardConfig = keyboardConfig; - mNavigationConfig = navigationConfig; - + public void notifyConfigurationChanged(long whenNanos) { mWindowManagerService.sendNewConfiguration(); } diff --git a/services/java/com/android/server/LocationManagerService.java b/services/java/com/android/server/LocationManagerService.java index 8452a9f..aa1bcf7 100644 --- a/services/java/com/android/server/LocationManagerService.java +++ b/services/java/com/android/server/LocationManagerService.java @@ -1960,7 +1960,7 @@ public class LocationManagerService extends ILocationManager.Stub implements Run // Geocoder - public boolean geocoderIsImplemented() { + public boolean geocoderIsPresent() { return mGeocodeProvider != null; } diff --git a/services/java/com/android/server/PackageManagerService.java b/services/java/com/android/server/PackageManagerService.java index 1069216..c82a085 100644 --- a/services/java/com/android/server/PackageManagerService.java +++ b/services/java/com/android/server/PackageManagerService.java @@ -222,6 +222,9 @@ class PackageManagerService extends IPackageManager.Stub { // This is the object monitoring the system app dir. final FileObserver mSystemInstallObserver; + // This is the object monitoring the system app dir. + final FileObserver mVendorInstallObserver; + // This is the object monitoring mAppInstallDir. final FileObserver mAppInstallObserver; @@ -234,6 +237,7 @@ class PackageManagerService extends IPackageManager.Stub { final File mFrameworkDir; final File mSystemAppDir; + final File mVendorAppDir; final File mAppInstallDir; final File mDalvikCacheDir; @@ -927,6 +931,14 @@ class PackageManagerService extends IPackageManager.Stub { scanDirLI(mSystemAppDir, PackageParser.PARSE_IS_SYSTEM | PackageParser.PARSE_IS_SYSTEM_DIR, scanMode); + // Collect all vendor packages. + mVendorAppDir = new File("/vendor/app"); + mVendorInstallObserver = new AppDirObserver( + mVendorAppDir.getPath(), OBSERVER_EVENTS, true); + mVendorInstallObserver.startWatching(); + scanDirLI(mVendorAppDir, PackageParser.PARSE_IS_SYSTEM + | PackageParser.PARSE_IS_SYSTEM_DIR, scanMode); + if (mInstaller != null) { if (DEBUG_UPGRADE) Log.v(TAG, "Running installd update commands"); mInstaller.moveFiles(); @@ -2493,9 +2505,13 @@ class PackageManagerService extends IPackageManager.Stub { } private void scanDirLI(File dir, int flags, int scanMode) { - Log.d(TAG, "Scanning app dir " + dir); - String[] files = dir.list(); + if (files == null) { + Log.d(TAG, "No files in app dir " + dir); + return; + } + + Log.d(TAG, "Scanning app dir " + dir); int i; for (i=0; i<files.length; i++) { diff --git a/services/java/com/android/server/WindowManagerService.java b/services/java/com/android/server/WindowManagerService.java index fb8e888..3e4f522 100644 --- a/services/java/com/android/server/WindowManagerService.java +++ b/services/java/com/android/server/WindowManagerService.java @@ -8325,6 +8325,11 @@ public class WindowManagerService extends IWindowManager.Stub return; } + if (mDisplay == null) { + // Not yet initialized, nothing to do. + return; + } + boolean recoveringMemory = false; if (mForceRemoves != null) { recoveringMemory = true; diff --git a/services/java/com/android/server/am/ActivityManagerService.java b/services/java/com/android/server/am/ActivityManagerService.java index 5432890..c896c94 100644 --- a/services/java/com/android/server/am/ActivityManagerService.java +++ b/services/java/com/android/server/am/ActivityManagerService.java @@ -562,6 +562,11 @@ public final class ActivityManagerService extends ActivityManagerNative BroadcastRecord mPendingBroadcast = null; /** + * The receiver index that is pending, to restart the broadcast if needed. + */ + int mPendingBroadcastRecvIndex; + + /** * Keeps track of all IIntentReceivers that have been registered for * broadcasts. Hash keys are the receiver IBinder, hash value is * a ReceiverList. @@ -748,6 +753,7 @@ public final class ActivityManagerService extends ActivityManagerNative ComponentName mTopComponent; String mTopAction; String mTopData; + boolean mProcessesReady = false; boolean mSystemReady = false; boolean mBooting = false; boolean mWaitingUpdate = false; @@ -965,7 +971,11 @@ public final class ActivityManagerService extends ActivityManagerNative return; } - broadcastIntentLocked(null, null, new Intent("android.intent.action.ANR"), + Intent intent = new Intent("android.intent.action.ANR"); + if (!mProcessesReady) { + intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY); + } + broadcastIntentLocked(null, null, intent, null, null, 0, null, null, null, false, false, MY_PID, Process.SYSTEM_UID); @@ -1052,7 +1062,7 @@ public final class ActivityManagerService extends ActivityManagerNative // Only process broadcast timeouts if the system is ready. That way // PRE_BOOT_COMPLETED broadcasts can't timeout as they are intended // to do heavy lifting for system up - if (mSystemReady) { + if (mProcessesReady) { broadcastTimeout(); } } break; @@ -1384,7 +1394,7 @@ public final class ActivityManagerService extends ActivityManagerNative mBatteryStatsService = new BatteryStatsService(new File( systemDir, "batterystats.bin").toString()); mBatteryStatsService.getActiveStatistics().readLocked(); - mBatteryStatsService.getActiveStatistics().writeLocked(); + mBatteryStatsService.getActiveStatistics().writeAsyncLocked(); mOnBattery = mBatteryStatsService.getActiveStatistics().getIsOnBattery(); mBatteryStatsService.getActiveStatistics().setCallback(this); @@ -1537,7 +1547,7 @@ public final class ActivityManagerService extends ActivityManagerNative if (mLastWriteTime < (now-BATTERY_STATS_TIME)) { mLastWriteTime = now; - mBatteryStatsService.getActiveStatistics().writeLocked(); + mBatteryStatsService.getActiveStatistics().writeAsyncLocked(); } } } @@ -1718,10 +1728,12 @@ public final class ActivityManagerService extends ActivityManagerNative if (!knownToBeDead || app.thread == null) { // We already have the app running, or are waiting for it to // come up (we have a pid but not yet its thread), so keep it. + if (DEBUG_PROCESSES) Slog.v(TAG, "App already running: " + app); return app; } else { // An application record is attached to a previous process, // clean it up now. + if (DEBUG_PROCESSES) Slog.v(TAG, "App died: " + app); handleAppDiedLocked(app, true); } } @@ -1733,6 +1745,8 @@ public final class ActivityManagerService extends ActivityManagerNative // If we are in the background, then check to see if this process // is bad. If so, we will just silently fail. if (mBadProcesses.get(info.processName, info.uid) != null) { + if (DEBUG_PROCESSES) Slog.v(TAG, "Bad process: " + info.uid + + "/" + info.processName); return null; } } else { @@ -1740,6 +1754,8 @@ public final class ActivityManagerService extends ActivityManagerNative // crash count so that we won't make it bad until they see at // least one crash dialog again, and make the process good again // if it had been bad. + if (DEBUG_PROCESSES) Slog.v(TAG, "Clearing bad process: " + info.uid + + "/" + info.processName); mProcessCrashTimes.remove(info.processName, info.uid); if (mBadProcesses.get(info.processName, info.uid) != null) { EventLog.writeEvent(EventLogTags.AM_PROC_GOOD, info.uid, @@ -1761,12 +1777,13 @@ public final class ActivityManagerService extends ActivityManagerNative // If the system is not ready yet, then hold off on starting this // process until it is. - if (!mSystemReady + if (!mProcessesReady && !isAllowedWhileBooting(info) && !allowWhileBooting) { if (!mProcessesOnHold.contains(app)) { mProcessesOnHold.add(app); } + if (DEBUG_PROCESSES) Slog.v(TAG, "System not ready, putting on hold: " + app); return app; } @@ -1788,6 +1805,8 @@ public final class ActivityManagerService extends ActivityManagerNative app.pid = 0; } + if (DEBUG_PROCESSES && mProcessesOnHold.contains(app)) Slog.v(TAG, + "startProcessLocked removing on hold: " + app); mProcessesOnHold.remove(app); updateCpuStats(); @@ -3045,11 +3064,8 @@ public final class ActivityManagerService extends ActivityManagerNative Intent intent = new Intent(Intent.ACTION_PACKAGE_DATA_CLEARED, Uri.fromParts("package", packageName, null)); intent.putExtra(Intent.EXTRA_UID, pkgUid); - synchronized (this) { - broadcastIntentLocked(null, null, intent, - null, null, 0, null, null, null, - false, false, MY_PID, Process.SYSTEM_UID); - } + broadcastIntentInPackage("android", Process.SYSTEM_UID, intent, + null, null, 0, null, null, null, false, false); } catch (RemoteException e) { } } finally { @@ -3153,6 +3169,7 @@ public final class ActivityManagerService extends ActivityManagerNative public void closeSystemDialogs(String reason) { Intent intent = new Intent(Intent.ACTION_CLOSE_SYSTEM_DIALOGS); + intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY); if (reason != null) { intent.putExtra("reason", reason); } @@ -3230,6 +3247,9 @@ public final class ActivityManagerService extends ActivityManagerNative forceStopPackageLocked(packageName, uid, false, false, true); Intent intent = new Intent(Intent.ACTION_PACKAGE_RESTARTED, Uri.fromParts("package", packageName, null)); + if (!mProcessesReady) { + intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY); + } intent.putExtra(Intent.EXTRA_UID, uid); broadcastIntentLocked(null, null, intent, null, null, 0, null, null, null, @@ -3432,6 +3452,8 @@ public final class ActivityManagerService extends ActivityManagerNative } if (mPendingBroadcast != null && mPendingBroadcast.curApp.pid == pid) { Slog.w(TAG, "Unattached app died before broadcast acknowledged, skipping"); + mPendingBroadcast.state = BroadcastRecord.IDLE; + mPendingBroadcast.nextReceiver = mPendingBroadcastRecvIndex; mPendingBroadcast = null; scheduleBroadcastsLocked(); } @@ -3507,7 +3529,7 @@ public final class ActivityManagerService extends ActivityManagerNative mHandler.removeMessages(PROC_START_TIMEOUT_MSG, app); - boolean normalMode = mSystemReady || isAllowedWhileBooting(app.info); + boolean normalMode = mProcessesReady || isAllowedWhileBooting(app.info); List providers = normalMode ? generateApplicationProvidersLocked(app) : null; if (!normalMode) { @@ -3566,6 +3588,8 @@ public final class ActivityManagerService extends ActivityManagerNative // Remove this record from the list of starting applications. mPersistentStartingProcesses.remove(app); + if (DEBUG_PROCESSES && mProcessesOnHold.contains(app)) Slog.v(TAG, + "Attach application locked removing on hold: " + app); mProcessesOnHold.remove(app); boolean badApp = false; @@ -3709,7 +3733,9 @@ public final class ActivityManagerService extends ActivityManagerNative ArrayList<ProcessRecord> procs = new ArrayList<ProcessRecord>(mProcessesOnHold); for (int ip=0; ip<NP; ip++) { - this.startProcessLocked(procs.get(ip), "on-hold", null); + if (DEBUG_PROCESSES) Slog.v(TAG, "Starting process on hold: " + + procs.get(ip)); + startProcessLocked(procs.get(ip), "on-hold", null); } } @@ -5260,7 +5286,7 @@ public final class ActivityManagerService extends ActivityManagerNative throw new SecurityException(msg); } - if (!mSystemReady && !mDidUpdate && !mWaitingUpdate + if (!mProcessesReady && !mDidUpdate && !mWaitingUpdate && !cpi.processName.equals("system")) { // If this content provider does not run in the system // process, and the system is not yet ready to run other @@ -6076,6 +6102,11 @@ public final class ActivityManagerService extends ActivityManagerNative Slog.i(TAG, "Removing system update proc: " + proc); removeProcessLocked(proc, true); } + + // Now that we have cleaned up any update processes, we + // are ready to start launching real processes and know that + // we won't trample on them any more. + mProcessesReady = true; } } @@ -7074,6 +7105,12 @@ public final class ActivityManagerService extends ActivityManagerNative dumpServicesLocked(fd, pw, args, opti, true); } return; + } else { + // Dumping a single activity? + if (dumpActivity(fd, pw, cmd, args, opti, dumpAll)) { + return; + } + pw.println("Bad activity command: " + cmd); } } @@ -7340,8 +7377,9 @@ public final class ActivityManagerService extends ActivityManagerNative if (dumpAll) { pw.println(" Total persistent processes: " + numPers); pw.println(" mStartRunning=" + mStartRunning - + " mSystemReady=" + mSystemReady - + " mBooting=" + mBooting + + " mProcessesReady=" + mProcessesReady + + " mSystemReady=" + mSystemReady); + pw.println(" mBooting=" + mBooting + " mBooted=" + mBooted + " mFactoryTest=" + mFactoryTest); pw.println(" mGoingToSleep=" + mMainStack.mGoingToSleep); @@ -7426,6 +7464,82 @@ public final class ActivityManagerService extends ActivityManagerNative } } + /** + * There are three things that cmd can be: + * - a flattened component name that matched an existing activity + * - the cmd arg isn't the flattened component name of an existing activity: + * dump all activity whose component contains the cmd as a substring + * - A hex number of the ActivityRecord object instance. + */ + protected boolean dumpActivity(FileDescriptor fd, PrintWriter pw, String name, String[] args, + int opti, boolean dumpAll) { + String[] newArgs; + ComponentName componentName = ComponentName.unflattenFromString(name); + int objectId = 0; + try { + objectId = Integer.parseInt(name, 16); + name = null; + componentName = null; + } catch (RuntimeException e) { + } + newArgs = new String[args.length - opti]; + if (args.length > 2) System.arraycopy(args, opti, newArgs, 0, args.length - opti); + + ArrayList<ActivityRecord> activities = new ArrayList<ActivityRecord>(); + synchronized (this) { + for (ActivityRecord r1 : (ArrayList<ActivityRecord>)mMainStack.mHistory) { + if (componentName != null) { + if (r1.intent.getComponent().equals(componentName)) { + activities.add(r1); + } + } else if (name != null) { + if (r1.intent.getComponent().flattenToString().contains(name)) { + activities.add(r1); + } + } else if (System.identityHashCode(this) == objectId) { + activities.add(r1); + } + } + } + + if (activities.size() <= 0) { + return false; + } + + for (int i=0; i<activities.size(); i++) { + dumpActivity(fd, pw, activities.get(i), newArgs, dumpAll); + } + return true; + } + + /** + * Invokes IApplicationThread.dumpActivity() on the thread of the specified activity if + * there is a thread associated with the activity. + */ + private void dumpActivity(FileDescriptor fd, PrintWriter pw, ActivityRecord r, String[] args, + boolean dumpAll) { + pw.println(" Activity " + r.intent.getComponent().flattenToString()); + if (dumpAll) { + synchronized (this) { + pw.print(" * "); pw.println(r); + r.dump(pw, " "); + } + pw.println(""); + } + if (r.app != null && r.app.thread != null) { + try { + // flush anything that is already in the PrintWriter since the thread is going + // to write to the file descriptor directly + pw.flush(); + r.app.thread.dumpActivity(fd, r, args); + pw.print("\n"); + pw.flush(); + } catch (RemoteException e) { + pw.println("got a RemoteException while dumping the activity"); + } + } + } + boolean dumpBroadcastsLocked(FileDescriptor fd, PrintWriter pw, String[] args, int opti, boolean dumpAll) { boolean needSep = false; @@ -8155,6 +8269,8 @@ public final class ActivityManagerService extends ActivityManagerNative restart = true; } } + if (DEBUG_PROCESSES && mProcessesOnHold.contains(app)) Slog.v(TAG, + "Clean-up removing on hold: " + app); mProcessesOnHold.remove(app); if (app == mHomeProcess) { @@ -10175,7 +10291,7 @@ public final class ActivityManagerService extends ActivityManagerNative } boolean replaced = false; if (replacePending) { - for (int i=mOrderedBroadcasts.size()-1; i>=0; i--) { + for (int i=mOrderedBroadcasts.size()-1; i>0; i--) { if (intent.filterEquals(mOrderedBroadcasts.get(i).intent)) { if (DEBUG_BROADCAST) Slog.v(TAG, "***** DROPPING ORDERED: " + intent); @@ -10194,35 +10310,41 @@ public final class ActivityManagerService extends ActivityManagerNative return BROADCAST_SUCCESS; } - public final int broadcastIntent(IApplicationThread caller, - Intent intent, String resolvedType, IIntentReceiver resultTo, - int resultCode, String resultData, Bundle map, - String requiredPermission, boolean serialized, boolean sticky) { + final Intent verifyBroadcastLocked(Intent intent) { // Refuse possible leaked file descriptors if (intent != null && intent.hasFileDescriptors() == true) { throw new IllegalArgumentException("File descriptors passed in Intent"); } - synchronized(this) { - int flags = intent.getFlags(); - - if (!mSystemReady) { - // if the caller really truly claims to know what they're doing, go - // ahead and allow the broadcast without launching any receivers - if ((flags&Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT) != 0) { - intent = new Intent(intent); - intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY); - } else if ((flags&Intent.FLAG_RECEIVER_REGISTERED_ONLY) == 0){ - Slog.e(TAG, "Attempt to launch receivers of broadcast intent " + intent - + " before boot completion"); - throw new IllegalStateException("Cannot broadcast before boot completed"); - } - } - - if ((flags&Intent.FLAG_RECEIVER_BOOT_UPGRADE) != 0) { - throw new IllegalArgumentException( - "Can't use FLAG_RECEIVER_BOOT_UPGRADE here"); + int flags = intent.getFlags(); + + if (!mProcessesReady) { + // if the caller really truly claims to know what they're doing, go + // ahead and allow the broadcast without launching any receivers + if ((flags&Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT) != 0) { + intent = new Intent(intent); + intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY); + } else if ((flags&Intent.FLAG_RECEIVER_REGISTERED_ONLY) == 0) { + Slog.e(TAG, "Attempt to launch receivers of broadcast intent " + intent + + " before boot completion"); + throw new IllegalStateException("Cannot broadcast before boot completed"); } + } + + if ((flags&Intent.FLAG_RECEIVER_BOOT_UPGRADE) != 0) { + throw new IllegalArgumentException( + "Can't use FLAG_RECEIVER_BOOT_UPGRADE here"); + } + + return intent; + } + + public final int broadcastIntent(IApplicationThread caller, + Intent intent, String resolvedType, IIntentReceiver resultTo, + int resultCode, String resultData, Bundle map, + String requiredPermission, boolean serialized, boolean sticky) { + synchronized(this) { + intent = verifyBroadcastLocked(intent); final ProcessRecord callerApp = getRecordForAppLocked(caller); final int callingPid = Binder.getCallingPid(); @@ -10243,6 +10365,8 @@ public final class ActivityManagerService extends ActivityManagerNative int resultCode, String resultData, Bundle map, String requiredPermission, boolean serialized, boolean sticky) { synchronized(this) { + intent = verifyBroadcastLocked(intent); + final long origId = Binder.clearCallingIdentity(); int res = broadcastIntentLocked(null, packageName, intent, resolvedType, resultTo, resultCode, resultData, map, requiredPermission, @@ -10456,6 +10580,8 @@ public final class ActivityManagerService extends ActivityManagerNative private final void processCurBroadcastLocked(BroadcastRecord r, ProcessRecord app) throws RemoteException { + if (DEBUG_BROADCAST) Slog.v(TAG, + "Process cur broadcast " + r + " for app " + app); if (app.thread == null) { throw new RemoteException(); } @@ -10475,9 +10601,13 @@ public final class ActivityManagerService extends ActivityManagerNative ensurePackageDexOpt(r.intent.getComponent().getPackageName()); app.thread.scheduleReceiver(new Intent(r.intent), r.curReceiver, r.resultCode, r.resultData, r.resultExtras, r.ordered); + if (DEBUG_BROADCAST) Slog.v(TAG, + "Process cur broadcast " + r + " DELIVERED for app " + app); started = true; } finally { if (!started) { + if (DEBUG_BROADCAST) Slog.v(TAG, + "Process cur broadcast " + r + ": NOT STARTED!"); r.receiver = null; r.curApp = null; app.curReceiver = null; @@ -10642,6 +10772,8 @@ public final class ActivityManagerService extends ActivityManagerNative } else { Slog.w(TAG, "pending app " + mPendingBroadcast.curApp + " died before responding to broadcast"); + mPendingBroadcast.state = BroadcastRecord.IDLE; + mPendingBroadcast.nextReceiver = mPendingBroadcastRecvIndex; mPendingBroadcast = null; } } @@ -10672,7 +10804,7 @@ public final class ActivityManagerService extends ActivityManagerNative // one time heavy lifting after system upgrades and can take // significant amounts of time. int numReceivers = (r.receivers != null) ? r.receivers.size() : 0; - if (mSystemReady && r.dispatchTime > 0) { + if (mProcessesReady && r.dispatchTime > 0) { long now = SystemClock.uptimeMillis(); if ((numReceivers > 0) && (now > r.dispatchTime + (2*BROADCAST_TIMEOUT*numReceivers))) { @@ -10743,7 +10875,7 @@ public final class ActivityManagerService extends ActivityManagerNative if (DEBUG_BROADCAST_LIGHT) Slog.v(TAG, "Processing ordered broadcast " + r); if (DEBUG_BROADCAST) Slog.v(TAG, - "Submitting BROADCAST_TIMEOUT_MSG for " + "Submitting BROADCAST_TIMEOUT_MSG for " + r + " at " + (r.receiverTime + BROADCAST_TIMEOUT)); Message msg = mHandler.obtainMessage(BROADCAST_TIMEOUT_MSG); mHandler.sendMessageAtTime(msg, r.receiverTime+BROADCAST_TIMEOUT); @@ -10811,10 +10943,15 @@ public final class ActivityManagerService extends ActivityManagerNative } if (r.curApp != null && r.curApp.crashing) { // If the target process is crashing, just skip it. + if (DEBUG_BROADCAST) Slog.v(TAG, + "Skipping deliver ordered " + r + " to " + r.curApp + + ": process crashing"); skip = true; } if (skip) { + if (DEBUG_BROADCAST) Slog.v(TAG, + "Skipping delivery of ordered " + r + " for whatever reason"); r.receiver = null; r.curFilter = null; r.state = BroadcastRecord.IDLE; @@ -10846,6 +10983,8 @@ public final class ActivityManagerService extends ActivityManagerNative } // Not running -- get it started, to be executed when the app comes up. + if (DEBUG_BROADCAST) Slog.v(TAG, + "Need to start app " + targetProcess + " for broadcast " + r); if ((r.curApp=startProcessLocked(targetProcess, info.activityInfo.applicationInfo, true, r.intent.getFlags() | Intent.FLAG_FROM_BACKGROUND, @@ -10867,6 +11006,7 @@ public final class ActivityManagerService extends ActivityManagerNative } mPendingBroadcast = r; + mPendingBroadcastRecvIndex = recIdx; } } diff --git a/services/java/com/android/server/am/ActivityStack.java b/services/java/com/android/server/am/ActivityStack.java index 4fc8020..a4497d6 100644 --- a/services/java/com/android/server/am/ActivityStack.java +++ b/services/java/com/android/server/am/ActivityStack.java @@ -1104,26 +1104,30 @@ public class ActivityStack { // Okay we are now going to start a switch, to 'next'. We may first // have to pause the current activity, but this is an important point // where we have decided to go to 'next' so keep track of that. - if (mLastStartedActivity != null && !mLastStartedActivity.finishing) { - long now = SystemClock.uptimeMillis(); - final boolean inTime = mLastStartedActivity.startTime != 0 - && (mLastStartedActivity.startTime + START_WARN_TIME) >= now; - final int lastUid = mLastStartedActivity.info.applicationInfo.uid; - final int nextUid = next.info.applicationInfo.uid; - if (inTime && lastUid != nextUid - && lastUid != next.launchedFromUid - && mService.checkPermission( - android.Manifest.permission.STOP_APP_SWITCHES, - -1, next.launchedFromUid) - != PackageManager.PERMISSION_GRANTED) { - mService.showLaunchWarningLocked(mLastStartedActivity, next); + // XXX "App Redirected" dialog is getting too many false positives + // at this point, so turn off for now. + if (false) { + if (mLastStartedActivity != null && !mLastStartedActivity.finishing) { + long now = SystemClock.uptimeMillis(); + final boolean inTime = mLastStartedActivity.startTime != 0 + && (mLastStartedActivity.startTime + START_WARN_TIME) >= now; + final int lastUid = mLastStartedActivity.info.applicationInfo.uid; + final int nextUid = next.info.applicationInfo.uid; + if (inTime && lastUid != nextUid + && lastUid != next.launchedFromUid + && mService.checkPermission( + android.Manifest.permission.STOP_APP_SWITCHES, + -1, next.launchedFromUid) + != PackageManager.PERMISSION_GRANTED) { + mService.showLaunchWarningLocked(mLastStartedActivity, next); + } else { + next.startTime = now; + mLastStartedActivity = next; + } } else { - next.startTime = now; + next.startTime = SystemClock.uptimeMillis(); mLastStartedActivity = next; } - } else { - next.startTime = SystemClock.uptimeMillis(); - mLastStartedActivity = next; } // We need to start pausing the current activity so the top one diff --git a/services/java/com/android/server/location/ComprehensiveCountryDetector.java b/services/java/com/android/server/location/ComprehensiveCountryDetector.java index e692f8d..e9ce3ce 100755 --- a/services/java/com/android/server/location/ComprehensiveCountryDetector.java +++ b/services/java/com/android/server/location/ComprehensiveCountryDetector.java @@ -16,10 +16,6 @@ package com.android.server.location; -import java.util.Locale; -import java.util.Timer; -import java.util.TimerTask; - import android.content.Context; import android.location.Country; import android.location.CountryListener; @@ -31,6 +27,10 @@ import android.telephony.TelephonyManager; import android.text.TextUtils; import android.util.Slog; +import java.util.Locale; +import java.util.Timer; +import java.util.TimerTask; + /** * This class is used to detect the country where the user is. The sources of * country are queried in order of reliability, like @@ -354,6 +354,6 @@ public class ComprehensiveCountryDetector extends CountryDetectorBase { } protected boolean isGeoCoderImplemented() { - return Geocoder.isImplemented(); + return Geocoder.isPresent(); } } diff --git a/services/java/com/android/server/location/GpsLocationProvider.java b/services/java/com/android/server/location/GpsLocationProvider.java index 3bf6ee4..39ce0b6 100755 --- a/services/java/com/android/server/location/GpsLocationProvider.java +++ b/services/java/com/android/server/location/GpsLocationProvider.java @@ -1171,7 +1171,10 @@ public class GpsLocationProvider implements LocationProviderInterface { private void reportAGpsStatus(int type, int status) { switch (status) { case GPS_REQUEST_AGPS_DATA_CONN: - int result = mConnMgr.startUsingNetworkFeature( + // Set mAGpsDataConnectionState before calling startUsingNetworkFeature + // to avoid a race condition with handleUpdateNetworkState() + mAGpsDataConnectionState = AGPS_DATA_CONNECTION_OPENING; + int result = mConnMgr.startUsingNetworkFeature( ConnectivityManager.TYPE_MOBILE, Phone.FEATURE_ENABLE_SUPL); if (result == Phone.APN_ALREADY_ACTIVE) { if (mAGpsApn != null) { @@ -1179,11 +1182,13 @@ public class GpsLocationProvider implements LocationProviderInterface { mAGpsDataConnectionState = AGPS_DATA_CONNECTION_OPEN; } else { Log.e(TAG, "mAGpsApn not set when receiving Phone.APN_ALREADY_ACTIVE"); + mAGpsDataConnectionState = AGPS_DATA_CONNECTION_CLOSED; native_agps_data_conn_failed(); } } else if (result == Phone.APN_REQUEST_STARTED) { - mAGpsDataConnectionState = AGPS_DATA_CONNECTION_OPENING; + // Nothing to do here } else { + mAGpsDataConnectionState = AGPS_DATA_CONNECTION_CLOSED; native_agps_data_conn_failed(); } break; diff --git a/services/java/com/android/server/sip/SipService.java b/services/java/com/android/server/sip/SipService.java index a2ebc69..f1dcd5a 100644 --- a/services/java/com/android/server/sip/SipService.java +++ b/services/java/com/android/server/sip/SipService.java @@ -172,7 +172,7 @@ public final class SipService extends ISipService.Stub { SipSessionGroupExt group = mSipGroups.remove(localProfileUri); if (group != null) { notifyProfileRemoved(group.getLocalProfile()); - group.closeToNotReceiveCalls(); + group.close(); if (isWifiOn() && !anyOpened()) releaseWifiLock(); } } @@ -449,9 +449,9 @@ public final class SipService extends ISipService.Stub { } } - public void closeToNotReceiveCalls() { + public void close() { mOpened = false; - mSipGroup.closeToNotReceiveCalls(); + mSipGroup.close(); mAutoRegistration.stop(); if (DEBUG) Log.d(TAG, " close: " + getUri() + ": " + mIncomingCallBroadcastAction); diff --git a/services/jni/com_android_server_InputManager.cpp b/services/jni/com_android_server_InputManager.cpp index d27c2c6..e3bae56 100644 --- a/services/jni/com_android_server_InputManager.cpp +++ b/services/jni/com_android_server_InputManager.cpp @@ -138,6 +138,14 @@ static struct { jfieldID mMotionRanges; } gInputDeviceClassInfo; +static struct { + jclass clazz; + + jfieldID touchscreen; + jfieldID keyboard; + jfieldID navigation; +} gConfigurationClassInfo; + // ---------------------------------------------------------------------------- static inline nsecs_t now() { @@ -698,11 +706,7 @@ void NativeInputManager::notifyConfigurationChanged(nsecs_t when) { JNIEnv* env = jniEnv(); - InputConfiguration config; - mInputManager->getReader()->getInputConfiguration(& config); - - env->CallVoidMethod(mCallbacksObj, gCallbacksClassInfo.notifyConfigurationChanged, - when, config.touchScreen, config.keyboard, config.navigation); + env->CallVoidMethod(mCallbacksObj, gCallbacksClassInfo.notifyConfigurationChanged, when); checkAndClearExceptionFromCallback(env, "notifyConfigurationChanged"); } @@ -1270,6 +1274,20 @@ static jintArray android_server_InputManager_nativeGetInputDeviceIds(JNIEnv* env return deviceIdsObj; } +static void android_server_InputManager_nativeGetInputConfiguration(JNIEnv* env, + jclass clazz, jobject configObj) { + if (checkInputManagerUnitialized(env)) { + return; + } + + InputConfiguration config; + gNativeInputManager->getInputManager()->getReader()->getInputConfiguration(& config); + + env->SetIntField(configObj, gConfigurationClassInfo.touchscreen, config.touchScreen); + env->SetIntField(configObj, gConfigurationClassInfo.keyboard, config.keyboard); + env->SetIntField(configObj, gConfigurationClassInfo.navigation, config.navigation); +} + static jstring android_server_InputManager_nativeDump(JNIEnv* env, jclass clazz) { if (checkInputManagerUnitialized(env)) { return NULL; @@ -1316,6 +1334,8 @@ static JNINativeMethod gInputManagerMethods[] = { (void*) android_server_InputManager_nativeGetInputDevice }, { "nativeGetInputDeviceIds", "()[I", (void*) android_server_InputManager_nativeGetInputDeviceIds }, + { "nativeGetInputConfiguration", "(Landroid/content/res/Configuration;)V", + (void*) android_server_InputManager_nativeGetInputConfiguration }, { "nativeDump", "()Ljava/lang/String;", (void*) android_server_InputManager_nativeDump }, }; @@ -1343,7 +1363,7 @@ int register_android_server_InputManager(JNIEnv* env) { FIND_CLASS(gCallbacksClassInfo.clazz, "com/android/server/InputManager$Callbacks"); GET_METHOD_ID(gCallbacksClassInfo.notifyConfigurationChanged, gCallbacksClassInfo.clazz, - "notifyConfigurationChanged", "(JIII)V"); + "notifyConfigurationChanged", "(J)V"); GET_METHOD_ID(gCallbacksClassInfo.notifyLidSwitchChanged, gCallbacksClassInfo.clazz, "notifyLidSwitchChanged", "(JZ)V"); @@ -1543,6 +1563,19 @@ int register_android_server_InputManager(JNIEnv* env) { GET_FIELD_ID(gInputDeviceClassInfo.mMotionRanges, gInputDeviceClassInfo.clazz, "mMotionRanges", "[Landroid/view/InputDevice$MotionRange;"); + // Configuration + + FIND_CLASS(gConfigurationClassInfo.clazz, "android/content/res/Configuration"); + + GET_FIELD_ID(gConfigurationClassInfo.touchscreen, gConfigurationClassInfo.clazz, + "touchscreen", "I"); + + GET_FIELD_ID(gConfigurationClassInfo.keyboard, gConfigurationClassInfo.clazz, + "keyboard", "I"); + + GET_FIELD_ID(gConfigurationClassInfo.navigation, gConfigurationClassInfo.clazz, + "navigation", "I"); + return 0; } diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp index 833181b..1b21a8d 100644 --- a/services/surfaceflinger/Layer.cpp +++ b/services/surfaceflinger/Layer.cpp @@ -367,6 +367,7 @@ sp<GraphicBuffer> Layer::requestBuffer(int index, Mutex::Autolock _l(mLock); // zero means default + const bool fixedSize = reqWidth && reqHeight; if (!reqFormat) reqFormat = mFormat; if (!reqWidth) reqWidth = mWidth; if (!reqHeight) reqHeight = mHeight; @@ -380,7 +381,7 @@ sp<GraphicBuffer> Layer::requestBuffer(int index, mReqWidth = reqWidth; mReqHeight = reqHeight; mReqFormat = reqFormat; - mFixedSize = reqWidth && reqHeight; + mFixedSize = fixedSize; lcblk->reallocateAllExcept(index); } diff --git a/telephony/java/com/android/internal/telephony/CallManager.java b/telephony/java/com/android/internal/telephony/CallManager.java index 4d8cbf0..23cb42a 100644 --- a/telephony/java/com/android/internal/telephony/CallManager.java +++ b/telephony/java/com/android/internal/telephony/CallManager.java @@ -82,7 +82,7 @@ public final class CallManager { // Singleton instance private static final CallManager INSTANCE = new CallManager(); - // list of registered phones + // list of registered phones, which are PhoneBase objs private final ArrayList<Phone> mPhones; // list of supported ringing calls @@ -97,7 +97,7 @@ public final class CallManager { // empty connection list private final ArrayList<Connection> emptyConnections = new ArrayList<Connection>(); - // default phone as the first phone registered + // default phone as the first phone registered, which is PhoneBase obj private Phone mDefaultPhone; // state registrants @@ -181,6 +181,46 @@ public final class CallManager { } /** + * Get the corresponding PhoneBase obj + * + * @param phone a Phone object + * @return the corresponding PhoneBase obj in Phone if Phone + * is a PhoneProxy obj + * or the Phone itself if Phone is not a PhoneProxy obj + */ + private static Phone getPhoneBase(Phone phone) { + if (phone instanceof PhoneProxy) { + return phone.getForegroundCall().getPhone(); + } + return phone; + } + + /** + * Check if two phones refer to the same PhoneBase obj + * + * Note: PhoneBase, not PhoneProxy, is to be used inside of CallManager + * + * Both PhoneBase and PhoneProxy implement Phone interface, so + * they have same phone APIs, such as dial(). The real implementation, for + * example in GSM, is in GSMPhone as extend from PhoneBase, so that + * foregroundCall.getPhone() returns GSMPhone obj. On the other hand, + * PhoneFactory.getDefaultPhone() returns PhoneProxy obj, which has a class + * member of GSMPhone. + * + * So for phone returned by PhoneFacotry, which is used by PhoneApp, + * phone.getForegroundCall().getPhone() != phone + * but + * isSamePhone(phone, phone.getForegroundCall().getPhone()) == true + * + * @param p1 is the first Phone obj + * @param p2 is the second Phone obj + * @return true if p1 and p2 refer to the same phone + */ + public static boolean isSamePhone(Phone p1, Phone p2) { + return (getPhoneBase(p1) == getPhoneBase(p2)); + } + + /** * Returns all the registered phone objects. * @return all the registered phone objects. */ @@ -198,9 +238,7 @@ public final class CallManager { Phone.State s = Phone.State.IDLE; for (Phone phone : mPhones) { - if (phone.getState() == Phone.State.ANSWERING) { - return Phone.State.ANSWERING; - } else if (phone.getState() == Phone.State.RINGING) { + if (phone.getState() == Phone.State.RINGING) { s = Phone.State.RINGING; } else if (phone.getState() == Phone.State.OFFHOOK) { if (s == Phone.State.IDLE) s = Phone.State.OFFHOOK; @@ -246,25 +284,50 @@ public final class CallManager { /** * Register phone to CallManager - * @param phone + * @param phone to be registered * @return true if register successfully */ public boolean registerPhone(Phone phone) { - if (phone != null && !mPhones.contains(phone)) { + Phone basePhone = getPhoneBase(phone); + + if (basePhone != null && !mPhones.contains(basePhone)) { if (mPhones.isEmpty()) { - mDefaultPhone = phone; + mDefaultPhone = basePhone; } - mPhones.add(phone); - mRingingCalls.add(phone.getRingingCall()); - mBackgroundCalls.add(phone.getBackgroundCall()); - mForegroundCalls.add(phone.getForegroundCall()); - registerForPhoneStates(phone); + mPhones.add(basePhone); + mRingingCalls.add(basePhone.getRingingCall()); + mBackgroundCalls.add(basePhone.getBackgroundCall()); + mForegroundCalls.add(basePhone.getForegroundCall()); + registerForPhoneStates(basePhone); return true; } return false; } /** + * unregister phone from CallManager + * @param phone to be unregistered + */ + public void unregisterPhone(Phone phone) { + Phone basePhone = getPhoneBase(phone); + + if (basePhone != null && mPhones.contains(basePhone)) { + mPhones.remove(basePhone); + mRingingCalls.remove(basePhone.getRingingCall()); + mBackgroundCalls.remove(basePhone.getBackgroundCall()); + mForegroundCalls.remove(basePhone.getForegroundCall()); + unregisterForPhoneStates(basePhone); + if (basePhone == mDefaultPhone) { + if (mPhones.isEmpty()) { + mDefaultPhone = null; + } else { + mDefaultPhone = mPhones.get(0); + } + } + } + } + + /** * return the default phone or null if no phone available */ public Phone getDefaultPhone() { @@ -292,39 +355,6 @@ public final class CallManager { return getFirstActiveRingingCall().getPhone(); } - /** - * @return the first answering call - */ - public Call getFirstAnsweringCall() { - for (Phone phone : mPhones) { - if (phone.getState() == Phone.State.ANSWERING) { - return phone.getForegroundCall(); - } - } - return null; - } - - /** - * unregister phone from CallManager - * @param phone - */ - public void unregisterPhone(Phone phone) { - if (phone != null && mPhones.contains(phone)) { - mPhones.remove(phone); - mRingingCalls.remove(phone.getRingingCall()); - mBackgroundCalls.remove(phone.getBackgroundCall()); - mForegroundCalls.remove(phone.getForegroundCall()); - unregisterForPhoneStates(phone); - if (phone == mDefaultPhone) { - if (mPhones.isEmpty()) { - mDefaultPhone = null; - } else { - mDefaultPhone = mPhones.get(0); - } - } - } - } - public void setAudioMode() { Context context = getContext(); if (context == null) return; @@ -592,8 +622,9 @@ public final class CallManager { * handled asynchronously. */ public Connection dial(Phone phone, String dialString) throws CallStateException { + Phone basePhone = getPhoneBase(phone); if (VDBG) { - Log.d(LOG_TAG, "CallManager.dial( phone=" + phone + ", dialString="+ dialString + ")"); + Log.d(LOG_TAG, "CallManager.dial( phone=" + basePhone + ", dialString="+ dialString + ")"); Log.d(LOG_TAG, this.toString()); } if ( hasActiveFgCall() ) { @@ -601,10 +632,10 @@ public final class CallManager { boolean hasBgCall = !(activePhone.getBackgroundCall().isIdle()); if (DBG) { - Log.d(LOG_TAG, "hasBgCall: "+ hasBgCall + " sameChannel:" + (activePhone == phone)); + Log.d(LOG_TAG, "hasBgCall: "+ hasBgCall + " sameChannel:" + (activePhone == basePhone)); } - if (activePhone != phone) { + if (activePhone != basePhone) { if (hasBgCall) { Log.d(LOG_TAG, "Hangup"); getActiveFgCall().hangup(); @@ -614,7 +645,7 @@ public final class CallManager { } } } - return phone.dial(dialString); + return basePhone.dial(dialString); } /** @@ -1312,7 +1343,7 @@ public final class CallManager { */ public Call getFirstActiveBgCall() { for (Call call : mBackgroundCalls) { - if (!call.isIdle()) { + if (call.getState() != Call.State.IDLE) { return call; } } diff --git a/telephony/java/com/android/internal/telephony/Phone.java b/telephony/java/com/android/internal/telephony/Phone.java index e5736ca..ec6c023 100644 --- a/telephony/java/com/android/internal/telephony/Phone.java +++ b/telephony/java/com/android/internal/telephony/Phone.java @@ -54,12 +54,10 @@ public interface Phone { * <li>OFFHOOK = The phone is off hook. At least one call * exists that is dialing, active or holding and no calls are * ringing or waiting.</li> - * <li>ANSWERING = The incoming call is picked up but the - * call is not established yet.</li> * </ul> */ enum State { - IDLE, RINGING, OFFHOOK, ANSWERING; + IDLE, RINGING, OFFHOOK; }; /** diff --git a/telephony/java/com/android/internal/telephony/cdma/CdmaServiceStateTracker.java b/telephony/java/com/android/internal/telephony/cdma/CdmaServiceStateTracker.java index 5d4dc58..b71cf13 100644 --- a/telephony/java/com/android/internal/telephony/cdma/CdmaServiceStateTracker.java +++ b/telephony/java/com/android/internal/telephony/cdma/CdmaServiceStateTracker.java @@ -16,6 +16,16 @@ package com.android.internal.telephony.cdma; +import com.android.internal.telephony.CommandException; +import com.android.internal.telephony.CommandsInterface; +import com.android.internal.telephony.DataConnectionTracker; +import com.android.internal.telephony.EventLogTags; +import com.android.internal.telephony.IccCard; +import com.android.internal.telephony.MccTable; +import com.android.internal.telephony.ServiceStateTracker; +import com.android.internal.telephony.TelephonyIntents; +import com.android.internal.telephony.TelephonyProperties; + import android.app.AlarmManager; import android.content.ContentResolver; import android.content.Context; @@ -38,19 +48,8 @@ import android.telephony.cdma.CdmaCellLocation; import android.text.TextUtils; import android.util.EventLog; import android.util.Log; -import android.util.Config; import android.util.TimeUtils; -import com.android.internal.telephony.CommandException; -import com.android.internal.telephony.CommandsInterface; -import com.android.internal.telephony.DataConnectionTracker; -import com.android.internal.telephony.EventLogTags; -import com.android.internal.telephony.IccCard; -import com.android.internal.telephony.MccTable; -import com.android.internal.telephony.ServiceStateTracker; -import com.android.internal.telephony.TelephonyIntents; -import com.android.internal.telephony.TelephonyProperties; - import java.util.Arrays; import java.util.Calendar; import java.util.Date; @@ -987,7 +986,7 @@ final class CdmaServiceStateTracker extends ServiceStateTracker { mNeedFixZone = false; if (zone != null) { - if (getAutoTime()) { + if (getAutoTimeZone()) { setAndBroadcastNetworkSetTimeZone(zone.getID()); } saveNitzTimeZone(zone.getID()); @@ -1439,7 +1438,7 @@ final class CdmaServiceStateTracker extends ServiceStateTracker { } if (zone != null) { - if (getAutoTime()) { + if (getAutoTimeZone()) { setAndBroadcastNetworkSetTimeZone(zone.getID()); } saveNitzTimeZone(zone.getID()); @@ -1529,6 +1528,14 @@ final class CdmaServiceStateTracker extends ServiceStateTracker { } } + private boolean getAutoTimeZone() { + try { + return Settings.System.getInt(cr, Settings.System.AUTO_TIME_ZONE) > 0; + } catch (SettingNotFoundException snfe) { + return true; + } + } + private void saveNitzTimeZone(String zoneId) { mSavedTimeZone = zoneId; } diff --git a/telephony/java/com/android/internal/telephony/gsm/GsmServiceStateTracker.java b/telephony/java/com/android/internal/telephony/gsm/GsmServiceStateTracker.java index b639eea..83ad552 100644 --- a/telephony/java/com/android/internal/telephony/gsm/GsmServiceStateTracker.java +++ b/telephony/java/com/android/internal/telephony/gsm/GsmServiceStateTracker.java @@ -16,6 +16,17 @@ package com.android.internal.telephony.gsm; +import com.android.internal.telephony.CommandException; +import com.android.internal.telephony.CommandsInterface; +import com.android.internal.telephony.DataConnectionTracker; +import com.android.internal.telephony.EventLogTags; +import com.android.internal.telephony.IccCard; +import com.android.internal.telephony.MccTable; +import com.android.internal.telephony.RILConstants; +import com.android.internal.telephony.ServiceStateTracker; +import com.android.internal.telephony.TelephonyIntents; +import com.android.internal.telephony.TelephonyProperties; + import android.app.AlarmManager; import android.app.Notification; import android.app.NotificationManager; @@ -47,17 +58,6 @@ import android.util.EventLog; import android.util.Log; import android.util.TimeUtils; -import com.android.internal.telephony.CommandException; -import com.android.internal.telephony.CommandsInterface; -import com.android.internal.telephony.DataConnectionTracker; -import com.android.internal.telephony.EventLogTags; -import com.android.internal.telephony.IccCard; -import com.android.internal.telephony.MccTable; -import com.android.internal.telephony.RILConstants; -import com.android.internal.telephony.ServiceStateTracker; -import com.android.internal.telephony.TelephonyIntents; -import com.android.internal.telephony.TelephonyProperties; - import java.util.Arrays; import java.util.Calendar; import java.util.Date; @@ -995,7 +995,7 @@ final class GsmServiceStateTracker extends ServiceStateTracker { mNeedFixZone = false; if (zone != null) { - if (getAutoTime()) { + if (getAutoTimeZone()) { setAndBroadcastNetworkSetTimeZone(zone.getID()); } saveNitzTimeZone(zone.getID()); @@ -1476,7 +1476,7 @@ final class GsmServiceStateTracker extends ServiceStateTracker { } if (zone != null) { - if (getAutoTime()) { + if (getAutoTimeZone()) { setAndBroadcastNetworkSetTimeZone(zone.getID()); } saveNitzTimeZone(zone.getID()); @@ -1546,6 +1546,15 @@ final class GsmServiceStateTracker extends ServiceStateTracker { } } + private boolean getAutoTimeZone() { + try { + return Settings.System.getInt(phone.getContext().getContentResolver(), + Settings.System.AUTO_TIME_ZONE) > 0; + } catch (SettingNotFoundException snfe) { + return true; + } + } + private void saveNitzTimeZone(String zoneId) { mSavedTimeZone = zoneId; } diff --git a/telephony/java/com/android/internal/telephony/sip/SipPhone.java b/telephony/java/com/android/internal/telephony/sip/SipPhone.java index 0f2736f..9fcf12d 100755 --- a/telephony/java/com/android/internal/telephony/sip/SipPhone.java +++ b/telephony/java/com/android/internal/telephony/sip/SipPhone.java @@ -150,23 +150,15 @@ public class SipPhone extends SipPhoneBase { // in case the active/holding call disappeared and this // is no longer call waiting - if (ringingCall.getState() == Call.State.INCOMING) { + if ((ringingCall.getState() == Call.State.INCOMING) || + (ringingCall.getState() == Call.State.WAITING)) { Log.v(LOG_TAG, "acceptCall"); // Always unmute when answering a new call setMute(false); - // make ringingCall foreground - foregroundCall.switchWith(ringingCall); - foregroundCall.acceptCall(); - } else if (ringingCall.getState() == Call.State.WAITING) { - setMute(false); - switchHoldingAndActive(); - // make ringingCall foreground - foregroundCall.switchWith(ringingCall); - foregroundCall.acceptCall(); + ringingCall.acceptCall(); } else { throw new CallStateException("phone not ringing"); } - updatePhoneState(); } } @@ -485,8 +477,8 @@ public class SipPhone extends SipPhoneBase { } void acceptCall() throws CallStateException { - if (this != foregroundCall) { - throw new CallStateException("acceptCall() in a non-fg call"); + if (this != ringingCall) { + throw new CallStateException("acceptCall() in a non-ringing call"); } if (connections.size() != 1) { throw new CallStateException("acceptCall() in a conf call"); @@ -649,6 +641,18 @@ public class SipPhone extends SipPhoneBase { if (newState == Call.State.INCOMING) { setState(mOwner.getState()); // INCOMING or WAITING } else { + if (mOwner == ringingCall) { + if (ringingCall.getState() == Call.State.WAITING) { + try { + switchHoldingAndActive(); + } catch (CallStateException e) { + // disconnect the call. + onCallEnded(DisconnectCause.LOCAL); + return; + } + } + foregroundCall.switchWith(ringingCall); + } if (newState == Call.State.ACTIVE) call.startAudio(); setState(newState); } diff --git a/telephony/java/com/android/internal/telephony/sip/SipPhoneBase.java b/telephony/java/com/android/internal/telephony/sip/SipPhoneBase.java index fec83d6..5f26af4 100755 --- a/telephony/java/com/android/internal/telephony/sip/SipPhoneBase.java +++ b/telephony/java/com/android/internal/telephony/sip/SipPhoneBase.java @@ -549,8 +549,6 @@ abstract class SipPhoneBase extends PhoneBase { if (getRingingCall().isRinging()) { state = State.RINGING; - } else if (getForegroundCall().isRinging()) { - state = State.ANSWERING; } else if (getForegroundCall().isIdle() && getBackgroundCall().isIdle()) { state = State.IDLE; diff --git a/tests/DumpRenderTree2/assets/run_apache2.py b/tests/DumpRenderTree2/assets/run_apache2.py index c799b5c..5edead1 100755 --- a/tests/DumpRenderTree2/assets/run_apache2.py +++ b/tests/DumpRenderTree2/assets/run_apache2.py @@ -109,18 +109,17 @@ def main(options, args): # Try to execute the commands logging.info("Will " + run_cmd + " apache2 server.") - cmd_template = export_envvars_cmd + " && " + apache2_restart_template + directives + conf_file_cmd # It is worth noting here that if the configuration file with which we restart the server points - # to a different PidFile it will not work and result in second apache2 instance. + # to a different PidFile it will not work and will result in a second apache2 instance. if (run_cmd == 'restart'): logging.info("First will stop...") - execute_cmd(cmd_template % ('stop')) + execute_cmd(export_envvars_cmd + " && " + (apache2_restart_template % ('stop')) + directives + conf_file_cmd) logging.info("Stopped. Will start now...") # We need to sleep breifly to avoid errors with apache being stopped and started too quickly time.sleep(0.5) - execute_cmd(cmd_template % (run_cmd)) + execute_cmd(export_envvars_cmd + " && " + (apache2_restart_template % (run_cmd)) + directives + conf_file_cmd) def execute_cmd(cmd): p = subprocess.Popen(cmd, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE) diff --git a/tests/DumpRenderTree2/src/com/android/dumprendertree2/AbstractResult.java b/tests/DumpRenderTree2/src/com/android/dumprendertree2/AbstractResult.java index 96c1e5e..614b03c 100644 --- a/tests/DumpRenderTree2/src/com/android/dumprendertree2/AbstractResult.java +++ b/tests/DumpRenderTree2/src/com/android/dumprendertree2/AbstractResult.java @@ -32,7 +32,7 @@ import java.io.Serializable; * A class that represent a result of the test. It is responsible for returning the result's * raw data and generating its own diff in HTML format. */ -public abstract class AbstractResult implements Comparable<AbstractResult> { +public abstract class AbstractResult implements Comparable<AbstractResult>, Serializable { private static final String LOG_TAG = "AbstractResult"; diff --git a/tests/DumpRenderTree2/src/com/android/dumprendertree2/LayoutTestsExecutor.java b/tests/DumpRenderTree2/src/com/android/dumprendertree2/LayoutTestsExecutor.java index b9fc274..c0ba9e5 100644 --- a/tests/DumpRenderTree2/src/com/android/dumprendertree2/LayoutTestsExecutor.java +++ b/tests/DumpRenderTree2/src/com/android/dumprendertree2/LayoutTestsExecutor.java @@ -22,6 +22,7 @@ import android.content.Context; import android.content.Intent; import android.content.ServiceConnection; import android.net.Uri; +import android.net.http.SslError; import android.os.Bundle; import android.os.Environment; import android.os.Handler; @@ -30,19 +31,20 @@ import android.os.Message; import android.os.Messenger; import android.os.PowerManager; import android.os.Process; -import android.os.RemoteException; import android.os.PowerManager.WakeLock; +import android.os.RemoteException; import android.util.Log; import android.view.Window; import android.webkit.ConsoleMessage; +import android.webkit.GeolocationPermissions; import android.webkit.HttpAuthHandler; import android.webkit.JsPromptResult; import android.webkit.JsResult; +import android.webkit.SslErrorHandler; import android.webkit.WebChromeClient; import android.webkit.WebSettings; import android.webkit.WebView; import android.webkit.WebViewClient; -import android.webkit.GeolocationPermissions; import android.webkit.WebStorage.QuotaUpdater; import java.io.File; @@ -74,7 +76,7 @@ public class LayoutTestsExecutor extends Activity { } } - private static final String LOG_TAG = "LayoutTestExecutor"; + private static final String LOG_TAG = "LayoutTestsExecutor"; public static final String EXTRA_TESTS_LIST = "TestsList"; public static final String EXTRA_TEST_INDEX = "TestIndex"; @@ -180,6 +182,13 @@ public class LayoutTestsExecutor extends Activity { } handler.cancel(); } + + @Override + public void onReceivedSslError(WebView view, SslErrorHandler handler, SslError error) { + // We ignore SSL errors. In particular, the certificate used by the LayoutTests server + // produces an error as it lacks a CN field. + handler.proceed(); + } }; private WebChromeClient mWebChromeClient = new WebChromeClient() { @@ -236,7 +245,7 @@ public class LayoutTestsExecutor extends Activity { * We never display the new window, just create the view and allow it's content to * execute and be recorded by the executor. */ - newWindowWebView = new WebView(LayoutTestsExecutor.this); + newWindowWebView = createWebViewWithJavascriptInterfaces(); setupWebView(newWindowWebView); } @@ -317,7 +326,7 @@ public class LayoutTestsExecutor extends Activity { mCurrentResult = null; mCurrentAdditionalTextOutput = null; - mCurrentWebView = new WebView(this); + mCurrentWebView = createWebViewWithJavascriptInterfaces(); setupWebView(mCurrentWebView); mEventSender.reset(mCurrentWebView); @@ -329,11 +338,26 @@ public class LayoutTestsExecutor extends Activity { } } + private static class WebViewWithJavascriptInterfaces extends WebView { + public WebViewWithJavascriptInterfaces( + Context context, Map<String, Object> javascriptInterfaces) { + super(context, + null, // attribute set + 0, // default style resource ID + javascriptInterfaces, + false); // is private browsing + } + } + private WebView createWebViewWithJavascriptInterfaces() { + Map<String, Object> javascriptInterfaces = new HashMap<String, Object>(); + javascriptInterfaces.put("layoutTestController", mLayoutTestController); + javascriptInterfaces.put("eventSender", mEventSender); + return new WebViewWithJavascriptInterfaces(this, javascriptInterfaces); + } + private void setupWebView(WebView webView) { webView.setWebViewClient(mWebViewClient); webView.setWebChromeClient(mWebChromeClient); - webView.addJavascriptInterface(mLayoutTestController, "layoutTestController"); - webView.addJavascriptInterface(mEventSender, "eventSender"); /** * Setting a touch interval of -1 effectively disables the optimisation in WebView diff --git a/tests/HwAccelerationTest/AndroidManifest.xml b/tests/HwAccelerationTest/AndroidManifest.xml index 8a08c48..af71a0f 100644 --- a/tests/HwAccelerationTest/AndroidManifest.xml +++ b/tests/HwAccelerationTest/AndroidManifest.xml @@ -31,6 +31,15 @@ </activity> <activity + android:name="AdvancedGradientsActivity" + android:label="_Advanced Gradients"> + <intent-filter> + <action android:name="android.intent.action.MAIN" /> + <category android:name="android.intent.category.LAUNCHER" /> + </intent-filter> + </activity> + + <activity android:name="ResizeActivity" android:label="_Resize" android:windowSoftInputMode="adjustResize"> @@ -250,7 +259,7 @@ <activity android:name="AdvancedBlendActivity" - android:label="_AdvancedBlend"> + android:label="_Advanced Blend"> <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> diff --git a/tests/HwAccelerationTest/src/com/android/test/hwui/AdvancedGradientsActivity.java b/tests/HwAccelerationTest/src/com/android/test/hwui/AdvancedGradientsActivity.java new file mode 100644 index 0000000..27974e7 --- /dev/null +++ b/tests/HwAccelerationTest/src/com/android/test/hwui/AdvancedGradientsActivity.java @@ -0,0 +1,114 @@ +/* + * Copyright (C) 2010 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.test.hwui; + +import android.app.Activity; +import android.content.Context; +import android.graphics.Canvas; +import android.graphics.Matrix; +import android.graphics.Paint; +import android.graphics.RadialGradient; +import android.graphics.Shader; +import android.graphics.SweepGradient; +import android.os.Bundle; +import android.view.View; + +@SuppressWarnings({"UnusedDeclaration"}) +public class AdvancedGradientsActivity extends Activity { + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + + setContentView(new GradientsView(this)); + } + + static class GradientsView extends View { + private final Paint mPaint; + private final SweepGradient mSweepGradient; + private final RadialGradient mRadialGradient; + private final Matrix mMatrix; + private final Matrix mMatrix2; + private final Matrix mMatrix3; + + GradientsView(Context c) { + super(c); + + mSweepGradient = new SweepGradient(0.0f, 0.0f, 0xff000000, 0xffffffff); + mRadialGradient = new RadialGradient(0.0f, 0.0f, 100.0f, 0xff000000, 0xffffffff, + Shader.TileMode.MIRROR); + + mMatrix = new Matrix(); + mMatrix.setRotate(-45, 0.0f, 0.0f); + mMatrix.postTranslate(100.0f, 100.0f); + + mMatrix2 = new Matrix(); + mMatrix2.setScale(1.0f, 2.0f); + mMatrix2.postRotate(-45, 0.0f, 0.0f); + + mMatrix3 = new Matrix(); + mMatrix3.setTranslate(100.0f, 100.0f); + + mPaint = new Paint(); + } + + @Override + protected void onDraw(Canvas canvas) { + super.onDraw(canvas); + canvas.drawRGB(255, 255, 255); + + canvas.save(); + canvas.translate(130.0f, 100.0f); + + mSweepGradient.setLocalMatrix(mMatrix3); + mPaint.setShader(mSweepGradient); + canvas.drawRect(0.0f, 0.0f, 200.0f, 200.0f, mPaint); + + canvas.translate(400.0f, 000.0f); + + mSweepGradient.setLocalMatrix(mMatrix); + mPaint.setShader(mSweepGradient); + canvas.drawRect(0.0f, 0.0f, 200.0f, 200.0f, mPaint); + + canvas.translate(400.0f, 000.0f); + + mSweepGradient.setLocalMatrix(mMatrix2); + mPaint.setShader(mSweepGradient); + canvas.drawRect(0.0f, 0.0f, 200.0f, 200.0f, mPaint); + + canvas.translate(-800.0f, 300.0f); + + mRadialGradient.setLocalMatrix(null); + mPaint.setShader(mRadialGradient); + canvas.drawRect(0.0f, 0.0f, 200.0f, 200.0f, mPaint); + + canvas.translate(400.0f, 000.0f); + + mRadialGradient.setLocalMatrix(mMatrix); + mPaint.setShader(mRadialGradient); + canvas.drawRect(0.0f, 0.0f, 200.0f, 200.0f, mPaint); + + canvas.translate(400.0f, 000.0f); + + mRadialGradient.setLocalMatrix(mMatrix2); + mPaint.setShader(mRadialGradient); + canvas.drawRect(0.0f, 0.0f, 200.0f, 200.0f, mPaint); + + + canvas.restore(); + } + } +} diff --git a/tools/layoutlib/bridge/src/android/view/BridgeInflater.java b/tools/layoutlib/bridge/src/android/view/BridgeInflater.java index 0910d79..4bc8855 100644 --- a/tools/layoutlib/bridge/src/android/view/BridgeInflater.java +++ b/tools/layoutlib/bridge/src/android/view/BridgeInflater.java @@ -116,10 +116,10 @@ public final class BridgeInflater extends LayoutInflater { } @Override - public View createViewFromTag(String name, AttributeSet attrs) { + public View createViewFromTag(View parent, String name, AttributeSet attrs) { View view = null; try { - view = super.createViewFromTag(name, attrs); + view = super.createViewFromTag(parent, name, attrs); } catch (InflateException e) { // try to load the class from using the custom view loader try { diff --git a/tools/layoutlib/create/README.txt b/tools/layoutlib/create/README.txt index 09b392b..c59e20d 100644 --- a/tools/layoutlib/create/README.txt +++ b/tools/layoutlib/create/README.txt @@ -4,68 +4,196 @@ - Description - --------------- -makeLayoutLib generates a library used by the Eclipse graphical layout editor +Layoutlib_create generates a JAR library used by the Eclipse graphical layout editor to perform layout. - - Usage - --------- - ./makeLayoutLib path/to/android.jar destination.jar + ./layoutlib_create path/to/android.jar destination.jar + + +- Design Overview - +------------------- + +Layoutlib_create uses the "android.jar" containing all the Java code used by Android +as generated by the Android build, right before the classes are converted to a DEX format. + +The Android JAR can't be used directly in Eclipse: +- it contains references to native code (which we want to avoid in Eclipse), +- some classes need to be overridden, for example all the drawing code that is + replaced by Java 2D calls in Eclipse. +- some of the classes that need to be changed are final and/or we need access + to their private internal state. + +Consequently this tool: +- parses the input JAR, +- modifies some of the classes directly using some bytecode manipulation, +- filters some packages and removes some that we don't want to end in the output JAR, +- injects some new classes, +- and generates a modified JAR file that is suitable for the Android plugin + for Eclipse to perform rendering. + +The ASM library is used to do the bytecode modification using its visitor pattern API. + +The layoutlib_create is *NOT* generic. There is no configuration file. Instead all the +configuration is done in the main() method and the CreateInfo structure is expected to +change with the Android platform as new classes are added, changed or removed. + +The resulting JAR is used by layoutlib_bridge (a.k.a. "the bridge"), also part of the +platform, that provides all the necessary missing implementation for rendering graphics +in Eclipse. - Implementation Notes - ------------------------ -The goal of makeLayoutLib is to list all the classes from the input jar and create a new -jar that only keeps certain classes and create stubs for all their dependencies. +The tool works in two phases: +- first analyze the input jar (AsmAnalyzer class) +- then generate the output jar (AsmGenerator class), + + +- Analyzer +---------- + +The goal of the analyzer is to create a graph of all the classes from the input JAR +with their dependencies and then only keep the ones we want. + +To do that, the analyzer is created with a list of base classes to keep -- everything +that derives from these is kept. Currently the one such class is android.view.View: +since we want to render layouts, anything that is sort of the view needs to be kept. + +The analyzer is also given a list of class names to keep in the output. +This is done using shell-like glob patterns that filter on the fully-qualified +class names, for example "android.*.R**" ("*" does not matches dots whilst "**" does, +and "." and "$" are interpreted as-is). +In practice we almost but not quite request the inclusion of full packages. + +With this information, the analyzer parses the input zip to find all the classes. +All classes deriving from the requested bases classes are kept. +All classes which name matched the glob pattern are kept. +The analysis then finds all the dependencies of the classes that are to be kept +using an ASM visitor on the class, the field types, the method types and annotations types. +Classes that belong to the current JRE are excluded. + +The output of the analyzer is a set of ASM ClassReader instances which are then +fed to the generator. + + +- Generator +----------- -First the input jar is parsed to find all the classes defined. +The generator is constructed from a CreateInfo struct that acts as a config file +and lists: +- the classes to inject in the output JAR -- these classes are directly implemented + in layoutlib_create and will be used to interface with the renderer in Eclipse. +- specific methods to override (see method stubs details below). +- specific methods to remove based on their return type. +- specific classes to rename. -In the Main(), the following list of classes are hardcoded (TODO config file later): -- keep all classes that derive from android.view.View. -- keep all classes in the android.view and android.widget packages (sub-packages excluded). -- keep specific classes such as android.policy.PhoneLayoutInflater. +Each of these are specific strategies we use to be able to modify the Android code +to fit within the Eclipse renderer. These strategies are explained beow. -For each class to keep, their dependencies are examined using BCEL. -A dependency is defined as a class needed to instantiate the given class that should be kept, -directly or indirectly. So a dependency is a class that is used by the input class, that is -defined in the input jar and that is not part of the current JRE. +The core method of the generator is transform(): it takes an input ASM ClassReader +and modifies it to produce a byte array suitable for the final JAR file. -Dependencies are computed recursively. +The first step of the transformation is changing the name of the class in case +we requested the class to be renamed. This uses the RenameClassAdapter to also rename +all inner classes and references in methods and types. Note that other classes are +not transformed and keep referencing the original name. -Once all dependencies are found, the final jar can be created. -There are three kind of classes to write: -- classes that are to be kept as-is. They are just dumped in the new jar unchanged. -- classes that are to be kept yet contain native methods or fields. -- classes that are just dependencies. We don't want to expose their implementation in the final - jar. +The TransformClassAdapter is then used to process the potentially renamed class. +All protected or private classes are market as public. +All classes are made non-final. +Interfaces are left as-is. -The implementation of native methods and all methods of mock classes is replaced by a stub -that throws UnsupportedOperationException. +If a method has a return type that must be erased, the whole method is skipped. +Methods are also changed from protected/private to public. +The code of the methods is then kept as-is, except for native methods which are +replaced by a stub. Methods that are to be overridden are also replaced by a stub. -Incidentally, the access level of native and mock classes needs to be changed in order for -native methods to be later overridden. Methods that are "final private native" must become -non-final, non-native and at most protected. Package-default access is changed to public. -Classes that are final are made non-final. Abstract methods are left untouched. +Finally fields are also visited and changed from protected/private to public. +- Method stubs +-------------- ----- -20080617 Replace Class +As indicated above, all native and overridden methods are replaced by a stub. +We don't have the code to replace with in layoutlib_create. +Instead the StubMethodAdapter replaces the code of the method by a call to +OverrideMethod.invokeX(). When using the final JAR, the bridge can register +listeners from these overridden method calls based on the method signatures. -Some classes are basically wrappers over native objects. -Subclassing doesn't work as most methods are either static or we don't -control object creation. In this scenario the idea is to be able to -replace classes in the final jar. +The listeners are currently pretty basic: we only pass the signature of the +method being called, its caller object and a flag indicating whether the +method was native. We do not currently provide the parameters. The listener +can however specify the return value of the overridden method. -Example: android.graphics.Paint would get renamed to OriginalPaint -in the generated jar. Then in the bridge we'll introduce a replacement -Paint class that derives from OriginalPaint. +An extension being worked on is to actually replace these listeners by +direct calls to a delegate class, complete with parameters. + + +- Strategies +------------ + +We currently have 4 strategies to deal with overriding the rendering code +and make it run in Eclipse. Most of these strategies are implemented hand-in-hand +by the bridge (which runs in Eclipse) and the generator. + + +1- Class Injection + +This is the easiest: we currently inject 4 classes, namely: +- OverrideMethod and its associated MethodListener and MethodAdapter are used + to intercept calls to some specific methods that are stubbed out and change + their return value. +- CreateInfo class, which configured the generator. Not used yet, but could + in theory help us track what the generator changed. + + +2- Overriding methods + +As explained earlier, the creator doesn't have any replacement code for +methods to override. Instead it removes the original code and replaces it +by a call to a specific OveriddeMethod.invokeX(). The bridge then registers +a listener on the method signature and can provide an implementation. + + +3- Renaming classes + +This simply changes the name of a class in its definition, as well as all its +references in internal inner classes and methods. +Calls from other classes are not modified -- they keep referencing the original +class name. This allows the bridge to literally replace an implementation. + +An example will make this easier: android.graphics.Paint is the main drawing +class that we need to replace. To do so, the generator renames Paint to _original_Paint. +Later the bridge provides its own replacement version of Paint which will be used +by the rest of the Android stack. The replacement version of Paint can still use +(either by inheritance or delegation) all the original non-native code of _original_Paint +if it so desires. + +Some of the Android classes are basically wrappers over native objects and since +we don't have the native code in Eclipse, we need to provide a full alternate +implementation. Sub-classing doesn't work as some native methods are static and +we don't control object creation. This won't rename/replace the inner static methods of a given class. +4- Method erasure based on return type + +This is mostly an implementation detail of the bridge: in the Paint class +mentioned above, some inner static classes are used to pass around +attributes (e.g. FontMetrics, or the Style enum) and all the original implementation +is native. + +In this case we have a strategy that tells the generator that anything returning, for +example, the inner class Paint$Style in the Paint class should be discarded and the +bridge will provide its own implementation. + +-- +end diff --git a/tools/obbtool/mkobb.sh b/tools/obbtool/mkobb.sh new file mode 100755 index 0000000..f4cae9a --- /dev/null +++ b/tools/obbtool/mkobb.sh @@ -0,0 +1,260 @@ +#!/bin/bash +# +# Copyright (C) 2010 The Android Open Source Project +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at + +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +# mkobb.sh - Creates OBB files on Linux machines + +# Directory where we should temporarily mount the OBB loopback to copy files +MOUNTDIR=/tmp + +# Presets. Changing these will probably break your OBB on the device +CRYPTO=blowfish +FS=vfat +MKFS=mkfs.vfat +LOSETUP=losetup +BLOCK_SIZE=512 +SLOP=512 # Amount of filesystem slop in ${BLOCK_SIZE} blocks + +find_binaries() { + MKFSBIN=`which ${MKFS}` + LOSETUPBIN=`which ${LOSETUP}` + MOUNTBIN=`which mount` + UMOUNTBIN=`which umount` + DDBIN=`which dd` + RSYNCBIN=`which rsync` +} + +check_prereqs() { + if [ "`uname -s`x" != "Linuxx" ]; then \ + echo "ERROR: This script only works on Linux!" + exit 1 + fi + + if ! egrep -q "^cryptoloop " /proc/modules; then \ + echo "ERROR: Could not find cryptoloop in the kernel." + echo "Perhaps you need to: modprobe cryptoloop" + exit 1 + fi + + if ! egrep -q "name\s*:\s*${CRYPTO}$" /proc/crypto; then \ + echo "ERROR: Could not find crypto \`${CRYPTO}' in the kernel." + echo "Perhaps you need to: modprobe ${CRYPTO}" + exit 1 + fi + + if ! egrep -q "^\s*${FS}$" /proc/filesystems; then \ + echo "ERROR: Could not find filesystem \`${FS}' in the kernel." + echo "Perhaps you need to: modprobe ${FS}" + exit 1 + fi + + if [ "${MKFSBIN}x" = "x" ]; then \ + echo "ERROR: Could not find ${MKFS} in your path!" + exit 1 + elif [ ! -x "${MKFSBIN}" ]; then \ + echo "ERROR: ${MKFSBIN} is not executable!" + exit 1 + fi + + if [ "${LOSETUPBIN}x" = "x" ]; then \ + echo "ERROR: Could not find ${LOSETUP} in your path!" + exit 1 + elif [ ! -x "${LOSETUPBIN}" ]; then \ + echo "ERROR: ${LOSETUPBIN} is not executable!" + exit 1 + fi +} + +cleanup() { + if [ "${loopdev}x" != "x" ]; then \ + ${LOSETUPBIN} -d ${loopdev} + fi +} + +hidden_prompt() { + unset output + prompt="$1" + outvar="$2" + while read -s -n 1 -p "$prompt" c; do \ + if [ "x$c" = "x" ]; then \ + break + fi + prompt='*' + output="${output}${c}" + done + echo + eval $outvar="$output" + unset output +} + +read_key() { + hidden_prompt " Encryption key: " key + + if [ "${key}x" = "x" ]; then \ + echo "ERROR: An empty key is not allowed!" + exit 1 + fi + + hidden_prompt "Encryption key (again): " key2 + + if [ "${key}x" != "${key2}x" ]; then \ + echo "ERROR: Encryption keys do not match!" + exit 1 + fi +} + +onexit() { + if [ "x${temp_mount}" != "x" ]; then \ + ${UMOUNTBIN} ${temp_mount} + rmdir ${temp_mount} + fi + if [ "x${loop_dev}" != "x" ]; then \ + ${LOSETUPBIN} -d ${loop_dev} + fi + if [ "x${tempfile}" != "x" -a -f "${tempfile}" ]; then \ + rm -f ${tempfile} + fi + if [ "x${keyfile}" != "x" -a -f "${keyfile}" ]; then \ + rm -f ${keyfile} + fi + echo "Fatal error." + exit 1 +} + +usage() { + echo "mkobb.sh -- Create OBB files for use on Android" + echo "" + echo " -c Use an encrypted OBB; must specify key" + echo " -d <directory> Use <directory> as input for OBB files" + echo " -k <key> Use <key> to encrypt OBB file" + echo " -K Prompt for key to encrypt OBB file" + echo " -o <filename> Write OBB file out to <filename>" + echo " -v Verbose mode" + echo " -h Help; this usage screen" +} + +find_binaries +check_prereqs + +use_crypto=0 + +args=`getopt -o cd:hk:Ko:v -- "$@"` +eval set -- "$args" + +while true; do \ + case "$1" in + -c) use_crypto=1; shift;; + -d) directory=$2; shift 2;; + -h) usage; exit 1;; + -k) key=$2; shift 2;; + -K) prompt_key=1; shift;; + -v) verbose=1; shift;; + -o) filename=$2; shift 2;; + --) shift; break;; + *) echo "ERROR: Invalid argument in option parsing! Cannot recover. Ever."; exit 1;; + esac +done + +if [ "${directory}x" = "x" -o ! -d "${directory}" ]; then \ + echo "ERROR: Must specify valid input directory" + echo "" + usage + exit 1; +fi + +if [ "${filename}x" = "x" ]; then \ + echo "ERROR: Must specify filename" + echo "" + usage + exit 1; +fi + +if [ ${use_crypto} -eq 1 -a "${key}x" = "x" -a 0${prompt_key} -eq 0 ]; then \ + echo "ERROR: Crypto desired, but no key supplied or requested to prompt for." + exit 1 +fi + +if [ 0${prompt_key} -eq 1 ]; then \ + read_key +fi + +outdir=`dirname ${filename}` +if [ ! -d "${outdir}" ]; then \ + echo "ERROR: Output directory does not exist: ${outdir}" + exit 1 +fi + +# Make sure we clean up any stuff we create from here on during error conditions +trap onexit ERR + +tempfile=$(tempfile -d ${outdir}) || ( echo "ERROR: couldn't create temporary file in ${outdir}"; exit 1 ) + +block_count=`du --apparent-size --block-size=512 ${directory} | awk '{ print $1; }'` +if [ $? -ne 0 ]; then \ + echo "ERROR: Couldn't read size of input directory ${directory}" + exit 1 +fi + +echo "Creating temporary file..." +${DDBIN} if=/dev/zero of=${tempfile} bs=${BLOCK_SIZE} count=$((${block_count} + ${SLOP})) > /dev/null 2>&1 +if [ $? -ne 0 ]; then \ + echo "ERROR: creating temporary file: $?" +fi + +loop_dev=$(${LOSETUPBIN} -f) || ( echo "ERROR: losetup wouldn't tell us the next unused device"; exit 1 ) + +if [ ${use_crypto} -eq 1 ]; then \ + keyfile=$(tempfile -d ${outdir}) || ( echo "ERROR: could not create temporary key file"; exit 1 ) + ${LOSETUPBIN} -p 5 -e ${CRYPTO} ${loop_dev} ${tempfile} 5< ${keyfile} || ( echo "ERROR: couldn't create loopback device"; exit 1 ) + rm -f ${keyfile} +else \ + ${LOSETUPBIN} ${loop_dev} ${tempfile} || ( echo "ERROR: couldn't create loopback device"; exit 1 ) +fi + +# +# Create the filesystem +# +echo "" +${MKFSBIN} -I ${loop_dev} +echo "" + +# +# Make the temporary mount point and mount it +# +temp_mount="${MOUNTDIR}/${RANDOM}" +mkdir ${temp_mount} +${MOUNTBIN} -t ${FS} -o loop ${loop_dev} ${temp_mount} + +# +# rsync the files! +# +echo "Copying files:" +${RSYNCBIN} -av --no-owner --no-group ${directory}/ ${temp_mount}/ +echo "" + +echo "Successfully created \`${filename}'" + +# +# Undo all the temporaries +# +umount ${temp_mount} +rmdir ${temp_mount} +${LOSETUPBIN} -d ${loop_dev} +mv ${tempfile} ${filename} + +trap - ERR + +exit 0 |