summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorTobias Haamel <haamel@google.com>2010-02-09 23:09:17 +0100
committerTobias Haamel <haamel@google.com>2010-02-11 21:25:58 +0100
commit27b28b3f62bd3b54fa13acd5d035940b9be464f3 (patch)
treed1f44096f7071bbc53e5bc979117be8e0f4aa55c
parentd5663a108760de672b130ffabd4f6632982f75e5 (diff)
downloadframeworks_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.mk1
-rw-r--r--api/current.xml11
-rw-r--r--core/java/android/app/IUiModeManager.aidl49
-rw-r--r--core/java/android/content/Intent.java10
-rw-r--r--core/java/android/content/pm/ActivityInfo.java7
-rw-r--r--core/java/android/content/res/AssetManager.java2
-rw-r--r--core/java/android/content/res/Configuration.java51
-rw-r--r--core/java/android/content/res/Resources.java2
-rw-r--r--core/jni/android_util_AssetManager.cpp6
-rw-r--r--core/res/AndroidManifest.xml8
-rw-r--r--core/res/res/values/strings.xml6
-rw-r--r--include/utils/ResourceTypes.h85
-rw-r--r--services/java/com/android/server/DockObserver.java120
-rw-r--r--tools/aapt/AaptAssets.cpp100
-rw-r--r--tools/aapt/AaptAssets.h6
-rw-r--r--tools/aapt/Resource.cpp4
-rw-r--r--tools/aapt/ResourceTable.cpp12
-rw-r--r--tools/layoutlib/bridge/src/com/android/layoutlib/bridge/BridgeAssetManager.java3
18 files changed, 444 insertions, 39 deletions
diff --git a/Android.mk b/Android.mk
index 7fc121d..4ecf5bd 100644
--- a/Android.mk
+++ b/Android.mk
@@ -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="&quot;android.intent.extra.CAR_MODE_ENABLED&quot;"
+ 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(), &params);
getScreenLayoutLongName(screenLayoutLong.string(), &params);
getOrientationName(orientation.string(), &params);
+ getUiModeTypeName(uiModeType.string(), &params);
+ getUiModeNightName(uiModeNight.string(), &params);
getDensityName(density.string(), &params);
getTouchscreenName(touchscreen.string(), &params);
getKeysHiddenName(keysHidden.string(), &params);
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;
}
}