diff options
author | Tobias Haamel <haamel@google.com> | 2010-02-09 23:09:17 +0100 |
---|---|---|
committer | Tobias Haamel <haamel@google.com> | 2010-02-11 21:25:58 +0100 |
commit | 27b28b3f62bd3b54fa13acd5d035940b9be464f3 (patch) | |
tree | d1f44096f7071bbc53e5bc979117be8e0f4aa55c | |
parent | d5663a108760de672b130ffabd4f6632982f75e5 (diff) | |
download | frameworks_base-27b28b3f62bd3b54fa13acd5d035940b9be464f3.zip frameworks_base-27b28b3f62bd3b54fa13acd5d035940b9be464f3.tar.gz frameworks_base-27b28b3f62bd3b54fa13acd5d035940b9be464f3.tar.bz2 |
Introduce special UI modes for night and car usage.
The device mode is now called ui mode. Furthermore is the order of
precedence for the resources now in such a way that the ui mode needs
to be specified after the orientation and before the density.
The ui mode can be set, like it is done for the locale, as follows:
IActivityManager am = ActivityManagerNative.getDefault();
Configuration config = am.getConfiguration();
config.uiMode = Configuration.UI_MODE_TYPE_CAR | Configuration.UI_MODE_NIGHT_ANY;
am.updateConfiguration(config);
To allow users to disable the car mode and set the night mode the IUiModeManager
interface is used.
The automatic night mode switching will be added in a separate change.
-rw-r--r-- | Android.mk | 1 | ||||
-rw-r--r-- | api/current.xml | 11 | ||||
-rw-r--r-- | core/java/android/app/IUiModeManager.aidl | 49 | ||||
-rw-r--r-- | core/java/android/content/Intent.java | 10 | ||||
-rw-r--r-- | core/java/android/content/pm/ActivityInfo.java | 7 | ||||
-rw-r--r-- | core/java/android/content/res/AssetManager.java | 2 | ||||
-rw-r--r-- | core/java/android/content/res/Configuration.java | 51 | ||||
-rw-r--r-- | core/java/android/content/res/Resources.java | 2 | ||||
-rw-r--r-- | core/jni/android_util_AssetManager.cpp | 6 | ||||
-rw-r--r-- | core/res/AndroidManifest.xml | 8 | ||||
-rw-r--r-- | core/res/res/values/strings.xml | 6 | ||||
-rw-r--r-- | include/utils/ResourceTypes.h | 85 | ||||
-rw-r--r-- | services/java/com/android/server/DockObserver.java | 120 | ||||
-rw-r--r-- | tools/aapt/AaptAssets.cpp | 100 | ||||
-rw-r--r-- | tools/aapt/AaptAssets.h | 6 | ||||
-rw-r--r-- | tools/aapt/Resource.cpp | 4 | ||||
-rw-r--r-- | tools/aapt/ResourceTable.cpp | 12 | ||||
-rw-r--r-- | tools/layoutlib/bridge/src/com/android/layoutlib/bridge/BridgeAssetManager.java | 3 |
18 files changed, 444 insertions, 39 deletions
@@ -90,6 +90,7 @@ LOCAL_SRC_FILES += \ core/java/android/app/IStatusBar.aidl \ core/java/android/app/IThumbnailReceiver.aidl \ core/java/android/app/ITransientNotification.aidl \ + core/java/android/app/IUiModeManager.aidl \ core/java/android/app/IWallpaperManager.aidl \ core/java/android/app/IWallpaperManagerCallback.aidl \ core/java/android/backup/IBackupManager.aidl \ diff --git a/api/current.xml b/api/current.xml index ab5a114..b2a2bc1 100644 --- a/api/current.xml +++ b/api/current.xml @@ -38037,6 +38037,17 @@ 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" diff --git a/core/java/android/app/IUiModeManager.aidl b/core/java/android/app/IUiModeManager.aidl new file mode 100644 index 0000000..6ac8a2a --- /dev/null +++ b/core/java/android/app/IUiModeManager.aidl @@ -0,0 +1,49 @@ +/* + * 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 android.app; + +/** + * Interface used to control special UI modes. + * @hide + */ +interface IUiModeManager { + /** + * Enables the car mode. Only the system can do this. + * @hide + */ + void enableCarMode(); + + /** + * Disables the car mode. + */ + void disableCarMode(); + + /** + * Sets the night mode. + * The mode can be one of: + * 1 - notnight mode + * 2 - night mode + * 3 - automatic mode switching + */ + void setNightMode(int mode); + + /** + * Gets the currently configured night mode. Return 1 for notnight, + * 2 for night, and 3 for automatic mode switching. + */ + int getNightMode(); +} diff --git a/core/java/android/content/Intent.java b/core/java/android/content/Intent.java index c32999f..e36eba9 100644 --- a/core/java/android/content/Intent.java +++ b/core/java/android/content/Intent.java @@ -1816,7 +1816,9 @@ public class Intent implements Parcelable, Cloneable { /** * Broadcast Action: A sticky broadcast indicating the phone was docked * or undocked. Includes the extra - * field {@link #EXTRA_DOCK_STATE}, containing the current dock state. + * field {@link #EXTRA_DOCK_STATE}, containing the current dock state. It also + * includes the boolean extra field {@link #EXTRA_CAR_MODE_ENABLED}, indicating + * the state of the car mode. * 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. @@ -2152,6 +2154,12 @@ public class Intent implements Parcelable, Cloneable { public static final int EXTRA_DOCK_STATE_CAR = 2; /** + * 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/pm/ActivityInfo.java b/core/java/android/content/pm/ActivityInfo.java index b94bb51..a13f7f9 100644 --- a/core/java/android/content/pm/ActivityInfo.java +++ b/core/java/android/content/pm/ActivityInfo.java @@ -251,6 +251,13 @@ public class ActivityInfo extends ComponentInfo public static final int CONFIG_SCREEN_LAYOUT = 0x0100; /** * Bit in {@link #configChanges} that indicates that the activity + * can itself handle the ui mode. Set from the + * {@link android.R.attr#configChanges} attribute. + * @hide (UIMODE) Pending API council approval + */ + public static final int CONFIG_UI_MODE = 0x0200; + /** + * Bit in {@link #configChanges} that indicates that the activity * can itself handle changes to the font scaling factor. Set from the * {@link android.R.attr#configChanges} attribute. This is * not a core resource configutation, but a higher-level value, so its diff --git a/core/java/android/content/res/AssetManager.java b/core/java/android/content/res/AssetManager.java index 23a408b..7f9a5c6 100644 --- a/core/java/android/content/res/AssetManager.java +++ b/core/java/android/content/res/AssetManager.java @@ -619,7 +619,7 @@ public final class AssetManager { public native final void setConfiguration(int mcc, int mnc, String locale, int orientation, int touchscreen, int density, int keyboard, int keyboardHidden, int navigation, int screenWidth, int screenHeight, - int screenLayout, int majorVersion); + int screenLayout, int uiMode, int majorVersion); /** * Retrieve the resource identifier for the given resource name. diff --git a/core/java/android/content/res/Configuration.java b/core/java/android/content/res/Configuration.java index 1fe34b5..aa5f128 100644 --- a/core/java/android/content/res/Configuration.java +++ b/core/java/android/content/res/Configuration.java @@ -161,7 +161,37 @@ public final class Configuration implements Parcelable, Comparable<Configuration * or {@link #ORIENTATION_SQUARE}. */ public int orientation; - + + /** @hide (UIMODE) Pending API council approval */ + public static final int UI_MODE_TYPE_MASK = 0x0f; + /** @hide (UIMODE) Pending API council approval */ + public static final int UI_MODE_TYPE_NORMAL = 0x00; + /** @hide (UIMODE) Pending API council approval */ + public static final int UI_MODE_TYPE_CAR = 0x01; + + /** @hide (UIMODE) Pending API council approval */ + public static final int UI_MODE_NIGHT_MASK = 0x30; + /** @hide (UIMODE) Pending API council approval */ + public static final int UI_MODE_NIGHT_UNDEFINED = 0x00; + /** @hide (UIMODE) Pending API council approval */ + public static final int UI_MODE_NIGHT_NO = 0x10; + /** @hide (UIMODE) Pending API council approval */ + public static final int UI_MODE_NIGHT_YES = 0x20; + + /** + * 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}. + * + * <p>The {@link #UI_MODE_NIGHT_MASK} defines whether the screen + * is in a special mode. They may be one of + * {@link #UI_MODE_NIGHT_NO} or {@link #UI_MODE_NIGHT_YES}. + * + * @hide (UIMODE) Pending API council approval + */ + public int uiMode; + /** * Construct an invalid Configuration. You must call {@link #setToDefaults} * for this object to be valid. {@more} @@ -189,6 +219,7 @@ public final class Configuration implements Parcelable, Comparable<Configuration navigationHidden = o.navigationHidden; orientation = o.orientation; screenLayout = o.screenLayout; + uiMode = o.uiMode; } public String toString() { @@ -217,6 +248,8 @@ public final class Configuration implements Parcelable, Comparable<Configuration sb.append(orientation); sb.append(" layout="); sb.append(screenLayout); + sb.append(" uiMode="); + sb.append(uiMode); sb.append('}'); return sb.toString(); } @@ -237,6 +270,7 @@ public final class Configuration implements Parcelable, Comparable<Configuration navigationHidden = NAVIGATIONHIDDEN_UNDEFINED; orientation = ORIENTATION_UNDEFINED; screenLayout = SCREENLAYOUT_SIZE_UNDEFINED; + uiMode = UI_MODE_TYPE_NORMAL; } /** {@hide} */ @@ -317,6 +351,11 @@ public final class Configuration implements Parcelable, Comparable<Configuration changed |= ActivityInfo.CONFIG_SCREEN_LAYOUT; screenLayout = delta.screenLayout; } + if (delta.uiMode != UI_MODE_TYPE_NORMAL + && uiMode != delta.uiMode) { + changed |= ActivityInfo.CONFIG_UI_MODE; + uiMode = delta.uiMode; + } return changed; } @@ -393,6 +432,10 @@ public final class Configuration implements Parcelable, Comparable<Configuration && screenLayout != delta.screenLayout) { changed |= ActivityInfo.CONFIG_SCREEN_LAYOUT; } + if (delta.uiMode != UI_MODE_TYPE_NORMAL + && uiMode != delta.uiMode) { + changed |= ActivityInfo.CONFIG_UI_MODE; + } return changed; } @@ -444,6 +487,7 @@ public final class Configuration implements Parcelable, Comparable<Configuration dest.writeInt(navigationHidden); dest.writeInt(orientation); dest.writeInt(screenLayout); + dest.writeInt(uiMode); } public static final Parcelable.Creator<Configuration> CREATOR @@ -477,6 +521,7 @@ public final class Configuration implements Parcelable, Comparable<Configuration navigationHidden = source.readInt(); orientation = source.readInt(); screenLayout = source.readInt(); + uiMode = source.readInt(); } public int compareTo(Configuration that) { @@ -510,6 +555,8 @@ public final class Configuration implements Parcelable, Comparable<Configuration n = this.orientation - that.orientation; if (n != 0) return n; n = this.screenLayout - that.screenLayout; + if (n != 0) return n; + n = this.uiMode - that.uiMode; //if (n != 0) return n; return n; } @@ -533,6 +580,6 @@ public final class Configuration implements Parcelable, Comparable<Configuration + this.locale.hashCode() + this.touchscreen + this.keyboard + this.keyboardHidden + this.hardKeyboardHidden + this.navigation + this.navigationHidden - + this.orientation + this.screenLayout; + + this.orientation + this.screenLayout + this.uiMode; } } diff --git a/core/java/android/content/res/Resources.java b/core/java/android/content/res/Resources.java index e4fc259..ae8e297 100644 --- a/core/java/android/content/res/Resources.java +++ b/core/java/android/content/res/Resources.java @@ -1294,7 +1294,7 @@ public class Resources { mConfiguration.touchscreen, (int)(mMetrics.density*160), mConfiguration.keyboard, keyboardHidden, mConfiguration.navigation, width, height, - mConfiguration.screenLayout, sSdkVersion); + mConfiguration.screenLayout, mConfiguration.uiMode, sSdkVersion); int N = mDrawableCache.size(); if (DEBUG_CONFIG) { Log.d(TAG, "Cleaning up drawables config changes: 0x" diff --git a/core/jni/android_util_AssetManager.cpp b/core/jni/android_util_AssetManager.cpp index 2fff727..a82a21e 100644 --- a/core/jni/android_util_AssetManager.cpp +++ b/core/jni/android_util_AssetManager.cpp @@ -537,7 +537,8 @@ static void android_content_AssetManager_setConfiguration(JNIEnv* env, jobject c jint keyboard, jint keyboardHidden, jint navigation, jint screenWidth, jint screenHeight, - jint screenLayout, jint sdkVersion) + jint screenLayout, jint uiMode, + jint sdkVersion) { AssetManager* am = assetManagerForJavaObject(env, clazz); if (am == NULL) { @@ -560,6 +561,7 @@ static void android_content_AssetManager_setConfiguration(JNIEnv* env, jobject c config.screenWidth = (uint16_t)screenWidth; config.screenHeight = (uint16_t)screenHeight; config.screenLayout = (uint8_t)screenLayout; + config.uiMode = (uint8_t)uiMode; config.sdkVersion = (uint16_t)sdkVersion; config.minorVersion = 0; am->setConfiguration(config, locale8); @@ -1614,7 +1616,7 @@ static JNINativeMethod gAssetManagerMethods[] = { (void*) android_content_AssetManager_setLocale }, { "getLocales", "()[Ljava/lang/String;", (void*) android_content_AssetManager_getLocales }, - { "setConfiguration", "(IILjava/lang/String;IIIIIIIIII)V", + { "setConfiguration", "(IILjava/lang/String;IIIIIIIIIII)V", (void*) android_content_AssetManager_setConfiguration }, { "getResourceIdentifier","(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)I", (void*) android_content_AssetManager_getResourceIdentifier }, diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml index 1ae736e..f5f5a27 100644 --- a/core/res/AndroidManifest.xml +++ b/core/res/AndroidManifest.xml @@ -564,6 +564,14 @@ android:label="@string/permlab_changeConfiguration" android:description="@string/permdesc_changeConfiguration" /> + <!-- Allows an application to enable the car mode. + @hide --> + <permission android:name="android.permission.ENABLE_CAR_MODE" + android:permissionGroup="android.permission-group.SYSTEM_TOOLS" + android:protectionLevel="signature" + android:label="@string/permlab_enableCarMode" + android:description="@string/permdesc_enableCarMode" /> + <!-- @deprecated The {@link android.app.ActivityManager#restartPackage} API is no longer supported. --> <permission android:name="android.permission.RESTART_PACKAGES" diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml index 0a5c584..7f66111 100644 --- a/core/res/res/values/strings.xml +++ b/core/res/res/values/strings.xml @@ -462,6 +462,12 @@ size.</string> <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. --> + <string name="permlab_enableCarMode">enable car mode</string> + <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. --> + <string name="permdesc_enableCarMode">Allows an application to + enable the car mode.</string> + + <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. --> <string name="permlab_killBackgroundProcesses">kill background processes</string> <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. --> <string name="permdesc_killBackgroundProcesses">Allows an application to diff --git a/include/utils/ResourceTypes.h b/include/utils/ResourceTypes.h index 6090f60..13ea27e 100644 --- a/include/utils/ResourceTypes.h +++ b/include/utils/ResourceTypes.h @@ -939,10 +939,23 @@ struct ResTable_config SCREENLONG_YES = 0x20, }; + enum { + // uiMode bits for the mode type. + MASK_UI_MODE_TYPE = 0x0f, + UI_MODE_TYPE_NORMAL = 0x00, + UI_MODE_TYPE_CAR = 0x01, + + // uiMode bits for the night switch. + MASK_UI_MODE_NIGHT = 0x30, + UI_MODE_NIGHT_ANY = 0x00, + UI_MODE_NIGHT_NO = 0x10, + UI_MODE_NIGHT_YES = 0x20, + }; + union { struct { uint8_t screenLayout; - uint8_t screenConfigPad0; + uint8_t uiMode; uint8_t screenConfigPad1; uint8_t screenConfigPad2; }; @@ -996,6 +1009,8 @@ struct ResTable_config diff = (int32_t)(version - o.version); if (diff != 0) return diff; diff = (int32_t)(screenLayout - o.screenLayout); + if (diff != 0) return diff; + diff = (int32_t)(uiMode - o.uiMode); return (int)diff; } @@ -1014,7 +1029,8 @@ struct ResTable_config CONFIG_DENSITY = 0x0100, CONFIG_SCREEN_SIZE = 0x0200, CONFIG_VERSION = 0x0400, - CONFIG_SCREEN_LAYOUT = 0x0800 + CONFIG_SCREEN_LAYOUT = 0x0800, + CONFIG_UI_MODE = 0x1000 }; // Compare two configuration, returning CONFIG_* flags set for each value @@ -1034,6 +1050,7 @@ struct ResTable_config if (screenSize != o.screenSize) diffs |= CONFIG_SCREEN_SIZE; if (version != o.version) diffs |= CONFIG_VERSION; if (screenLayout != o.screenLayout) diffs |= CONFIG_SCREEN_LAYOUT; + if (uiMode != o.uiMode) diffs |= CONFIG_UI_MODE; return diffs; } @@ -1078,19 +1095,28 @@ struct ResTable_config } } - if (screenType || o.screenType) { - if (orientation != o.orientation) { - if (!orientation) return false; - if (!o.orientation) return true; + if (orientation != o.orientation) { + if (!orientation) return false; + if (!o.orientation) return true; + } + + if (screenConfig || o.screenConfig) { + if (((uiMode^o.uiMode) & MASK_UI_MODE_TYPE) != 0) { + if (!(uiMode & MASK_UI_MODE_TYPE)) return false; + if (!(o.uiMode & MASK_UI_MODE_TYPE)) return true; + } + if (((uiMode^o.uiMode) & MASK_UI_MODE_NIGHT) != 0) { + if (!(uiMode & MASK_UI_MODE_NIGHT)) return false; + if (!(o.uiMode & MASK_UI_MODE_NIGHT)) return true; } + } - // density is never 'more specific' - // as the default just equals 160 + // density is never 'more specific' + // as the default just equals 160 - if (touchscreen != o.touchscreen) { - if (!touchscreen) return false; - if (!o.touchscreen) return true; - } + if (touchscreen != o.touchscreen) { + if (!touchscreen) return false; + if (!o.touchscreen) return true; } if (input || o.input) { @@ -1186,11 +1212,22 @@ struct ResTable_config } } - if (screenType || o.screenType) { - if ((orientation != o.orientation) && requested->orientation) { - return (orientation); + if ((orientation != o.orientation) && requested->orientation) { + return (orientation); + } + + if (screenConfig || o.screenConfig) { + if (((uiMode^o.uiMode) & MASK_UI_MODE_TYPE) != 0 + && (requested->uiMode & MASK_UI_MODE_TYPE)) { + return (uiMode & MASK_UI_MODE_TYPE); + } + if (((uiMode^o.uiMode) & MASK_UI_MODE_NIGHT) != 0 + && (requested->uiMode & MASK_UI_MODE_NIGHT)) { + return (uiMode & MASK_UI_MODE_NIGHT); } + } + if (screenType || o.screenType) { if (density != o.density) { // density is tough. Any density is potentially useful // because the system will scale it. Scaling down @@ -1340,6 +1377,20 @@ struct ResTable_config && screenLong != setScreenLong) { return false; } + + const int uiModeType = uiMode&MASK_UI_MODE_TYPE; + const int setUiModeType = settings.uiMode&MASK_UI_MODE_TYPE; + if (setUiModeType != 0 && uiModeType != 0 + && uiModeType != setUiModeType) { + return false; + } + + const int uiModeNight = uiMode&MASK_UI_MODE_NIGHT; + const int setUiModeNight = settings.uiMode&MASK_UI_MODE_NIGHT; + if (setUiModeNight != 0 && uiModeNight != 0 + && uiModeNight != setUiModeNight) { + return false; + } } if (screenType != 0) { if (settings.orientation != 0 && orientation != 0 @@ -1420,13 +1471,15 @@ struct ResTable_config String8 toString() const { char buf[200]; sprintf(buf, "imsi=%d/%d lang=%c%c reg=%c%c orient=%d touch=%d dens=%d " - "kbd=%d nav=%d input=%d scrnW=%d scrnH=%d sz=%d long=%d vers=%d.%d", + "kbd=%d nav=%d input=%d scrnW=%d scrnH=%d sz=%d long=%d " + "ui=%d night=%d vers=%d.%d", mcc, mnc, language[0] ? language[0] : '-', language[1] ? language[1] : '-', country[0] ? country[0] : '-', country[1] ? country[1] : '-', orientation, touchscreen, density, keyboard, navigation, inputFlags, screenWidth, screenHeight, screenLayout&MASK_SCREENSIZE, screenLayout&MASK_SCREENLONG, + uiMode&MASK_UI_MODE_TYPE, uiMode&MASK_UI_MODE_NIGHT, sdkVersion, minorVersion); return String8(buf); } diff --git a/services/java/com/android/server/DockObserver.java b/services/java/com/android/server/DockObserver.java index 363e93e..742a7d8 100644 --- a/services/java/com/android/server/DockObserver.java +++ b/services/java/com/android/server/DockObserver.java @@ -17,6 +17,9 @@ package com.android.server; import android.app.Activity; +import android.app.ActivityManagerNative; +import android.app.IActivityManager; +import android.app.IUiModeManager; import android.app.KeyguardManager; import android.bluetooth.BluetoothAdapter; import android.bluetooth.BluetoothDevice; @@ -24,8 +27,12 @@ import android.content.ActivityNotFoundException; import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; +import android.content.res.Configuration; +import android.os.Binder; 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; @@ -47,7 +54,13 @@ 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"; + 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 int mDockState = Intent.EXTRA_DOCK_STATE_UNDOCKED; + private int mNightMode = MODE_NIGHT_NO; + private boolean mCarModeEnabled = false; private boolean mSystemReady; private final Context mContext; @@ -71,16 +84,12 @@ class DockObserver extends UEventObserver { // Launch a dock activity String category; - switch (mDockState) { - case Intent.EXTRA_DOCK_STATE_CAR: - category = Intent.CATEGORY_CAR_DOCK; - break; - case Intent.EXTRA_DOCK_STATE_DESK: - category = Intent.CATEGORY_DESK_DOCK; - break; - default: - category = null; - break; + if (mCarModeEnabled || mDockState == Intent.EXTRA_DOCK_STATE_CAR) { + 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); @@ -101,6 +110,9 @@ class DockObserver extends UEventObserver { mPowerManager = pm; mLockPatternUtils = new LockPatternUtils(context); init(); // set initial status + + ServiceManager.addService("uimode", mBinder); + startObserving(DOCK_UEVENT_MATCH); } @@ -116,6 +128,14 @@ class DockObserver extends UEventObserver { if (newState != mDockState) { int oldState = mDockState; mDockState = newState; + boolean carModeEnabled = mDockState == Intent.EXTRA_DOCK_STATE_CAR; + if (mCarModeEnabled != carModeEnabled) { + try { + setCarMode(carModeEnabled); + } catch (RemoteException e1) { + Log.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. @@ -180,7 +200,13 @@ 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); - intent.putExtra(Intent.EXTRA_DOCK_STATE, mDockState); + 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 { + intent.putExtra(Intent.EXTRA_DOCK_STATE, mDockState); + } + intent.putExtra(Intent.EXTRA_CAR_MODE_ENABLED, mCarModeEnabled); // Check if this is Bluetooth Dock String address = BluetoothService.readDockBluetoothAddress(); @@ -199,4 +225,76 @@ class DockObserver extends UEventObserver { } } }; + + private void setCarMode(boolean enabled) throws RemoteException { + mCarModeEnabled = enabled; + if (enabled) { + setMode(Configuration.UI_MODE_TYPE_CAR, mNightMode); + } else { + // Disabling the car mode clears the night mode. + setMode(Configuration.UI_MODE_TYPE_NORMAL, MODE_NIGHT_NO); + } + } + + private void setMode(int modeType, int modeNight) throws RemoteException { + final IActivityManager am = ActivityManagerNative.getDefault(); + Configuration config = am.getConfiguration(); + + if (config.uiMode != (modeType | modeNight)) { + config.uiMode = modeType | modeNight; + long ident = Binder.clearCallingIdentity(); + am.updateConfiguration(config); + Binder.restoreCallingIdentity(ident); + } + } + + private void setNightMode(int mode) throws RemoteException { + 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: + // FIXME: not yet supported, this functionality will be + // added in a separate change. + break; + default: + setMode(Configuration.UI_MODE_TYPE_CAR, MODE_NIGHT_NO << 4); + break; + } + } + + /** + * 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/tools/aapt/AaptAssets.cpp b/tools/aapt/AaptAssets.cpp index c346b90..663a33a 100644 --- a/tools/aapt/AaptAssets.cpp +++ b/tools/aapt/AaptAssets.cpp @@ -163,6 +163,20 @@ AaptGroupEntry::parseNamePart(const String8& part, int* axis, uint32_t* value) return 0; } + // ui mode type + if (getUiModeTypeName(part.string(), &config)) { + *axis = AXIS_UIMODETYPE; + *value = (config.uiMode&ResTable_config::MASK_UI_MODE_TYPE); + return 0; + } + + // ui mode night + if (getUiModeNightName(part.string(), &config)) { + *axis = AXIS_UIMODENIGHT; + *value = (config.uiMode&ResTable_config::MASK_UI_MODE_NIGHT); + return 0; + } + // density if (getDensityName(part.string(), &config)) { *axis = AXIS_DENSITY; @@ -229,6 +243,7 @@ AaptGroupEntry::initFromDirName(const char* dir, String8* resType) String8 mcc, mnc, loc, layoutsize, layoutlong, orient, den; String8 touch, key, keysHidden, nav, navHidden, size, vers; + String8 uiModeType, uiModeNight; const char *p = dir; const char *q; @@ -352,6 +367,32 @@ AaptGroupEntry::initFromDirName(const char* dir, String8* resType) //printf("not orientation: %s\n", part.string()); } + // ui mode type + if (getUiModeTypeName(part.string())) { + uiModeType = part; + + index++; + if (index == N) { + goto success; + } + part = parts[index]; + } else { + //printf("not ui mode type: %s\n", part.string()); + } + + // ui mode night + if (getUiModeNightName(part.string())) { + uiModeNight = part; + + index++; + if (index == N) { + goto success; + } + part = parts[index]; + } else { + //printf("not ui mode night: %s\n", part.string()); + } + // density if (getDensityName(part.string())) { den = part; @@ -463,6 +504,8 @@ success: this->screenLayoutSize = layoutsize; this->screenLayoutLong = layoutlong; this->orientation = orient; + this->uiModeType = uiModeType; + this->uiModeNight = uiModeNight; this->density = den; this->touchscreen = touch; this->keysHidden = keysHidden; @@ -493,6 +536,10 @@ AaptGroupEntry::toString() const s += ","; s += this->orientation; s += ","; + s += uiModeType; + s += ","; + s += uiModeNight; + s += ","; s += density; s += ","; s += touchscreen; @@ -539,6 +586,14 @@ AaptGroupEntry::toDirName(const String8& resType) const s += "-"; s += orientation; } + if (this->uiModeType != "") { + s += "-"; + s += uiModeType; + } + if (this->uiModeNight != "") { + s += "-"; + s += uiModeNight; + } if (this->density != "") { s += "-"; s += density; @@ -759,6 +814,47 @@ bool AaptGroupEntry::getOrientationName(const char* name, return false; } +bool AaptGroupEntry::getUiModeTypeName(const char* name, + ResTable_config* out) +{ + if (strcmp(name, kWildcardName) == 0) { + if (out) out->uiMode = + (out->uiMode&~ResTable_config::MASK_UI_MODE_TYPE) + | ResTable_config::UI_MODE_TYPE_NORMAL; + return true; + } else if (strcmp(name, "car") == 0) { + if (out) out->uiMode = + (out->uiMode&~ResTable_config::MASK_UI_MODE_TYPE) + | ResTable_config::UI_MODE_TYPE_CAR; + return true; + } + + return false; +} + +bool AaptGroupEntry::getUiModeNightName(const char* name, + ResTable_config* out) +{ + if (strcmp(name, kWildcardName) == 0) { + if (out) out->uiMode = + (out->uiMode&~ResTable_config::MASK_UI_MODE_NIGHT) + | ResTable_config::UI_MODE_NIGHT_ANY; + return true; + } else if (strcmp(name, "night") == 0) { + if (out) out->uiMode = + (out->uiMode&~ResTable_config::MASK_UI_MODE_NIGHT) + | ResTable_config::UI_MODE_NIGHT_YES; + return true; + } else if (strcmp(name, "notnight") == 0) { + if (out) out->uiMode = + (out->uiMode&~ResTable_config::MASK_UI_MODE_NIGHT) + | ResTable_config::UI_MODE_NIGHT_NO; + return true; + } + + return false; +} + bool AaptGroupEntry::getDensityName(const char* name, ResTable_config* out) { @@ -1004,6 +1100,8 @@ int AaptGroupEntry::compare(const AaptGroupEntry& o) const if (v == 0) v = screenLayoutSize.compare(o.screenLayoutSize); if (v == 0) v = screenLayoutLong.compare(o.screenLayoutLong); if (v == 0) v = orientation.compare(o.orientation); + if (v == 0) v = uiModeType.compare(o.uiModeType); + if (v == 0) v = uiModeNight.compare(o.uiModeNight); if (v == 0) v = density.compare(o.density); if (v == 0) v = touchscreen.compare(o.touchscreen); if (v == 0) v = keysHidden.compare(o.keysHidden); @@ -1025,6 +1123,8 @@ ResTable_config AaptGroupEntry::toParams() const getScreenLayoutSizeName(screenLayoutSize.string(), ¶ms); getScreenLayoutLongName(screenLayoutLong.string(), ¶ms); getOrientationName(orientation.string(), ¶ms); + getUiModeTypeName(uiModeType.string(), ¶ms); + getUiModeNightName(uiModeNight.string(), ¶ms); getDensityName(density.string(), ¶ms); getTouchscreenName(touchscreen.string(), ¶ms); getKeysHiddenName(keysHidden.string(), ¶ms); diff --git a/tools/aapt/AaptAssets.h b/tools/aapt/AaptAssets.h index 26500a3..9a848e4 100644 --- a/tools/aapt/AaptAssets.h +++ b/tools/aapt/AaptAssets.h @@ -33,6 +33,8 @@ enum { AXIS_SCREENLAYOUTSIZE, AXIS_SCREENLAYOUTLONG, AXIS_ORIENTATION, + AXIS_UIMODETYPE, + AXIS_UIMODENIGHT, AXIS_DENSITY, AXIS_TOUCHSCREEN, AXIS_KEYSHIDDEN, @@ -61,6 +63,8 @@ public: String8 screenLayoutSize; String8 screenLayoutLong; String8 orientation; + String8 uiModeType; + String8 uiModeNight; String8 density; String8 touchscreen; String8 keysHidden; @@ -80,6 +84,8 @@ public: static bool getScreenLayoutSizeName(const char* name, ResTable_config* out = NULL); static bool getScreenLayoutLongName(const char* name, ResTable_config* out = NULL); static bool getOrientationName(const char* name, ResTable_config* out = NULL); + static bool getUiModeTypeName(const char* name, ResTable_config* out = NULL); + static bool getUiModeNightName(const char* name, ResTable_config* out = NULL); static bool getDensityName(const char* name, ResTable_config* out = NULL); static bool getTouchscreenName(const char* name, ResTable_config* out = NULL); static bool getKeysHiddenName(const char* name, ResTable_config* out = NULL); diff --git a/tools/aapt/Resource.cpp b/tools/aapt/Resource.cpp index 0d2ea60..88c5441 100644 --- a/tools/aapt/Resource.cpp +++ b/tools/aapt/Resource.cpp @@ -101,13 +101,13 @@ public: String8 leaf(group->getLeaf()); mLeafName = String8(leaf); mParams = file->getGroupEntry().toParams(); - NOISY(printf("Dir %s: mcc=%d mnc=%d lang=%c%c cnt=%c%c orient=%d density=%d touch=%d key=%d inp=%d nav=%d\n", + NOISY(printf("Dir %s: mcc=%d mnc=%d lang=%c%c cnt=%c%c orient=%d ui=%d density=%d touch=%d key=%d inp=%d nav=%d\n", group->getPath().string(), mParams.mcc, mParams.mnc, mParams.language[0] ? mParams.language[0] : '-', mParams.language[1] ? mParams.language[1] : '-', mParams.country[0] ? mParams.country[0] : '-', mParams.country[1] ? mParams.country[1] : '-', - mParams.orientation, + mParams.orientation, mParams.uiMode, mParams.density, mParams.touchscreen, mParams.keyboard, mParams.inputFlags, mParams.navigation)); mPath = "res"; diff --git a/tools/aapt/ResourceTable.cpp b/tools/aapt/ResourceTable.cpp index b682702..a389bfb 100644 --- a/tools/aapt/ResourceTable.cpp +++ b/tools/aapt/ResourceTable.cpp @@ -2472,6 +2472,12 @@ ResourceFilter::match(const ResTable_config& config) if (!match(AXIS_ORIENTATION, config.orientation)) { return false; } + if (!match(AXIS_UIMODETYPE, (config.uiMode&ResTable_config::MASK_UI_MODE_TYPE))) { + return false; + } + if (!match(AXIS_UIMODENIGHT, (config.uiMode&ResTable_config::MASK_UI_MODE_NIGHT))) { + return false; + } if (!match(AXIS_DENSITY, config.density)) { return false; } @@ -2674,7 +2680,7 @@ status_t ResourceTable::flatten(Bundle* bundle, const sp<AaptFile>& dest) ConfigDescription config = t->getUniqueConfigs().itemAt(ci); NOISY(printf("Writing config %d config: imsi:%d/%d lang:%c%c cnt:%c%c " - "orien:%d touch:%d density:%d key:%d inp:%d nav:%d w:%d h:%d\n", + "orien:%d ui:%d touch:%d density:%d key:%d inp:%d nav:%d w:%d h:%d\n", ti+1, config.mcc, config.mnc, config.language[0] ? config.language[0] : '-', @@ -2682,6 +2688,7 @@ status_t ResourceTable::flatten(Bundle* bundle, const sp<AaptFile>& dest) config.country[0] ? config.country[0] : '-', config.country[1] ? config.country[1] : '-', config.orientation, + config.uiMode, config.touchscreen, config.density, config.keyboard, @@ -2711,7 +2718,7 @@ status_t ResourceTable::flatten(Bundle* bundle, const sp<AaptFile>& dest) tHeader->entriesStart = htodl(typeSize); tHeader->config = config; NOISY(printf("Writing type %d config: imsi:%d/%d lang:%c%c cnt:%c%c " - "orien:%d touch:%d density:%d key:%d inp:%d nav:%d w:%d h:%d\n", + "orien:%d ui:%d touch:%d density:%d key:%d inp:%d nav:%d w:%d h:%d\n", ti+1, tHeader->config.mcc, tHeader->config.mnc, tHeader->config.language[0] ? tHeader->config.language[0] : '-', @@ -2719,6 +2726,7 @@ status_t ResourceTable::flatten(Bundle* bundle, const sp<AaptFile>& dest) tHeader->config.country[0] ? tHeader->config.country[0] : '-', tHeader->config.country[1] ? tHeader->config.country[1] : '-', tHeader->config.orientation, + tHeader->config.uiMode, tHeader->config.touchscreen, tHeader->config.density, tHeader->config.keyboard, diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/BridgeAssetManager.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/BridgeAssetManager.java index 6c1b5b3..43ff424 100644 --- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/BridgeAssetManager.java +++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/BridgeAssetManager.java @@ -59,7 +59,7 @@ public class BridgeAssetManager extends AssetManager { public void setConfiguration(int mcc, int mnc, String locale, int orientation, int touchscreen, int density, int keyboard, int keyboardHidden, int navigation, int screenWidth, int screenHeight, - int screenLayout, int version) { + int screenLayout, int uiMode, int version) { Configuration c = new Configuration(); c.mcc = mcc; @@ -71,5 +71,6 @@ public class BridgeAssetManager extends AssetManager { c.navigation = navigation; c.orientation = orientation; c.screenLayout = screenLayout; + c.uiMode = uiMode; } } |