diff options
| -rw-r--r-- | api/current.xml | 96 | ||||
| -rw-r--r-- | core/java/android/app/IUiModeManager.aidl | 5 | ||||
| -rw-r--r-- | core/java/android/app/UiModeManager.java | 111 | ||||
| -rw-r--r-- | core/java/android/content/Intent.java | 40 | ||||
| -rw-r--r-- | core/java/android/content/res/Configuration.java | 25 | ||||
| -rw-r--r-- | core/res/AndroidManifest.xml | 6 | ||||
| -rw-r--r-- | include/utils/ResourceTypes.h | 3 | ||||
| -rw-r--r-- | media/libstagefright/AwesomePlayer.cpp | 94 | ||||
| -rw-r--r-- | media/libstagefright/include/AwesomePlayer.h | 11 | ||||
| -rw-r--r-- | services/java/com/android/server/DockObserver.java | 519 | ||||
| -rw-r--r-- | services/java/com/android/server/PackageManagerService.java | 46 | ||||
| -rw-r--r-- | services/java/com/android/server/SystemServer.java | 11 | ||||
| -rw-r--r-- | services/java/com/android/server/UiModeManagerService.java | 629 | ||||
| -rw-r--r-- | tools/aapt/AaptAssets.cpp | 7 | ||||
| -rw-r--r-- | tools/aapt/Resource.cpp | 29 |
15 files changed, 974 insertions, 658 deletions
diff --git a/api/current.xml b/api/current.xml index 3e8b9ac3c531..7f0fb94165dd 100644 --- a/api/current.xml +++ b/api/current.xml @@ -25564,6 +25564,17 @@ visibility="public" > </method> +<method name="getCurrentModeType" + return="int" + abstract="false" + native="false" + synchronized="false" + static="false" + final="false" + deprecated="not deprecated" + visibility="public" +> +</method> <method name="getNightMode" return="int" abstract="false" @@ -25588,33 +25599,73 @@ <parameter name="mode" type="int"> </parameter> </method> -<field name="MODE_AUTO" +<field name="ACTION_ENTER_CAR_MODE" + type="java.lang.String" + transient="false" + volatile="false" + static="true" + final="false" + deprecated="not deprecated" + visibility="public" +> +</field> +<field name="ACTION_ENTER_DESK_MODE" + type="java.lang.String" + transient="false" + volatile="false" + static="true" + final="false" + deprecated="not deprecated" + visibility="public" +> +</field> +<field name="ACTION_EXIT_CAR_MODE" + type="java.lang.String" + transient="false" + volatile="false" + static="true" + final="false" + deprecated="not deprecated" + visibility="public" +> +</field> +<field name="ACTION_EXIT_DESK_MODE" + type="java.lang.String" + transient="false" + volatile="false" + static="true" + final="false" + deprecated="not deprecated" + visibility="public" +> +</field> +<field name="MODE_NIGHT_AUTO" type="int" transient="false" volatile="false" - value="3" + value="0" static="true" final="true" deprecated="not deprecated" visibility="public" > </field> -<field name="MODE_NIGHT" +<field name="MODE_NIGHT_NO" type="int" transient="false" volatile="false" - value="2" + value="1" static="true" final="true" deprecated="not deprecated" visibility="public" > </field> -<field name="MODE_NOTNIGHT" +<field name="MODE_NIGHT_YES" type="int" transient="false" volatile="false" - value="1" + value="2" static="true" final="true" deprecated="not deprecated" @@ -39068,17 +39119,6 @@ visibility="public" > </field> -<field name="EXTRA_CAR_MODE_ENABLED" - type="java.lang.String" - transient="false" - volatile="false" - value=""android.intent.extra.CAR_MODE_ENABLED"" - static="true" - final="true" - deprecated="not deprecated" - visibility="public" -> -</field> <field name="EXTRA_CC" type="java.lang.String" transient="false" @@ -39233,17 +39273,6 @@ visibility="public" > </field> -<field name="EXTRA_PHYSICAL_DOCK_STATE" - type="java.lang.String" - transient="false" - volatile="false" - value=""android.intent.extra.PHYSICAL_DOCK_STATE"" - static="true" - final="true" - deprecated="not deprecated" - visibility="public" -> -</field> <field name="EXTRA_REMOTE_INTENT_TOKEN" type="java.lang.String" transient="false" @@ -47911,6 +47940,17 @@ type="int" transient="false" volatile="false" + value="3" + static="true" + final="true" + deprecated="not deprecated" + visibility="public" +> +</field> +<field name="UI_MODE_TYPE_DESK" + type="int" + transient="false" + volatile="false" value="2" static="true" final="true" diff --git a/core/java/android/app/IUiModeManager.aidl b/core/java/android/app/IUiModeManager.aidl index 6ac8a2a6ad78..bd637b7ac801 100644 --- a/core/java/android/app/IUiModeManager.aidl +++ b/core/java/android/app/IUiModeManager.aidl @@ -33,6 +33,11 @@ interface IUiModeManager { void disableCarMode(); /** + * Return the current running mode. + */ + int getCurrentModeType(); + + /** * Sets the night mode. * The mode can be one of: * 1 - notnight mode diff --git a/core/java/android/app/UiModeManager.java b/core/java/android/app/UiModeManager.java index aca8ab4ad613..defe42149b23 100644 --- a/core/java/android/app/UiModeManager.java +++ b/core/java/android/app/UiModeManager.java @@ -1,5 +1,7 @@ package android.app; +import android.content.Context; +import android.content.res.Configuration; import android.os.RemoteException; import android.os.ServiceManager; import android.util.Log; @@ -9,6 +11,22 @@ import android.util.Log; * allow applications to control UI modes of the device. * It provides functionality to disable the car mode and it gives access to the * night mode settings. + * + * <p>These facilities are built on top of the underlying + * {@link android.content.Intent#ACTION_DOCK_EVENT} broadcasts that are sent when the user + * physical places the device into and out of a dock. When that happens, + * the UiModeManager switches the system {@link android.content.res.Configuration} + * to the appropriate UI mode, sends broadcasts about the mode switch, and + * starts the corresponding mode activity if appropriate. See the + * broadcasts {@link #ACTION_ENTER_CAR_MODE} and + * {@link #ACTION_ENTER_DESK_MODE} for more information. + * + * <p>In addition, the user may manually switch the system to car mode without + * physically being in a dock. While in car mode -- whether by manual action + * from the user or being physically placed in a dock -- a notification is + * displayed allowing the user to exit dock mode. Thus the dock mode + * represented here may be different than the current state of the underlying + * dock event broadcast. * * <p>You do not instantiate this class directly; instead, retrieve it through * {@link android.content.Context#getSystemService @@ -17,19 +35,72 @@ import android.util.Log; public class UiModeManager { private static final String TAG = "UiModeManager"; - public static final int MODE_NOTNIGHT = 1; - public static final int MODE_NIGHT = 2; - public static final int MODE_AUTO = 3; + /** + * Broadcast sent when the device's UI has switched to car mode, either + * by being placed in a car dock or explicit action of the user. After + * sending the broadcast, the system will start the intent + * {@link android.content.Intent#ACTION_MAIN} with category + * {@link android.content.Intent#CATEGORY_CAR_DOCK} + * to display the car UI, which typically what an application would + * implement to provide their own interface. However, applications can + * also monitor this Intent in order to be informed of mode changes or + * prevent the normal car UI from being displayed by setting the result + * of the broadcast to {@link Activity#RESULT_CANCELED}. + */ + public static String ACTION_ENTER_CAR_MODE = "android.app.action.ENTER_CAR_MODE"; + + /** + * Broadcast sent when the device's UI has switch away from car mode back + * to normal mode. Typically used by a car mode app, to dismiss itself + * when the user exits car mode. + */ + public static String ACTION_EXIT_CAR_MODE = "android.app.action.EXIT_CAR_MODE"; + + /** + * Broadcast sent when the device's UI has switched to desk mode, + * by being placed in a desk dock. After + * sending the broadcast, the system will start the intent + * {@link android.content.Intent#ACTION_MAIN} with category + * {@link android.content.Intent#CATEGORY_DESK_DOCK} + * to display the desk UI, which typically what an application would + * implement to provide their own interface. However, applications can + * also monitor this Intent in order to be informed of mode changes or + * prevent the normal desk UI from being displayed by setting the result + * of the broadcast to {@link Activity#RESULT_CANCELED}. + */ + public static String ACTION_ENTER_DESK_MODE = "android.app.action.ENTER_DESK_MODE"; + + /** + * Broadcast sent when the device's UI has switch away from car mode back + * to normal mode. Typically used by a car mode app, to dismiss itself + * when the user exits car mode. + */ + public static String ACTION_EXIT_DESK_MODE = "android.app.action.EXIT_DESK_MODE"; + + /** Constant for {@link #setNightMode(int)} and {@link #getNightMode()}: + * automatically switch night mode on and off based on the time. + */ + public static final int MODE_NIGHT_AUTO = Configuration.UI_MODE_NIGHT_UNDEFINED >> 4; + + /** Constant for {@link #setNightMode(int)} and {@link #getNightMode()}: + * never run in night mode. + */ + public static final int MODE_NIGHT_NO = Configuration.UI_MODE_NIGHT_NO >> 4; + + /** Constant for {@link #setNightMode(int)} and {@link #getNightMode()}: + * always run in night mode. + */ + public static final int MODE_NIGHT_YES = Configuration.UI_MODE_NIGHT_YES >> 4; private IUiModeManager mService; /*package*/ UiModeManager() { mService = IUiModeManager.Stub.asInterface( - ServiceManager.getService("uimode")); + ServiceManager.getService(Context.UI_MODE_SERVICE)); } /** - * Disables the car mode. + * Turn off special mode if currently in car mode. */ public void disableCarMode() { if (mService != null) { @@ -42,17 +113,35 @@ public class UiModeManager { } /** + * Return the current running mode type. May be one of + * {@link Configuration#UI_MODE_TYPE_NORMAL Configuration.UI_MODE_TYPE_NORMAL}, + * {@link Configuration#UI_MODE_TYPE_DESK Configuration.UI_MODE_TYPE_DESK}, or + * {@link Configuration#UI_MODE_TYPE_CAR Configuration.UI_MODE_TYPE_CAR}, + */ + public int getCurrentModeType() { + if (mService != null) { + try { + return mService.getCurrentModeType(); + } catch (RemoteException e) { + Log.e(TAG, "getCurrentModeType: RemoteException", e); + } + } + return Configuration.UI_MODE_TYPE_NORMAL; + } + + /** * Sets the night mode. Changes to the night mode are only effective when - * the car mode is enabled on a device. + * the car or desk mode is enabled on a device. * * <p>The mode can be one of: * <ul> - * <li><em>{@link #MODE_NOTNIGHT}<em> - sets the device into notnight + * <li><em>{@link #MODE_NIGHT_NO}<em> - sets the device into notnight * mode.</li> - * <li><em>{@link #MODE_NIGHT}</em> - sets the device into night mode. + * <li><em>{@link #MODE_NIGHT_YES}</em> - sets the device into night mode. * </li> - * <li><em>{@link #MODE_AUTO}</em> - automatic night/notnight switching + * <li><em>{@link #MODE_NIGHT_AUTO}</em> - automatic night/notnight switching * depending on the location and certain other sensors.</li> + * </ul> */ public void setNightMode(int mode) { if (mService != null) { @@ -67,8 +156,8 @@ public class UiModeManager { /** * Returns the currently configured night mode. * - * @return {@link #MODE_NOTNIGHT}, {@link #MODE_NIGHT} or {@link #MODE_AUTO} - * When an error occurred -1 is returned. + * @return {@link #MODE_NIGHT_NO}, {@link #MODE_NIGHT_YES}, or + * {@link #MODE_NIGHT_AUTO}. When an error occurred -1 is returned. */ public int getNightMode() { if (mService != null) { diff --git a/core/java/android/content/Intent.java b/core/java/android/content/Intent.java index e63851f0a603..fd5591d674be 100644 --- a/core/java/android/content/Intent.java +++ b/core/java/android/content/Intent.java @@ -1838,21 +1838,17 @@ public class Intent implements Parcelable, Cloneable { "android.intent.action.REBOOT"; /** - * Broadcast Action: A sticky broadcast indicating the phone was docked - * or undocked. + * Broadcast Action: A sticky broadcast for changes in the physical + * docking state of the device. * * <p>The intent will have the following extra values: * <ul> * <li><em>{@link #EXTRA_DOCK_STATE}</em> - the current dock - * state, which depends on the state of the car mode.</li> - * <li><em>{@link #EXTRA_PHYSICAL_DOCK_STATE}</em> - the physical dock - * state.</li> - * <li><em>{@link #EXTRA_CAR_MODE_ENABLED}</em> - a boolean indicating the - * state of the car mode.</li> + * state, indicating which dock the device is physically in.</li> * </ul> - * <p>This is intended for monitoring the current dock state. - * To launch an activity from a dock state change, use {@link #CATEGORY_CAR_DOCK} - * or {@link #CATEGORY_DESK_DOCK} instead. + * <p>This is intended for monitoring the current physical dock state. + * See {@link android.app.UiModeManager} for the normal API dealing with + * dock mode changes. */ @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) public static final String ACTION_DOCK_EVENT = @@ -2014,15 +2010,15 @@ public class Intent implements Parcelable, Cloneable { "android.intent.category.FRAMEWORK_INSTRUMENTATION_TEST"; /** * An activity to run when device is inserted into a car dock. - * Used with {@link #ACTION_MAIN} to launch an activity. - * To monitor dock state, use {@link #ACTION_DOCK_EVENT} instead. + * Used with {@link #ACTION_MAIN} to launch an activity. For more + * information, see {@link android.app.UiModeManager}. */ @SdkConstant(SdkConstantType.INTENT_CATEGORY) public static final String CATEGORY_CAR_DOCK = "android.intent.category.CAR_DOCK"; /** * An activity to run when device is inserted into a car dock. - * Used with {@link #ACTION_MAIN} to launch an activity. - * To monitor dock state, use {@link #ACTION_DOCK_EVENT} instead. + * Used with {@link #ACTION_MAIN} to launch an activity. For more + * information, see {@link android.app.UiModeManager}. */ @SdkConstant(SdkConstantType.INTENT_CATEGORY) public static final String CATEGORY_DESK_DOCK = "android.intent.category.DESK_DOCK"; @@ -2191,22 +2187,6 @@ public class Intent implements Parcelable, Cloneable { public static final int EXTRA_DOCK_STATE_CAR = 2; /** - * Used as an int extra field in {@link android.content.Intent#ACTION_DOCK_EVENT} - * intents to request the physical dock state. Possible values are - * {@link android.content.Intent#EXTRA_DOCK_STATE_UNDOCKED}, - * {@link android.content.Intent#EXTRA_DOCK_STATE_DESK}, or - * {@link android.content.Intent#EXTRA_DOCK_STATE_CAR}. - */ - public static final String EXTRA_PHYSICAL_DOCK_STATE = - "android.intent.extra.PHYSICAL_DOCK_STATE"; - - /** - * Used as an boolean extra field in {@link android.content.Intent#ACTION_DOCK_EVENT} - * intents to indicate that the car mode is enabled or not. - */ - public static final String EXTRA_CAR_MODE_ENABLED = "android.intent.extra.CAR_MODE_ENABLED"; - - /** * Boolean that can be supplied as meta-data with a dock activity, to * indicate that the dock should take over the home key when it is active. */ diff --git a/core/java/android/content/res/Configuration.java b/core/java/android/content/res/Configuration.java index a737283cf4ec..61e3004c327e 100644 --- a/core/java/android/content/res/Configuration.java +++ b/core/java/android/content/res/Configuration.java @@ -165,7 +165,8 @@ public final class Configuration implements Parcelable, Comparable<Configuration public static final int UI_MODE_TYPE_MASK = 0x0f; public static final int UI_MODE_TYPE_UNDEFINED = 0x00; public static final int UI_MODE_TYPE_NORMAL = 0x01; - public static final int UI_MODE_TYPE_CAR = 0x02; + public static final int UI_MODE_TYPE_DESK = 0x02; + public static final int UI_MODE_TYPE_CAR = 0x03; public static final int UI_MODE_NIGHT_MASK = 0x30; public static final int UI_MODE_NIGHT_UNDEFINED = 0x00; @@ -175,11 +176,12 @@ public final class Configuration implements Parcelable, Comparable<Configuration /** * Bit mask of the ui mode. Currently there are two fields: * <p>The {@link #UI_MODE_TYPE_MASK} bits define the overall ui mode of the - * device. They may be one of - * {@link #UI_MODE_TYPE_NORMAL} or {@link #UI_MODE_TYPE_CAR}. + * device. They may be one of {@link #UI_MODE_TYPE_UNDEFINED}, + * {@link #UI_MODE_TYPE_NORMAL}, {@link #UI_MODE_TYPE_DESK}, + * or {@link #UI_MODE_TYPE_CAR}. * * <p>The {@link #UI_MODE_NIGHT_MASK} defines whether the screen - * is in a special mode. They may be one of + * is in a special mode. They may be one of {@link #UI_MODE_NIGHT_UNDEFINED}, * {@link #UI_MODE_NIGHT_NO} or {@link #UI_MODE_NIGHT_YES}. */ public int uiMode; @@ -272,7 +274,7 @@ public final class Configuration implements Parcelable, Comparable<Configuration navigationHidden = NAVIGATIONHIDDEN_UNDEFINED; orientation = ORIENTATION_UNDEFINED; screenLayout = SCREENLAYOUT_SIZE_UNDEFINED; - uiMode = UI_MODE_TYPE_NORMAL; + uiMode = UI_MODE_TYPE_UNDEFINED; seq = 0; } @@ -354,10 +356,17 @@ public final class Configuration implements Parcelable, Comparable<Configuration changed |= ActivityInfo.CONFIG_SCREEN_LAYOUT; screenLayout = delta.screenLayout; } - if (delta.uiMode != UI_MODE_TYPE_NORMAL + if (delta.uiMode != (UI_MODE_TYPE_UNDEFINED|UI_MODE_NIGHT_UNDEFINED) && uiMode != delta.uiMode) { changed |= ActivityInfo.CONFIG_UI_MODE; - uiMode = delta.uiMode; + if ((delta.uiMode&UI_MODE_TYPE_MASK) != UI_MODE_TYPE_UNDEFINED) { + uiMode = (uiMode&~UI_MODE_TYPE_MASK) + | (delta.uiMode&UI_MODE_TYPE_MASK); + } + if ((delta.uiMode&UI_MODE_NIGHT_MASK) != UI_MODE_NIGHT_UNDEFINED) { + uiMode = (uiMode&~UI_MODE_NIGHT_MASK) + | (delta.uiMode&UI_MODE_NIGHT_MASK); + } } if (delta.seq != 0) { @@ -439,7 +448,7 @@ public final class Configuration implements Parcelable, Comparable<Configuration && screenLayout != delta.screenLayout) { changed |= ActivityInfo.CONFIG_SCREEN_LAYOUT; } - if (delta.uiMode != UI_MODE_TYPE_NORMAL + if (delta.uiMode != (UI_MODE_TYPE_UNDEFINED|UI_MODE_NIGHT_UNDEFINED) && uiMode != delta.uiMode) { changed |= ActivityInfo.CONFIG_UI_MODE; } diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml index a41d25bf1a97..f1e614b8dfb1 100644 --- a/core/res/AndroidManifest.xml +++ b/core/res/AndroidManifest.xml @@ -52,7 +52,13 @@ <protected-broadcast android:name="android.intent.action.DEVICE_STORAGE_OK" /> <protected-broadcast android:name="android.intent.action.NEW_OUTGOING_CALL" /> <protected-broadcast android:name="android.intent.action.REBOOT" /> + <protected-broadcast android:name="android.intent.action.DOCK_EVENT" /> + <protected-broadcast android:name="android.app.action.ENTER_CAR_MODE" /> + <protected-broadcast android:name="android.app.action.EXIT_CAR_MODE" /> + <protected-broadcast android:name="android.app.action.ENTER_DESK_MODE" /> + <protected-broadcast android:name="android.app.action.EXIT_DESK_MODE" /> + <protected-broadcast android:name="android.backup.intent.RUN" /> <protected-broadcast android:name="android.backup.intent.CLEAR" /> <protected-broadcast android:name="android.backup.intent.INIT" /> diff --git a/include/utils/ResourceTypes.h b/include/utils/ResourceTypes.h index cbcef4e1af77..0e796dc561f1 100644 --- a/include/utils/ResourceTypes.h +++ b/include/utils/ResourceTypes.h @@ -946,7 +946,8 @@ struct ResTable_config MASK_UI_MODE_TYPE = 0x0f, UI_MODE_TYPE_ANY = 0x00, UI_MODE_TYPE_NORMAL = 0x01, - UI_MODE_TYPE_CAR = 0x02, + UI_MODE_TYPE_DESK = 0x02, + UI_MODE_TYPE_CAR = 0x03, // uiMode bits for the night switch. MASK_UI_MODE_NIGHT = 0x30, diff --git a/media/libstagefright/AwesomePlayer.cpp b/media/libstagefright/AwesomePlayer.cpp index ab65b4414e2c..5090c3939cb0 100644 --- a/media/libstagefright/AwesomePlayer.cpp +++ b/media/libstagefright/AwesomePlayer.cpp @@ -297,13 +297,11 @@ status_t AwesomePlayer::setDataSource_l(const sp<MediaExtractor> &extractor) { CHECK(meta->findCString(kKeyMIMEType, &mime)); if (!haveVideo && !strncasecmp(mime, "video/", 6)) { - if (setVideoSource(extractor->getTrack(i)) == OK) { - haveVideo = true; - } + setVideoSource(extractor->getTrack(i)); + haveVideo = true; } else if (!haveAudio && !strncasecmp(mime, "audio/", 6)) { - if (setAudioSource(extractor->getTrack(i)) == OK) { - haveAudio = true; - } + setAudioSource(extractor->getTrack(i)); + haveAudio = true; } if (haveAudio && haveVideo) { @@ -331,6 +329,9 @@ void AwesomePlayer::reset_l() { } mPrefetcher.clear(); + mAudioTrack.clear(); + mVideoTrack.clear(); + // Shutdown audio first, so that the respone to the reset request // appears to happen instantaneously as far as the user is concerned // If we did this later, audio would continue playing while we @@ -699,32 +700,34 @@ status_t AwesomePlayer::getVideoDimensions( return OK; } -status_t AwesomePlayer::setAudioSource(sp<MediaSource> source) { - if (source == NULL) { - return UNKNOWN_ERROR; - } +void AwesomePlayer::setAudioSource(sp<MediaSource> source) { + CHECK(source != NULL); if (mPrefetcher != NULL) { source = mPrefetcher->addSource(source); } - sp<MetaData> meta = source->getFormat(); + mAudioTrack = source; +} + +status_t AwesomePlayer::initAudioDecoder() { + sp<MetaData> meta = mAudioTrack->getFormat(); const char *mime; CHECK(meta->findCString(kKeyMIMEType, &mime)); if (!strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_RAW)) { - mAudioSource = source; + mAudioSource = mAudioTrack; } else { mAudioSource = OMXCodec::Create( - mClient.interface(), source->getFormat(), + mClient.interface(), mAudioTrack->getFormat(), false, // createEncoder - source); + mAudioTrack); } if (mAudioSource != NULL) { int64_t durationUs; - if (source->getFormat()->findInt64(kKeyDuration, &durationUs)) { + if (mAudioTrack->getFormat()->findInt64(kKeyDuration, &durationUs)) { if (mDurationUs < 0 || durationUs > mDurationUs) { mDurationUs = durationUs; } @@ -734,30 +737,32 @@ status_t AwesomePlayer::setAudioSource(sp<MediaSource> source) { return mAudioSource != NULL ? OK : UNKNOWN_ERROR; } -status_t AwesomePlayer::setVideoSource(sp<MediaSource> source) { - if (source == NULL) { - return UNKNOWN_ERROR; - } +void AwesomePlayer::setVideoSource(sp<MediaSource> source) { + CHECK(source != NULL); if (mPrefetcher != NULL) { source = mPrefetcher->addSource(source); } + mVideoTrack = source; +} + +status_t AwesomePlayer::initVideoDecoder() { mVideoSource = OMXCodec::Create( - mClient.interface(), source->getFormat(), + mClient.interface(), mVideoTrack->getFormat(), false, // createEncoder - source); + mVideoTrack); if (mVideoSource != NULL) { int64_t durationUs; - if (source->getFormat()->findInt64(kKeyDuration, &durationUs)) { + if (mVideoTrack->getFormat()->findInt64(kKeyDuration, &durationUs)) { if (mDurationUs < 0 || durationUs > mDurationUs) { mDurationUs = durationUs; } } - CHECK(source->getFormat()->findInt32(kKeyWidth, &mVideoWidth)); - CHECK(source->getFormat()->findInt32(kKeyHeight, &mVideoHeight)); + CHECK(mVideoTrack->getFormat()->findInt32(kKeyWidth, &mVideoWidth)); + CHECK(mVideoTrack->getFormat()->findInt32(kKeyHeight, &mVideoHeight)); mVideoSource->start(); } @@ -1045,6 +1050,19 @@ status_t AwesomePlayer::finishSetDataSource_l() { return setDataSource_l(extractor); } +void AwesomePlayer::abortPrepare(status_t err) { + CHECK(err != OK); + + if (mIsAsyncPrepare) { + notifyListener_l(MEDIA_ERROR, MEDIA_ERROR_UNKNOWN, err); + } + + mPrepareResult = err; + mFlags &= ~PREPARING; + mAsyncPrepareEvent = NULL; + mPreparedCondition.broadcast(); +} + void AwesomePlayer::onPrepareAsyncEvent() { { Mutex::Autolock autoLock(mLock); @@ -1053,15 +1071,7 @@ void AwesomePlayer::onPrepareAsyncEvent() { status_t err = finishSetDataSource_l(); if (err != OK) { - if (mIsAsyncPrepare) { - notifyListener_l(MEDIA_ERROR, MEDIA_ERROR_UNKNOWN, err); - } - - mPrepareResult = err; - mFlags &= ~PREPARING; - mAsyncPrepareEvent = NULL; - mPreparedCondition.broadcast(); - + abortPrepare(err); return; } } @@ -1081,6 +1091,24 @@ void AwesomePlayer::onPrepareAsyncEvent() { Mutex::Autolock autoLock(mLock); + if (mVideoTrack != NULL && mVideoSource == NULL) { + status_t err = initVideoDecoder(); + + if (err != OK) { + abortPrepare(err); + return; + } + } + + if (mAudioTrack != NULL && mAudioSource == NULL) { + status_t err = initAudioDecoder(); + + if (err != OK) { + abortPrepare(err); + return; + } + } + if (mIsAsyncPrepare) { if (mVideoWidth < 0 || mVideoHeight < 0) { notifyListener_l(MEDIA_SET_VIDEO_SIZE, 0, 0); diff --git a/media/libstagefright/include/AwesomePlayer.h b/media/libstagefright/include/AwesomePlayer.h index 3590987d0a13..7106524afbb5 100644 --- a/media/libstagefright/include/AwesomePlayer.h +++ b/media/libstagefright/include/AwesomePlayer.h @@ -112,10 +112,12 @@ private: sp<DataSource> mFileSource; + sp<MediaSource> mVideoTrack; sp<MediaSource> mVideoSource; sp<AwesomeRenderer> mVideoRenderer; bool mVideoRendererIsPreview; + sp<MediaSource> mAudioTrack; sp<MediaSource> mAudioSource; AudioPlayer *mAudioPlayer; int64_t mDurationUs; @@ -199,8 +201,11 @@ private: void cancelPlayerEvents(bool keepBufferingGoing = false); - status_t setAudioSource(sp<MediaSource> source); - status_t setVideoSource(sp<MediaSource> source); + void setAudioSource(sp<MediaSource> source); + status_t initAudioDecoder(); + + void setVideoSource(sp<MediaSource> source); + status_t initVideoDecoder(); void onStreamDone(); @@ -210,6 +215,8 @@ private: void onBufferingUpdate(); void onCheckAudioStatus(); void onPrepareAsyncEvent(); + void abortPrepare(status_t err); + status_t finishSetDataSource_l(); AwesomePlayer(const AwesomePlayer &); diff --git a/services/java/com/android/server/DockObserver.java b/services/java/com/android/server/DockObserver.java index 28236f00b4ab..bee8872ede0a 100644 --- a/services/java/com/android/server/DockObserver.java +++ b/services/java/com/android/server/DockObserver.java @@ -16,53 +16,24 @@ package com.android.server; -import android.app.Activity; -import android.app.ActivityManagerNative; -import android.app.AlarmManager; -import android.app.IActivityManager; -import android.app.IUiModeManager; -import android.app.KeyguardManager; -import android.app.Notification; -import android.app.NotificationManager; -import android.app.PendingIntent; -import android.app.StatusBarManager; import android.bluetooth.BluetoothAdapter; import android.bluetooth.BluetoothDevice; -import android.content.ActivityNotFoundException; -import android.content.BroadcastReceiver; import android.content.ContentResolver; import android.content.Context; import android.content.Intent; -import android.content.IntentFilter; -import android.content.res.Configuration; -import android.location.Criteria; -import android.location.Location; -import android.location.LocationListener; -import android.location.LocationManager; -import android.location.LocationProvider; -import android.os.Binder; import android.media.AudioManager; import android.media.Ringtone; import android.media.RingtoneManager; import android.net.Uri; -import android.os.Bundle; import android.os.Handler; import android.os.Message; -import android.os.RemoteException; -import android.os.ServiceManager; import android.os.SystemClock; import android.os.UEventObserver; import android.provider.Settings; import android.server.BluetoothService; -import android.text.format.DateUtils; -import android.text.format.Time; import android.util.Log; import android.util.Slog; -import com.android.internal.R; -import com.android.internal.app.DisableCarModeActivity; -import com.android.internal.widget.LockPatternUtils; - import java.io.FileNotFoundException; import java.io.FileReader; @@ -76,187 +47,22 @@ class DockObserver extends UEventObserver { private static final String DOCK_UEVENT_MATCH = "DEVPATH=/devices/virtual/switch/dock"; private static final String DOCK_STATE_PATH = "/sys/class/switch/dock/state"; - private static final String KEY_LAST_UPDATE_INTERVAL = "LAST_UPDATE_INTERVAL"; - private static final int MSG_DOCK_STATE = 0; - private static final int MSG_UPDATE_TWILIGHT = 1; - private static final int MSG_ENABLE_LOCATION_UPDATES = 2; - - public static final int MODE_NIGHT_AUTO = Configuration.UI_MODE_NIGHT_MASK >> 4; - public static final int MODE_NIGHT_NO = Configuration.UI_MODE_NIGHT_NO >> 4; - public static final int MODE_NIGHT_YES = Configuration.UI_MODE_NIGHT_YES >> 4; - - private static final long LOCATION_UPDATE_MS = 30 * DateUtils.MINUTE_IN_MILLIS; - private static final float LOCATION_UPDATE_DISTANCE_METER = 1000 * 20; - private static final long LOCATION_UPDATE_ENABLE_INTERVAL_MIN = 5000; - private static final long LOCATION_UPDATE_ENABLE_INTERVAL_MAX = 5 * DateUtils.MINUTE_IN_MILLIS; - private static final double FACTOR_GMT_OFFSET_LONGITUDE = 1000.0 * 360.0 / DateUtils.DAY_IN_MILLIS; - - private static final String ACTION_UPDATE_NIGHT_MODE = "com.android.server.action.UPDATE_NIGHT_MODE"; private int mDockState = Intent.EXTRA_DOCK_STATE_UNDOCKED; private int mPreviousDockState = Intent.EXTRA_DOCK_STATE_UNDOCKED; - private int mNightMode = MODE_NIGHT_NO; - private boolean mCarModeEnabled = false; - private boolean mSystemReady; private final Context mContext; private PowerManagerService mPowerManager; - private NotificationManager mNotificationManager; - - private KeyguardManager.KeyguardLock mKeyguardLock; - private boolean mKeyguardDisabled; - private LockPatternUtils mLockPatternUtils; - - private AlarmManager mAlarmManager; - - private LocationManager mLocationManager; - private Location mLocation; - private StatusBarManager mStatusBarManager; - - // The broadcast receiver which receives the result of the ordered broadcast sent when - // the dock state changes. The original ordered broadcast is sent with an initial result - // code of RESULT_OK. If any of the registered broadcast receivers changes this value, e.g., - // to RESULT_CANCELED, then the intent to start a dock app will not be sent. - private final BroadcastReceiver mResultReceiver = new BroadcastReceiver() { - @Override - public void onReceive(Context context, Intent intent) { - if (getResultCode() != Activity.RESULT_OK) { - return; - } - - // Launch a dock activity - String category; - if (mCarModeEnabled) { - // Only launch car home when car mode is enabled. - category = Intent.CATEGORY_CAR_DOCK; - } else if (mDockState == Intent.EXTRA_DOCK_STATE_DESK) { - category = Intent.CATEGORY_DESK_DOCK; - } else { - category = null; - } - if (category != null) { - intent = new Intent(Intent.ACTION_MAIN); - intent.addCategory(category); - intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK - | Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED); - try { - mContext.startActivity(intent); - } catch (ActivityNotFoundException e) { - Slog.w(TAG, e.getCause()); - } - } - } - }; - - private final BroadcastReceiver mTwilightUpdateReceiver = new BroadcastReceiver() { - @Override - public void onReceive(Context context, Intent intent) { - if (mCarModeEnabled && mNightMode == MODE_NIGHT_AUTO) { - mHandler.sendEmptyMessage(MSG_UPDATE_TWILIGHT); - } - } - }; - - // A LocationListener to initialize the network location provider. The location updates - // are handled through the passive location provider. - private final LocationListener mEmptyLocationListener = new LocationListener() { - public void onLocationChanged(Location location) { - } - - public void onProviderDisabled(String provider) { - } - - public void onProviderEnabled(String provider) { - } - - public void onStatusChanged(String provider, int status, Bundle extras) { - } - }; - - private final LocationListener mLocationListener = new LocationListener() { - - public void onLocationChanged(Location location) { - final boolean hasMoved = hasMoved(location); - if (hasMoved || hasBetterAccuracy(location)) { - synchronized (this) { - mLocation = location; - } - if (hasMoved && mCarModeEnabled && mNightMode == MODE_NIGHT_AUTO) { - mHandler.sendEmptyMessage(MSG_UPDATE_TWILIGHT); - } - } - } - - public void onProviderDisabled(String provider) { - } - - public void onProviderEnabled(String provider) { - } - - public void onStatusChanged(String provider, int status, Bundle extras) { - } - - private boolean hasBetterAccuracy(Location location) { - if (location == null) { - return false; - } - if (mLocation == null) { - return true; - } - return location.getAccuracy() < mLocation.getAccuracy(); - } - - /* - * The user has moved if the accuracy circles of the two locations - * don't overlap. - */ - private boolean hasMoved(Location location) { - if (location == null) { - return false; - } - if (mLocation == null) { - return true; - } - - /* if new location is older than the current one, the devices hasn't - * moved. - */ - if (location.getTime() < mLocation.getTime()) { - return false; - } - - /* Get the distance between the two points */ - float distance = mLocation.distanceTo(location); - - /* Get the total accuracy radius for both locations */ - float totalAccuracy = mLocation.getAccuracy() + location.getAccuracy(); - - /* If the distance is greater than the combined accuracy of the two - * points then they can't overlap and hence the user has moved. - */ - return distance >= totalAccuracy; - } - }; public DockObserver(Context context, PowerManagerService pm) { mContext = context; mPowerManager = pm; - mLockPatternUtils = new LockPatternUtils(context); init(); // set initial status - ServiceManager.addService("uimode", mBinder); - - mAlarmManager = - (AlarmManager)mContext.getSystemService(Context.ALARM_SERVICE); - mLocationManager = - (LocationManager)mContext.getSystemService(Context.LOCATION_SERVICE); - mContext.registerReceiver(mTwilightUpdateReceiver, - new IntentFilter(ACTION_UPDATE_NIGHT_MODE)); - startObserving(DOCK_UEVENT_MATCH); } @@ -272,14 +78,6 @@ class DockObserver extends UEventObserver { if (newState != mDockState) { mPreviousDockState = mDockState; mDockState = newState; - boolean carModeEnabled = mDockState == Intent.EXTRA_DOCK_STATE_CAR; - if (mCarModeEnabled != carModeEnabled) { - try { - setCarMode(carModeEnabled); - } catch (RemoteException e1) { - Slog.w(TAG, "Unable to change car mode.", e1); - } - } if (mSystemReady) { // Don't force screen on when undocking from the desk dock. // The change in power state will do this anyway. @@ -315,24 +113,11 @@ class DockObserver extends UEventObserver { void systemReady() { synchronized (this) { - KeyguardManager keyguardManager = - (KeyguardManager)mContext.getSystemService(Context.KEYGUARD_SERVICE); - mKeyguardLock = keyguardManager.newKeyguardLock(TAG); - - final boolean enableCarMode = mDockState == Intent.EXTRA_DOCK_STATE_CAR; - if (enableCarMode) { - try { - setCarMode(enableCarMode); - } catch (RemoteException e) { - Slog.w(TAG, "Unable to change car mode.", e); - } - } // don't bother broadcasting undocked here if (mDockState != Intent.EXTRA_DOCK_STATE_UNDOCKED) { update(); } mSystemReady = true; - mHandler.sendEmptyMessage(MSG_ENABLE_LOCATION_UPDATES); } } @@ -341,10 +126,6 @@ class DockObserver extends UEventObserver { } private final Handler mHandler = new Handler() { - - boolean mPassiveListenerEnabled; - boolean mNetworkListenerEnabled; - @Override public void handleMessage(Message msg) { switch (msg.what) { @@ -362,17 +143,7 @@ class DockObserver extends UEventObserver { // Pack up the values and broadcast them to everyone Intent intent = new Intent(Intent.ACTION_DOCK_EVENT); intent.addFlags(Intent.FLAG_RECEIVER_REPLACE_PENDING); - if (mCarModeEnabled && mDockState != Intent.EXTRA_DOCK_STATE_CAR) { - // Pretend to be in DOCK_STATE_CAR. - intent.putExtra(Intent.EXTRA_DOCK_STATE, Intent.EXTRA_DOCK_STATE_CAR); - } else if (!mCarModeEnabled && mDockState == Intent.EXTRA_DOCK_STATE_CAR) { - // Pretend to be in DOCK_STATE_UNDOCKED. - intent.putExtra(Intent.EXTRA_DOCK_STATE, Intent.EXTRA_DOCK_STATE_UNDOCKED); - } else { - intent.putExtra(Intent.EXTRA_DOCK_STATE, mDockState); - } - intent.putExtra(Intent.EXTRA_PHYSICAL_DOCK_STATE, mDockState); - intent.putExtra(Intent.EXTRA_CAR_MODE_ENABLED, mCarModeEnabled); + intent.putExtra(Intent.EXTRA_DOCK_STATE, mDockState); // Check if this is Bluetooth Dock String address = BluetoothService.readDockBluetoothAddress(); @@ -415,296 +186,10 @@ class DockObserver extends UEventObserver { } } - // Send the ordered broadcast; the result receiver will receive after all - // broadcasts have been sent. If any broadcast receiver changes the result - // code from the initial value of RESULT_OK, then the result receiver will - // not launch the corresponding dock application. This gives apps a chance - // to override the behavior and stay in their app even when the device is - // placed into a dock. - mContext.sendStickyOrderedBroadcast( - intent, mResultReceiver, null, Activity.RESULT_OK, null, null); - - } - break; - case MSG_UPDATE_TWILIGHT: - synchronized (this) { - if (mCarModeEnabled && mLocation != null && mNightMode == MODE_NIGHT_AUTO) { - try { - DockObserver.this.updateTwilight(); - } catch (RemoteException e) { - Slog.w(TAG, "Unable to change night mode.", e); - } - } - } - break; - case MSG_ENABLE_LOCATION_UPDATES: - // enable passive provider to receive updates from location fixes (gps - // and network). - boolean passiveLocationEnabled; - try { - passiveLocationEnabled = - mLocationManager.isProviderEnabled(LocationManager.PASSIVE_PROVIDER); - } catch (Exception e) { - // we may get IllegalArgumentException if passive location provider - // does not exist or is not yet installed. - passiveLocationEnabled = false; - } - if (!mPassiveListenerEnabled && passiveLocationEnabled) { - mPassiveListenerEnabled = true; - mLocationManager.requestLocationUpdates(LocationManager.PASSIVE_PROVIDER, - 0, LOCATION_UPDATE_DISTANCE_METER , mLocationListener); - } - // enable network provider to receive at least location updates for a given - // distance. - boolean networkLocationEnabled; - try { - networkLocationEnabled = - mLocationManager.isProviderEnabled(LocationManager.NETWORK_PROVIDER); - } catch (Exception e) { - // we may get IllegalArgumentException if network location provider - // does not exist or is not yet installed. - networkLocationEnabled = false; - } - if (!mNetworkListenerEnabled && networkLocationEnabled) { - mNetworkListenerEnabled = true; - mLocationManager.requestLocationUpdates(LocationManager.NETWORK_PROVIDER, - LOCATION_UPDATE_MS, 0, mEmptyLocationListener); - - retrieveLocation(); - if (mCarModeEnabled && mLocation != null && mNightMode == MODE_NIGHT_AUTO) { - try { - DockObserver.this.updateTwilight(); - } catch (RemoteException e) { - Slog.w(TAG, "Unable to change night mode.", e); - } - } - } - if (!(mNetworkListenerEnabled && mPassiveListenerEnabled)) { - long interval = msg.getData().getLong(KEY_LAST_UPDATE_INTERVAL); - interval *= 1.5; - if (interval == 0) { - interval = LOCATION_UPDATE_ENABLE_INTERVAL_MIN; - } else if (interval > LOCATION_UPDATE_ENABLE_INTERVAL_MAX) { - interval = LOCATION_UPDATE_ENABLE_INTERVAL_MAX; - } - Bundle bundle = new Bundle(); - bundle.putLong(KEY_LAST_UPDATE_INTERVAL, interval); - Message newMsg = mHandler.obtainMessage(MSG_ENABLE_LOCATION_UPDATES); - newMsg.setData(bundle); - mHandler.sendMessageDelayed(newMsg, interval); + mContext.sendStickyBroadcast(intent); } break; } } - - private void retrieveLocation() { - final Location gpsLocation = - mLocationManager.getLastKnownLocation(LocationManager.GPS_PROVIDER); - Location location; - Criteria criteria = new Criteria(); - criteria.setSpeedRequired(false); - criteria.setAltitudeRequired(false); - criteria.setBearingRequired(false); - criteria.setAccuracy(Criteria.ACCURACY_FINE); - final String bestProvider = mLocationManager.getBestProvider(criteria, true); - location = mLocationManager.getLastKnownLocation(bestProvider); - // In the case there is no location available (e.g. GPS fix or network location - // is not available yet), the longitude of the location is estimated using the timezone, - // latitude and accuracy are set to get a good average. - if (location == null) { - Time currentTime = new Time(); - currentTime.set(System.currentTimeMillis()); - double lngOffset = FACTOR_GMT_OFFSET_LONGITUDE * - (currentTime.gmtoff - (currentTime.isDst > 0 ? 3600 : 0)); - location = new Location("fake"); - location.setLongitude(lngOffset); - location.setLatitude(0); - location.setAccuracy(417000.0f); - location.setTime(System.currentTimeMillis()); - } - synchronized (this) { - mLocation = location; - } - } - }; - - private void adjustStatusBarCarMode() { - if (mStatusBarManager == null) { - mStatusBarManager = (StatusBarManager) mContext.getSystemService(Context.STATUS_BAR_SERVICE); - } - - // Fear not: StatusBarService manages a list of requests to disable - // features of the status bar; these are ORed together to form the - // active disabled list. So if (for example) the device is locked and - // the status bar should be totally disabled, the calls below will - // have no effect until the device is unlocked. - if (mStatusBarManager != null) { - long ident = Binder.clearCallingIdentity(); - mStatusBarManager.disable(mCarModeEnabled - ? StatusBarManager.DISABLE_NOTIFICATION_TICKER - : StatusBarManager.DISABLE_NONE); - Binder.restoreCallingIdentity(ident); - } - - if (mNotificationManager == null) { - mNotificationManager = (NotificationManager) - mContext.getSystemService(Context.NOTIFICATION_SERVICE); - } - - if (mNotificationManager != null) { - long ident = Binder.clearCallingIdentity(); - if (mCarModeEnabled) { - Intent carModeOffIntent = new Intent(mContext, DisableCarModeActivity.class); - - Notification n = new Notification(); - n.icon = R.drawable.stat_notify_car_mode; - n.defaults = Notification.DEFAULT_LIGHTS; - n.flags = Notification.FLAG_ONGOING_EVENT; - n.when = 0; - n.setLatestEventInfo( - mContext, - mContext.getString(R.string.car_mode_disable_notification_title), - mContext.getString(R.string.car_mode_disable_notification_message), - PendingIntent.getActivity(mContext, 0, carModeOffIntent, 0)); - mNotificationManager.notify(0, n); - } else { - mNotificationManager.cancel(0); - } - Binder.restoreCallingIdentity(ident); - } - } - - private void setCarMode(boolean enabled) throws RemoteException { - mCarModeEnabled = enabled; - if (enabled) { - if (mNightMode == MODE_NIGHT_AUTO) { - updateTwilight(); - } else { - setMode(Configuration.UI_MODE_TYPE_CAR, mNightMode << 4); - } - } else { - // Disabling the car mode clears the night mode. - setMode(Configuration.UI_MODE_TYPE_NORMAL, - Configuration.UI_MODE_NIGHT_UNDEFINED); - } - adjustStatusBarCarMode(); - } - - private void setMode(int modeType, int modeNight) throws RemoteException { - long ident = Binder.clearCallingIdentity(); - final IActivityManager am = ActivityManagerNative.getDefault(); - Configuration config = am.getConfiguration(); - if (config.uiMode != (modeType | modeNight)) { - config.uiMode = modeType | modeNight; - am.updateConfiguration(config); - } - Binder.restoreCallingIdentity(ident); - } - - private void setNightMode(int mode) throws RemoteException { - if (mNightMode != mode) { - mNightMode = mode; - switch (mode) { - case MODE_NIGHT_NO: - case MODE_NIGHT_YES: - setMode(Configuration.UI_MODE_TYPE_CAR, mode << 4); - break; - case MODE_NIGHT_AUTO: - long ident = Binder.clearCallingIdentity(); - updateTwilight(); - Binder.restoreCallingIdentity(ident); - break; - default: - setMode(Configuration.UI_MODE_TYPE_CAR, MODE_NIGHT_NO << 4); - break; - } - } - } - - private void updateTwilight() throws RemoteException { - synchronized (this) { - if (mLocation == null) { - return; - } - final long currentTime = System.currentTimeMillis(); - int nightMode; - // calculate current twilight - TwilightCalculator tw = new TwilightCalculator(); - tw.calculateTwilight(currentTime, - mLocation.getLatitude(), mLocation.getLongitude()); - if (tw.mState == TwilightCalculator.DAY) { - nightMode = MODE_NIGHT_NO; - } else { - nightMode = MODE_NIGHT_YES; - } - - // schedule next update - long nextUpdate = 0; - if (tw.mSunrise == -1 || tw.mSunset == -1) { - // In the case the day or night never ends the update is scheduled 12 hours later. - nextUpdate = currentTime + 12 * DateUtils.HOUR_IN_MILLIS; - } else { - final int mLastTwilightState = tw.mState; - // add some extra time to be on the save side. - nextUpdate += DateUtils.MINUTE_IN_MILLIS; - if (currentTime > tw.mSunset) { - // next update should be on the following day - tw.calculateTwilight(currentTime - + DateUtils.DAY_IN_MILLIS, mLocation.getLatitude(), - mLocation.getLongitude()); - } - - if (mLastTwilightState == TwilightCalculator.NIGHT) { - nextUpdate += tw.mSunrise; - } else { - nextUpdate += tw.mSunset; - } - } - - Intent updateIntent = new Intent(ACTION_UPDATE_NIGHT_MODE); - PendingIntent pendingIntent = - PendingIntent.getBroadcast(mContext, 0, updateIntent, 0); - mAlarmManager.cancel(pendingIntent); - mAlarmManager.set(AlarmManager.RTC_WAKEUP, nextUpdate, pendingIntent); - - // Make sure that we really set the new mode only if we're in car mode and - // automatic switching is enables. - if (mCarModeEnabled && mNightMode == MODE_NIGHT_AUTO) { - setMode(Configuration.UI_MODE_TYPE_CAR, nightMode << 4); - } - } - } - - /** - * Wrapper class implementing the IUiModeManager interface. - */ - private final IUiModeManager.Stub mBinder = new IUiModeManager.Stub() { - - public void disableCarMode() throws RemoteException { - if (mCarModeEnabled) { - setCarMode(false); - update(); - } - } - - public void enableCarMode() throws RemoteException { - mContext.enforceCallingOrSelfPermission( - android.Manifest.permission.ENABLE_CAR_MODE, - "Need ENABLE_CAR_MODE permission"); - if (!mCarModeEnabled) { - setCarMode(true); - update(); - } - } - - public void setNightMode(int mode) throws RemoteException { - if (mCarModeEnabled) { - DockObserver.this.setNightMode(mode); - } - } - - public int getNightMode() throws RemoteException { - return mNightMode; - } }; } diff --git a/services/java/com/android/server/PackageManagerService.java b/services/java/com/android/server/PackageManagerService.java index 664f02889229..9e11546d5f7d 100644 --- a/services/java/com/android/server/PackageManagerService.java +++ b/services/java/com/android/server/PackageManagerService.java @@ -540,6 +540,7 @@ class PackageManagerService extends IPackageManager.Stub { if (DEBUG_INSTALL) Log.v(TAG, "Handling post-install for " + msg.arg1); PostInstallData data = mRunningInstalls.get(msg.arg1); mRunningInstalls.delete(msg.arg1); + boolean deleteOld = false; if (data != null) { InstallArgs args = data.args; @@ -563,13 +564,17 @@ class PackageManagerService extends IPackageManager.Stub { } if (res.removedInfo.args != null) { // Remove the replaced package's older resources safely now - synchronized (mInstallLock) { - res.removedInfo.args.doPostDeleteLI(true); - } + deleteOld = true; } } + // Force a gc to clear up things Runtime.getRuntime().gc(); - + // We delete after a gc for applications on sdcard. + if (deleteOld) { + synchronized (mInstallLock) { + res.removedInfo.args.doPostDeleteLI(true); + } + } if (args.observer != null) { try { args.observer.packageInstalled(res.name, res.returnCode); @@ -1350,6 +1355,10 @@ class PackageManagerService extends IPackageManager.Stub { if(ps.pkg == null) { ps.pkg = new PackageParser.Package(packageName); ps.pkg.applicationInfo.packageName = packageName; + ps.pkg.applicationInfo.flags = ps.pkgFlags; + ps.pkg.applicationInfo.publicSourceDir = ps.resourcePathString; + ps.pkg.applicationInfo.sourceDir = ps.codePathString; + ps.pkg.applicationInfo.dataDir = getDataPathForPackage(ps.pkg).getPath(); } return generatePackageInfo(ps.pkg, flags); } @@ -2567,6 +2576,17 @@ class PackageManagerService extends IPackageManager.Stub { } return true; } + + private File getDataPathForPackage(PackageParser.Package pkg) { + boolean useEncryptedFSDir = useEncryptedFilesystemForPackage(pkg); + File dataPath; + if (useEncryptedFSDir) { + dataPath = new File(mSecureAppDataDir, pkg.packageName); + } else { + dataPath = new File(mAppDataDir, pkg.packageName); + } + return dataPath; + } private PackageParser.Package scanPackageLI(PackageParser.Package pkg, int parseFlags, int scanMode) { @@ -2932,11 +2952,7 @@ class PackageManagerService extends IPackageManager.Stub { } else { // This is a normal package, need to make its data directory. boolean useEncryptedFSDir = useEncryptedFilesystemForPackage(pkg); - if (useEncryptedFSDir) { - dataPath = new File(mSecureAppDataDir, pkgName); - } else { - dataPath = new File(mAppDataDir, pkgName); - } + dataPath = getDataPathForPackage(pkg); boolean uidError = false; @@ -5159,14 +5175,9 @@ class PackageManagerService extends IPackageManager.Stub { int scanMode, String installerPackageName, PackageInstalledInfo res) { // Remember this for later, in case we need to rollback this install - boolean dataDirExists; String pkgName = pkg.packageName; - if (useEncryptedFilesystemForPackage(pkg)) { - dataDirExists = (new File(mSecureAppDataDir, pkgName)).exists(); - } else { - dataDirExists = (new File(mAppDataDir, pkgName)).exists(); - } + boolean dataDirExists = getDataPathForPackage(pkg).exists(); res.name = pkgName; synchronized(mPackages) { if (mPackages.containsKey(pkgName) || mAppDirs.containsKey(pkg.mPath)) { @@ -5741,6 +5752,8 @@ class PackageManagerService extends IPackageManager.Stub { sendPackageBroadcast(Intent.ACTION_PACKAGE_REPLACED, packageName, extras); } } + // Force a gc here. + Runtime.getRuntime().gc(); // Delete the resources here after sending the broadcast to let // other processes clean up before deleting resources. if (info.args != null) { @@ -7136,7 +7149,8 @@ class PackageManagerService extends IPackageManager.Stub { void setFlags(int pkgFlags) { this.pkgFlags = (pkgFlags & ApplicationInfo.FLAG_SYSTEM) | (pkgFlags & ApplicationInfo.FLAG_FORWARD_LOCK) | - (pkgFlags & ApplicationInfo.FLAG_ON_SDCARD); + (pkgFlags & ApplicationInfo.FLAG_ON_SDCARD) | + (pkgFlags & ApplicationInfo.FLAG_NEVER_ENCRYPT); } } diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java index deee7f376221..b023958101da 100644 --- a/services/java/com/android/server/SystemServer.java +++ b/services/java/com/android/server/SystemServer.java @@ -97,6 +97,7 @@ class ServerThread extends Thread { BluetoothA2dpService bluetoothA2dp = null; HeadsetObserver headset = null; DockObserver dock = null; + UiModeManagerService uiMode = null; RecognitionManagerService recognition = null; // Critical services... @@ -363,6 +364,14 @@ class ServerThread extends Thread { } try { + Slog.i(TAG, "UI Mode Manager Service"); + // Listen for dock station changes + uiMode = new UiModeManagerService(context); + } catch (Throwable e) { + Slog.e(TAG, "Failure starting UiModeManagerService", e); + } + + try { Slog.i(TAG, "Backup Service"); ServiceManager.addService(Context.BACKUP_SERVICE, new BackupManagerService(context)); @@ -441,6 +450,7 @@ class ServerThread extends Thread { final BatteryService batteryF = battery; final ConnectivityService connectivityF = connectivity; final DockObserver dockF = dock; + final UiModeManagerService uiModeF = uiMode; final AppWidgetService appWidgetF = appWidget; final WallpaperManagerService wallpaperF = wallpaper; final InputMethodManagerService immF = imm; @@ -460,6 +470,7 @@ class ServerThread extends Thread { if (batteryF != null) batteryF.systemReady(); if (connectivityF != null) connectivityF.systemReady(); if (dockF != null) dockF.systemReady(); + if (uiModeF != null) uiModeF.systemReady(); if (recognitionF != null) recognitionF.systemReady(); Watchdog.getInstance().start(); diff --git a/services/java/com/android/server/UiModeManagerService.java b/services/java/com/android/server/UiModeManagerService.java new file mode 100644 index 000000000000..e225edb7c280 --- /dev/null +++ b/services/java/com/android/server/UiModeManagerService.java @@ -0,0 +1,629 @@ +/* + * Copyright (C) 2008 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.server; + +import android.app.Activity; +import android.app.ActivityManagerNative; +import android.app.AlarmManager; +import android.app.IActivityManager; +import android.app.IUiModeManager; +import android.app.Notification; +import android.app.NotificationManager; +import android.app.PendingIntent; +import android.app.StatusBarManager; +import android.app.UiModeManager; +import android.content.ActivityNotFoundException; +import android.content.BroadcastReceiver; +import android.content.Context; +import android.content.Intent; +import android.content.IntentFilter; +import android.content.pm.PackageManager; +import android.content.res.Configuration; +import android.location.Criteria; +import android.location.Location; +import android.location.LocationListener; +import android.location.LocationManager; +import android.os.Binder; +import android.os.Bundle; +import android.os.Handler; +import android.os.Message; +import android.os.RemoteException; +import android.os.ServiceManager; +import android.text.format.DateUtils; +import android.text.format.Time; +import android.util.Slog; + +import java.io.FileDescriptor; +import java.io.PrintWriter; + +import com.android.internal.R; +import com.android.internal.app.DisableCarModeActivity; + +class UiModeManagerService extends IUiModeManager.Stub { + private static final String TAG = UiModeManager.class.getSimpleName(); + private static final boolean LOG = false; + + private static final String KEY_LAST_UPDATE_INTERVAL = "LAST_UPDATE_INTERVAL"; + + private static final int MSG_UPDATE_TWILIGHT = 0; + private static final int MSG_ENABLE_LOCATION_UPDATES = 1; + + private static final long LOCATION_UPDATE_MS = 30 * DateUtils.MINUTE_IN_MILLIS; + private static final float LOCATION_UPDATE_DISTANCE_METER = 1000 * 20; + private static final long LOCATION_UPDATE_ENABLE_INTERVAL_MIN = 5000; + private static final long LOCATION_UPDATE_ENABLE_INTERVAL_MAX = 5 * DateUtils.MINUTE_IN_MILLIS; + private static final double FACTOR_GMT_OFFSET_LONGITUDE = 1000.0 * 360.0 / DateUtils.DAY_IN_MILLIS; + + private static final String ACTION_UPDATE_NIGHT_MODE = "com.android.server.action.UPDATE_NIGHT_MODE"; + + private final Context mContext; + + final Object mLock = new Object(); + + private int mDockState = Intent.EXTRA_DOCK_STATE_UNDOCKED; + private int mLastBroadcastState = Intent.EXTRA_DOCK_STATE_UNDOCKED; + + private int mNightMode = UiModeManager.MODE_NIGHT_NO; + private boolean mCarModeEnabled = false; + + private boolean mComputedNightMode; + private int mCurUiMode = 0; + + private Configuration mConfiguration = new Configuration(); + + private boolean mSystemReady; + + private NotificationManager mNotificationManager; + + private AlarmManager mAlarmManager; + + private LocationManager mLocationManager; + private Location mLocation; + private StatusBarManager mStatusBarManager; + + // The broadcast receiver which receives the result of the ordered broadcast sent when + // the dock state changes. The original ordered broadcast is sent with an initial result + // code of RESULT_OK. If any of the registered broadcast receivers changes this value, e.g., + // to RESULT_CANCELED, then the intent to start a dock app will not be sent. + private final BroadcastReceiver mResultReceiver = new BroadcastReceiver() { + @Override + public void onReceive(Context context, Intent intent) { + if (getResultCode() != Activity.RESULT_OK) { + return; + } + + // Launch a dock activity + String category; + if (UiModeManager.ACTION_ENTER_CAR_MODE.equals(intent.getAction())) { + // Only launch car home when car mode is enabled. + category = Intent.CATEGORY_CAR_DOCK; + } else if (UiModeManager.ACTION_ENTER_DESK_MODE.equals(intent.getAction())) { + category = Intent.CATEGORY_DESK_DOCK; + } else { + category = null; + } + if (category != null) { + intent = new Intent(Intent.ACTION_MAIN); + intent.addCategory(category); + intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK + | Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED); + try { + mContext.startActivity(intent); + } catch (ActivityNotFoundException e) { + Slog.w(TAG, e.getCause()); + } + } + } + }; + + private final BroadcastReceiver mTwilightUpdateReceiver = new BroadcastReceiver() { + @Override + public void onReceive(Context context, Intent intent) { + if (isDoingNightMode() && mNightMode == UiModeManager.MODE_NIGHT_AUTO) { + mHandler.sendEmptyMessage(MSG_UPDATE_TWILIGHT); + } + } + }; + + private final BroadcastReceiver mDockModeReceiver = new BroadcastReceiver() { + @Override + public void onReceive(Context context, Intent intent) { + int state = intent.getIntExtra(Intent.EXTRA_DOCK_STATE, + Intent.EXTRA_DOCK_STATE_UNDOCKED); + updateDockState(state); + } + }; + + // A LocationListener to initialize the network location provider. The location updates + // are handled through the passive location provider. + private final LocationListener mEmptyLocationListener = new LocationListener() { + public void onLocationChanged(Location location) { + } + + public void onProviderDisabled(String provider) { + } + + public void onProviderEnabled(String provider) { + } + + public void onStatusChanged(String provider, int status, Bundle extras) { + } + }; + + private final LocationListener mLocationListener = new LocationListener() { + + public void onLocationChanged(Location location) { + final boolean hasMoved = hasMoved(location); + final boolean hasBetterAccuracy = mLocation == null + || location.getAccuracy() < mLocation.getAccuracy(); + if (hasMoved || hasBetterAccuracy) { + synchronized (mLock) { + mLocation = location; + if (hasMoved && isDoingNightMode() + && mNightMode == UiModeManager.MODE_NIGHT_AUTO) { + mHandler.sendEmptyMessage(MSG_UPDATE_TWILIGHT); + } + } + } + } + + public void onProviderDisabled(String provider) { + } + + public void onProviderEnabled(String provider) { + } + + public void onStatusChanged(String provider, int status, Bundle extras) { + } + + /* + * The user has moved if the accuracy circles of the two locations + * don't overlap. + */ + private boolean hasMoved(Location location) { + if (location == null) { + return false; + } + if (mLocation == null) { + return true; + } + + /* if new location is older than the current one, the devices hasn't + * moved. + */ + if (location.getTime() < mLocation.getTime()) { + return false; + } + + /* Get the distance between the two points */ + float distance = mLocation.distanceTo(location); + + /* Get the total accuracy radius for both locations */ + float totalAccuracy = mLocation.getAccuracy() + location.getAccuracy(); + + /* If the distance is greater than the combined accuracy of the two + * points then they can't overlap and hence the user has moved. + */ + return distance >= totalAccuracy; + } + }; + + public UiModeManagerService(Context context) { + mContext = context; + + ServiceManager.addService(Context.UI_MODE_SERVICE, this); + + mAlarmManager = + (AlarmManager)mContext.getSystemService(Context.ALARM_SERVICE); + mLocationManager = + (LocationManager)mContext.getSystemService(Context.LOCATION_SERVICE); + mContext.registerReceiver(mTwilightUpdateReceiver, + new IntentFilter(ACTION_UPDATE_NIGHT_MODE)); + mContext.registerReceiver(mDockModeReceiver, + new IntentFilter(Intent.ACTION_DOCK_EVENT)); + + mConfiguration.setToDefaults(); + } + + public void disableCarMode() { + synchronized (mLock) { + setCarModeLocked(false); + } + } + + public void enableCarMode() { + mContext.enforceCallingOrSelfPermission( + android.Manifest.permission.ENABLE_CAR_MODE, + "Need ENABLE_CAR_MODE permission"); + synchronized (mLock) { + setCarModeLocked(true); + } + } + + public int getCurrentModeType() { + synchronized (mLock) { + return mCurUiMode & Configuration.UI_MODE_TYPE_MASK; + } + } + + public void setNightMode(int mode) throws RemoteException { + synchronized (mLock) { + switch (mode) { + case UiModeManager.MODE_NIGHT_NO: + case UiModeManager.MODE_NIGHT_YES: + case UiModeManager.MODE_NIGHT_AUTO: + break; + default: + throw new IllegalArgumentException("Unknown mode: " + mode); + } + if (!isDoingNightMode()) { + return; + } + + if (mNightMode != mode) { + mNightMode = mode; + updateLocked(); + } + } + } + + public int getNightMode() throws RemoteException { + return mNightMode; + } + + void systemReady() { + synchronized (mLock) { + mSystemReady = true; + mCarModeEnabled = mDockState == Intent.EXTRA_DOCK_STATE_CAR; + updateLocked(); + mHandler.sendEmptyMessage(MSG_ENABLE_LOCATION_UPDATES); + } + } + + boolean isDoingNightMode() { + return mCarModeEnabled || mDockState != Intent.EXTRA_DOCK_STATE_UNDOCKED; + } + + void setCarModeLocked(boolean enabled) { + if (mCarModeEnabled != enabled) { + mCarModeEnabled = enabled; + updateLocked(); + } + } + + void updateDockState(int newState) { + synchronized (mLock) { + if (newState != mDockState) { + mDockState = newState; + mCarModeEnabled = mDockState == Intent.EXTRA_DOCK_STATE_CAR; + if (mSystemReady) { + updateLocked(); + } + } + } + } + + final void updateLocked() { + long ident = Binder.clearCallingIdentity(); + + try { + int uiMode = 0; + if (mCarModeEnabled) { + uiMode = Configuration.UI_MODE_TYPE_CAR; + } else if (mDockState == Intent.EXTRA_DOCK_STATE_DESK) { + uiMode = Configuration.UI_MODE_TYPE_DESK; + } + if (uiMode != 0) { + if (mNightMode == UiModeManager.MODE_NIGHT_AUTO) { + updateTwilightLocked(); + uiMode |= mComputedNightMode ? Configuration.UI_MODE_NIGHT_YES + : Configuration.UI_MODE_NIGHT_NO; + } else { + uiMode |= mNightMode << 4; + } + } else { + // Disabling the car mode clears the night mode. + uiMode = Configuration.UI_MODE_TYPE_NORMAL | + Configuration.UI_MODE_NIGHT_NO; + } + + if (uiMode != mCurUiMode) { + mCurUiMode = uiMode; + + try { + final IActivityManager am = ActivityManagerNative.getDefault(); + mConfiguration.uiMode = uiMode; + am.updateConfiguration(mConfiguration); + } catch (RemoteException e) { + Slog.w(TAG, "Failure communicating with activity manager", e); + } + } + + String action = null; + String oldAction = null; + if (mLastBroadcastState == Intent.EXTRA_DOCK_STATE_CAR) { + oldAction = UiModeManager.ACTION_EXIT_CAR_MODE; + } else if (mLastBroadcastState == Intent.EXTRA_DOCK_STATE_DESK) { + oldAction = UiModeManager.ACTION_EXIT_DESK_MODE; + } + + if (mCarModeEnabled) { + if (mLastBroadcastState != Intent.EXTRA_DOCK_STATE_CAR) { + adjustStatusBarCarModeLocked(); + + if (oldAction != null) { + mContext.sendBroadcast(new Intent(oldAction)); + } + mLastBroadcastState = Intent.EXTRA_DOCK_STATE_CAR; + action = UiModeManager.ACTION_ENTER_CAR_MODE; + } + } else if (mDockState == Intent.EXTRA_DOCK_STATE_DESK) { + if (mLastBroadcastState != Intent.EXTRA_DOCK_STATE_DESK) { + if (oldAction != null) { + mContext.sendBroadcast(new Intent(oldAction)); + } + mLastBroadcastState = Intent.EXTRA_DOCK_STATE_DESK; + action = UiModeManager.ACTION_ENTER_DESK_MODE; + } + } else { + if (mLastBroadcastState == Intent.EXTRA_DOCK_STATE_CAR) { + adjustStatusBarCarModeLocked(); + } + + mLastBroadcastState = Intent.EXTRA_DOCK_STATE_UNDOCKED; + action = oldAction; + } + + if (action != null) { + // Send the ordered broadcast; the result receiver will receive after all + // broadcasts have been sent. If any broadcast receiver changes the result + // code from the initial value of RESULT_OK, then the result receiver will + // not launch the corresponding dock application. This gives apps a chance + // to override the behavior and stay in their app even when the device is + // placed into a dock. + mContext.sendOrderedBroadcast(new Intent(action), null, + mResultReceiver, null, Activity.RESULT_OK, null, null); + } + } finally { + Binder.restoreCallingIdentity(ident); + } + } + + private void adjustStatusBarCarModeLocked() { + if (mStatusBarManager == null) { + mStatusBarManager = (StatusBarManager) mContext.getSystemService(Context.STATUS_BAR_SERVICE); + } + + // Fear not: StatusBarService manages a list of requests to disable + // features of the status bar; these are ORed together to form the + // active disabled list. So if (for example) the device is locked and + // the status bar should be totally disabled, the calls below will + // have no effect until the device is unlocked. + if (mStatusBarManager != null) { + mStatusBarManager.disable(mCarModeEnabled + ? StatusBarManager.DISABLE_NOTIFICATION_TICKER + : StatusBarManager.DISABLE_NONE); + } + + if (mNotificationManager == null) { + mNotificationManager = (NotificationManager) + mContext.getSystemService(Context.NOTIFICATION_SERVICE); + } + + if (mNotificationManager != null) { + if (mCarModeEnabled) { + Intent carModeOffIntent = new Intent(mContext, DisableCarModeActivity.class); + + Notification n = new Notification(); + n.icon = R.drawable.stat_notify_car_mode; + n.defaults = Notification.DEFAULT_LIGHTS; + n.flags = Notification.FLAG_ONGOING_EVENT; + n.when = 0; + n.setLatestEventInfo( + mContext, + mContext.getString(R.string.car_mode_disable_notification_title), + mContext.getString(R.string.car_mode_disable_notification_message), + PendingIntent.getActivity(mContext, 0, carModeOffIntent, 0)); + mNotificationManager.notify(0, n); + } else { + mNotificationManager.cancel(0); + } + } + } + + private final Handler mHandler = new Handler() { + + boolean mPassiveListenerEnabled; + boolean mNetworkListenerEnabled; + + @Override + public void handleMessage(Message msg) { + switch (msg.what) { + case MSG_UPDATE_TWILIGHT: + synchronized (mLock) { + if (isDoingNightMode() && mLocation != null + && mNightMode == UiModeManager.MODE_NIGHT_AUTO) { + updateTwilightLocked(); + updateLocked(); + } + } + break; + case MSG_ENABLE_LOCATION_UPDATES: + // enable network provider to receive at least location updates for a given + // distance. + boolean networkLocationEnabled; + try { + networkLocationEnabled = + mLocationManager.isProviderEnabled(LocationManager.NETWORK_PROVIDER); + } catch (Exception e) { + // we may get IllegalArgumentException if network location provider + // does not exist or is not yet installed. + networkLocationEnabled = false; + } + if (!mNetworkListenerEnabled && networkLocationEnabled) { + mNetworkListenerEnabled = true; + mLocationManager.requestLocationUpdates(LocationManager.NETWORK_PROVIDER, + LOCATION_UPDATE_MS, 0, mEmptyLocationListener); + + if (mLocation == null) { + retrieveLocation(); + } + synchronized (mLock) { + if (isDoingNightMode() && mLocation != null + && mNightMode == UiModeManager.MODE_NIGHT_AUTO) { + updateTwilightLocked(); + updateLocked(); + } + } + } + // enable passive provider to receive updates from location fixes (gps + // and network). + boolean passiveLocationEnabled; + try { + passiveLocationEnabled = + mLocationManager.isProviderEnabled(LocationManager.PASSIVE_PROVIDER); + } catch (Exception e) { + // we may get IllegalArgumentException if passive location provider + // does not exist or is not yet installed. + passiveLocationEnabled = false; + } + if (!mPassiveListenerEnabled && passiveLocationEnabled) { + mPassiveListenerEnabled = true; + mLocationManager.requestLocationUpdates(LocationManager.PASSIVE_PROVIDER, + 0, LOCATION_UPDATE_DISTANCE_METER , mLocationListener); + } + if (!(mNetworkListenerEnabled && mPassiveListenerEnabled)) { + long interval = msg.getData().getLong(KEY_LAST_UPDATE_INTERVAL); + interval *= 1.5; + if (interval == 0) { + interval = LOCATION_UPDATE_ENABLE_INTERVAL_MIN; + } else if (interval > LOCATION_UPDATE_ENABLE_INTERVAL_MAX) { + interval = LOCATION_UPDATE_ENABLE_INTERVAL_MAX; + } + Bundle bundle = new Bundle(); + bundle.putLong(KEY_LAST_UPDATE_INTERVAL, interval); + Message newMsg = mHandler.obtainMessage(MSG_ENABLE_LOCATION_UPDATES); + newMsg.setData(bundle); + mHandler.sendMessageDelayed(newMsg, interval); + } + break; + } + } + + private void retrieveLocation() { + Location location; + Criteria criteria = new Criteria(); + criteria.setSpeedRequired(false); + criteria.setAltitudeRequired(false); + criteria.setBearingRequired(false); + criteria.setAccuracy(Criteria.ACCURACY_FINE); + final String bestProvider = mLocationManager.getBestProvider(criteria, true); + location = mLocationManager.getLastKnownLocation(bestProvider); + // In the case there is no location available (e.g. GPS fix or network location + // is not available yet), the longitude of the location is estimated using the timezone, + // latitude and accuracy are set to get a good average. + if (location == null) { + Time currentTime = new Time(); + currentTime.set(System.currentTimeMillis()); + double lngOffset = FACTOR_GMT_OFFSET_LONGITUDE * + (currentTime.gmtoff - (currentTime.isDst > 0 ? 3600 : 0)); + location = new Location("fake"); + location.setLongitude(lngOffset); + location.setLatitude(0); + location.setAccuracy(417000.0f); + location.setTime(System.currentTimeMillis()); + } + synchronized (mLock) { + mLocation = location; + } + } + }; + + void updateTwilightLocked() { + if (mLocation == null) { + return; + } + final long currentTime = System.currentTimeMillis(); + boolean nightMode; + // calculate current twilight + TwilightCalculator tw = new TwilightCalculator(); + tw.calculateTwilight(currentTime, + mLocation.getLatitude(), mLocation.getLongitude()); + if (tw.mState == TwilightCalculator.DAY) { + nightMode = false; + } else { + nightMode = true; + } + + // schedule next update + long nextUpdate = 0; + if (tw.mSunrise == -1 || tw.mSunset == -1) { + // In the case the day or night never ends the update is scheduled 12 hours later. + nextUpdate = currentTime + 12 * DateUtils.HOUR_IN_MILLIS; + } else { + final int mLastTwilightState = tw.mState; + // add some extra time to be on the save side. + nextUpdate += DateUtils.MINUTE_IN_MILLIS; + if (currentTime > tw.mSunset) { + // next update should be on the following day + tw.calculateTwilight(currentTime + + DateUtils.DAY_IN_MILLIS, mLocation.getLatitude(), + mLocation.getLongitude()); + } + + if (mLastTwilightState == TwilightCalculator.NIGHT) { + nextUpdate += tw.mSunrise; + } else { + nextUpdate += tw.mSunset; + } + } + + Intent updateIntent = new Intent(ACTION_UPDATE_NIGHT_MODE); + PendingIntent pendingIntent = + PendingIntent.getBroadcast(mContext, 0, updateIntent, 0); + mAlarmManager.cancel(pendingIntent); + mAlarmManager.set(AlarmManager.RTC_WAKEUP, nextUpdate, pendingIntent); + + mComputedNightMode = nightMode; + } + + @Override + protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) { + if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DUMP) + != PackageManager.PERMISSION_GRANTED) { + + pw.println("Permission Denial: can't dump uimode service from from pid=" + + Binder.getCallingPid() + + ", uid=" + Binder.getCallingUid()); + return; + } + + synchronized (mLock) { + pw.println("Current UI Mode Service state:"); + pw.print(" mDockState="); pw.print(mDockState); + pw.print(" mLastBroadcastState="); pw.println(mLastBroadcastState); + pw.print(" mNightMode="); pw.print(mNightMode); + pw.print(" mCarModeEnabled="); pw.print(mCarModeEnabled); + pw.print(" mComputedNightMode="); pw.println(mComputedNightMode); + pw.print(" mCurUiMode=0x"); pw.print(Integer.toHexString(mCurUiMode)); + pw.print(" mSystemReady="); pw.println(mSystemReady); + if (mLocation != null) { + pw.print(" mLocation="); pw.println(mLocation); + } + } + } +} diff --git a/tools/aapt/AaptAssets.cpp b/tools/aapt/AaptAssets.cpp index 6e7a66da75ba..fc655a7abbb7 100644 --- a/tools/aapt/AaptAssets.cpp +++ b/tools/aapt/AaptAssets.cpp @@ -820,7 +820,12 @@ bool AaptGroupEntry::getUiModeTypeName(const char* name, if (strcmp(name, kWildcardName) == 0) { if (out) out->uiMode = (out->uiMode&~ResTable_config::MASK_UI_MODE_TYPE) - | ResTable_config::UI_MODE_TYPE_NORMAL; + | ResTable_config::UI_MODE_TYPE_ANY; + return true; + } else if (strcmp(name, "desk") == 0) { + if (out) out->uiMode = + (out->uiMode&~ResTable_config::MASK_UI_MODE_TYPE) + | ResTable_config::UI_MODE_TYPE_DESK; return true; } else if (strcmp(name, "car") == 0) { if (out) out->uiMode = diff --git a/tools/aapt/Resource.cpp b/tools/aapt/Resource.cpp index ea021d82e4da..b7580b33c723 100644 --- a/tools/aapt/Resource.cpp +++ b/tools/aapt/Resource.cpp @@ -447,7 +447,7 @@ static void checkForIds(const String8& path, ResXMLParser& parser) static bool applyFileOverlay(Bundle *bundle, const sp<AaptAssets>& assets, - const sp<ResourceTypeSet>& baseSet, + sp<ResourceTypeSet> *baseSet, const char *resType) { if (bundle->getVerbose()) { @@ -475,13 +475,16 @@ static bool applyFileOverlay(Bundle *bundle, if (bundle->getVerbose()) { printf("trying overlaySet Key=%s\n",overlaySet->keyAt(overlayIndex).string()); } - size_t baseIndex = baseSet->indexOfKey(overlaySet->keyAt(overlayIndex)); + size_t baseIndex = UNKNOWN_ERROR; + if (baseSet->get() != NULL) { + baseIndex = (*baseSet)->indexOfKey(overlaySet->keyAt(overlayIndex)); + } if (baseIndex < UNKNOWN_ERROR) { // look for same flavor. For a given file (strings.xml, for example) // there may be a locale specific or other flavors - we want to match // the same flavor. sp<AaptGroup> overlayGroup = overlaySet->valueAt(overlayIndex); - sp<AaptGroup> baseGroup = baseSet->valueAt(baseIndex); + sp<AaptGroup> baseGroup = (*baseSet)->valueAt(baseIndex); DefaultKeyedVector<AaptGroupEntry, sp<AaptFile> > overlayFiles = overlayGroup->getFiles(); @@ -520,8 +523,12 @@ static bool applyFileOverlay(Bundle *bundle, assets->addGroupEntry(overlayFiles.keyAt(overlayGroupIndex)); } } else { + if (baseSet->get() == NULL) { + *baseSet = new ResourceTypeSet(); + assets->getResources()->add(String8(resType), *baseSet); + } // this group doesn't exist (a file that's only in the overlay) - baseSet->add(overlaySet->keyAt(overlayIndex), + (*baseSet)->add(overlaySet->keyAt(overlayIndex), overlaySet->valueAt(overlayIndex)); // make sure all flavors are defined in the resources. sp<AaptGroup> overlayGroup = overlaySet->valueAt(overlayIndex); @@ -751,13 +758,13 @@ status_t buildResources(Bundle* bundle, const sp<AaptAssets>& assets) current = current->getOverlay(); } // apply the overlay files to the base set - if (!applyFileOverlay(bundle, assets, drawables, "drawable") || - !applyFileOverlay(bundle, assets, layouts, "layout") || - !applyFileOverlay(bundle, assets, anims, "anim") || - !applyFileOverlay(bundle, assets, xmls, "xml") || - !applyFileOverlay(bundle, assets, raws, "raw") || - !applyFileOverlay(bundle, assets, colors, "color") || - !applyFileOverlay(bundle, assets, menus, "menu")) { + if (!applyFileOverlay(bundle, assets, &drawables, "drawable") || + !applyFileOverlay(bundle, assets, &layouts, "layout") || + !applyFileOverlay(bundle, assets, &anims, "anim") || + !applyFileOverlay(bundle, assets, &xmls, "xml") || + !applyFileOverlay(bundle, assets, &raws, "raw") || + !applyFileOverlay(bundle, assets, &colors, "color") || + !applyFileOverlay(bundle, assets, &menus, "menu")) { return UNKNOWN_ERROR; } |