Merge "Pass EXCLUDE_FROM_RECENTS when starting secure camera." into jb-mr1-dev
diff --git a/Android.mk b/Android.mk
index 07500b1..cb1b90b 100644
--- a/Android.mk
+++ b/Android.mk
@@ -153,6 +153,7 @@
 	core/java/android/view/accessibility/IAccessibilityManager.aidl \
 	core/java/android/view/accessibility/IAccessibilityManagerClient.aidl \
 	core/java/android/view/IApplicationToken.aidl \
+	core/java/android/view/IDisplayContentChangeListener.aidl \
 	core/java/android/view/IInputFilter.aidl \
 	core/java/android/view/IInputFilterHost.aidl \
 	core/java/android/view/IOnKeyguardExitResult.aidl \
diff --git a/api/current.txt b/api/current.txt
index 4a99427..f975bf8 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -2066,6 +2066,7 @@
     field public static final int DEFAULT = 1; // 0x1
     field public static final int FEEDBACK_ALL_MASK = -1; // 0xffffffff
     field public static final int FEEDBACK_AUDIBLE = 4; // 0x4
+    field public static final int FEEDBACK_BRAILLE = 32; // 0x20
     field public static final int FEEDBACK_GENERIC = 16; // 0x10
     field public static final int FEEDBACK_HAPTIC = 2; // 0x2
     field public static final int FEEDBACK_SPOKEN = 1; // 0x1
@@ -3348,9 +3349,11 @@
     method public final boolean equals(java.lang.Object);
     method public final android.app.Activity getActivity();
     method public final android.os.Bundle getArguments();
+    method public final android.app.FragmentManager getChildFragmentManager();
     method public final android.app.FragmentManager getFragmentManager();
     method public final int getId();
     method public android.app.LoaderManager getLoaderManager();
+    method public final android.app.Fragment getParentFragment();
     method public final android.content.res.Resources getResources();
     method public final boolean getRetainInstance();
     method public final java.lang.String getString(int);
@@ -3399,6 +3402,7 @@
     method public void onStop();
     method public void onTrimMemory(int);
     method public void onViewCreated(android.view.View, android.os.Bundle);
+    method public void onViewStateRestored(android.os.Bundle);
     method public void registerForContextMenu(android.view.View);
     method public void setArguments(android.os.Bundle);
     method public void setHasOptionsMenu(boolean);
@@ -6324,6 +6328,7 @@
     field public static final int FLAG_FACTORY_TEST = 16; // 0x10
     field public static final int FLAG_HAS_CODE = 4; // 0x4
     field public static final int FLAG_INSTALLED = 8388608; // 0x800000
+    field public static final int FLAG_IS_DATA_ONLY = 16777216; // 0x1000000
     field public static final int FLAG_KILL_AFTER_RESTORE = 65536; // 0x10000
     field public static final int FLAG_LARGE_HEAP = 1048576; // 0x100000
     field public static final int FLAG_PERSISTENT = 8; // 0x8
@@ -15613,6 +15618,7 @@
     method public static final void flushPendingCommands();
     method public static final int getCallingPid();
     method public static final int getCallingUid();
+    method public static final android.os.UserHandle getCallingUserHandle();
     method public java.lang.String getInterfaceDescriptor();
     method public boolean isBinderAlive();
     method public static final void joinThreadPool();
@@ -16416,6 +16422,7 @@
     method public void finishBroadcast();
     method public java.lang.Object getBroadcastCookie(int);
     method public E getBroadcastItem(int);
+    method public int getRegisteredCallbackCount();
     method public void kill();
     method public void onCallbackDied(E);
     method public void onCallbackDied(E, java.lang.Object);
@@ -18716,6 +18723,53 @@
     field public static final java.lang.String EXTRA_INPUT_METHOD_ID = "input_method_id";
   }
 
+  public static final class Settings.Global extends android.provider.Settings.NameValueTable {
+    ctor public Settings.Global();
+    method public static float getFloat(android.content.ContentResolver, java.lang.String, float);
+    method public static float getFloat(android.content.ContentResolver, java.lang.String) throws android.provider.Settings.SettingNotFoundException;
+    method public static int getInt(android.content.ContentResolver, java.lang.String, int);
+    method public static int getInt(android.content.ContentResolver, java.lang.String) throws android.provider.Settings.SettingNotFoundException;
+    method public static long getLong(android.content.ContentResolver, java.lang.String, long);
+    method public static long getLong(android.content.ContentResolver, java.lang.String) throws android.provider.Settings.SettingNotFoundException;
+    method public static synchronized java.lang.String getString(android.content.ContentResolver, java.lang.String);
+    method public static android.net.Uri getUriFor(java.lang.String);
+    method public static boolean putFloat(android.content.ContentResolver, java.lang.String, float);
+    method public static boolean putInt(android.content.ContentResolver, java.lang.String, int);
+    method public static boolean putLong(android.content.ContentResolver, java.lang.String, long);
+    method public static boolean putString(android.content.ContentResolver, java.lang.String, java.lang.String);
+    field public static final java.lang.String ADB_ENABLED = "adb_enabled";
+    field public static final java.lang.String AIRPLANE_MODE_ON = "airplane_mode_on";
+    field public static final java.lang.String AIRPLANE_MODE_RADIOS = "airplane_mode_radios";
+    field public static final java.lang.String AUTO_TIME = "auto_time";
+    field public static final java.lang.String AUTO_TIME_ZONE = "auto_time_zone";
+    field public static final java.lang.String BLUETOOTH_ON = "bluetooth_on";
+    field public static final android.net.Uri CONTENT_URI;
+    field public static final java.lang.String DATA_ROAMING = "data_roaming";
+    field public static final java.lang.String DEVELOPMENT_SETTINGS_ENABLED = "development_settings_enabled";
+    field public static final java.lang.String DEVICE_PROVISIONED = "device_provisioned";
+    field public static final java.lang.String INSTALL_NON_MARKET_APPS = "install_non_market_apps";
+    field public static final java.lang.String NETWORK_PREFERENCE = "network_preference";
+    field public static final java.lang.String RADIO_BLUETOOTH = "bluetooth";
+    field public static final java.lang.String RADIO_CELL = "cell";
+    field public static final java.lang.String RADIO_NFC = "nfc";
+    field public static final java.lang.String RADIO_WIFI = "wifi";
+    field public static final java.lang.String STAY_ON_WHILE_PLUGGED_IN = "stay_on_while_plugged_in";
+    field public static final java.lang.String SYS_PROP_SETTING_VERSION = "sys.settings_global_version";
+    field public static final java.lang.String USB_MASS_STORAGE_ENABLED = "usb_mass_storage_enabled";
+    field public static final java.lang.String USE_GOOGLE_MAIL = "use_google_mail";
+    field public static final java.lang.String WIFI_MAX_DHCP_RETRY_COUNT = "wifi_max_dhcp_retry_count";
+    field public static final java.lang.String WIFI_MOBILE_DATA_TRANSITION_WAKELOCK_TIMEOUT_MS = "wifi_mobile_data_transition_wakelock_timeout_ms";
+    field public static final java.lang.String WIFI_NETWORKS_AVAILABLE_NOTIFICATION_ON = "wifi_networks_available_notification_on";
+    field public static final java.lang.String WIFI_NETWORKS_AVAILABLE_REPEAT_DELAY = "wifi_networks_available_repeat_delay";
+    field public static final java.lang.String WIFI_NUM_OPEN_NETWORKS_KEPT = "wifi_num_open_networks_kept";
+    field public static final java.lang.String WIFI_ON = "wifi_on";
+    field public static final java.lang.String WIFI_SLEEP_POLICY = "wifi_sleep_policy";
+    field public static final int WIFI_SLEEP_POLICY_DEFAULT = 0; // 0x0
+    field public static final int WIFI_SLEEP_POLICY_NEVER = 2; // 0x2
+    field public static final int WIFI_SLEEP_POLICY_NEVER_WHILE_PLUGGED = 1; // 0x1
+    field public static final java.lang.String WIFI_WATCHDOG_ON = "wifi_watchdog_on";
+  }
+
   public static class Settings.NameValueTable implements android.provider.BaseColumns {
     ctor public Settings.NameValueTable();
     method public static android.net.Uri getUriFor(android.net.Uri, java.lang.String);
@@ -18742,28 +18796,28 @@
     method public static final void setLocationProviderEnabled(android.content.ContentResolver, java.lang.String, boolean);
     field public static final java.lang.String ACCESSIBILITY_ENABLED = "accessibility_enabled";
     field public static final java.lang.String ACCESSIBILITY_SPEAK_PASSWORD = "speak_password";
-    field public static final java.lang.String ADB_ENABLED = "adb_enabled";
+    field public static final deprecated java.lang.String ADB_ENABLED = "adb_enabled";
     field public static final java.lang.String ALLOWED_GEOLOCATION_ORIGINS = "allowed_geolocation_origins";
     field public static final java.lang.String ALLOW_MOCK_LOCATION = "mock_location";
     field public static final java.lang.String ANDROID_ID = "android_id";
     field public static final deprecated java.lang.String BACKGROUND_DATA = "background_data";
-    field public static final java.lang.String BLUETOOTH_ON = "bluetooth_on";
+    field public static final deprecated java.lang.String BLUETOOTH_ON = "bluetooth_on";
     field public static final android.net.Uri CONTENT_URI;
-    field public static final java.lang.String DATA_ROAMING = "data_roaming";
+    field public static final deprecated java.lang.String DATA_ROAMING = "data_roaming";
     field public static final java.lang.String DEFAULT_INPUT_METHOD = "default_input_method";
-    field public static final java.lang.String DEVELOPMENT_SETTINGS_ENABLED = "development_settings_enabled";
-    field public static final java.lang.String DEVICE_PROVISIONED = "device_provisioned";
+    field public static final deprecated java.lang.String DEVELOPMENT_SETTINGS_ENABLED = "development_settings_enabled";
+    field public static final deprecated java.lang.String DEVICE_PROVISIONED = "device_provisioned";
     field public static final java.lang.String ENABLED_ACCESSIBILITY_SERVICES = "enabled_accessibility_services";
     field public static final java.lang.String ENABLED_INPUT_METHODS = "enabled_input_methods";
     field public static final java.lang.String HTTP_PROXY = "http_proxy";
     field public static final java.lang.String INPUT_METHOD_SELECTOR_VISIBILITY = "input_method_selector_visibility";
-    field public static final java.lang.String INSTALL_NON_MARKET_APPS = "install_non_market_apps";
+    field public static final deprecated java.lang.String INSTALL_NON_MARKET_APPS = "install_non_market_apps";
     field public static final java.lang.String LOCATION_PROVIDERS_ALLOWED = "location_providers_allowed";
     field public static final java.lang.String LOCK_PATTERN_ENABLED = "lock_pattern_autolock";
     field public static final java.lang.String LOCK_PATTERN_TACTILE_FEEDBACK_ENABLED = "lock_pattern_tactile_feedback_enabled";
     field public static final java.lang.String LOCK_PATTERN_VISIBLE = "lock_pattern_visible_pattern";
     field public static final deprecated java.lang.String LOGGING_ID = "logging_id";
-    field public static final java.lang.String NETWORK_PREFERENCE = "network_preference";
+    field public static final deprecated java.lang.String NETWORK_PREFERENCE = "network_preference";
     field public static final java.lang.String PARENTAL_CONTROL_ENABLED = "parental_control_enabled";
     field public static final java.lang.String PARENTAL_CONTROL_LAST_UPDATE = "parental_control_last_update";
     field public static final java.lang.String PARENTAL_CONTROL_REDIRECT_URL = "parental_control_redirect_url";
@@ -18779,9 +18833,9 @@
     field public static final deprecated java.lang.String TTS_DEFAULT_VARIANT = "tts_default_variant";
     field public static final java.lang.String TTS_ENABLED_PLUGINS = "tts_enabled_plugins";
     field public static final deprecated java.lang.String TTS_USE_DEFAULTS = "tts_use_defaults";
-    field public static final java.lang.String USB_MASS_STORAGE_ENABLED = "usb_mass_storage_enabled";
-    field public static final java.lang.String USE_GOOGLE_MAIL = "use_google_mail";
-    field public static final java.lang.String WIFI_MAX_DHCP_RETRY_COUNT = "wifi_max_dhcp_retry_count";
+    field public static final deprecated java.lang.String USB_MASS_STORAGE_ENABLED = "usb_mass_storage_enabled";
+    field public static final deprecated java.lang.String USE_GOOGLE_MAIL = "use_google_mail";
+    field public static final deprecated java.lang.String WIFI_MAX_DHCP_RETRY_COUNT = "wifi_max_dhcp_retry_count";
     field public static final java.lang.String WIFI_MOBILE_DATA_TRANSITION_WAKELOCK_TIMEOUT_MS = "wifi_mobile_data_transition_wakelock_timeout_ms";
     field public static final java.lang.String WIFI_NETWORKS_AVAILABLE_NOTIFICATION_ON = "wifi_networks_available_notification_on";
     field public static final java.lang.String WIFI_NETWORKS_AVAILABLE_REPEAT_DELAY = "wifi_networks_available_repeat_delay";
@@ -18814,7 +18868,7 @@
     method public static int getInt(android.content.ContentResolver, java.lang.String) throws android.provider.Settings.SettingNotFoundException;
     method public static long getLong(android.content.ContentResolver, java.lang.String, long);
     method public static long getLong(android.content.ContentResolver, java.lang.String) throws android.provider.Settings.SettingNotFoundException;
-    method public static boolean getShowGTalkServiceStatus(android.content.ContentResolver);
+    method public static deprecated boolean getShowGTalkServiceStatus(android.content.ContentResolver);
     method public static synchronized java.lang.String getString(android.content.ContentResolver, java.lang.String);
     method public static android.net.Uri getUriFor(java.lang.String);
     method public static boolean putConfiguration(android.content.ContentResolver, android.content.res.Configuration);
@@ -18822,18 +18876,18 @@
     method public static boolean putInt(android.content.ContentResolver, java.lang.String, int);
     method public static boolean putLong(android.content.ContentResolver, java.lang.String, long);
     method public static boolean putString(android.content.ContentResolver, java.lang.String, java.lang.String);
-    method public static void setShowGTalkServiceStatus(android.content.ContentResolver, boolean);
+    method public static deprecated void setShowGTalkServiceStatus(android.content.ContentResolver, boolean);
     field public static final java.lang.String ACCELEROMETER_ROTATION = "accelerometer_rotation";
     field public static final deprecated java.lang.String ADB_ENABLED = "adb_enabled";
-    field public static final java.lang.String AIRPLANE_MODE_ON = "airplane_mode_on";
-    field public static final java.lang.String AIRPLANE_MODE_RADIOS = "airplane_mode_radios";
+    field public static final deprecated java.lang.String AIRPLANE_MODE_ON = "airplane_mode_on";
+    field public static final deprecated java.lang.String AIRPLANE_MODE_RADIOS = "airplane_mode_radios";
     field public static final java.lang.String ALARM_ALERT = "alarm_alert";
     field public static final java.lang.String ALWAYS_FINISH_ACTIVITIES = "always_finish_activities";
     field public static final deprecated java.lang.String ANDROID_ID = "android_id";
     field public static final java.lang.String ANIMATOR_DURATION_SCALE = "animator_duration_scale";
     field public static final java.lang.String APPEND_FOR_LAST_AUDIBLE = "_last_audible";
-    field public static final java.lang.String AUTO_TIME = "auto_time";
-    field public static final java.lang.String AUTO_TIME_ZONE = "auto_time_zone";
+    field public static final deprecated java.lang.String AUTO_TIME = "auto_time";
+    field public static final deprecated java.lang.String AUTO_TIME_ZONE = "auto_time_zone";
     field public static final java.lang.String BLUETOOTH_DISCOVERABILITY = "bluetooth_discoverability";
     field public static final java.lang.String BLUETOOTH_DISCOVERABILITY_TIMEOUT = "bluetooth_discoverability_timeout";
     field public static final deprecated java.lang.String BLUETOOTH_ON = "bluetooth_on";
@@ -18866,10 +18920,10 @@
     field public static final deprecated java.lang.String PARENTAL_CONTROL_ENABLED = "parental_control_enabled";
     field public static final deprecated java.lang.String PARENTAL_CONTROL_LAST_UPDATE = "parental_control_last_update";
     field public static final deprecated java.lang.String PARENTAL_CONTROL_REDIRECT_URL = "parental_control_redirect_url";
-    field public static final java.lang.String RADIO_BLUETOOTH = "bluetooth";
-    field public static final java.lang.String RADIO_CELL = "cell";
-    field public static final java.lang.String RADIO_NFC = "nfc";
-    field public static final java.lang.String RADIO_WIFI = "wifi";
+    field public static final deprecated java.lang.String RADIO_BLUETOOTH = "bluetooth";
+    field public static final deprecated java.lang.String RADIO_CELL = "cell";
+    field public static final deprecated java.lang.String RADIO_NFC = "nfc";
+    field public static final deprecated java.lang.String RADIO_WIFI = "wifi";
     field public static final java.lang.String RINGTONE = "ringtone";
     field public static final java.lang.String SCREEN_BRIGHTNESS = "screen_brightness";
     field public static final java.lang.String SCREEN_BRIGHTNESS_MODE = "screen_brightness_mode";
@@ -18882,7 +18936,7 @@
     field public static final java.lang.String SHOW_PROCESSES = "show_processes";
     field public static final deprecated java.lang.String SHOW_WEB_SUGGESTIONS = "show_web_suggestions";
     field public static final java.lang.String SOUND_EFFECTS_ENABLED = "sound_effects_enabled";
-    field public static final java.lang.String STAY_ON_WHILE_PLUGGED_IN = "stay_on_while_plugged_in";
+    field public static final deprecated java.lang.String STAY_ON_WHILE_PLUGGED_IN = "stay_on_while_plugged_in";
     field public static final java.lang.String SYS_PROP_SETTING_VERSION = "sys.settings_system_version";
     field public static final java.lang.String TEXT_AUTO_CAPS = "auto_caps";
     field public static final java.lang.String TEXT_AUTO_PUNCTUATE = "auto_punctuate";
@@ -18910,10 +18964,10 @@
     field public static final deprecated java.lang.String WIFI_NETWORKS_AVAILABLE_REPEAT_DELAY = "wifi_networks_available_repeat_delay";
     field public static final deprecated java.lang.String WIFI_NUM_OPEN_NETWORKS_KEPT = "wifi_num_open_networks_kept";
     field public static final deprecated java.lang.String WIFI_ON = "wifi_on";
-    field public static final java.lang.String WIFI_SLEEP_POLICY = "wifi_sleep_policy";
-    field public static final int WIFI_SLEEP_POLICY_DEFAULT = 0; // 0x0
-    field public static final int WIFI_SLEEP_POLICY_NEVER = 2; // 0x2
-    field public static final int WIFI_SLEEP_POLICY_NEVER_WHILE_PLUGGED = 1; // 0x1
+    field public static final deprecated java.lang.String WIFI_SLEEP_POLICY = "wifi_sleep_policy";
+    field public static final deprecated int WIFI_SLEEP_POLICY_DEFAULT = 0; // 0x0
+    field public static final deprecated int WIFI_SLEEP_POLICY_NEVER = 2; // 0x2
+    field public static final deprecated int WIFI_SLEEP_POLICY_NEVER_WHILE_PLUGGED = 1; // 0x1
     field public static final java.lang.String WIFI_STATIC_DNS1 = "wifi_static_dns1";
     field public static final java.lang.String WIFI_STATIC_DNS2 = "wifi_static_dns2";
     field public static final java.lang.String WIFI_STATIC_GATEWAY = "wifi_static_gateway";
@@ -24976,6 +25030,7 @@
     method public void setId(int);
     method public void setImportantForAccessibility(int);
     method public void setKeepScreenOn(boolean);
+    method public void setLayerPaint(android.graphics.Paint);
     method public void setLayerType(int, android.graphics.Paint);
     method public void setLayoutDirection(int);
     method public void setLayoutParams(android.view.ViewGroup.LayoutParams);
diff --git a/cmds/am/src/com/android/commands/am/Am.java b/cmds/am/src/com/android/commands/am/Am.java
index bcd4588..bb108c8 100644
--- a/cmds/am/src/com/android/commands/am/Am.java
+++ b/cmds/am/src/com/android/commands/am/Am.java
@@ -36,6 +36,7 @@
 import android.os.RemoteException;
 import android.os.ServiceManager;
 import android.os.SystemProperties;
+import android.os.UserHandle;
 import android.util.AndroidException;
 import android.view.Display;
 import android.view.IWindowManager;
@@ -147,6 +148,18 @@
         }
     }
 
+    int parseUserArg(String arg) {
+        int userId;
+        if ("all".equals(arg)) {
+            userId = UserHandle.USER_ALL;
+        } else if ("current".equals(arg) || "cur".equals(arg)) {
+            userId = UserHandle.USER_CURRENT;
+        } else {
+            userId = Integer.parseInt(arg);
+        }
+        return userId;
+    }
+
     private Intent makeIntent() throws URISyntaxException {
         Intent intent = new Intent();
         Intent baseIntent = intent;
@@ -321,7 +334,7 @@
             } else if (opt.equals("--opengl-trace")) {
                 mStartFlags |= ActivityManager.START_FLAG_OPENGL_TRACES;
             } else if (opt.equals("--user")) {
-                mUserId = Integer.parseInt(nextArgRequired());
+                mUserId = parseUserArg(nextArgRequired());
             } else {
                 System.err.println("Error: Unknown option: " + opt);
                 return null;
@@ -392,8 +405,12 @@
 
     private void runStartService() throws Exception {
         Intent intent = makeIntent();
+        if (mUserId == UserHandle.USER_ALL) {
+            System.err.println("Error: Can't start activity with user 'all'");
+            return;
+        }
         System.out.println("Starting service: " + intent);
-        ComponentName cn = mAm.startService(null, intent, intent.getType(), 0);
+        ComponentName cn = mAm.startService(null, intent, intent.getType(), mUserId);
         if (cn == null) {
             System.err.println("Error: Not found; no service started.");
         }
@@ -402,10 +419,15 @@
     private void runStart() throws Exception {
         Intent intent = makeIntent();
 
+        if (mUserId == UserHandle.USER_ALL) {
+            System.err.println("Error: Can't start service with user 'all'");
+            return;
+        }
+
         String mimeType = intent.getType();
         if (mimeType == null && intent.getData() != null
                 && "content".equals(intent.getData().getScheme())) {
-            mimeType = mAm.getProviderMimeType(intent.getData());
+            mimeType = mAm.getProviderMimeType(intent.getData(), mUserId);
         }
 
         do {
@@ -460,11 +482,11 @@
             int res;
             if (mWaitOption) {
                 result = mAm.startActivityAndWait(null, intent, mimeType,
-                            null, null, 0, mStartFlags, mProfileFile, fd, null);
+                            null, null, 0, mStartFlags, mProfileFile, fd, null, mUserId);
                 res = result.result;
             } else {
-                res = mAm.startActivity(null, intent, mimeType,
-                        null, null, 0, mStartFlags, mProfileFile, fd, null);
+                res = mAm.startActivityAsUser(null, intent, mimeType,
+                        null, null, 0, mStartFlags, mProfileFile, fd, null, mUserId);
             }
             PrintStream out = mWaitOption ? System.out : System.err;
             boolean launched = false;
@@ -573,6 +595,7 @@
         boolean wait = false;
         boolean rawMode = false;
         boolean no_window_animation = false;
+        int userId = 0;
         Bundle args = new Bundle();
         String argKey = null, argValue = null;
         IWindowManager wm = IWindowManager.Stub.asInterface(ServiceManager.getService("window"));
@@ -592,12 +615,19 @@
             } else if (opt.equals("--no_window_animation")
                     || opt.equals("--no-window-animation")) {
                 no_window_animation = true;
+            } else if (opt.equals("--user")) {
+                userId = parseUserArg(nextArgRequired());
             } else {
                 System.err.println("Error: Unknown option: " + opt);
                 return;
             }
         }
 
+        if (userId == UserHandle.USER_ALL) {
+            System.err.println("Error: Can't start instrumentation with user 'all'");
+            return;
+        }
+
         String cnArg = nextArgRequired();
         ComponentName cn = ComponentName.unflattenFromString(cnArg);
         if (cn == null) throw new IllegalArgumentException("Bad component name: " + cnArg);
@@ -614,7 +644,7 @@
             wm.setAnimationScale(1, 0.0f);
         }
 
-        if (!mAm.startInstrumentation(cn, profileFile, 0, args, watcher)) {
+        if (!mAm.startInstrumentation(cn, profileFile, 0, args, watcher, userId)) {
             throw new AndroidException("INSTRUMENTATION_FAILED: " + cn.flattenToString());
         }
 
@@ -1188,8 +1218,10 @@
             if (data != null) line = line + ", data=\"" + data + "\"";
             if (extras != null) line = line + ", extras: " + extras;
             System.out.println(line);
-            mFinished = true;
-            notifyAll();
+            synchronized (this) {
+              mFinished = true;
+              notifyAll();
+            }
         }
 
         public synchronized void waitForFinish() {
@@ -1338,6 +1370,7 @@
                 "       am kill-all\n" +
                 "       am broadcast <INTENT>\n" +
                 "       am instrument [-r] [-e <NAME> <VALUE>] [-p <FILE>] [-w]\n" +
+                "               [--user <USER_ID> | all | current]\n" +
                 "               [--no-window-animation] <COMPONENT>\n" +
                 "       am profile start <PROCESS> <FILE>\n" +
                 "       am profile stop [<PROCESS>]\n" +
@@ -1384,6 +1417,7 @@
                 "    -p <FILE>: write profiling data to <FILE>\n" +
                 "    -w: wait for instrumentation to finish before returning.  Required for\n" +
                 "        test runners.\n" +
+                "    --user [<USER_ID> | all | current]: Specify user instrumentation runs in.\n" +
                 "    --no-window-animation: turn off window animations will running.\n" +
                 "\n" +
                 "am profile: start and stop profiler on a process.\n" +
@@ -1431,6 +1465,7 @@
                 "    [--ela <EXTRA_KEY> <EXTRA_LONG_VALUE>[,<EXTRA_LONG_VALUE...]]\n" +
                 "    [--efa <EXTRA_KEY> <EXTRA_FLOAT_VALUE>[,<EXTRA_FLOAT_VALUE...]]\n" +
                 "    [-n <COMPONENT>] [-f <FLAGS>]\n" +
+                "    [--user [<USER_ID> | all | current]\n" +
                 "    [--grant-read-uri-permission] [--grant-write-uri-permission]\n" +
                 "    [--debug-log-resolution] [--exclude-stopped-packages]\n" +
                 "    [--include-stopped-packages]\n" +
diff --git a/cmds/installd/commands.c b/cmds/installd/commands.c
index 9e83a67..68f8400 100644
--- a/cmds/installd/commands.c
+++ b/cmds/installd/commands.c
@@ -403,37 +403,6 @@
     }
 }
 
-int protect(char *pkgname, gid_t gid)
-{
-    struct stat s;
-    char pkgpath[PKG_PATH_MAX];
-
-    if (gid < AID_SYSTEM) return -1;
-
-    if (create_pkg_path_in_dir(pkgpath, &android_app_private_dir, pkgname, ".apk"))
-        return -1;
-
-    if (stat(pkgpath, &s) < 0) return -1;
-
-    if (chown(pkgpath, s.st_uid, gid) < 0) {
-        ALOGE("failed to chgrp '%s': %s\n", pkgpath, strerror(errno));
-        return -1;
-    }
-    if (chmod(pkgpath, S_IRUSR|S_IWUSR|S_IRGRP) < 0) {
-        ALOGE("failed to chmod '%s': %s\n", pkgpath, strerror(errno));
-        return -1;
-    }
-
-#ifdef HAVE_SELINUX
-    if (selinux_android_setfilecon(pkgpath, pkgname, s.st_uid) < 0) {
-        ALOGE("cannot setfilecon dir '%s': %s\n", pkgpath, strerror(errno));
-        return -1;
-    }
-#endif
-
-    return 0;
-}
-
 int get_size(const char *pkgname, int persona, const char *apkpath,
              const char *fwdlock_apkpath, const char *asecpath,
              int64_t *_codesize, int64_t *_datasize, int64_t *_cachesize,
@@ -1014,13 +983,13 @@
 
     if (stat(dataDir, &s) < 0) return -1;
 
-    if (chown(dataDir, 0, 0) < 0) {
+    if (chown(dataDir, AID_INSTALL, AID_INSTALL) < 0) {
         ALOGE("failed to chown '%s': %s\n", dataDir, strerror(errno));
         return -1;
     }
 
     if (chmod(dataDir, 0700) < 0) {
-        ALOGE("failed to chmod '%s': %s\n", dataDir, strerror(errno));
+        ALOGE("linklib() 1: failed to chmod '%s': %s\n", dataDir, strerror(errno));
         rc = -1;
         goto out;
     }
@@ -1058,7 +1027,7 @@
 
 out:
     if (chmod(dataDir, s.st_mode) < 0) {
-        ALOGE("failed to chmod '%s': %s\n", dataDir, strerror(errno));
+        ALOGE("linklib() 2: failed to chmod '%s': %s\n", dataDir, strerror(errno));
         rc = -errno;
     }
 
@@ -1091,13 +1060,13 @@
         return -1;
     }
 
-    if (chown(dataDir, 0, 0) < 0) {
+    if (chown(dataDir, AID_INSTALL, AID_INSTALL) < 0) {
         ALOGE("failed to chown '%s': %s\n", dataDir, strerror(errno));
         return -1;
     }
 
     if (chmod(dataDir, 0700) < 0) {
-        ALOGE("failed to chmod '%s': %s\n", dataDir, strerror(errno));
+        ALOGE("unlinklib() 1: failed to chmod '%s': %s\n", dataDir, strerror(errno));
         rc = -1;
         goto out;
     }
@@ -1140,7 +1109,7 @@
 
 out:
     if (chmod(dataDir, s.st_mode) < 0) {
-        ALOGE("failed to chmod '%s': %s\n", dataDir, strerror(errno));
+        ALOGE("unlinklib() 2: failed to chmod '%s': %s\n", dataDir, strerror(errno));
         rc = -1;
     }
 
diff --git a/cmds/installd/installd.c b/cmds/installd/installd.c
index 652543fd..cc8f014 100644
--- a/cmds/installd/installd.c
+++ b/cmds/installd/installd.c
@@ -75,11 +75,6 @@
     return delete_cache(arg[0]); /* pkgname */
 }
 
-static int do_protect(char **arg, char reply[REPLY_MAX])
-{
-    return protect(arg[0], atoi(arg[1])); /* pkgname, gid */
-}
-
 static int do_get_size(char **arg, char reply[REPLY_MAX])
 {
     int64_t codesize = 0;
@@ -153,7 +148,6 @@
     { "fixuid",               3, do_fixuid },
     { "freecache",            1, do_free_cache },
     { "rmcache",              1, do_rm_cache },
-    { "protect",              2, do_protect },
     { "getsize",              5, do_get_size },
     { "rmuserdata",           2, do_rm_user_data },
     { "movefiles",            0, do_movefiles },
diff --git a/cmds/pm/src/com/android/commands/pm/Pm.java b/cmds/pm/src/com/android/commands/pm/Pm.java
index 36bf38a..e0f54fb 100644
--- a/cmds/pm/src/com/android/commands/pm/Pm.java
+++ b/cmds/pm/src/com/android/commands/pm/Pm.java
@@ -20,7 +20,6 @@
 
 import android.app.ActivityManagerNative;
 import android.content.ComponentName;
-import android.content.Context;
 import android.content.pm.ApplicationInfo;
 import android.content.pm.ContainerEncryptionParams;
 import android.content.pm.FeatureInfo;
@@ -40,12 +39,10 @@
 import android.content.res.AssetManager;
 import android.content.res.Resources;
 import android.net.Uri;
-import android.os.Binder;
 import android.os.IUserManager;
-import android.os.Process;
 import android.os.RemoteException;
 import android.os.ServiceManager;
-import android.os.UserManager;
+import android.os.UserHandle;
 
 import java.io.File;
 import java.lang.reflect.Field;
@@ -74,7 +71,6 @@
 
     private static final String PM_NOT_RUNNING_ERR =
         "Error: Could not access the Package Manager.  Is the system running?";
-    private static final int ROOT_UID = 0;
 
     public static void main(String[] args) {
         new Pm().run(args);
@@ -246,6 +242,7 @@
         boolean listDisabled = false, listEnabled = false;
         boolean listSystem = false, listThirdParty = false;
         boolean listInstaller = false;
+        int userId = UserHandle.USER_OWNER;
         try {
             String opt;
             while ((opt=nextOption()) != null) {
@@ -265,6 +262,8 @@
                     listThirdParty = true;
                 } else if (opt.equals("-i")) {
                     listInstaller = true;
+                } else if (opt.equals("--user")) {
+                    userId = Integer.parseInt(nextArg());
                 } else if (opt.equals("-u")) {
                     getFlags |= PackageManager.GET_UNINSTALLED_PACKAGES;
                 } else {
@@ -280,7 +279,7 @@
         String filter = nextArg();
 
         try {
-            final List<PackageInfo> packages = getInstalledPackages(mPm, getFlags);
+            final List<PackageInfo> packages = getInstalledPackages(mPm, getFlags, userId);
 
             int count = packages.size();
             for (int p = 0 ; p < count ; p++) {
@@ -314,7 +313,7 @@
     }
 
     @SuppressWarnings("unchecked")
-    private List<PackageInfo> getInstalledPackages(IPackageManager pm, int flags)
+    private List<PackageInfo> getInstalledPackages(IPackageManager pm, int flags, int userId)
             throws RemoteException {
         final List<PackageInfo> packageInfos = new ArrayList<PackageInfo>();
         PackageInfo lastItem = null;
@@ -322,7 +321,7 @@
 
         do {
             final String lastKey = lastItem != null ? lastItem.packageName : null;
-            slice = pm.getInstalledPackages(flags, lastKey);
+            slice = pm.getInstalledPackages(flags, lastKey, userId);
             lastItem = slice.populateList(packageInfos, PackageInfo.CREATOR);
         } while (!slice.isLastSlice());
 
@@ -1054,11 +1053,16 @@
     }
 
     private void runUninstall() {
-        int unInstallFlags = 0;
+        int unInstallFlags = PackageManager.DELETE_ALL_USERS;
 
-        String opt = nextOption();
-        if (opt != null && opt.equals("-k")) {
-            unInstallFlags = PackageManager.DELETE_KEEP_DATA;
+        String opt;
+        while ((opt=nextOption()) != null) {
+            if (opt.equals("-k")) {
+                unInstallFlags |= PackageManager.DELETE_KEEP_DATA;
+            } else {
+                System.err.println("Error: Unknown option: " + opt);
+                return;
+            }
         }
 
         String pkg = nextArg();
@@ -1420,7 +1424,7 @@
     }
 
     private static void showUsage() {
-        System.err.println("usage: pm list packages [-f] [-d] [-e] [-s] [-3] [-i] [-u] [FILTER]");
+        System.err.println("usage: pm list packages [-f] [-d] [-e] [-s] [-3] [-i] [-u] [--user USER_ID] [FILTER]");
         System.err.println("       pm list permission-groups");
         System.err.println("       pm list permissions [-g] [-f] [-d] [-u] [GROUP]");
         System.err.println("       pm list instrumentation [-f] [TARGET-PACKAGE]");
diff --git a/cmds/svc/src/com/android/commands/svc/PowerCommand.java b/cmds/svc/src/com/android/commands/svc/PowerCommand.java
index ec3ec3e..58105fa 100644
--- a/cmds/svc/src/com/android/commands/svc/PowerCommand.java
+++ b/cmds/svc/src/com/android/commands/svc/PowerCommand.java
@@ -16,14 +16,12 @@
 
 package com.android.commands.svc;
 
-import android.os.Binder;
-import android.os.IBinder;
-import android.os.IPowerManager;
-import android.os.PowerManager;
-import android.os.ServiceManager;
-import android.os.RemoteException;
-import android.os.BatteryManager;
 import android.content.Context;
+import android.os.BatteryManager;
+import android.os.IPowerManager;
+import android.os.RemoteException;
+import android.os.ServiceManager;
+import android.os.SystemClock;
 
 public class PowerCommand extends Svc.Command {
     public PowerCommand() {
@@ -65,10 +63,12 @@
                     IPowerManager pm
                             = IPowerManager.Stub.asInterface(ServiceManager.getService(Context.POWER_SERVICE));
                     try {
-                        IBinder lock = new Binder();
-                        pm.acquireWakeLock(lock, PowerManager.FULL_WAKE_LOCK, "svc power", null);
+                        if (val != 0) {
+                            // if the request is not to set it to false, wake up the screen so that
+                            // it can stay on as requested
+                            pm.wakeUp(SystemClock.uptimeMillis());
+                        }
                         pm.setStayOnSetting(val);
-                        pm.releaseWakeLock(lock, 0);
                     }
                     catch (RemoteException e) {
                         System.err.println("Faild to set setting: " + e);
diff --git a/core/java/android/accessibilityservice/AccessibilityServiceInfo.java b/core/java/android/accessibilityservice/AccessibilityServiceInfo.java
index 10ea0fe..75a4f83 100644
--- a/core/java/android/accessibilityservice/AccessibilityServiceInfo.java
+++ b/core/java/android/accessibilityservice/AccessibilityServiceInfo.java
@@ -85,6 +85,11 @@
     public static final int FEEDBACK_GENERIC = 0x0000010;
 
     /**
+     * Denotes braille feedback.
+     */
+    public static final int FEEDBACK_BRAILLE = 0x0000020;
+
+    /**
      * Mask for all feedback types.
      *
      * @see #FEEDBACK_SPOKEN
@@ -92,6 +97,7 @@
      * @see #FEEDBACK_AUDIBLE
      * @see #FEEDBACK_VISUAL
      * @see #FEEDBACK_GENERIC
+     * @see #FEEDBACK_BRAILLE
      */
     public static final int FEEDBACK_ALL_MASK = 0xFFFFFFFF;
 
@@ -186,6 +192,7 @@
      * @see #FEEDBACK_HAPTIC
      * @see #FEEDBACK_SPOKEN
      * @see #FEEDBACK_VISUAL
+     * @see #FEEDBACK_BRAILLE
      */
     public int feedbackType;
 
@@ -591,6 +598,12 @@
                     }
                     builder.append("FEEDBACK_VISUAL");
                     break;
+                case FEEDBACK_BRAILLE:
+                    if (builder.length() > 1) {
+                        builder.append(", ");
+                    }
+                    builder.append("FEEDBACK_BRAILLE");
+                    break;
             }
         }
         builder.append("]");
diff --git a/core/java/android/app/Activity.java b/core/java/android/app/Activity.java
index 99dfccb..05b04dc 100644
--- a/core/java/android/app/Activity.java
+++ b/core/java/android/app/Activity.java
@@ -653,8 +653,9 @@
     /** Start of user-defined activity results. */
     public static final int RESULT_FIRST_USER   = 1;
 
+    static final String FRAGMENTS_TAG = "android:fragments";
+
     private static final String WINDOW_HIERARCHY_TAG = "android:viewHierarchyState";
-    private static final String FRAGMENTS_TAG = "android:fragments";
     private static final String SAVED_DIALOG_IDS_KEY = "android:savedDialogIds";
     private static final String SAVED_DIALOGS_TAG = "android:savedDialogs";
     private static final String SAVED_DIALOG_KEY_PREFIX = "android:dialog_";
@@ -697,7 +698,7 @@
         Object activity;
         HashMap<String, Object> children;
         ArrayList<Fragment> fragments;
-        SparseArray<LoaderManagerImpl> loaders;
+        HashMap<String, LoaderManagerImpl> loaders;
     }
     /* package */ NonConfigurationInstances mLastNonConfigurationInstances;
     
@@ -715,8 +716,14 @@
     private int mTitleColor = 0;
 
     final FragmentManagerImpl mFragments = new FragmentManagerImpl();
+    final FragmentContainer mContainer = new FragmentContainer() {
+        @Override
+        public View findViewById(int id) {
+            return Activity.this.findViewById(id);
+        }
+    };
     
-    SparseArray<LoaderManagerImpl> mAllLoaderManagers;
+    HashMap<String, LoaderManagerImpl> mAllLoaderManagers;
     LoaderManagerImpl mLoaderManager;
     
     private static final class ManagedCursor {
@@ -744,6 +751,7 @@
     
     protected static final int[] FOCUSED_STATE_SET = {com.android.internal.R.attr.state_focused};
 
+    @SuppressWarnings("unused")
     private final Object mInstanceTracker = StrictMode.trackActivity(this);
 
     private Thread mUiThread;
@@ -808,19 +816,19 @@
             return mLoaderManager;
         }
         mCheckedForLoaderManager = true;
-        mLoaderManager = getLoaderManager(-1, mLoadersStarted, true);
+        mLoaderManager = getLoaderManager(null, mLoadersStarted, true);
         return mLoaderManager;
     }
     
-    LoaderManagerImpl getLoaderManager(int index, boolean started, boolean create) {
+    LoaderManagerImpl getLoaderManager(String who, boolean started, boolean create) {
         if (mAllLoaderManagers == null) {
-            mAllLoaderManagers = new SparseArray<LoaderManagerImpl>();
+            mAllLoaderManagers = new HashMap<String, LoaderManagerImpl>();
         }
-        LoaderManagerImpl lm = mAllLoaderManagers.get(index);
+        LoaderManagerImpl lm = mAllLoaderManagers.get(who);
         if (lm == null) {
             if (create) {
-                lm = new LoaderManagerImpl(this, started);
-                mAllLoaderManagers.put(index, lm);
+                lm = new LoaderManagerImpl(who, this, started);
+                mAllLoaderManagers.put(who, lm);
             }
         } else {
             lm.updateActivity(this);
@@ -1025,7 +1033,7 @@
             if (mLoaderManager != null) {
                 mLoaderManager.doStart();
             } else if (!mCheckedForLoaderManager) {
-                mLoaderManager = getLoaderManager(-1, mLoadersStarted, false);
+                mLoaderManager = getLoaderManager(null, mLoadersStarted, false);
             }
             mCheckedForLoaderManager = true;
         }
@@ -1601,13 +1609,17 @@
         if (mAllLoaderManagers != null) {
             // prune out any loader managers that were already stopped and so
             // have nothing useful to retain.
-            for (int i=mAllLoaderManagers.size()-1; i>=0; i--) {
-                LoaderManagerImpl lm = mAllLoaderManagers.valueAt(i);
-                if (lm.mRetaining) {
-                    retainLoaders = true;
-                } else {
-                    lm.doDestroy();
-                    mAllLoaderManagers.removeAt(i);
+            LoaderManagerImpl loaders[] = new LoaderManagerImpl[mAllLoaderManagers.size()];
+            mAllLoaderManagers.values().toArray(loaders);
+            if (loaders != null) {
+                for (int i=0; i<loaders.length; i++) {
+                    LoaderManagerImpl lm = loaders[i];
+                    if (lm.mRetaining) {
+                        retainLoaders = true;
+                    } else {
+                        lm.doDestroy();
+                        mAllLoaderManagers.remove(lm.mWho);
+                    }
                 }
             }
         }
@@ -1643,13 +1655,13 @@
         return mFragments;
     }
 
-    void invalidateFragmentIndex(int index) {
+    void invalidateFragment(String who) {
         //Log.v(TAG, "invalidateFragmentIndex: index=" + index);
         if (mAllLoaderManagers != null) {
-            LoaderManagerImpl lm = mAllLoaderManagers.get(index);
+            LoaderManagerImpl lm = mAllLoaderManagers.get(who);
             if (lm != null && !lm.mRetaining) {
                 lm.doDestroy();
-                mAllLoaderManagers.remove(index);
+                mAllLoaderManagers.remove(who);
             }
         }
     }
@@ -4739,6 +4751,10 @@
      * @param args additional arguments to the dump request.
      */
     public void dump(String prefix, FileDescriptor fd, PrintWriter writer, String[] args) {
+        dumpInner(prefix, fd, writer, args);
+    }
+
+    void dumpInner(String prefix, FileDescriptor fd, PrintWriter writer, String[] args) {
         writer.print(prefix); writer.print("Local Activity ");
                 writer.print(Integer.toHexString(System.identityHashCode(this)));
                 writer.println(" State:");
@@ -5019,7 +5035,7 @@
             Configuration config) {
         attachBaseContext(context);
 
-        mFragments.attachActivity(this);
+        mFragments.attachActivity(this, mContainer, null);
         
         mWindow = PolicyManager.makeNewWindow(this);
         mWindow.setCallback(this);
@@ -5080,10 +5096,14 @@
         }
         mFragments.dispatchStart();
         if (mAllLoaderManagers != null) {
-            for (int i=mAllLoaderManagers.size()-1; i>=0; i--) {
-                LoaderManagerImpl lm = mAllLoaderManagers.valueAt(i);
-                lm.finishRetain();
-                lm.doReportStart();
+            LoaderManagerImpl loaders[] = new LoaderManagerImpl[mAllLoaderManagers.size()];
+            mAllLoaderManagers.values().toArray(loaders);
+            if (loaders != null) {
+                for (int i=0; i<loaders.length; i++) {
+                    LoaderManagerImpl lm = loaders[i];
+                    lm.finishRetain();
+                    lm.doReportStart();
+                }
             }
         }
     }
diff --git a/core/java/android/app/ActivityManager.java b/core/java/android/app/ActivityManager.java
index cd22aad..bb3c56a 100644
--- a/core/java/android/app/ActivityManager.java
+++ b/core/java/android/app/ActivityManager.java
@@ -1957,4 +1957,21 @@
             return false;
         }
     }
+
+    /**
+     * Return whether the given user is actively running.  This means that
+     * the user is in the "started" state, not "stopped" -- it is currently
+     * allowed to run code through scheduled alarms, receiving broadcasts,
+     * etc.  A started user may be either the current foreground user or a
+     * background user; the result here does not distinguish between the two.
+     * @param userid the user's id. Zero indicates the default user.
+     * @hide
+     */
+    public boolean isUserRunning(int userid) {
+        try {
+            return ActivityManagerNative.getDefault().isUserRunning(userid);
+        } catch (RemoteException e) {
+            return false;
+        }
+    }
 }
diff --git a/core/java/android/app/ActivityManagerNative.java b/core/java/android/app/ActivityManagerNative.java
index eed9254..e5dd7b1 100644
--- a/core/java/android/app/ActivityManagerNative.java
+++ b/core/java/android/app/ActivityManagerNative.java
@@ -177,9 +177,10 @@
                     ? data.readFileDescriptor() : null;
             Bundle options = data.readInt() != 0
                     ? Bundle.CREATOR.createFromParcel(data) : null;
+            int userId = data.readInt();
             WaitResult result = startActivityAndWait(app, intent, resolvedType,
                     resultTo, resultWho, requestCode, startFlags,
-                    profileFile, profileFd, options);
+                    profileFile, profileFd, options, userId);
             reply.writeNoException();
             result.writeToParcel(reply, 0);
             return true;
@@ -811,7 +812,8 @@
             Bundle arguments = data.readBundle();
             IBinder b = data.readStrongBinder();
             IInstrumentationWatcher w = IInstrumentationWatcher.Stub.asInterface(b);
-            boolean res = startInstrumentation(className, profileFile, fl, arguments, w);
+            int userId = data.readInt();
+            boolean res = startInstrumentation(className, profileFile, fl, arguments, w, userId);
             reply.writeNoException();
             reply.writeInt(res ? 1 : 0);
             return true;
@@ -1323,11 +1325,11 @@
             return true;
         }
         
-        case KILL_APPLICATION_WITH_UID_TRANSACTION: {
+        case KILL_APPLICATION_WITH_APPID_TRANSACTION: {
             data.enforceInterface(IActivityManager.descriptor);
             String pkg = data.readString();
-            int uid = data.readInt();
-            killApplicationWithUid(pkg, uid);
+            int appid = data.readInt();
+            killApplicationWithAppId(pkg, appid);
             reply.writeNoException();
             return true;
         }
@@ -1424,7 +1426,8 @@
         case GET_PROVIDER_MIME_TYPE_TRANSACTION: {
             data.enforceInterface(IActivityManager.descriptor);
             Uri uri = Uri.CREATOR.createFromParcel(data);
-            String type = getProviderMimeType(uri);
+            int userId = data.readInt();
+            String type = getProviderMimeType(uri, userId);
             reply.writeNoException();
             reply.writeString(type);
             return true;
@@ -1573,6 +1576,15 @@
             return true;
         }
 
+        case IS_USER_RUNNING_TRANSACTION: {
+            data.enforceInterface(IActivityManager.descriptor);
+            int userid = data.readInt();
+            boolean result = isUserRunning(userid);
+            reply.writeNoException();
+            reply.writeInt(result ? 1 : 0);
+            return true;
+        }
+
         case REMOVE_SUB_TASK_TRANSACTION:
         {
             data.enforceInterface(IActivityManager.descriptor);
@@ -1827,7 +1839,7 @@
     public WaitResult startActivityAndWait(IApplicationThread caller, Intent intent,
             String resolvedType, IBinder resultTo, String resultWho,
             int requestCode, int startFlags, String profileFile,
-            ParcelFileDescriptor profileFd, Bundle options) throws RemoteException {
+            ParcelFileDescriptor profileFd, Bundle options, int userId) throws RemoteException {
         Parcel data = Parcel.obtain();
         Parcel reply = Parcel.obtain();
         data.writeInterfaceToken(IActivityManager.descriptor);
@@ -1851,6 +1863,7 @@
         } else {
             data.writeInt(0);
         }
+        data.writeInt(userId);
         mRemote.transact(START_ACTIVITY_AND_WAIT_TRANSACTION, data, reply, 0);
         reply.readException();
         WaitResult result = WaitResult.CREATOR.createFromParcel(reply);
@@ -2719,7 +2732,7 @@
     }
 
     public boolean startInstrumentation(ComponentName className, String profileFile,
-            int flags, Bundle arguments, IInstrumentationWatcher watcher)
+            int flags, Bundle arguments, IInstrumentationWatcher watcher, int userId)
             throws RemoteException {
         Parcel data = Parcel.obtain();
         Parcel reply = Parcel.obtain();
@@ -2729,6 +2742,7 @@
         data.writeInt(flags);
         data.writeBundle(arguments);
         data.writeStrongBinder(watcher != null ? watcher.asBinder() : null);
+        data.writeInt(userId);
         mRemote.transact(START_INSTRUMENTATION_TRANSACTION, data, reply, 0);
         reply.readException();
         boolean res = reply.readInt() != 0;
@@ -3366,13 +3380,13 @@
         data.recycle();
     }
     
-    public void killApplicationWithUid(String pkg, int uid) throws RemoteException {
+    public void killApplicationWithAppId(String pkg, int appid) throws RemoteException {
         Parcel data = Parcel.obtain();
         Parcel reply = Parcel.obtain();
         data.writeInterfaceToken(IActivityManager.descriptor);
         data.writeString(pkg);
-        data.writeInt(uid);
-        mRemote.transact(KILL_APPLICATION_WITH_UID_TRANSACTION, data, reply, 0);
+        data.writeInt(appid);
+        mRemote.transact(KILL_APPLICATION_WITH_APPID_TRANSACTION, data, reply, 0);
         reply.readException();
         data.recycle();
         reply.recycle();
@@ -3507,12 +3521,12 @@
         reply.recycle();
     }
 
-    public String getProviderMimeType(Uri uri)
-            throws RemoteException {
+    public String getProviderMimeType(Uri uri, int userId) throws RemoteException {
         Parcel data = Parcel.obtain();
         Parcel reply = Parcel.obtain();
         data.writeInterfaceToken(IActivityManager.descriptor);
         uri.writeToParcel(data, 0);
+        data.writeInt(userId);
         mRemote.transact(GET_PROVIDER_MIME_TYPE_TRANSACTION, data, reply, 0);
         reply.readException();
         String res = reply.readString();
@@ -3747,6 +3761,19 @@
         return userInfo;
     }
 
+    public boolean isUserRunning(int userid) throws RemoteException {
+        Parcel data = Parcel.obtain();
+        Parcel reply = Parcel.obtain();
+        data.writeInterfaceToken(IActivityManager.descriptor);
+        data.writeInt(userid);
+        mRemote.transact(IS_USER_RUNNING_TRANSACTION, data, reply, 0);
+        reply.readException();
+        boolean result = reply.readInt() != 0;
+        reply.recycle();
+        data.recycle();
+        return result;
+    }
+
     public boolean removeSubTask(int taskId, int subTaskIndex) throws RemoteException {
         Parcel data = Parcel.obtain();
         Parcel reply = Parcel.obtain();
diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java
index 97dcec0..38e6970 100644
--- a/core/java/android/app/ActivityThread.java
+++ b/core/java/android/app/ActivityThread.java
@@ -1586,7 +1586,15 @@
         CompatibilityInfoHolder cih = new CompatibilityInfoHolder();
         cih.set(ci);
         Display d = displayManager.getCompatibleDisplay(displayId, cih);
-        d.getMetrics(dm);
+        if (d != null) {
+            d.getMetrics(dm);
+        } else {
+            // Display no longer exists
+            // FIXME: This would not be a problem if we kept the Display object around
+            // instead of using the raw display id everywhere.  The Display object caches
+            // its information even after the display has been removed.
+            dm.setToDefaults();
+        }
         //Slog.i("foo", "New metrics: w=" + metrics.widthPixels + " h="
         //        + metrics.heightPixels + " den=" + metrics.density
         //        + " xdpi=" + metrics.xdpi + " ydpi=" + metrics.ydpi);
diff --git a/core/java/android/app/ApplicationPackageManager.java b/core/java/android/app/ApplicationPackageManager.java
index c4f1371..7870031 100644
--- a/core/java/android/app/ApplicationPackageManager.java
+++ b/core/java/android/app/ApplicationPackageManager.java
@@ -407,6 +407,12 @@
     @SuppressWarnings("unchecked")
     @Override
     public List<PackageInfo> getInstalledPackages(int flags) {
+        return getInstalledPackages(flags, UserHandle.myUserId());
+    }
+
+    /** @hide */
+    @Override
+    public List<PackageInfo> getInstalledPackages(int flags, int userId) {
         try {
             final List<PackageInfo> packageInfos = new ArrayList<PackageInfo>();
             PackageInfo lastItem = null;
@@ -414,7 +420,7 @@
 
             do {
                 final String lastKey = lastItem != null ? lastItem.packageName : null;
-                slice = mPM.getInstalledPackages(flags, lastKey);
+                slice = mPM.getInstalledPackages(flags, lastKey, userId);
                 lastItem = slice.populateList(packageInfos, PackageInfo.CREATOR);
             } while (!slice.isLastSlice());
 
@@ -460,12 +466,19 @@
     @Override
     public List<ResolveInfo> queryIntentActivities(Intent intent,
                                                    int flags) {
+        return queryIntentActivitiesForUser(intent, flags, UserHandle.myUserId());
+    }
+
+    /** @hide Same as above but for a specific user */
+    @Override
+    public List<ResolveInfo> queryIntentActivitiesForUser(Intent intent,
+                                                   int flags, int userId) {
         try {
             return mPM.queryIntentActivities(
                 intent,
                 intent.resolveTypeIfNeeded(mContext.getContentResolver()),
                 flags,
-                UserHandle.myUserId());
+                userId);
         } catch (RemoteException e) {
             throw new RuntimeException("Package manager has died", e);
         }
diff --git a/core/java/android/app/ContextImpl.java b/core/java/android/app/ContextImpl.java
index 65ea6a0..3498919 100644
--- a/core/java/android/app/ContextImpl.java
+++ b/core/java/android/app/ContextImpl.java
@@ -1428,7 +1428,7 @@
                 arguments.setAllowFds(false);
             }
             return ActivityManagerNative.getDefault().startInstrumentation(
-                    className, profileFile, 0, arguments, null);
+                    className, profileFile, 0, arguments, null, UserHandle.myUserId());
         } catch (RemoteException e) {
             // System has crashed, nothing we can do.
         }
diff --git a/core/java/android/app/Fragment.java b/core/java/android/app/Fragment.java
index 28876d3..c5a382d 100644
--- a/core/java/android/app/Fragment.java
+++ b/core/java/android/app/Fragment.java
@@ -85,7 +85,7 @@
         mSavedFragmentState = in.readBundle();
     }
     
-    public Fragment instantiate(Activity activity) {
+    public Fragment instantiate(Activity activity, Fragment parent) {
         if (mInstance != null) {
             return mInstance;
         }
@@ -100,7 +100,7 @@
             mSavedFragmentState.setClassLoader(activity.getClassLoader());
             mInstance.mSavedFragmentState = mSavedFragmentState;
         }
-        mInstance.setIndex(mIndex);
+        mInstance.setIndex(mIndex, parent);
         mInstance.mFromLayout = mFromLayout;
         mInstance.mRestored = true;
         mInstance.mFragmentId = mFragmentId;
@@ -207,6 +207,8 @@
  * with the fragment.
  * <li> {@link #onActivityCreated} tells the fragment that its activity has
  * completed its own {@link Activity#onCreate Activity.onCreate()}.
+ * <li> {@link #onViewStateRestored} tells the fragment that all of the saved
+ * state of its view hierarchy has been restored.
  * <li> {@link #onStart} makes the fragment visible to the user (based on its
  * containing activity being started).
  * <li> {@link #onResume} makes the fragment interacting with the user (based on its
@@ -412,7 +414,13 @@
 
     // Activity this fragment is attached to.
     Activity mActivity;
-    
+
+    // Private fragment manager for child fragments inside of this one.
+    FragmentManagerImpl mChildFragmentManager;
+
+    // If this Fragment is contained in another Fragment, this is that container.
+    Fragment mParentFragment;
+
     // The optional identifier for this fragment -- either the container ID if it
     // was dynamically added to the view hierarchy, or the ID supplied in
     // layout.
@@ -595,18 +603,28 @@
         }
     }
     
-    final void restoreViewState() {
+    final void restoreViewState(Bundle savedInstanceState) {
         if (mSavedViewState != null) {
             mView.restoreHierarchyState(mSavedViewState);
             mSavedViewState = null;
         }
+        mCalled = false;
+        onViewStateRestored(savedInstanceState);
+        if (!mCalled) {
+            throw new SuperNotCalledException("Fragment " + this
+                    + " did not call through to super.onViewStateRestored()");
+        }
     }
-    
-    final void setIndex(int index) {
+
+    final void setIndex(int index, Fragment parent) {
         mIndex = index;
-        mWho = "android:fragment:" + mIndex;
-   }
-    
+        if (parent != null) {
+            mWho = parent.mWho + ":" + mIndex;
+        } else {
+            mWho = "android:fragment:" + mIndex;
+        }
+    }
+
     final boolean isInBackStack() {
         return mBackStackNesting > 0;
     }
@@ -785,12 +803,43 @@
      * before {@link #getActivity()}, during the time from when the fragment is
      * placed in a {@link FragmentTransaction} until it is committed and
      * attached to its activity.
+     *
+     * <p>If this Fragment is a child of another Fragment, the FragmentManager
+     * returned here will be the parent's {@link #getChildFragmentManager()}.
      */
     final public FragmentManager getFragmentManager() {
         return mFragmentManager;
     }
 
     /**
+     * Return a private FragmentManager for placing and managing Fragments
+     * inside of this Fragment.
+     */
+    final public FragmentManager getChildFragmentManager() {
+        if (mChildFragmentManager == null) {
+            instantiateChildFragmentManager();
+            if (mState >= RESUMED) {
+                mChildFragmentManager.dispatchResume();
+            } else if (mState >= STARTED) {
+                mChildFragmentManager.dispatchStart();
+            } else if (mState >= ACTIVITY_CREATED) {
+                mChildFragmentManager.dispatchActivityCreated();
+            } else if (mState >= CREATED) {
+                mChildFragmentManager.dispatchCreate();
+            }
+        }
+        return mChildFragmentManager;
+    }
+
+    /**
+     * Returns the parent Fragment containing this Fragment.  If this Fragment
+     * is attached directly to an Activity, returns null.
+     */
+    final public Fragment getParentFragment() {
+        return mParentFragment;
+    }
+
+    /**
      * Return true if the fragment is currently added to its activity.
      */
     final public boolean isAdded() {
@@ -880,6 +929,10 @@
      * </ul>
      */
     public void setRetainInstance(boolean retain) {
+        if (retain && mParentFragment != null) {
+            throw new IllegalStateException(
+                    "Can't retain fragements that are nested in other fragments");
+        }
         mRetainInstance = retain;
     }
     
@@ -961,7 +1014,7 @@
             throw new IllegalStateException("Fragment " + this + " not attached to Activity");
         }
         mCheckedForLoaderManager = true;
-        mLoaderManager = mActivity.getLoaderManager(mIndex, mLoadersStarted, true);
+        mLoaderManager = mActivity.getLoaderManager(mWho, mLoadersStarted, true);
         return mLoaderManager;
     }
 
@@ -1135,20 +1188,7 @@
     public void onCreate(Bundle savedInstanceState) {
         mCalled = true;
     }
-    
-    /**
-     * Called immediately after {@link #onCreateView(LayoutInflater, ViewGroup, Bundle)}
-     * has returned, but before any saved state has been restored in to the view.
-     * This gives subclasses a chance to initialize themselves once
-     * they know their view hierarchy has been completely created.  The fragment's
-     * view hierarchy is not however attached to its parent at this point.
-     * @param view The View returned by {@link #onCreateView(LayoutInflater, ViewGroup, Bundle)}.
-     * @param savedInstanceState If non-null, this fragment is being re-constructed
-     * from a previous saved state as given here.
-     */
-    public void onViewCreated(View view, Bundle savedInstanceState) {
-    }
-    
+
     /**
      * Called to have the fragment instantiate its user interface view.
      * This is optional, and non-graphical fragments can return null (which
@@ -1172,6 +1212,19 @@
             Bundle savedInstanceState) {
         return null;
     }
+
+    /**
+     * Called immediately after {@link #onCreateView(LayoutInflater, ViewGroup, Bundle)}
+     * has returned, but before any saved state has been restored in to the view.
+     * This gives subclasses a chance to initialize themselves once
+     * they know their view hierarchy has been completely created.  The fragment's
+     * view hierarchy is not however attached to its parent at this point.
+     * @param view The View returned by {@link #onCreateView(LayoutInflater, ViewGroup, Bundle)}.
+     * @param savedInstanceState If non-null, this fragment is being re-constructed
+     * from a previous saved state as given here.
+     */
+    public void onViewCreated(View view, Bundle savedInstanceState) {
+    }
     
     /**
      * Get the root view for the fragment's layout (the one returned by {@link #onCreateView}),
@@ -1191,15 +1244,30 @@
      * {@link #setRetainInstance(boolean)} to retain their instance,
      * as this callback tells the fragment when it is fully associated with
      * the new activity instance.  This is called after {@link #onCreateView}
-     * and before {@link #onStart()}.
-     * 
+     * and before {@link #onViewStateRestored(Bundle)}.
+     *
      * @param savedInstanceState If the fragment is being re-created from
      * a previous saved state, this is the state.
      */
     public void onActivityCreated(Bundle savedInstanceState) {
         mCalled = true;
     }
-    
+
+    /**
+     * Called when all saved state has been restored into the view hierarchy
+     * of the fragment.  This can be used to do initialization based on saved
+     * state that you are letting the view hierarchy track itself, such as
+     * whether check box widgets are currently checked.  This is called
+     * after {@link #onActivityCreated(Bundle)} and before
+     * {@link #onStart()}.
+     *
+     * @param savedInstanceState If the fragment is being re-created from
+     * a previous saved state, this is the state.
+     */
+    public void onViewStateRestored(Bundle savedInstanceState) {
+        mCalled = true;
+    }
+
     /**
      * Called when the Fragment is visible to the user.  This is generally
      * tied to {@link Activity#onStart() Activity.onStart} of the containing
@@ -1212,7 +1280,7 @@
             mLoadersStarted = true;
             if (!mCheckedForLoaderManager) {
                 mCheckedForLoaderManager = true;
-                mLoaderManager = mActivity.getLoaderManager(mIndex, mLoadersStarted, false);
+                mLoaderManager = mActivity.getLoaderManager(mWho, mLoadersStarted, false);
             }
             if (mLoaderManager != null) {
                 mLoaderManager.doStart();
@@ -1305,7 +1373,7 @@
         //        + " mLoaderManager=" + mLoaderManager);
         if (!mCheckedForLoaderManager) {
             mCheckedForLoaderManager = true;
-            mLoaderManager = mActivity.getLoaderManager(mIndex, mLoadersStarted, false);
+            mLoaderManager = mActivity.getLoaderManager(mWho, mLoadersStarted, false);
         }
         if (mLoaderManager != null) {
             mLoaderManager.doDestroy();
@@ -1530,6 +1598,10 @@
             writer.print(prefix); writer.print("mActivity=");
                     writer.println(mActivity);
         }
+        if (mParentFragment != null) {
+            writer.print(prefix); writer.print("mParentFragment=");
+                    writer.println(mParentFragment);
+        }
         if (mArguments != null) {
             writer.print(prefix); writer.print("mArguments="); writer.println(mArguments);
         }
@@ -1564,23 +1636,244 @@
             writer.print(prefix); writer.println("Loader Manager:");
             mLoaderManager.dump(prefix + "  ", fd, writer, args);
         }
+        if (mChildFragmentManager != null) {
+            writer.print(prefix); writer.println("Child " + mChildFragmentManager + ":");
+            mChildFragmentManager.dump(prefix + "  ", fd, writer, args);
+        }
+    }
+
+    Fragment findFragmentByWho(String who) {
+        if (who.equals(mWho)) {
+            return this;
+        }
+        if (mChildFragmentManager != null) {
+            return mChildFragmentManager.findFragmentByWho(who);
+        }
+        return null;
+    }
+
+    void instantiateChildFragmentManager() {
+        mChildFragmentManager = new FragmentManagerImpl();
+        mChildFragmentManager.attachActivity(mActivity, new FragmentContainer() {
+            @Override
+            public View findViewById(int id) {
+                if (mView == null) {
+                    throw new IllegalStateException("Fragment does not have a view");
+                }
+                return mView.findViewById(id);
+            }
+        }, this);
+    }
+
+    void performCreate(Bundle savedInstanceState) {
+        if (mChildFragmentManager != null) {
+            mChildFragmentManager.noteStateNotSaved();
+        }
+        mCalled = false;
+        onCreate(savedInstanceState);
+        if (!mCalled) {
+            throw new SuperNotCalledException("Fragment " + this
+                    + " did not call through to super.onCreate()");
+        }
+        if (savedInstanceState != null) {
+            Parcelable p = savedInstanceState.getParcelable(Activity.FRAGMENTS_TAG);
+            if (p != null) {
+                if (mChildFragmentManager == null) {
+                    instantiateChildFragmentManager();
+                }
+                mChildFragmentManager.restoreAllState(p, null);
+                mChildFragmentManager.dispatchCreate();
+            }
+        }
+    }
+
+    View performCreateView(LayoutInflater inflater, ViewGroup container,
+            Bundle savedInstanceState) {
+        if (mChildFragmentManager != null) {
+            mChildFragmentManager.noteStateNotSaved();
+        }
+        return onCreateView(inflater, container, savedInstanceState);
+    }
+
+    void performActivityCreated(Bundle savedInstanceState) {
+        if (mChildFragmentManager != null) {
+            mChildFragmentManager.noteStateNotSaved();
+        }
+        mCalled = false;
+        onActivityCreated(savedInstanceState);
+        if (!mCalled) {
+            throw new SuperNotCalledException("Fragment " + this
+                    + " did not call through to super.onActivityCreated()");
+        }
+        if (mChildFragmentManager != null) {
+            mChildFragmentManager.dispatchActivityCreated();
+        }
     }
 
     void performStart() {
+        if (mChildFragmentManager != null) {
+            mChildFragmentManager.noteStateNotSaved();
+            mChildFragmentManager.execPendingActions();
+        }
+        mCalled = false;
         onStart();
+        if (!mCalled) {
+            throw new SuperNotCalledException("Fragment " + this
+                    + " did not call through to super.onStart()");
+        }
+        if (mChildFragmentManager != null) {
+            mChildFragmentManager.dispatchStart();
+        }
         if (mLoaderManager != null) {
             mLoaderManager.doReportStart();
         }
     }
 
+    void performResume() {
+        if (mChildFragmentManager != null) {
+            mChildFragmentManager.noteStateNotSaved();
+            mChildFragmentManager.execPendingActions();
+        }
+        mCalled = false;
+        onResume();
+        if (!mCalled) {
+            throw new SuperNotCalledException("Fragment " + this
+                    + " did not call through to super.onResume()");
+        }
+        if (mChildFragmentManager != null) {
+            mChildFragmentManager.dispatchResume();
+            mChildFragmentManager.execPendingActions();
+        }
+    }
+
+    void performConfigurationChanged(Configuration newConfig) {
+        onConfigurationChanged(newConfig);
+        if (mChildFragmentManager != null) {
+            mChildFragmentManager.dispatchConfigurationChanged(newConfig);
+        }
+    }
+
+    void performLowMemory() {
+        onLowMemory();
+        if (mChildFragmentManager != null) {
+            mChildFragmentManager.dispatchLowMemory();
+        }
+    }
+
+    void performTrimMemory(int level) {
+        onTrimMemory(level);
+        if (mChildFragmentManager != null) {
+            mChildFragmentManager.dispatchTrimMemory(level);
+        }
+    }
+
+    boolean performCreateOptionsMenu(Menu menu, MenuInflater inflater) {
+        boolean show = false;
+        if (!mHidden) {
+            if (mHasMenu && mMenuVisible) {
+                show = true;
+                onCreateOptionsMenu(menu, inflater);
+            }
+            if (mChildFragmentManager != null) {
+                show |= mChildFragmentManager.dispatchCreateOptionsMenu(menu, inflater);
+            }
+        }
+        return show;
+    }
+
+    boolean performPrepareOptionsMenu(Menu menu) {
+        boolean show = false;
+        if (!mHidden) {
+            if (mHasMenu && mMenuVisible) {
+                show = true;
+                onPrepareOptionsMenu(menu);
+            }
+            if (mChildFragmentManager != null) {
+                show |= mChildFragmentManager.dispatchPrepareOptionsMenu(menu);
+            }
+        }
+        return show;
+    }
+
+    boolean performOptionsItemSelected(MenuItem item) {
+        if (!mHidden) {
+            if (mHasMenu && mMenuVisible) {
+                if (onOptionsItemSelected(item)) {
+                    return true;
+                }
+            }
+            if (mChildFragmentManager != null) {
+                if (mChildFragmentManager.dispatchOptionsItemSelected(item)) {
+                    return true;
+                }
+            }
+        }
+        return false;
+    }
+
+    boolean performContextItemSelected(MenuItem item) {
+        if (!mHidden) {
+            if (onContextItemSelected(item)) {
+                return true;
+            }
+            if (mChildFragmentManager != null) {
+                if (mChildFragmentManager.dispatchContextItemSelected(item)) {
+                    return true;
+                }
+            }
+        }
+        return false;
+    }
+
+    void performOptionsMenuClosed(Menu menu) {
+        if (!mHidden) {
+            if (mHasMenu && mMenuVisible) {
+                onOptionsMenuClosed(menu);
+            }
+            if (mChildFragmentManager != null) {
+                mChildFragmentManager.dispatchOptionsMenuClosed(menu);
+            }
+        }
+    }
+
+    void performSaveInstanceState(Bundle outState) {
+        onSaveInstanceState(outState);
+        if (mChildFragmentManager != null) {
+            Parcelable p = mChildFragmentManager.saveAllState();
+            if (p != null) {
+                outState.putParcelable(Activity.FRAGMENTS_TAG, p);
+            }
+        }
+    }
+
+    void performPause() {
+        if (mChildFragmentManager != null) {
+            mChildFragmentManager.dispatchPause();
+        }
+        mCalled = false;
+        onPause();
+        if (!mCalled) {
+            throw new SuperNotCalledException("Fragment " + this
+                    + " did not call through to super.onPause()");
+        }
+    }
+
     void performStop() {
+        if (mChildFragmentManager != null) {
+            mChildFragmentManager.dispatchStop();
+        }
+        mCalled = false;
         onStop();
+        if (!mCalled) {
+            throw new SuperNotCalledException("Fragment " + this
+                    + " did not call through to super.onStop()");
+        }
         
         if (mLoadersStarted) {
             mLoadersStarted = false;
             if (!mCheckedForLoaderManager) {
                 mCheckedForLoaderManager = true;
-                mLoaderManager = mActivity.getLoaderManager(mIndex, mLoadersStarted, false);
+                mLoaderManager = mActivity.getLoaderManager(mWho, mLoadersStarted, false);
             }
             if (mLoaderManager != null) {
                 if (mActivity == null || !mActivity.mChangingConfigurations) {
@@ -1593,9 +1886,29 @@
     }
 
     void performDestroyView() {
+        if (mChildFragmentManager != null) {
+            mChildFragmentManager.dispatchDestroyView();
+        }
+        mCalled = false;
         onDestroyView();
+        if (!mCalled) {
+            throw new SuperNotCalledException("Fragment " + this
+                    + " did not call through to super.onDestroyView()");
+        }
         if (mLoaderManager != null) {
             mLoaderManager.doReportNextStart();
         }
     }
+
+    void performDestroy() {
+        if (mChildFragmentManager != null) {
+            mChildFragmentManager.dispatchDestroy();
+        }
+        mCalled = false;
+        onDestroy();
+        if (!mCalled) {
+            throw new SuperNotCalledException("Fragment " + this
+                    + " did not call through to super.onDestroy()");
+        }
+    }
 }
diff --git a/core/java/android/app/FragmentManager.java b/core/java/android/app/FragmentManager.java
index 52a6557..7f11437 100644
--- a/core/java/android/app/FragmentManager.java
+++ b/core/java/android/app/FragmentManager.java
@@ -20,7 +20,6 @@
 import android.animation.AnimatorInflater;
 import android.animation.AnimatorListenerAdapter;
 import android.content.res.Configuration;
-import android.content.res.Resources;
 import android.content.res.TypedArray;
 import android.os.Bundle;
 import android.os.Handler;
@@ -30,7 +29,6 @@
 import android.util.DebugUtils;
 import android.util.Log;
 import android.util.LogWriter;
-import android.util.Slog;
 import android.util.SparseArray;
 import android.view.Menu;
 import android.view.MenuInflater;
@@ -381,6 +379,13 @@
 }
 
 /**
+ * Callbacks from FragmentManagerImpl to its container.
+ */
+interface FragmentContainer {
+    public View findViewById(int id);
+}
+
+/**
  * Container for fragments associated with an activity.
  */
 final class FragmentManagerImpl extends FragmentManager {
@@ -410,6 +415,8 @@
 
     int mCurState = Fragment.INITIALIZING;
     Activity mActivity;
+    FragmentContainer mContainer;
+    Fragment mParent;
     
     boolean mNeedMenuInvalidate;
     boolean mStateSaved;
@@ -585,7 +592,11 @@
         sb.append("FragmentManager{");
         sb.append(Integer.toHexString(System.identityHashCode(this)));
         sb.append(" in ");
-        DebugUtils.buildShortClassTag(mActivity, sb);
+        if (mParent != null) {
+            DebugUtils.buildShortClassTag(mParent, sb);
+        } else {
+            DebugUtils.buildShortClassTag(mActivity, sb);
+        }
         sb.append("}}");
         return sb.toString();
     }
@@ -681,6 +692,11 @@
         }
 
         writer.print(prefix); writer.println("FragmentManager misc state:");
+        writer.print(prefix); writer.print("  mActivity="); writer.println(mActivity);
+        writer.print(prefix); writer.print("  mContainer="); writer.println(mContainer);
+        if (mParent != null) {
+            writer.print(prefix); writer.print("  mParent="); writer.println(mParent);
+        }
         writer.print(prefix); writer.print("  mCurState="); writer.print(mCurState);
                 writer.print(" mStateSaved="); writer.print(mStateSaved);
                 writer.print(" mDestroyed="); writer.println(mDestroyed);
@@ -809,30 +825,29 @@
                         }
                     }
                     f.mActivity = mActivity;
-                    f.mFragmentManager = mActivity.mFragments;
+                    f.mParentFragment = mParent;
+                    f.mFragmentManager = mParent != null
+                            ? mParent.mChildFragmentManager : mActivity.mFragments;
                     f.mCalled = false;
                     f.onAttach(mActivity);
                     if (!f.mCalled) {
                         throw new SuperNotCalledException("Fragment " + f
                                 + " did not call through to super.onAttach()");
                     }
-                    mActivity.onAttachFragment(f);
-                    
+                    if (f.mParentFragment == null) {
+                        mActivity.onAttachFragment(f);
+                    }
+
                     if (!f.mRetaining) {
-                        f.mCalled = false;
-                        f.onCreate(f.mSavedFragmentState);
-                        if (!f.mCalled) {
-                            throw new SuperNotCalledException("Fragment " + f
-                                    + " did not call through to super.onCreate()");
-                        }
+                        f.performCreate(f.mSavedFragmentState);
                     }
                     f.mRetaining = false;
                     if (f.mFromLayout) {
                         // For fragments that are part of the content view
                         // layout, we need to instantiate the view immediately
                         // and the inflater will take care of adding it.
-                        f.mView = f.onCreateView(f.getLayoutInflater(f.mSavedFragmentState),
-                                null, f.mSavedFragmentState);
+                        f.mView = f.performCreateView(f.getLayoutInflater(
+                                f.mSavedFragmentState), null, f.mSavedFragmentState);
                         if (f.mView != null) {
                             f.mView.setSaveFromParentEnabled(false);
                             if (f.mHidden) f.mView.setVisibility(View.GONE);
@@ -845,7 +860,7 @@
                         if (!f.mFromLayout) {
                             ViewGroup container = null;
                             if (f.mContainerId != 0) {
-                                container = (ViewGroup)mActivity.findViewById(f.mContainerId);
+                                container = (ViewGroup)mContainer.findViewById(f.mContainerId);
                                 if (container == null && !f.mRestored) {
                                     throwException(new IllegalArgumentException(
                                             "No view found for id 0x"
@@ -855,8 +870,8 @@
                                 }
                             }
                             f.mContainer = container;
-                            f.mView = f.onCreateView(f.getLayoutInflater(f.mSavedFragmentState),
-                                    container, f.mSavedFragmentState);
+                            f.mView = f.performCreateView(f.getLayoutInflater(
+                                    f.mSavedFragmentState), container, f.mSavedFragmentState);
                             if (f.mView != null) {
                                 f.mView.setSaveFromParentEnabled(false);
                                 if (container != null) {
@@ -872,15 +887,10 @@
                                 f.onViewCreated(f.mView, f.mSavedFragmentState);
                             }
                         }
-                        
-                        f.mCalled = false;
-                        f.onActivityCreated(f.mSavedFragmentState);
-                        if (!f.mCalled) {
-                            throw new SuperNotCalledException("Fragment " + f
-                                    + " did not call through to super.onActivityCreated()");
-                        }
+
+                        f.performActivityCreated(f.mSavedFragmentState);
                         if (f.mView != null) {
-                            f.restoreViewState();
+                            f.restoreViewState(f.mSavedFragmentState);
                         }
                         f.mSavedFragmentState = null;
                     }
@@ -888,23 +898,13 @@
                 case Fragment.STOPPED:
                     if (newState > Fragment.STOPPED) {
                         if (DEBUG) Log.v(TAG, "moveto STARTED: " + f);
-                        f.mCalled = false;
                         f.performStart();
-                        if (!f.mCalled) {
-                            throw new SuperNotCalledException("Fragment " + f
-                                    + " did not call through to super.onStart()");
-                        }
                     }
                 case Fragment.STARTED:
                     if (newState > Fragment.STARTED) {
                         if (DEBUG) Log.v(TAG, "moveto RESUMED: " + f);
-                        f.mCalled = false;
                         f.mResumed = true;
-                        f.onResume();
-                        if (!f.mCalled) {
-                            throw new SuperNotCalledException("Fragment " + f
-                                    + " did not call through to super.onResume()");
-                        }
+                        f.performResume();
                         // Get rid of this in case we saved it and never needed it.
                         f.mSavedFragmentState = null;
                         f.mSavedViewState = null;
@@ -915,23 +915,13 @@
                 case Fragment.RESUMED:
                     if (newState < Fragment.RESUMED) {
                         if (DEBUG) Log.v(TAG, "movefrom RESUMED: " + f);
-                        f.mCalled = false;
-                        f.onPause();
-                        if (!f.mCalled) {
-                            throw new SuperNotCalledException("Fragment " + f
-                                    + " did not call through to super.onPause()");
-                        }
+                        f.performPause();
                         f.mResumed = false;
                     }
                 case Fragment.STARTED:
                     if (newState < Fragment.STARTED) {
                         if (DEBUG) Log.v(TAG, "movefrom STARTED: " + f);
-                        f.mCalled = false;
                         f.performStop();
-                        if (!f.mCalled) {
-                            throw new SuperNotCalledException("Fragment " + f
-                                    + " did not call through to super.onStop()");
-                        }
                     }
                 case Fragment.STOPPED:
                 case Fragment.ACTIVITY_CREATED:
@@ -944,12 +934,7 @@
                                 saveFragmentViewState(f);
                             }
                         }
-                        f.mCalled = false;
                         f.performDestroyView();
-                        if (!f.mCalled) {
-                            throw new SuperNotCalledException("Fragment " + f
-                                    + " did not call through to super.onDestroyView()");
-                        }
                         if (f.mView != null && f.mContainer != null) {
                             Animator anim = null;
                             if (mCurState > Fragment.INITIALIZING && !mDestroyed) {
@@ -1008,12 +993,7 @@
                         } else {
                             if (DEBUG) Log.v(TAG, "movefrom CREATED: " + f);
                             if (!f.mRetaining) {
-                                f.mCalled = false;
-                                f.onDestroy();
-                                if (!f.mCalled) {
-                                    throw new SuperNotCalledException("Fragment " + f
-                                            + " did not call through to super.onDestroy()");
-                                }
+                                f.performDestroy();
                             }
 
                             f.mCalled = false;
@@ -1027,6 +1007,7 @@
                                     makeInactive(f);
                                 } else {
                                     f.mActivity = null;
+                                    f.mParentFragment = null;
                                     f.mFragmentManager = null;
                                 }
                             }
@@ -1050,11 +1031,11 @@
         if (mActivity == null && newState != Fragment.INITIALIZING) {
             throw new IllegalStateException("No activity");
         }
-        
+
         if (!always && mCurState == newState) {
             return;
         }
-        
+
         mCurState = newState;
         if (mActive != null) {
             boolean loadersRunning = false;
@@ -1099,11 +1080,11 @@
             if (mActive == null) {
                 mActive = new ArrayList<Fragment>();
             }
-            f.setIndex(mActive.size());
+            f.setIndex(mActive.size(), mParent);
             mActive.add(f);
             
         } else {
-            f.setIndex(mAvailIndices.remove(mAvailIndices.size()-1));
+            f.setIndex(mAvailIndices.remove(mAvailIndices.size()-1), mParent);
             mActive.set(f.mIndex, f);
         }
         if (DEBUG) Log.v(TAG, "Allocated fragment index " + f);
@@ -1120,7 +1101,7 @@
             mAvailIndices = new ArrayList<Integer>();
         }
         mAvailIndices.add(f.mIndex);
-        mActivity.invalidateFragmentIndex(f.mIndex);
+        mActivity.invalidateFragment(f.mWho);
         f.initState();
     }
     
@@ -1296,7 +1277,7 @@
         if (mActive != null && who != null) {
             for (int i=mActive.size()-1; i>=0; i--) {
                 Fragment f = mActive.get(i);
-                if (f != null && who.equals(f.mWho)) {
+                if (f != null && (f=f.findFragmentByWho(who)) != null) {
                     return f;
                 }
             }
@@ -1566,7 +1547,7 @@
         if (mStateBundle == null) {
             mStateBundle = new Bundle();
         }
-        f.onSaveInstanceState(mStateBundle);
+        f.performSaveInstanceState(mStateBundle);
         if (!mStateBundle.isEmpty()) {
             result = mStateBundle;
             mStateBundle = null;
@@ -1735,7 +1716,7 @@
         for (int i=0; i<fms.mActive.length; i++) {
             FragmentState fs = fms.mActive[i];
             if (fs != null) {
-                Fragment f = fs.instantiate(mActivity);
+                Fragment f = fs.instantiate(mActivity, mParent);
                 if (DEBUG) Log.v(TAG, "restoreAllState: adding #" + i + ": " + f);
                 mActive.add(f);
                 // Now that the fragment is instantiated (or came from being
@@ -1803,9 +1784,11 @@
         }
     }
     
-    public void attachActivity(Activity activity) {
+    public void attachActivity(Activity activity, FragmentContainer container, Fragment parent) {
         if (mActivity != null) throw new IllegalStateException("Already attached");
         mActivity = activity;
+        mContainer = container;
+        mParent = parent;
     }
     
     public void noteStateNotSaved() {
@@ -1840,11 +1823,17 @@
         moveToState(Fragment.STOPPED, false);
     }
     
+    public void dispatchDestroyView() {
+        moveToState(Fragment.CREATED, false);
+    }
+
     public void dispatchDestroy() {
         mDestroyed = true;
         execPendingActions();
         moveToState(Fragment.INITIALIZING, false);
         mActivity = null;
+        mContainer = null;
+        mParent = null;
     }
     
     public void dispatchConfigurationChanged(Configuration newConfig) {
@@ -1852,7 +1841,7 @@
             for (int i=0; i<mAdded.size(); i++) {
                 Fragment f = mAdded.get(i);
                 if (f != null) {
-                    f.onConfigurationChanged(newConfig);
+                    f.performConfigurationChanged(newConfig);
                 }
             }
         }
@@ -1863,7 +1852,7 @@
             for (int i=0; i<mAdded.size(); i++) {
                 Fragment f = mAdded.get(i);
                 if (f != null) {
-                    f.onLowMemory();
+                    f.performLowMemory();
                 }
             }
         }
@@ -1874,7 +1863,7 @@
             for (int i=0; i<mAdded.size(); i++) {
                 Fragment f = mAdded.get(i);
                 if (f != null) {
-                    f.onTrimMemory(level);
+                    f.performTrimMemory(level);
                 }
             }
         }
@@ -1886,13 +1875,14 @@
         if (mAdded != null) {
             for (int i=0; i<mAdded.size(); i++) {
                 Fragment f = mAdded.get(i);
-                if (f != null && !f.mHidden && f.mHasMenu && f.mMenuVisible) {
-                    show = true;
-                    f.onCreateOptionsMenu(menu, inflater);
-                    if (newMenus == null) {
-                        newMenus = new ArrayList<Fragment>();
+                if (f != null) {
+                    if (f.performCreateOptionsMenu(menu, inflater)) {
+                        show = true;
+                        if (newMenus == null) {
+                            newMenus = new ArrayList<Fragment>();
+                        }
+                        newMenus.add(f);
                     }
-                    newMenus.add(f);
                 }
             }
         }
@@ -1916,9 +1906,10 @@
         if (mAdded != null) {
             for (int i=0; i<mAdded.size(); i++) {
                 Fragment f = mAdded.get(i);
-                if (f != null && !f.mHidden && f.mHasMenu && f.mMenuVisible) {
-                    show = true;
-                    f.onPrepareOptionsMenu(menu);
+                if (f != null) {
+                    if (f.performPrepareOptionsMenu(menu)) {
+                        show = true;
+                    }
                 }
             }
         }
@@ -1929,8 +1920,8 @@
         if (mAdded != null) {
             for (int i=0; i<mAdded.size(); i++) {
                 Fragment f = mAdded.get(i);
-                if (f != null && !f.mHidden && f.mHasMenu && f.mMenuVisible) {
-                    if (f.onOptionsItemSelected(item)) {
+                if (f != null) {
+                    if (f.performOptionsItemSelected(item)) {
                         return true;
                     }
                 }
@@ -1943,8 +1934,8 @@
         if (mAdded != null) {
             for (int i=0; i<mAdded.size(); i++) {
                 Fragment f = mAdded.get(i);
-                if (f != null && !f.mHidden) {
-                    if (f.onContextItemSelected(item)) {
+                if (f != null) {
+                    if (f.performContextItemSelected(item)) {
                         return true;
                     }
                 }
@@ -1957,8 +1948,8 @@
         if (mAdded != null) {
             for (int i=0; i<mAdded.size(); i++) {
                 Fragment f = mAdded.get(i);
-                if (f != null && !f.mHidden && f.mHasMenu && f.mMenuVisible) {
-                    f.onOptionsMenuClosed(menu);
+                if (f != null) {
+                    f.performOptionsMenuClosed(menu);
                 }
             }
         }
diff --git a/core/java/android/app/IActivityManager.java b/core/java/android/app/IActivityManager.java
index 7a633ed..9cb3621 100644
--- a/core/java/android/app/IActivityManager.java
+++ b/core/java/android/app/IActivityManager.java
@@ -62,7 +62,7 @@
     public WaitResult startActivityAndWait(IApplicationThread caller,
             Intent intent, String resolvedType, IBinder resultTo, String resultWho,
             int requestCode, int flags, String profileFile,
-            ParcelFileDescriptor profileFd, Bundle options) throws RemoteException;
+            ParcelFileDescriptor profileFd, Bundle options, int userId) throws RemoteException;
     public int startActivityWithConfig(IApplicationThread caller,
             Intent intent, String resolvedType, IBinder resultTo, String resultWho,
             int requestCode, int startFlags, Configuration newConfig,
@@ -160,7 +160,7 @@
     public void killApplicationProcess(String processName, int uid) throws RemoteException;
     
     public boolean startInstrumentation(ComponentName className, String profileFile,
-            int flags, Bundle arguments, IInstrumentationWatcher watcher)
+            int flags, Bundle arguments, IInstrumentationWatcher watcher, int userId)
             throws RemoteException;
     public void finishInstrumentation(IApplicationThread target,
             int resultCode, Bundle results) throws RemoteException;
@@ -275,7 +275,7 @@
     public void stopAppSwitches() throws RemoteException;
     public void resumeAppSwitches() throws RemoteException;
     
-    public void killApplicationWithUid(String pkg, int uid) throws RemoteException;
+    public void killApplicationWithAppId(String pkg, int appid) throws RemoteException;
     
     public void closeSystemDialogs(String reason) throws RemoteException;
     
@@ -296,7 +296,7 @@
     public void crashApplication(int uid, int initialPid, String packageName,
             String message) throws RemoteException;
 
-    public String getProviderMimeType(Uri uri) throws RemoteException;
+    public String getProviderMimeType(Uri uri, int userId) throws RemoteException;
     
     public IBinder newUriPermissionOwner(String name) throws RemoteException;
     public void grantUriPermissionFromOwner(IBinder owner, int fromUid, String targetPkg,
@@ -328,6 +328,7 @@
     public boolean switchUser(int userid) throws RemoteException;
     public int stopUser(int userid, IStopUserCallback callback) throws RemoteException;
     public UserInfo getCurrentUser() throws RemoteException;
+    public boolean isUserRunning(int userid) throws RemoteException;
 
     public boolean removeSubTask(int taskId, int subTaskIndex) throws RemoteException;
 
@@ -548,7 +549,7 @@
     int GET_UID_FOR_INTENT_SENDER_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+92;
     int HANDLE_INCOMING_USER_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+93;
 
-    int KILL_APPLICATION_WITH_UID_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+95;
+    int KILL_APPLICATION_WITH_APPID_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+95;
     int CLOSE_SYSTEM_DIALOGS_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+96;
     int GET_PROCESS_MEMORY_INFO_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+97;
     int KILL_APPLICATION_PROCESS_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+98;
@@ -574,7 +575,7 @@
     int CHECK_GRANT_URI_PERMISSION_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+118;
     int DUMP_HEAP_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+119;
     int START_ACTIVITIES_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+120;
-
+    int IS_USER_RUNNING_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+121;
     int ACTIVITY_SLEPT_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+122;
     int GET_FRONT_ACTIVITY_SCREEN_COMPAT_MODE_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+123;
     int SET_FRONT_ACTIVITY_SCREEN_COMPAT_MODE_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+124;
diff --git a/core/java/android/app/LoaderManager.java b/core/java/android/app/LoaderManager.java
index ff71ee7..fd0f0bf 100644
--- a/core/java/android/app/LoaderManager.java
+++ b/core/java/android/app/LoaderManager.java
@@ -17,7 +17,6 @@
 package android.app;
 
 import android.content.Loader;
-import android.content.Loader.OnLoadCanceledListener;
 import android.os.Bundle;
 import android.util.DebugUtils;
 import android.util.Log;
@@ -213,6 +212,8 @@
     // previously run loader until the new loader's data is available.
     final SparseArray<LoaderInfo> mInactiveLoaders = new SparseArray<LoaderInfo>();
 
+    final String mWho;
+
     Activity mActivity;
     boolean mStarted;
     boolean mRetaining;
@@ -529,7 +530,8 @@
         }
     }
     
-    LoaderManagerImpl(Activity activity, boolean started) {
+    LoaderManagerImpl(String who, Activity activity, boolean started) {
+        mWho = who;
         mActivity = activity;
         mStarted = started;
     }
diff --git a/core/java/android/content/ContentResolver.java b/core/java/android/content/ContentResolver.java
index 0a5a26a9..ece8841 100644
--- a/core/java/android/content/ContentResolver.java
+++ b/core/java/android/content/ContentResolver.java
@@ -39,6 +39,7 @@
 import android.os.RemoteException;
 import android.os.ServiceManager;
 import android.os.SystemClock;
+import android.os.UserHandle;
 import android.text.TextUtils;
 import android.util.EventLog;
 import android.util.Log;
@@ -230,7 +231,8 @@
         }
 
         try {
-            String type = ActivityManagerNative.getDefault().getProviderMimeType(url);
+            String type = ActivityManagerNative.getDefault().getProviderMimeType(
+                    url, UserHandle.myUserId());
             return type;
         } catch (RemoteException e) {
             // Arbitrary and not worth documenting, as Activity
diff --git a/core/java/android/content/pm/ApplicationInfo.java b/core/java/android/content/pm/ApplicationInfo.java
index 1a82d58..a0283d3 100644
--- a/core/java/android/content/pm/ApplicationInfo.java
+++ b/core/java/android/content/pm/ApplicationInfo.java
@@ -308,6 +308,13 @@
     public static final int FLAG_INSTALLED = 1<<23;
 
     /**
+     * Value for {@link #flags}: true if the application only has its
+     * data installed; the application package itself does not currently
+     * exist on the device.
+     */
+    public static final int FLAG_IS_DATA_ONLY = 1<<24;
+
+    /**
      * Value for {@link #flags}: Set to true if the application has been
      * installed using the forward lock option.
      *
diff --git a/core/java/android/content/pm/IPackageManager.aidl b/core/java/android/content/pm/IPackageManager.aidl
index 0e1fe3e..b0ae5da 100644
--- a/core/java/android/content/pm/IPackageManager.aidl
+++ b/core/java/android/content/pm/IPackageManager.aidl
@@ -127,7 +127,7 @@
      * limit that kicks in when flags are included that bloat up the data
      * returned.
      */
-    ParceledListSlice getInstalledPackages(int flags, in String lastRead);
+    ParceledListSlice getInstalledPackages(int flags, in String lastRead, in int userId);
 
     /**
      * This implements getInstalledApplications via a "last returned row"
diff --git a/core/java/android/content/pm/InstrumentationInfo.java b/core/java/android/content/pm/InstrumentationInfo.java
index ea47e8e..a977e41 100644
--- a/core/java/android/content/pm/InstrumentationInfo.java
+++ b/core/java/android/content/pm/InstrumentationInfo.java
@@ -18,10 +18,6 @@
 
 import android.os.Parcel;
 import android.os.Parcelable;
-import android.text.TextUtils;
-
-import java.text.Collator;
-import java.util.Comparator;
 
 /**
  * Information you can retrieve about a particular piece of test
diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java
index e5ddfda..5399583 100644
--- a/core/java/android/content/pm/PackageManager.java
+++ b/core/java/android/content/pm/PackageManager.java
@@ -1469,6 +1469,45 @@
     public abstract List<PackageInfo> getInstalledPackages(int flags);
 
     /**
+     * Return a List of all packages that are installed on the device, for a specific user.
+     * Requesting a list of installed packages for another user
+     * will require the permission INTERACT_ACROSS_USERS_FULL.
+     * @param flags Additional option flags. Use any combination of
+     * {@link #GET_ACTIVITIES},
+     * {@link #GET_GIDS},
+     * {@link #GET_CONFIGURATIONS},
+     * {@link #GET_INSTRUMENTATION},
+     * {@link #GET_PERMISSIONS},
+     * {@link #GET_PROVIDERS},
+     * {@link #GET_RECEIVERS},
+     * {@link #GET_SERVICES},
+     * {@link #GET_SIGNATURES},
+     * {@link #GET_UNINSTALLED_PACKAGES} to modify the data returned.
+     * @param userId The user for whom the installed packages are to be listed
+     *
+     * @return A List of PackageInfo objects, one for each package that is
+     *         installed on the device.  In the unlikely case of there being no
+     *         installed packages, an empty list is returned.
+     *         If flag GET_UNINSTALLED_PACKAGES is set, a list of all
+     *         applications including those deleted with DONT_DELETE_DATA
+     *         (partially installed apps with data directory) will be returned.
+     *
+     * @see #GET_ACTIVITIES
+     * @see #GET_GIDS
+     * @see #GET_CONFIGURATIONS
+     * @see #GET_INSTRUMENTATION
+     * @see #GET_PERMISSIONS
+     * @see #GET_PROVIDERS
+     * @see #GET_RECEIVERS
+     * @see #GET_SERVICES
+     * @see #GET_SIGNATURES
+     * @see #GET_UNINSTALLED_PACKAGES
+     *
+     * @hide
+     */
+    public abstract List<PackageInfo> getInstalledPackages(int flags, int userId);
+
+    /**
      * Check whether a particular package has been granted a particular
      * permission.
      *
@@ -1755,6 +1794,29 @@
             int flags);
 
     /**
+     * Retrieve all activities that can be performed for the given intent, for a specific user.
+     *
+     * @param intent The desired intent as per resolveActivity().
+     * @param flags Additional option flags.  The most important is
+     * {@link #MATCH_DEFAULT_ONLY}, to limit the resolution to only
+     * those activities that support the {@link android.content.Intent#CATEGORY_DEFAULT}.
+     *
+     * @return A List&lt;ResolveInfo&gt; containing one entry for each matching
+     *         Activity. These are ordered from best to worst match -- that
+     *         is, the first item in the list is what is returned by
+     *         {@link #resolveActivity}.  If there are no matching activities, an empty
+     *         list is returned.
+     *
+     * @see #MATCH_DEFAULT_ONLY
+     * @see #GET_INTENT_FILTERS
+     * @see #GET_RESOLVED_FILTER
+     * @hide
+     */
+    public abstract List<ResolveInfo> queryIntentActivitiesForUser(Intent intent,
+            int flags, int userId);
+
+
+    /**
      * Retrieve a set of activities that should be presented to the user as
      * similar options.  This is like {@link #queryIntentActivities}, except it
      * also allows you to supply a list of more explicit Intents that you would
diff --git a/core/java/android/content/res/Configuration.java b/core/java/android/content/res/Configuration.java
index 0b77842..7164713 100644
--- a/core/java/android/content/res/Configuration.java
+++ b/core/java/android/content/res/Configuration.java
@@ -536,8 +536,8 @@
         int layoutDir = (screenLayout&SCREENLAYOUT_LAYOUTDIR_MASK);
         switch (layoutDir) {
             case SCREENLAYOUT_LAYOUTDIR_UNDEFINED: sb.append(" ?layoutDir"); break;
-            case SCREENLAYOUT_LAYOUTDIR_LTR: sb.append(" ltr"); break;
-            case SCREENLAYOUT_LAYOUTDIR_RTL: sb.append(" rtl"); break;
+            case SCREENLAYOUT_LAYOUTDIR_LTR: sb.append(" ldltr"); break;
+            case SCREENLAYOUT_LAYOUTDIR_RTL: sb.append(" ldrtl"); break;
             default: sb.append(" layoutDir=");
                 sb.append(layoutDir >> SCREENLAYOUT_LAYOUTDIR_SHIFT); break;
         }
diff --git a/core/java/android/content/res/Resources.java b/core/java/android/content/res/Resources.java
index 42a6bdc..b316f23 100755
--- a/core/java/android/content/res/Resources.java
+++ b/core/java/android/content/res/Resources.java
@@ -1897,12 +1897,14 @@
             }
         }
 
-        final long key = (((long) value.assetCookie) << 32) | value.data;
         boolean isColorDrawable = false;
         if (value.type >= TypedValue.TYPE_FIRST_COLOR_INT &&
                 value.type <= TypedValue.TYPE_LAST_COLOR_INT) {
             isColorDrawable = true;
         }
+        final long key = isColorDrawable ? value.data :
+                (((long) value.assetCookie) << 32) | value.data;
+
         Drawable dr = getCachedDrawable(isColorDrawable ? mColorDrawableCache : mDrawableCache, key);
 
         if (dr != null) {
diff --git a/core/java/android/hardware/display/DisplayManager.java b/core/java/android/hardware/display/DisplayManager.java
index 2814301..4347e75 100644
--- a/core/java/android/hardware/display/DisplayManager.java
+++ b/core/java/android/hardware/display/DisplayManager.java
@@ -40,6 +40,28 @@
     private final Object mLock = new Object();
     private final SparseArray<Display> mDisplays = new SparseArray<Display>();
 
+    /**
+     * Broadcast receiver that indicates when the Wifi display status changes.
+     * <p>
+     * The status is provided as a {@link WifiDisplayStatus} object in the
+     * {@link #EXTRA_WIFI_DISPLAY_STATUS} extra.
+     * </p><p>
+     * This broadcast is only sent to registered receivers with the
+     * {@link android.Manifest.permission#CONFIGURE_WIFI_DISPLAY} permission and can
+     * only be sent by the system.
+     * </p>
+     * @hide
+     */
+    public static final String ACTION_WIFI_DISPLAY_STATUS_CHANGED =
+            "android.hardware.display.action.WIFI_DISPLAY_STATUS_CHANGED";
+
+    /**
+     * Contains a {@link WifiDisplayStatus} object.
+     * @hide
+     */
+    public static final String EXTRA_WIFI_DISPLAY_STATUS =
+            "android.hardware.display.extra.WIFI_DISPLAY_STATUS";
+
     /** @hide */
     public DisplayManager(Context context) {
         mContext = context;
@@ -127,6 +149,47 @@
     }
 
     /**
+     * Initiates a fresh scan of availble Wifi displays.
+     * The results are sent as a {@link #ACTION_WIFI_DISPLAY_STATUS_CHANGED} broadcast.
+     * @hide
+     */
+    public void scanWifiDisplays() {
+        mGlobal.scanWifiDisplays();
+    }
+
+    /**
+     * Connects to a Wifi display.
+     * The results are sent as a {@link #ACTION_WIFI_DISPLAY_STATUS_CHANGED} broadcast.
+     *
+     * @param deviceAddress The MAC address of the device to which we should connect.
+     * @hide
+     */
+    public void connectWifiDisplay(String deviceAddress) {
+        mGlobal.connectWifiDisplay(deviceAddress);
+    }
+
+    /**
+     * Disconnects from the current Wifi display.
+     * The results are sent as a {@link #ACTION_WIFI_DISPLAY_STATUS_CHANGED} broadcast.
+     * @hide
+     */
+    public void disconnectWifiDisplay() {
+        mGlobal.disconnectWifiDisplay();
+    }
+
+    /**
+     * Gets the current Wifi display status.
+     * Watch for changes in the status by registering a broadcast receiver for
+     * {@link #ACTION_WIFI_DISPLAY_STATUS_CHANGED}.
+     *
+     * @return The current Wifi display status.
+     * @hide
+     */
+    public WifiDisplayStatus getWifiDisplayStatus() {
+        return mGlobal.getWifiDisplayStatus();
+    }
+
+    /**
      * Listens for changes in available display devices.
      */
     public interface DisplayListener {
diff --git a/core/java/android/hardware/display/DisplayManagerGlobal.java b/core/java/android/hardware/display/DisplayManagerGlobal.java
index 4077964..14b5440 100644
--- a/core/java/android/hardware/display/DisplayManagerGlobal.java
+++ b/core/java/android/hardware/display/DisplayManagerGlobal.java
@@ -253,6 +253,43 @@
         }
     }
 
+    public void scanWifiDisplays() {
+        try {
+            mDm.scanWifiDisplays();
+        } catch (RemoteException ex) {
+            Log.e(TAG, "Failed to scan for Wifi displays.", ex);
+        }
+    }
+
+    public void connectWifiDisplay(String deviceAddress) {
+        if (deviceAddress == null) {
+            throw new IllegalArgumentException("deviceAddress must not be null");
+        }
+
+        try {
+            mDm.connectWifiDisplay(deviceAddress);
+        } catch (RemoteException ex) {
+            Log.e(TAG, "Failed to connect to Wifi display " + deviceAddress + ".", ex);
+        }
+    }
+
+    public void disconnectWifiDisplay() {
+        try {
+            mDm.disconnectWifiDisplay();
+        } catch (RemoteException ex) {
+            Log.e(TAG, "Failed to disconnect from Wifi display.", ex);
+        }
+    }
+
+    public WifiDisplayStatus getWifiDisplayStatus() {
+        try {
+            return mDm.getWifiDisplayStatus();
+        } catch (RemoteException ex) {
+            Log.e(TAG, "Failed to get Wifi display status.", ex);
+            return new WifiDisplayStatus();
+        }
+    }
+
     private final class DisplayManagerCallback extends IDisplayManagerCallback.Stub {
         @Override
         public void onDisplayEvent(int displayId, int event) {
diff --git a/core/java/android/hardware/display/IDisplayManager.aidl b/core/java/android/hardware/display/IDisplayManager.aidl
index d802aa1..36a9a7f 100644
--- a/core/java/android/hardware/display/IDisplayManager.aidl
+++ b/core/java/android/hardware/display/IDisplayManager.aidl
@@ -17,6 +17,8 @@
 package android.hardware.display;
 
 import android.hardware.display.IDisplayManagerCallback;
+import android.hardware.display.WifiDisplay;
+import android.hardware.display.WifiDisplayStatus;
 import android.view.DisplayInfo;
 
 /** @hide */
@@ -25,4 +27,16 @@
     int[] getDisplayIds();
 
     void registerCallback(in IDisplayManagerCallback callback);
+
+    // Requires CONFIGURE_WIFI_DISPLAY permission.
+    void scanWifiDisplays();
+
+    // Requires CONFIGURE_WIFI_DISPLAY permission.
+    void connectWifiDisplay(String address);
+
+    // Requires CONFIGURE_WIFI_DISPLAY permission.
+    void disconnectWifiDisplay();
+
+    // Requires CONFIGURE_WIFI_DISPLAY permission.
+    WifiDisplayStatus getWifiDisplayStatus();
 }
diff --git a/core/java/android/hardware/display/WifiDisplay.aidl b/core/java/android/hardware/display/WifiDisplay.aidl
new file mode 100644
index 0000000..7733075
--- /dev/null
+++ b/core/java/android/hardware/display/WifiDisplay.aidl
@@ -0,0 +1,19 @@
+/*
+ * Copyright (C) 2012 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.hardware.display;
+
+parcelable WifiDisplay;
diff --git a/core/java/android/hardware/display/WifiDisplay.java b/core/java/android/hardware/display/WifiDisplay.java
new file mode 100644
index 0000000..e51e97e
--- /dev/null
+++ b/core/java/android/hardware/display/WifiDisplay.java
@@ -0,0 +1,107 @@
+/*
+ * Copyright (C) 2012 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.hardware.display;
+
+import android.os.Parcel;
+import android.os.Parcelable;
+
+/**
+ * Describes the properties of a Wifi display.
+ * <p>
+ * This object is immutable.
+ * </p>
+ *
+ * @hide
+ */
+public final class WifiDisplay implements Parcelable {
+    private final String mDeviceAddress;
+    private final String mDeviceName;
+
+    public static final WifiDisplay[] EMPTY_ARRAY = new WifiDisplay[0];
+
+    public static final Creator<WifiDisplay> CREATOR = new Creator<WifiDisplay>() {
+        public WifiDisplay createFromParcel(Parcel in) {
+            String deviceAddress = in.readString();
+            String deviceName = in.readString();
+            return new WifiDisplay(deviceAddress, deviceName);
+        }
+
+        public WifiDisplay[] newArray(int size) {
+            return size == 0 ? EMPTY_ARRAY : new WifiDisplay[size];
+        }
+    };
+
+    public WifiDisplay(String deviceAddress, String deviceName) {
+        if (deviceAddress == null) {
+            throw new IllegalArgumentException("deviceAddress must not be null");
+        }
+        if (deviceName == null) {
+            throw new IllegalArgumentException("deviceName must not be null");
+        }
+
+        mDeviceAddress = deviceAddress;
+        mDeviceName = deviceName;
+    }
+
+    /**
+     * Gets the MAC address of the Wifi display device.
+     */
+    public String getDeviceAddress() {
+        return mDeviceAddress;
+    }
+
+    /**
+     * Gets the name of the Wifi display device.
+     */
+    public String getDeviceName() {
+        return mDeviceName;
+    }
+
+    @Override
+    public boolean equals(Object o) {
+        return o instanceof WifiDisplay && equals((WifiDisplay)o);
+    }
+
+    public boolean equals(WifiDisplay other) {
+        return other != null
+                && mDeviceAddress.equals(other.mDeviceAddress)
+                && mDeviceName.equals(other.mDeviceName);
+    }
+
+    @Override
+    public int hashCode() {
+        // The address on its own should be sufficiently unique for hashing purposes.
+        return mDeviceAddress.hashCode();
+    }
+
+    @Override
+    public void writeToParcel(Parcel dest, int flags) {
+        dest.writeString(mDeviceAddress);
+        dest.writeString(mDeviceName);
+    }
+
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    // For debugging purposes only.
+    @Override
+    public String toString() {
+        return mDeviceName + " (" + mDeviceAddress + ")";
+    }
+}
diff --git a/core/java/android/hardware/display/WifiDisplayStatus.aidl b/core/java/android/hardware/display/WifiDisplayStatus.aidl
new file mode 100644
index 0000000..35c633e
--- /dev/null
+++ b/core/java/android/hardware/display/WifiDisplayStatus.aidl
@@ -0,0 +1,19 @@
+/*
+ * Copyright (C) 2012 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.hardware.display;
+
+parcelable WifiDisplayStatus;
diff --git a/core/java/android/hardware/display/WifiDisplayStatus.java b/core/java/android/hardware/display/WifiDisplayStatus.java
new file mode 100644
index 0000000..d5fe45d
--- /dev/null
+++ b/core/java/android/hardware/display/WifiDisplayStatus.java
@@ -0,0 +1,170 @@
+/*
+ * Copyright (C) 2012 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.hardware.display;
+
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import java.util.Arrays;
+
+/**
+ * Describes the current global state of Wifi display connectivity, including the
+ * currently connected display and all known displays.
+ * <p>
+ * This object is immutable.
+ * </p>
+ *
+ * @hide
+ */
+public final class WifiDisplayStatus implements Parcelable {
+    private final boolean mEnabled;
+    private final int mScanState;
+    private final int mActiveDisplayState;
+    private final WifiDisplay mActiveDisplay;
+    private final WifiDisplay[] mKnownDisplays;
+
+    public static final int SCAN_STATE_NOT_SCANNING = 0;
+    public static final int SCAN_STATE_SCANNING = 1;
+
+    public static final int DISPLAY_STATE_NOT_CONNECTED = 0;
+    public static final int DISPLAY_STATE_CONNECTING = 1;
+    public static final int DISPLAY_STATE_CONNECTED = 2;
+
+    public static final Creator<WifiDisplayStatus> CREATOR = new Creator<WifiDisplayStatus>() {
+        public WifiDisplayStatus createFromParcel(Parcel in) {
+            boolean enabled = (in.readInt() != 0);
+            int scanState = in.readInt();
+            int activeDisplayState= in.readInt();
+
+            WifiDisplay activeDisplay = null;
+            if (in.readInt() != 0) {
+                activeDisplay = WifiDisplay.CREATOR.createFromParcel(in);
+            }
+
+            WifiDisplay[] knownDisplays = WifiDisplay.CREATOR.newArray(in.readInt());
+            for (int i = 0; i < knownDisplays.length; i++) {
+                knownDisplays[i] = WifiDisplay.CREATOR.createFromParcel(in);
+            }
+
+            return new WifiDisplayStatus(enabled, scanState, activeDisplayState,
+                    activeDisplay, knownDisplays);
+        }
+
+        public WifiDisplayStatus[] newArray(int size) {
+            return new WifiDisplayStatus[size];
+        }
+    };
+
+    public WifiDisplayStatus() {
+        this(false, SCAN_STATE_NOT_SCANNING, DISPLAY_STATE_NOT_CONNECTED,
+                null, WifiDisplay.EMPTY_ARRAY);
+    }
+
+    public WifiDisplayStatus(boolean enabled, int scanState, int activeDisplayState,
+            WifiDisplay activeDisplay, WifiDisplay[] knownDisplays) {
+        if (knownDisplays == null) {
+            throw new IllegalArgumentException("knownDisplays must not be null");
+        }
+
+        mEnabled = enabled;
+        mScanState = scanState;
+        mActiveDisplayState = activeDisplayState;
+        mActiveDisplay = activeDisplay;
+        mKnownDisplays = knownDisplays;
+    }
+
+    /**
+     * Returns true if the Wifi display feature is enabled and available for use.
+     * <p>
+     * The value of this property reflects whether Wifi and Wifi P2P functions
+     * are enabled.  Enablement is not directly controllable by the user at this
+     * time, except indirectly such as by turning off Wifi altogether.
+     * </p>
+     */
+    public boolean isEnabled() {
+        return mEnabled;
+    }
+
+    /**
+     * Returns the current state of the Wifi display scan.
+     *
+     * @return One of: {@link #SCAN_STATE_NOT_SCANNING} or {@link #SCAN_STATE_SCANNING}.
+     */
+    public int getScanState() {
+        return mScanState;
+    }
+
+    /**
+     * Get the state of the currently active display.
+     *
+     * @return One of: {@link #DISPLAY_STATE_NOT_CONNECTED}, {@link #DISPLAY_STATE_CONNECTING},
+     * or {@link #DISPLAY_STATE_CONNECTED}.
+     */
+    public int getActiveDisplayState() {
+        return mActiveDisplayState;
+    }
+
+    /**
+     * Gets the Wifi display that is currently active.  It may be connecting or
+     * connected.
+     */
+    public WifiDisplay getActiveDisplay() {
+        return mActiveDisplay;
+    }
+
+    /**
+     * Gets the list of all known Wifi displays, never null.
+     */
+    public WifiDisplay[] getKnownDisplays() {
+        return mKnownDisplays;
+    }
+
+    @Override
+    public void writeToParcel(Parcel dest, int flags) {
+        dest.writeInt(mEnabled ? 1 : 0);
+        dest.writeInt(mScanState);
+        dest.writeInt(mActiveDisplayState);
+
+        if (mActiveDisplay != null) {
+            dest.writeInt(1);
+            mActiveDisplay.writeToParcel(dest, flags);
+        } else {
+            dest.writeInt(0);
+        }
+
+        dest.writeInt(mKnownDisplays.length);
+        for (WifiDisplay display : mKnownDisplays) {
+            display.writeToParcel(dest, flags);
+        }
+    }
+
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    // For debugging purposes only.
+    @Override
+    public String toString() {
+        return "WifiDisplayStatus{enabled=" + mEnabled
+                + ", scanState=" + mScanState
+                + ", activeDisplayState=" + mActiveDisplayState
+                + ", activeDisplay=" + mActiveDisplay
+                + ", knownDisplays=" + Arrays.toString(mKnownDisplays)
+                + "}";
+    }
+}
diff --git a/core/java/android/nfc/NdefRecord.java b/core/java/android/nfc/NdefRecord.java
index ed1c5b3..2d9dae9 100644
--- a/core/java/android/nfc/NdefRecord.java
+++ b/core/java/android/nfc/NdefRecord.java
@@ -688,7 +688,8 @@
                         }
                     } catch (FormatException e) {  }
                 } else if (Arrays.equals(mType, RTD_URI)) {
-                    return parseWktUri().normalizeScheme();
+                    Uri wktUri = parseWktUri();
+                    return (wktUri != null ? wktUri.normalizeScheme() : null);
                 }
                 break;
 
diff --git a/core/java/android/os/Binder.java b/core/java/android/os/Binder.java
index ea14098..16b4835 100644
--- a/core/java/android/os/Binder.java
+++ b/core/java/android/os/Binder.java
@@ -64,7 +64,7 @@
     public static final native int getCallingPid();
     
     /**
-     * Return the ID of the user assigned to the process that sent you the
+     * Return the Linux uid assigned to the process that sent you the
      * current transaction that is being processed.  This uid can be used with
      * higher-level system services to determine its identity and check
      * permissions.  If the current thread is not currently executing an
@@ -73,6 +73,18 @@
     public static final native int getCallingUid();
 
     /**
+     * Return the UserHandle assigned to the process that sent you the
+     * current transaction that is being processed.  This is the user
+     * of the caller.  It is distinct from {@link #getCallingUid()} in that a
+     * particular user will have multiple distinct apps running under it each
+     * with their own uid.  If the current thread is not currently executing an
+     * incoming transaction, then its own UserHandle is returned.
+     */
+    public static final UserHandle getCallingUserHandle() {
+        return new UserHandle(UserHandle.getUserId(getCallingUid()));
+    }
+
+    /**
      * Reset the identity of the incoming IPC on the current thread.  This can
      * be useful if, while handling an incoming call, you will be calling
      * on interfaces of other objects that may be local to your process and
diff --git a/core/java/android/os/PowerManager.java b/core/java/android/os/PowerManager.java
index a1901a5..cc2c002 100644
--- a/core/java/android/os/PowerManager.java
+++ b/core/java/android/os/PowerManager.java
@@ -331,6 +331,15 @@
     }
 
     /**
+     * Returns true if the screen auto-brightness adjustment setting should
+     * be available in the UI.  This setting is experimental and disabled by default.
+     * @hide
+     */
+    public static boolean useScreenAutoBrightnessAdjustmentFeature() {
+        return SystemProperties.getBoolean("persist.power.useautobrightadj", false);
+    }
+
+    /**
      * Creates a new wake lock with the specified level and flags.
      * <p>
      * The {@code levelAndFlags} parameter specifies a wake lock level and optional flags
diff --git a/core/java/android/os/RemoteCallbackList.java b/core/java/android/os/RemoteCallbackList.java
index b74af16..d02a320 100644
--- a/core/java/android/os/RemoteCallbackList.java
+++ b/core/java/android/os/RemoteCallbackList.java
@@ -304,4 +304,25 @@
         
         mBroadcastCount = -1;
     }
+
+    /**
+     * Returns the number of registered callbacks. Note that the number of registered
+     * callbacks may differ from the value returned by {@link #beginBroadcast()} since
+     * the former returns the number of callbacks registered at the time of the call
+     * and the second the number of callback to which the broadcast will be delivered.
+     * <p>
+     * This function is useful to decide whether to schedule a broadcast if this
+     * requires doing some work which otherwise would not be performed.
+     * </p>
+     *
+     * @return The size.
+     */
+    public int getRegisteredCallbackCount() {
+        synchronized (mCallbacks) {
+            if (mKilled) {
+                return 0;
+            }
+            return mCallbacks.size();
+        }
+    }
 }
diff --git a/core/java/android/os/storage/StorageVolume.java b/core/java/android/os/storage/StorageVolume.java
index 79c8f3b..b5983d1 100644
--- a/core/java/android/os/storage/StorageVolume.java
+++ b/core/java/android/os/storage/StorageVolume.java
@@ -26,16 +26,16 @@
  */
 public class StorageVolume implements Parcelable {
 
-    //private static final String TAG = "StorageVolume";
+    private int mStorageId;
 
     private final String mPath;
     private final int mDescriptionId;
+    private final boolean mPrimary;
     private final boolean mRemovable;
     private final boolean mEmulated;
     private final int mMtpReserveSpace;
     private final boolean mAllowMassStorage;
-    private int mStorageId;
-    // maximum file size for the storage, or zero for no limit
+    /** Maximum file size for the storage, or zero for no limit */
     private final long mMaxFileSize;
 
     // StorageVolume extra for ACTION_MEDIA_REMOVED, ACTION_MEDIA_UNMOUNTED, ACTION_MEDIA_CHECKING,
@@ -43,10 +43,11 @@
     // ACTION_MEDIA_BAD_REMOVAL, ACTION_MEDIA_UNMOUNTABLE and ACTION_MEDIA_EJECT broadcasts.
     public static final String EXTRA_STORAGE_VOLUME = "storage_volume";
 
-    public StorageVolume(String path, int descriptionId, boolean removable,
+    public StorageVolume(String path, int descriptionId, boolean primary, boolean removable,
             boolean emulated, int mtpReserveSpace, boolean allowMassStorage, long maxFileSize) {
         mPath = path;
         mDescriptionId = descriptionId;
+        mPrimary = primary;
         mRemovable = removable;
         mEmulated = emulated;
         mMtpReserveSpace = mtpReserveSpace;
@@ -54,18 +55,16 @@
         mMaxFileSize = maxFileSize;
     }
 
-    // for parcelling only
-    private StorageVolume(String path, int descriptionId, boolean removable,
-            boolean emulated, int mtpReserveSpace, int storageId,
-            boolean allowMassStorage, long maxFileSize) {
-        mPath = path;
-        mDescriptionId = descriptionId;
-        mRemovable = removable;
-        mEmulated = emulated;
-        mMtpReserveSpace = mtpReserveSpace;
-        mAllowMassStorage = allowMassStorage;
-        mStorageId = storageId;
-        mMaxFileSize = maxFileSize;
+    private StorageVolume(Parcel in) {
+        mStorageId = in.readInt();
+        mPath = in.readString();
+        mDescriptionId = in.readInt();
+        mPrimary = in.readByte() != 0;
+        mRemovable = in.readByte() != 0;
+        mEmulated = in.readByte() != 0;
+        mMtpReserveSpace = in.readInt();
+        mAllowMassStorage = in.readByte() != 0;
+        mMaxFileSize = in.readLong();
     }
 
     /**
@@ -90,6 +89,10 @@
         return mDescriptionId;
     }
 
+    public boolean isPrimary() {
+        return mPrimary;
+    }
+
     /**
      * Returns true if the volume is removable.
      *
@@ -183,37 +186,31 @@
                 + mRemovable + ", mStorageId=" + mStorageId + "]";
     }
 
-    public static final Parcelable.Creator<StorageVolume> CREATOR =
-        new Parcelable.Creator<StorageVolume>() {
+    public static final Creator<StorageVolume> CREATOR = new Creator<StorageVolume>() {
+        @Override
         public StorageVolume createFromParcel(Parcel in) {
-            String path = in.readString();
-            int descriptionId = in.readInt();
-            int removable = in.readInt();
-            int emulated = in.readInt();
-            int storageId = in.readInt();
-            int mtpReserveSpace = in.readInt();
-            int allowMassStorage = in.readInt();
-            long maxFileSize = in.readLong();
-            return new StorageVolume(path, descriptionId,
-                    removable == 1, emulated == 1, mtpReserveSpace,
-                    storageId, allowMassStorage == 1, maxFileSize);
+            return new StorageVolume(in);
         }
 
+        @Override
         public StorageVolume[] newArray(int size) {
             return new StorageVolume[size];
         }
     };
 
+    @Override
     public int describeContents() {
         return 0;
     }
 
+    @Override
     public void writeToParcel(Parcel parcel, int flags) {
+        parcel.writeInt(mStorageId);
         parcel.writeString(mPath);
         parcel.writeInt(mDescriptionId);
+        parcel.writeInt(mPrimary ? 1 : 0);
         parcel.writeInt(mRemovable ? 1 : 0);
         parcel.writeInt(mEmulated ? 1 : 0);
-        parcel.writeInt(mStorageId);
         parcel.writeInt(mMtpReserveSpace);
         parcel.writeInt(mAllowMassStorage ? 1 : 0);
         parcel.writeLong(mMaxFileSize);
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index b4841b1..841a076 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -621,6 +621,25 @@
     public static final String CALL_METHOD_GET_SECURE = "GET_secure";
 
     /**
+     * @hide - Private call() method on SettingsProvider to read from 'global' table.
+     */
+    public static final String CALL_METHOD_GET_GLOBAL = "GET_global";
+
+    /**
+     * @hide - User handle argument extra to the fast-path call()-based requests
+     */
+    public static final String CALL_METHOD_USER_KEY = "_user";
+
+    /** @hide - Private call() method to write to 'system' table */
+    public static final String CALL_METHOD_PUT_SYSTEM = "PUT_system";
+
+    /** @hide - Private call() method to write to 'secure' table */
+    public static final String CALL_METHOD_PUT_SECURE = "PUT_secure";
+
+    /** @hide - Private call() method to write to 'global' table */
+    public static final String CALL_METHOD_PUT_GLOBAL= "PUT_global";
+
+    /**
      * Activity Extra: Limit available options in launched activity based on the given authority.
      * <p>
      * This can be passed as an extra field in an Activity Intent with one or more syncable content
@@ -640,7 +659,7 @@
     public static final String AUTHORITY = "settings";
 
     private static final String TAG = "Settings";
-    private static final boolean LOCAL_LOGV = false || false;
+    private static final boolean LOCAL_LOGV = false;
 
     public static class SettingNotFoundException extends AndroidException {
         public SettingNotFoundException(String msg) {
@@ -693,20 +712,52 @@
 
         // The method we'll call (or null, to not use) on the provider
         // for the fast path of retrieving settings.
-        private final String mCallCommand;
+        private final String mCallGetCommand;
+        private final String mCallSetCommand;
 
-        public NameValueCache(String versionSystemProperty, Uri uri, String callCommand) {
+        public NameValueCache(String versionSystemProperty, Uri uri,
+                String getCommand, String setCommand) {
             mVersionSystemProperty = versionSystemProperty;
             mUri = uri;
-            mCallCommand = callCommand;
+            mCallGetCommand = getCommand;
+            mCallSetCommand = setCommand;
         }
 
-        public String getString(ContentResolver cr, String name) {
+        private IContentProvider lazyGetProvider(ContentResolver cr) {
+            IContentProvider cp = null;
+            synchronized (this) {
+                cp = mContentProvider;
+                if (cp == null) {
+                    cp = mContentProvider = cr.acquireProvider(mUri.getAuthority());
+                }
+            }
+            return cp;
+        }
+
+        public boolean putStringForUser(ContentResolver cr, String name, String value,
+                final int userHandle) {
+            try {
+                Bundle arg = new Bundle();
+                arg.putString(Settings.NameValueTable.VALUE, value);
+                IContentProvider cp = lazyGetProvider(cr);
+                cp.call(mCallSetCommand, name, arg);
+            } catch (RemoteException e) {
+                Log.w(TAG, "Can't set key " + name + " in " + mUri, e);
+                return false;
+            }
+            return true;
+        }
+
+        public boolean putString(ContentResolver cr, String name, String value) {
+            return putStringForUser(cr, name, value, UserHandle.myUserId());
+        }
+
+        public String getStringForUser(ContentResolver cr, String name, final int userHandle) {
             long newValuesVersion = SystemProperties.getLong(mVersionSystemProperty, 0);
 
             synchronized (this) {
                 if (mValuesVersion != newValuesVersion) {
-                    if (LOCAL_LOGV) {
+                    if (LOCAL_LOGV || false) {
                         Log.v(TAG, "invalidate [" + mUri.getLastPathSegment() + "]: current " +
                                 newValuesVersion + " != cached " + mValuesVersion);
                     }
@@ -720,21 +771,20 @@
                 }
             }
 
-            IContentProvider cp = null;
-            synchronized (this) {
-                cp = mContentProvider;
-                if (cp == null) {
-                    cp = mContentProvider = cr.acquireProvider(mUri.getAuthority());
-                }
-            }
+            IContentProvider cp = lazyGetProvider(cr);
 
             // Try the fast path first, not using query().  If this
             // fails (alternate Settings provider that doesn't support
             // this interface?) then we fall back to the query/table
             // interface.
-            if (mCallCommand != null) {
+            if (mCallGetCommand != null) {
                 try {
-                    Bundle b = cp.call(mCallCommand, name, null);
+                    Bundle args = null;
+                    if (userHandle != UserHandle.myUserId()) {
+                        args = new Bundle();
+                        args.putInt(CALL_METHOD_USER_KEY, userHandle);
+                    }
+                    Bundle b = cp.call(mCallGetCommand, name, args);
                     if (b != null) {
                         String value = b.getPairValue();
                         synchronized (this) {
@@ -775,6 +825,10 @@
                 if (c != null) c.close();
             }
         }
+
+        public String getString(ContentResolver cr, String name) {
+            return getStringForUser(cr, name, UserHandle.myUserId());
+        }
     }
 
     /**
@@ -791,13 +845,8 @@
         private static final HashSet<String> MOVED_TO_SECURE;
         static {
             MOVED_TO_SECURE = new HashSet<String>(30);
-            MOVED_TO_SECURE.add(Secure.ADB_ENABLED);
             MOVED_TO_SECURE.add(Secure.ANDROID_ID);
-            MOVED_TO_SECURE.add(Secure.BLUETOOTH_ON);
-            MOVED_TO_SECURE.add(Secure.DATA_ROAMING);
-            MOVED_TO_SECURE.add(Secure.DEVICE_PROVISIONED);
             MOVED_TO_SECURE.add(Secure.HTTP_PROXY);
-            MOVED_TO_SECURE.add(Secure.INSTALL_NON_MARKET_APPS);
             MOVED_TO_SECURE.add(Secure.LOCATION_PROVIDERS_ALLOWED);
             MOVED_TO_SECURE.add(Secure.LOCK_BIOMETRIC_WEAK_FLAGS);
             MOVED_TO_SECURE.add(Secure.LOCK_PATTERN_ENABLED);
@@ -808,7 +857,6 @@
             MOVED_TO_SECURE.add(Secure.PARENTAL_CONTROL_LAST_UPDATE);
             MOVED_TO_SECURE.add(Secure.PARENTAL_CONTROL_REDIRECT_URL);
             MOVED_TO_SECURE.add(Secure.SETTINGS_CLASSNAME);
-            MOVED_TO_SECURE.add(Secure.USB_MASS_STORAGE_ENABLED);
             MOVED_TO_SECURE.add(Secure.USE_GOOGLE_MAIL);
             MOVED_TO_SECURE.add(Secure.WIFI_NETWORKS_AVAILABLE_NOTIFICATION_ON);
             MOVED_TO_SECURE.add(Secure.WIFI_NETWORKS_AVAILABLE_REPEAT_DELAY);
@@ -827,6 +875,47 @@
             MOVED_TO_SECURE.add(Secure.WIFI_WATCHDOG_PING_TIMEOUT_MS);
         }
 
+        private static final HashSet<String> MOVED_TO_GLOBAL;
+        static {
+            MOVED_TO_GLOBAL = new HashSet<String>();
+            // these were originally in system but migrated to secure in the past,
+            // so are duplicated in the Secure.* namespace
+            MOVED_TO_GLOBAL.add(Global.ADB_ENABLED);
+            MOVED_TO_GLOBAL.add(Global.BLUETOOTH_ON);
+            MOVED_TO_GLOBAL.add(Global.DATA_ROAMING);
+            MOVED_TO_GLOBAL.add(Global.DEVICE_PROVISIONED);
+            MOVED_TO_GLOBAL.add(Global.INSTALL_NON_MARKET_APPS);
+            MOVED_TO_GLOBAL.add(Global.USB_MASS_STORAGE_ENABLED);
+
+            // these are moving directly from system to global
+            MOVED_TO_GLOBAL.add(Settings.Global.AIRPLANE_MODE_ON);
+            MOVED_TO_GLOBAL.add(Settings.Global.AIRPLANE_MODE_RADIOS);
+            MOVED_TO_GLOBAL.add(Settings.Global.AIRPLANE_MODE_TOGGLEABLE_RADIOS);
+            MOVED_TO_GLOBAL.add(Settings.Global.AUTO_TIME);
+            MOVED_TO_GLOBAL.add(Settings.Global.AUTO_TIME_ZONE);
+            MOVED_TO_GLOBAL.add(Settings.Global.CAR_DOCK_SOUND);
+            MOVED_TO_GLOBAL.add(Settings.Global.CAR_UNDOCK_SOUND);
+            MOVED_TO_GLOBAL.add(Settings.Global.DESK_DOCK_SOUND);
+            MOVED_TO_GLOBAL.add(Settings.Global.DESK_UNDOCK_SOUND);
+            MOVED_TO_GLOBAL.add(Settings.Global.DOCK_SOUNDS_ENABLED);
+            MOVED_TO_GLOBAL.add(Settings.Global.LOCK_SOUND);
+            MOVED_TO_GLOBAL.add(Settings.Global.UNLOCK_SOUND);
+            MOVED_TO_GLOBAL.add(Settings.Global.LOW_BATTERY_SOUND);
+            MOVED_TO_GLOBAL.add(Settings.Global.POWER_SOUNDS_ENABLED);
+            MOVED_TO_GLOBAL.add(Settings.Global.STAY_ON_WHILE_PLUGGED_IN);
+            MOVED_TO_GLOBAL.add(Settings.Global.WIFI_SLEEP_POLICY);
+        }
+
+        private static void lazyInitCache() {
+            if (sNameValueCache == null) {
+                sNameValueCache = new NameValueCache(
+                        SYS_PROP_SETTING_VERSION + '_' + UserHandle.myUserId(),
+                        CONTENT_URI,
+                        CALL_METHOD_GET_SYSTEM,
+                        CALL_METHOD_PUT_SYSTEM);
+            }
+        }
+
         /**
          * Look up a name in the database.
          * @param resolver to access the database with
@@ -834,16 +923,24 @@
          * @return the corresponding value, or null if not present
          */
         public synchronized static String getString(ContentResolver resolver, String name) {
+            return getStringForUser(resolver, name, UserHandle.myUserId());
+        }
+
+        /** @hide */
+        public synchronized static String getStringForUser(ContentResolver resolver, String name,
+                int userHandle) {
             if (MOVED_TO_SECURE.contains(name)) {
                 Log.w(TAG, "Setting " + name + " has moved from android.provider.Settings.System"
                         + " to android.provider.Settings.Secure, returning read-only value.");
-                return Secure.getString(resolver, name);
+                return Secure.getStringForUser(resolver, name, userHandle);
             }
-            if (sNameValueCache == null) {
-                sNameValueCache = new NameValueCache(SYS_PROP_SETTING_VERSION, CONTENT_URI,
-                                                     CALL_METHOD_GET_SYSTEM);
+            if (MOVED_TO_GLOBAL.contains(name)) {
+                Log.w(TAG, "Setting " + name + " has moved from android.provider.Settings.System"
+                        + " to android.provider.Settings.Global, returning read-only value.");
+                return Global.getStringForUser(resolver, name, userHandle);
             }
-            return sNameValueCache.getString(resolver, name);
+            lazyInitCache();
+            return sNameValueCache.getStringForUser(resolver, name, userHandle);
         }
 
         /**
@@ -854,12 +951,24 @@
          * @return true if the value was set, false on database errors
          */
         public static boolean putString(ContentResolver resolver, String name, String value) {
+            return putStringForUser(resolver, name, value, UserHandle.myUserId());
+        }
+
+        /** @hide */
+        public static boolean putStringForUser(ContentResolver resolver, String name, String value,
+                int userHandle) {
             if (MOVED_TO_SECURE.contains(name)) {
                 Log.w(TAG, "Setting " + name + " has moved from android.provider.Settings.System"
                         + " to android.provider.Settings.Secure, value is unchanged.");
                 return false;
             }
-            return putString(resolver, CONTENT_URI, name, value);
+            if (MOVED_TO_GLOBAL.contains(name)) {
+                Log.w(TAG, "Setting " + name + " has moved from android.provider.Settings.System"
+                        + " to android.provider.Settings.Global, value is unchanged.");
+                return false;
+            }
+            lazyInitCache();
+            return sNameValueCache.putStringForUser(resolver, name, value, userHandle);
         }
 
         /**
@@ -874,6 +983,11 @@
                     + " to android.provider.Settings.Secure, returning Secure URI.");
                 return Secure.getUriFor(Secure.CONTENT_URI, name);
             }
+            if (MOVED_TO_GLOBAL.contains(name)) {
+                Log.w(TAG, "Setting " + name + " has moved from android.provider.Settings.System"
+                        + " to android.provider.Settings.Global, returning read-only global URI.");
+                return Global.getUriFor(Global.CONTENT_URI, name);
+            }
             return getUriFor(CONTENT_URI, name);
         }
 
@@ -892,7 +1006,12 @@
          * or not a valid integer.
          */
         public static int getInt(ContentResolver cr, String name, int def) {
-            String v = getString(cr, name);
+            return getIntForUser(cr, name, def, UserHandle.myUserId());
+        }
+
+        /** @hide */
+        public static int getIntForUser(ContentResolver cr, String name, int def, int userHandle) {
+            String v = getStringForUser(cr, name, userHandle);
             try {
                 return v != null ? Integer.parseInt(v) : def;
             } catch (NumberFormatException e) {
@@ -920,7 +1039,13 @@
          */
         public static int getInt(ContentResolver cr, String name)
                 throws SettingNotFoundException {
-            String v = getString(cr, name);
+            return getIntForUser(cr, name, UserHandle.myUserId());
+        }
+
+        /** @hide */
+        public static int getIntForUser(ContentResolver cr, String name, int userHandle)
+                throws SettingNotFoundException {
+            String v = getStringForUser(cr, name, userHandle);
             try {
                 return Integer.parseInt(v);
             } catch (NumberFormatException e) {
@@ -942,7 +1067,13 @@
          * @return true if the value was set, false on database errors
          */
         public static boolean putInt(ContentResolver cr, String name, int value) {
-            return putString(cr, name, Integer.toString(value));
+            return putIntForUser(cr, name, value, UserHandle.myUserId());
+        }
+
+        /** @hide */
+        public static boolean putIntForUser(ContentResolver cr, String name, int value,
+                int userHandle) {
+            return putStringForUser(cr, name, Integer.toString(value), userHandle);
         }
 
         /**
@@ -960,7 +1091,13 @@
          * or not a valid {@code long}.
          */
         public static long getLong(ContentResolver cr, String name, long def) {
-            String valString = getString(cr, name);
+            return getLongForUser(cr, name, def, UserHandle.myUserId());
+        }
+
+        /** @hide */
+        public static long getLongForUser(ContentResolver cr, String name, long def,
+                int userHandle) {
+            String valString = getStringForUser(cr, name, userHandle);
             long value;
             try {
                 value = valString != null ? Long.parseLong(valString) : def;
@@ -989,7 +1126,13 @@
          */
         public static long getLong(ContentResolver cr, String name)
                 throws SettingNotFoundException {
-            String valString = getString(cr, name);
+            return getLongForUser(cr, name, UserHandle.myUserId());
+        }
+
+        /** @hide */
+        public static long getLongForUser(ContentResolver cr, String name, int userHandle)
+                throws SettingNotFoundException {
+            String valString = getStringForUser(cr, name, userHandle);
             try {
                 return Long.parseLong(valString);
             } catch (NumberFormatException e) {
@@ -1011,7 +1154,13 @@
          * @return true if the value was set, false on database errors
          */
         public static boolean putLong(ContentResolver cr, String name, long value) {
-            return putString(cr, name, Long.toString(value));
+            return putLongForUser(cr, name, value, UserHandle.myUserId());
+        }
+
+        /** @hide */
+        public static boolean putLongForUser(ContentResolver cr, String name, long value,
+                int userHandle) {
+            return putStringForUser(cr, name, Long.toString(value), userHandle);
         }
 
         /**
@@ -1029,7 +1178,13 @@
          * or not a valid float.
          */
         public static float getFloat(ContentResolver cr, String name, float def) {
-            String v = getString(cr, name);
+            return getFloatForUser(cr, name, def, UserHandle.myUserId());
+        }
+
+        /** @hide */
+        public static float getFloatForUser(ContentResolver cr, String name, float def,
+                int userHandle) {
+            String v = getStringForUser(cr, name, userHandle);
             try {
                 return v != null ? Float.parseFloat(v) : def;
             } catch (NumberFormatException e) {
@@ -1057,7 +1212,13 @@
          */
         public static float getFloat(ContentResolver cr, String name)
                 throws SettingNotFoundException {
-            String v = getString(cr, name);
+            return getFloatForUser(cr, name, UserHandle.myUserId());
+        }
+
+        /** @hide */
+        public static float getFloatForUser(ContentResolver cr, String name, int userHandle)
+                throws SettingNotFoundException {
+            String v = getStringForUser(cr, name, userHandle);
             if (v == null) {
                 throw new SettingNotFoundException(name);
             }
@@ -1082,7 +1243,13 @@
          * @return true if the value was set, false on database errors
          */
         public static boolean putFloat(ContentResolver cr, String name, float value) {
-            return putString(cr, name, Float.toString(value));
+            return putFloatForUser(cr, name, value, UserHandle.myUserId());
+        }
+
+        /** @hide */
+        public static boolean putFloatForUser(ContentResolver cr, String name, float value,
+                int userHandle) {
+            return putStringForUser(cr, name, Float.toString(value), userHandle);
         }
 
         /**
@@ -1094,8 +1261,14 @@
          * @param outConfig Where to place the configuration settings.
          */
         public static void getConfiguration(ContentResolver cr, Configuration outConfig) {
-            outConfig.fontScale = Settings.System.getFloat(
-                cr, FONT_SCALE, outConfig.fontScale);
+            getConfigurationForUser(cr, outConfig, UserHandle.myUserId());
+        }
+
+        /** @hide */
+        public static void getConfigurationForUser(ContentResolver cr, Configuration outConfig,
+                int userHandle) {
+            outConfig.fontScale = Settings.System.getFloatForUser(
+                cr, FONT_SCALE, outConfig.fontScale, userHandle);
             if (outConfig.fontScale < 0) {
                 outConfig.fontScale = 1;
             }
@@ -1118,7 +1291,13 @@
          * @return true if the values were set, false on database errors
          */
         public static boolean putConfiguration(ContentResolver cr, Configuration config) {
-            return Settings.System.putFloat(cr, FONT_SCALE, config.fontScale);
+            return putConfigurationForUser(cr, config, UserHandle.myUserId());
+        }
+
+        /** @hide */
+        public static boolean putConfigurationForUser(ContentResolver cr, Configuration config,
+                int userHandle) {
+            return Settings.System.putFloatForUser(cr, FONT_SCALE, config.fontScale, userHandle);
         }
 
         /** @hide */
@@ -1126,12 +1305,35 @@
             return (changes&ActivityInfo.CONFIG_FONT_SCALE) != 0;
         }
 
+        /** @deprecated - Do not use */
+        @Deprecated
         public static boolean getShowGTalkServiceStatus(ContentResolver cr) {
-            return getInt(cr, SHOW_GTALK_SERVICE_STATUS, 0) != 0;
+            return getShowGTalkServiceStatusForUser(cr, UserHandle.myUserId());
         }
 
+        /**
+         * @hide
+         * @deprecated - Do not use
+         */
+        public static boolean getShowGTalkServiceStatusForUser(ContentResolver cr,
+                int userHandle) {
+            return getIntForUser(cr, SHOW_GTALK_SERVICE_STATUS, 0, userHandle) != 0;
+        }
+
+        /** @deprecated - Do not use */
+        @Deprecated
         public static void setShowGTalkServiceStatus(ContentResolver cr, boolean flag) {
-            putInt(cr, SHOW_GTALK_SERVICE_STATUS, flag ? 1 : 0);
+            /* intentionally empty */
+        }
+
+        /**
+         * @hide
+         * @deprecated - Do not use
+         */
+        @Deprecated
+        public static void setShowGTalkServiceStatusForUser(ContentResolver cr, boolean flag,
+                int userHandle) {
+            putIntForUser(cr, SHOW_GTALK_SERVICE_STATUS, flag ? 1 : 0, userHandle);
         }
 
         /**
@@ -1141,17 +1343,10 @@
             Uri.parse("content://" + AUTHORITY + "/system");
 
         /**
-         * Whether we keep the device on while the device is plugged in.
-         * Supported values are:
-         * <ul>
-         * <li>{@code 0} to never stay on while plugged in</li>
-         * <li>{@link BatteryManager#BATTERY_PLUGGED_AC} to stay on for AC charger</li>
-         * <li>{@link BatteryManager#BATTERY_PLUGGED_USB} to stay on for USB charger</li>
-         * <li>{@link BatteryManager#BATTERY_PLUGGED_WIRELESS} to stay on for wireless charger</li>
-         * </ul>
-         * These values can be OR-ed together.
+         * @deprecated Use {@link android.provider.Settings.Global#STAY_ON_WHILE_PLUGGED_IN} instead
          */
-        public static final String STAY_ON_WHILE_PLUGGED_IN = "stay_on_while_plugged_in";
+        @Deprecated
+        public static final String STAY_ON_WHILE_PLUGGED_IN = Global.STAY_ON_WHILE_PLUGGED_IN;
 
         /**
          * What happens when the user presses the end call button if they're not
@@ -1196,80 +1391,81 @@
         public static final int ADVANCED_SETTINGS_DEFAULT = 0;
 
         /**
-         * Whether Airplane Mode is on.
+         * @deprecated Use {@link android.provider.Settings.Global#AIRPLANE_MODE_ON} instead
          */
-        public static final String AIRPLANE_MODE_ON = "airplane_mode_on";
+        @Deprecated
+        public static final String AIRPLANE_MODE_ON = Global.AIRPLANE_MODE_ON;
 
         /**
-         * Constant for use in AIRPLANE_MODE_RADIOS to specify Bluetooth radio.
+         * @deprecated Use {@link android.provider.Settings.Global#RADIO_BLUETOOTH} instead
          */
-        public static final String RADIO_BLUETOOTH = "bluetooth";
+        @Deprecated
+        public static final String RADIO_BLUETOOTH = Global.RADIO_BLUETOOTH;
 
         /**
-         * Constant for use in AIRPLANE_MODE_RADIOS to specify Wi-Fi radio.
+         * @deprecated Use {@link android.provider.Settings.Global#RADIO_WIFI} instead
          */
-        public static final String RADIO_WIFI = "wifi";
+        @Deprecated
+        public static final String RADIO_WIFI = Global.RADIO_WIFI;
 
         /**
+         * @deprecated Use {@link android.provider.Settings.Global#RADIO_WIMAX} instead
          * {@hide}
          */
-        public static final String RADIO_WIMAX = "wimax";
-        /**
-         * Constant for use in AIRPLANE_MODE_RADIOS to specify Cellular radio.
-         */
-        public static final String RADIO_CELL = "cell";
+        @Deprecated
+        public static final String RADIO_WIMAX = Global.RADIO_WIMAX;
 
         /**
-         * Constant for use in AIRPLANE_MODE_RADIOS to specify NFC radio.
+         * @deprecated Use {@link android.provider.Settings.Global#RADIO_CELL} instead
          */
-        public static final String RADIO_NFC = "nfc";
+        @Deprecated
+        public static final String RADIO_CELL = Global.RADIO_CELL;
 
         /**
-         * A comma separated list of radios that need to be disabled when airplane mode
-         * is on. This overrides WIFI_ON and BLUETOOTH_ON, if Wi-Fi and bluetooth are
-         * included in the comma separated list.
+         * @deprecated Use {@link android.provider.Settings.Global#RADIO_NFC} instead
          */
-        public static final String AIRPLANE_MODE_RADIOS = "airplane_mode_radios";
+        @Deprecated
+        public static final String RADIO_NFC = Global.RADIO_NFC;
 
         /**
-         * A comma separated list of radios that should to be disabled when airplane mode
-         * is on, but can be manually reenabled by the user.  For example, if RADIO_WIFI is
-         * added to both AIRPLANE_MODE_RADIOS and AIRPLANE_MODE_TOGGLEABLE_RADIOS, then Wifi
-         * will be turned off when entering airplane mode, but the user will be able to reenable
-         * Wifi in the Settings app.
+         * @deprecated Use {@link android.provider.Settings.Global#AIRPLANE_MODE_RADIOS} instead
+         */
+        @Deprecated
+        public static final String AIRPLANE_MODE_RADIOS = Global.AIRPLANE_MODE_RADIOS;
+
+        /**
+         * @deprecated Use {@link android.provider.Settings.Global#AIRPLANE_MODE_TOGGLEABLE_RADIOS} instead
          *
          * {@hide}
          */
-        public static final String AIRPLANE_MODE_TOGGLEABLE_RADIOS = "airplane_mode_toggleable_radios";
+        @Deprecated
+        public static final String AIRPLANE_MODE_TOGGLEABLE_RADIOS =
+                Global.AIRPLANE_MODE_TOGGLEABLE_RADIOS;
 
         /**
-         * The policy for deciding when Wi-Fi should go to sleep (which will in
-         * turn switch to using the mobile data as an Internet connection).
-         * <p>
-         * Set to one of {@link #WIFI_SLEEP_POLICY_DEFAULT},
-         * {@link #WIFI_SLEEP_POLICY_NEVER_WHILE_PLUGGED}, or
-         * {@link #WIFI_SLEEP_POLICY_NEVER}.
+         * @deprecated Use {@link android.provider.Settings.Global#WIFI_SLEEP_POLICY} instead
          */
-        public static final String WIFI_SLEEP_POLICY = "wifi_sleep_policy";
+        @Deprecated
+        public static final String WIFI_SLEEP_POLICY = Global.WIFI_SLEEP_POLICY;
 
         /**
-         * Value for {@link #WIFI_SLEEP_POLICY} to use the default Wi-Fi sleep
-         * policy, which is to sleep shortly after the turning off
-         * according to the {@link #STAY_ON_WHILE_PLUGGED_IN} setting.
+         * @deprecated Use {@link android.provider.Settings.Global#WIFI_SLEEP_POLICY_DEFAULT} instead
          */
-        public static final int WIFI_SLEEP_POLICY_DEFAULT = 0;
+        @Deprecated
+        public static final int WIFI_SLEEP_POLICY_DEFAULT = Global.WIFI_SLEEP_POLICY_DEFAULT;
 
         /**
-         * Value for {@link #WIFI_SLEEP_POLICY} to use the default policy when
-         * the device is on battery, and never go to sleep when the device is
-         * plugged in.
+         * @deprecated Use {@link android.provider.Settings.Global#WIFI_SLEEP_POLICY_NEVER_WHILE_PLUGGED} instead
          */
-        public static final int WIFI_SLEEP_POLICY_NEVER_WHILE_PLUGGED = 1;
+        @Deprecated
+        public static final int WIFI_SLEEP_POLICY_NEVER_WHILE_PLUGGED =
+                Global.WIFI_SLEEP_POLICY_NEVER_WHILE_PLUGGED;
 
         /**
-         * Value for {@link #WIFI_SLEEP_POLICY} to never go to sleep.
+         * @deprecated Use {@link android.provider.Settings.Global#WIFI_SLEEP_POLICY_NEVER} instead
          */
-        public static final int WIFI_SLEEP_POLICY_NEVER = 2;
+        @Deprecated
+        public static final int WIFI_SLEEP_POLICY_NEVER = Global.WIFI_SLEEP_POLICY_NEVER;
 
         //TODO: deprecate static IP constants
         /**
@@ -1673,16 +1869,18 @@
         public static final String WALLPAPER_ACTIVITY = "wallpaper_activity";
 
         /**
-         * Value to specify if the user prefers the date, time and time zone
-         * to be automatically fetched from the network (NITZ). 1=yes, 0=no
+         * @deprecated Use {@link android.provider.Settings.Global#AUTO_TIME}
+         * instead
          */
-        public static final String AUTO_TIME = "auto_time";
+        @Deprecated
+        public static final String AUTO_TIME = Global.AUTO_TIME;
 
         /**
-         * Value to specify if the user prefers the time zone
-         * to be automatically fetched from the network (NITZ). 1=yes, 0=no
+         * @deprecated Use {@link android.provider.Settings.Global#AUTO_TIME_ZONE}
+         * instead
          */
-        public static final String AUTO_TIME_ZONE = "auto_time_zone";
+        @Deprecated
+        public static final String AUTO_TIME_ZONE = Global.AUTO_TIME_ZONE;
 
         /**
          * Display times as 12 or 24 hours
@@ -1883,16 +2081,20 @@
                 "window_orientation_listener_log";
 
         /**
-         * Whether to play a sound for low-battery alerts.
+         * @deprecated Use {@link android.provider.Settings.Global#POWER_SOUNDS_ENABLED}
+         * instead
          * @hide
          */
-        public static final String POWER_SOUNDS_ENABLED = "power_sounds_enabled";
+        @Deprecated
+        public static final String POWER_SOUNDS_ENABLED = Global.POWER_SOUNDS_ENABLED;
 
         /**
-         * Whether to play a sound for dock events.
+         * @deprecated Use {@link android.provider.Settings.Global#DOCK_SOUNDS_ENABLED}
+         * instead
          * @hide
          */
-        public static final String DOCK_SOUNDS_ENABLED = "dock_sounds_enabled";
+        @Deprecated
+        public static final String DOCK_SOUNDS_ENABLED = Global.DOCK_SOUNDS_ENABLED;
 
         /**
          * Whether to play sounds when the keyguard is shown and dismissed.
@@ -1907,46 +2109,60 @@
         public static final String LOCKSCREEN_DISABLED = "lockscreen.disabled";
 
         /**
-         * URI for the low battery sound file.
+         * @deprecated Use {@link android.provider.Settings.Global#LOW_BATTERY_SOUND}
+         * instead
          * @hide
          */
-        public static final String LOW_BATTERY_SOUND = "low_battery_sound";
+        @Deprecated
+        public static final String LOW_BATTERY_SOUND = Global.LOW_BATTERY_SOUND;
 
         /**
-         * URI for the desk dock "in" event sound.
+         * @deprecated Use {@link android.provider.Settings.Global#DESK_DOCK_SOUND}
+         * instead
          * @hide
          */
-        public static final String DESK_DOCK_SOUND = "desk_dock_sound";
+        @Deprecated
+        public static final String DESK_DOCK_SOUND = Global.DESK_DOCK_SOUND;
 
         /**
-         * URI for the desk dock "out" event sound.
+         * @deprecated Use {@link android.provider.Settings.Global#DESK_UNDOCK_SOUND}
+         * instead
          * @hide
          */
-        public static final String DESK_UNDOCK_SOUND = "desk_undock_sound";
+        @Deprecated
+        public static final String DESK_UNDOCK_SOUND = Global.DESK_UNDOCK_SOUND;
 
         /**
-         * URI for the car dock "in" event sound.
+         * @deprecated Use {@link android.provider.Settings.Global#CAR_DOCK_SOUND}
+         * instead
          * @hide
          */
-        public static final String CAR_DOCK_SOUND = "car_dock_sound";
+        @Deprecated
+        public static final String CAR_DOCK_SOUND = Global.CAR_DOCK_SOUND;
 
         /**
-         * URI for the car dock "out" event sound.
+         * @deprecated Use {@link android.provider.Settings.Global#CAR_UNDOCK_SOUND}
+         * instead
          * @hide
          */
-        public static final String CAR_UNDOCK_SOUND = "car_undock_sound";
+        @Deprecated
+        public static final String CAR_UNDOCK_SOUND = Global.CAR_UNDOCK_SOUND;
 
         /**
-         * URI for the "device locked" (keyguard shown) sound.
+         * @deprecated Use {@link android.provider.Settings.Global#LOCK_SOUND}
+         * instead
          * @hide
          */
-        public static final String LOCK_SOUND = "lock_sound";
+        @Deprecated
+        public static final String LOCK_SOUND = Global.LOCK_SOUND;
 
         /**
-         * URI for the "device unlocked" (keyguard dismissed) sound.
+         * @deprecated Use {@link android.provider.Settings.Global#UNLOCK_SOUND}
+         * instead
          * @hide
          */
-        public static final String UNLOCK_SOUND = "unlock_sound";
+        @Deprecated
+        public static final String UNLOCK_SOUND = Global.UNLOCK_SOUND;
 
         /**
          * Receive incoming SIP calls?
@@ -2066,11 +2282,11 @@
         // Settings moved to Settings.Secure
 
         /**
-         * @deprecated Use {@link android.provider.Settings.Secure#ADB_ENABLED}
+         * @deprecated Use {@link android.provider.Settings.Global#ADB_ENABLED}
          * instead
          */
         @Deprecated
-        public static final String ADB_ENABLED = Secure.ADB_ENABLED;
+        public static final String ADB_ENABLED = Global.ADB_ENABLED;
 
         /**
          * @deprecated Use {@link android.provider.Settings.Secure#ANDROID_ID} instead
@@ -2079,22 +2295,22 @@
         public static final String ANDROID_ID = Secure.ANDROID_ID;
 
         /**
-         * @deprecated Use {@link android.provider.Settings.Secure#BLUETOOTH_ON} instead
+         * @deprecated Use {@link android.provider.Settings.Global#BLUETOOTH_ON} instead
          */
         @Deprecated
-        public static final String BLUETOOTH_ON = Secure.BLUETOOTH_ON;
+        public static final String BLUETOOTH_ON = Global.BLUETOOTH_ON;
 
         /**
-         * @deprecated Use {@link android.provider.Settings.Secure#DATA_ROAMING} instead
+         * @deprecated Use {@link android.provider.Settings.Global#DATA_ROAMING} instead
          */
         @Deprecated
-        public static final String DATA_ROAMING = Secure.DATA_ROAMING;
+        public static final String DATA_ROAMING = Global.DATA_ROAMING;
 
         /**
-         * @deprecated Use {@link android.provider.Settings.Secure#DEVICE_PROVISIONED} instead
+         * @deprecated Use {@link android.provider.Settings.Global#DEVICE_PROVISIONED} instead
          */
         @Deprecated
-        public static final String DEVICE_PROVISIONED = Secure.DEVICE_PROVISIONED;
+        public static final String DEVICE_PROVISIONED = Global.DEVICE_PROVISIONED;
 
         /**
          * @deprecated Use {@link android.provider.Settings.Secure#HTTP_PROXY} instead
@@ -2103,10 +2319,10 @@
         public static final String HTTP_PROXY = Secure.HTTP_PROXY;
 
         /**
-         * @deprecated Use {@link android.provider.Settings.Secure#INSTALL_NON_MARKET_APPS} instead
+         * @deprecated Use {@link android.provider.Settings.Global#INSTALL_NON_MARKET_APPS} instead
          */
         @Deprecated
-        public static final String INSTALL_NON_MARKET_APPS = Secure.INSTALL_NON_MARKET_APPS;
+        public static final String INSTALL_NON_MARKET_APPS = Global.INSTALL_NON_MARKET_APPS;
 
         /**
          * @deprecated Use {@link android.provider.Settings.Secure#LOCATION_PROVIDERS_ALLOWED}
@@ -2122,10 +2338,10 @@
         public static final String LOGGING_ID = Secure.LOGGING_ID;
 
         /**
-         * @deprecated Use {@link android.provider.Settings.Secure#NETWORK_PREFERENCE} instead
+         * @deprecated Use {@link android.provider.Settings.Global#NETWORK_PREFERENCE} instead
          */
         @Deprecated
-        public static final String NETWORK_PREFERENCE = Secure.NETWORK_PREFERENCE;
+        public static final String NETWORK_PREFERENCE = Global.NETWORK_PREFERENCE;
 
         /**
          * @deprecated Use {@link android.provider.Settings.Secure#PARENTAL_CONTROL_ENABLED}
@@ -2156,60 +2372,60 @@
         public static final String SETTINGS_CLASSNAME = Secure.SETTINGS_CLASSNAME;
 
         /**
-         * @deprecated Use {@link android.provider.Settings.Secure#USB_MASS_STORAGE_ENABLED} instead
+         * @deprecated Use {@link android.provider.Settings.Global#USB_MASS_STORAGE_ENABLED} instead
          */
         @Deprecated
-        public static final String USB_MASS_STORAGE_ENABLED = Secure.USB_MASS_STORAGE_ENABLED;
+        public static final String USB_MASS_STORAGE_ENABLED = Global.USB_MASS_STORAGE_ENABLED;
 
         /**
-         * @deprecated Use {@link android.provider.Settings.Secure#USE_GOOGLE_MAIL} instead
+         * @deprecated Use {@link android.provider.Settings.Global#USE_GOOGLE_MAIL} instead
          */
         @Deprecated
-        public static final String USE_GOOGLE_MAIL = Secure.USE_GOOGLE_MAIL;
+        public static final String USE_GOOGLE_MAIL = Global.USE_GOOGLE_MAIL;
 
        /**
          * @deprecated Use
-         * {@link android.provider.Settings.Secure#WIFI_MAX_DHCP_RETRY_COUNT} instead
+         * {@link android.provider.Settings.Global#WIFI_MAX_DHCP_RETRY_COUNT} instead
          */
         @Deprecated
-        public static final String WIFI_MAX_DHCP_RETRY_COUNT = Secure.WIFI_MAX_DHCP_RETRY_COUNT;
+        public static final String WIFI_MAX_DHCP_RETRY_COUNT = Global.WIFI_MAX_DHCP_RETRY_COUNT;
 
         /**
          * @deprecated Use
-         * {@link android.provider.Settings.Secure#WIFI_MOBILE_DATA_TRANSITION_WAKELOCK_TIMEOUT_MS} instead
+         * {@link android.provider.Settings.Global#WIFI_MOBILE_DATA_TRANSITION_WAKELOCK_TIMEOUT_MS} instead
          */
         @Deprecated
         public static final String WIFI_MOBILE_DATA_TRANSITION_WAKELOCK_TIMEOUT_MS =
-                Secure.WIFI_MOBILE_DATA_TRANSITION_WAKELOCK_TIMEOUT_MS;
+                Global.WIFI_MOBILE_DATA_TRANSITION_WAKELOCK_TIMEOUT_MS;
 
         /**
          * @deprecated Use
-         * {@link android.provider.Settings.Secure#WIFI_NETWORKS_AVAILABLE_NOTIFICATION_ON} instead
+         * {@link android.provider.Settings.Global#WIFI_NETWORKS_AVAILABLE_NOTIFICATION_ON} instead
          */
         @Deprecated
         public static final String WIFI_NETWORKS_AVAILABLE_NOTIFICATION_ON =
-            Secure.WIFI_NETWORKS_AVAILABLE_NOTIFICATION_ON;
+                Global.WIFI_NETWORKS_AVAILABLE_NOTIFICATION_ON;
 
         /**
          * @deprecated Use
-         * {@link android.provider.Settings.Secure#WIFI_NETWORKS_AVAILABLE_REPEAT_DELAY} instead
+         * {@link android.provider.Settings.Global#WIFI_NETWORKS_AVAILABLE_REPEAT_DELAY} instead
          */
         @Deprecated
         public static final String WIFI_NETWORKS_AVAILABLE_REPEAT_DELAY =
-            Secure.WIFI_NETWORKS_AVAILABLE_REPEAT_DELAY;
+                Global.WIFI_NETWORKS_AVAILABLE_REPEAT_DELAY;
 
         /**
-         * @deprecated Use {@link android.provider.Settings.Secure#WIFI_NUM_OPEN_NETWORKS_KEPT}
+         * @deprecated Use {@link android.provider.Settings.Global#WIFI_NUM_OPEN_NETWORKS_KEPT}
          * instead
          */
         @Deprecated
-        public static final String WIFI_NUM_OPEN_NETWORKS_KEPT = Secure.WIFI_NUM_OPEN_NETWORKS_KEPT;
+        public static final String WIFI_NUM_OPEN_NETWORKS_KEPT = Global.WIFI_NUM_OPEN_NETWORKS_KEPT;
 
         /**
-         * @deprecated Use {@link android.provider.Settings.Secure#WIFI_ON} instead
+         * @deprecated Use {@link android.provider.Settings.Global#WIFI_ON} instead
          */
         @Deprecated
-        public static final String WIFI_ON = Secure.WIFI_ON;
+        public static final String WIFI_ON = Global.WIFI_ON;
 
         /**
          * @deprecated Use
@@ -2267,10 +2483,10 @@
         public static final String WIFI_WATCHDOG_MAX_AP_CHECKS = Secure.WIFI_WATCHDOG_MAX_AP_CHECKS;
 
         /**
-         * @deprecated Use {@link android.provider.Settings.Secure#WIFI_WATCHDOG_ON} instead
+         * @deprecated Use {@link android.provider.Settings.Global#WIFI_WATCHDOG_ON} instead
          */
         @Deprecated
-        public static final String WIFI_WATCHDOG_ON = Secure.WIFI_WATCHDOG_ON;
+        public static final String WIFI_WATCHDOG_ON = Global.WIFI_WATCHDOG_ON;
 
         /**
          * @deprecated Use {@link android.provider.Settings.Secure#WIFI_WATCHDOG_PING_COUNT} instead
@@ -2310,11 +2526,106 @@
 
         private static boolean sIsSystemProcess;
         private static final HashSet<String> MOVED_TO_LOCK_SETTINGS;
+        private static final HashSet<String> MOVED_TO_GLOBAL;
         static {
             MOVED_TO_LOCK_SETTINGS = new HashSet<String>(3);
             MOVED_TO_LOCK_SETTINGS.add(Secure.LOCK_PATTERN_ENABLED);
             MOVED_TO_LOCK_SETTINGS.add(Secure.LOCK_PATTERN_VISIBLE);
             MOVED_TO_LOCK_SETTINGS.add(Secure.LOCK_PATTERN_TACTILE_FEEDBACK_ENABLED);
+
+            MOVED_TO_GLOBAL = new HashSet<String>();
+            MOVED_TO_GLOBAL.add(Settings.Global.ADB_ENABLED);
+            MOVED_TO_GLOBAL.add(Settings.Global.ASSISTED_GPS_ENABLED);
+            MOVED_TO_GLOBAL.add(Settings.Global.BLUETOOTH_ON);
+            MOVED_TO_GLOBAL.add(Settings.Global.CDMA_CELL_BROADCAST_SMS);
+            MOVED_TO_GLOBAL.add(Settings.Global.CDMA_ROAMING_MODE);
+            MOVED_TO_GLOBAL.add(Settings.Global.CDMA_SUBSCRIPTION_MODE);
+            MOVED_TO_GLOBAL.add(Settings.Global.DATA_ACTIVITY_TIMEOUT_MOBILE);
+            MOVED_TO_GLOBAL.add(Settings.Global.DATA_ACTIVITY_TIMEOUT_WIFI);
+            MOVED_TO_GLOBAL.add(Settings.Global.DATA_ROAMING);
+            MOVED_TO_GLOBAL.add(Settings.Global.DEVELOPMENT_SETTINGS_ENABLED);
+            MOVED_TO_GLOBAL.add(Settings.Global.DEVICE_PROVISIONED);
+            MOVED_TO_GLOBAL.add(Settings.Global.DISPLAY_DENSITY_FORCED);
+            MOVED_TO_GLOBAL.add(Settings.Global.DISPLAY_SIZE_FORCED);
+            MOVED_TO_GLOBAL.add(Settings.Global.DOWNLOAD_MAX_BYTES_OVER_MOBILE);
+            MOVED_TO_GLOBAL.add(Settings.Global.DOWNLOAD_RECOMMENDED_MAX_BYTES_OVER_MOBILE);
+            MOVED_TO_GLOBAL.add(Settings.Global.INSTALL_NON_MARKET_APPS);
+            MOVED_TO_GLOBAL.add(Settings.Global.MOBILE_DATA);
+            MOVED_TO_GLOBAL.add(Settings.Global.NETSTATS_DEV_BUCKET_DURATION);
+            MOVED_TO_GLOBAL.add(Settings.Global.NETSTATS_DEV_DELETE_AGE);
+            MOVED_TO_GLOBAL.add(Settings.Global.NETSTATS_DEV_PERSIST_BYTES);
+            MOVED_TO_GLOBAL.add(Settings.Global.NETSTATS_DEV_ROTATE_AGE);
+            MOVED_TO_GLOBAL.add(Settings.Global.NETSTATS_ENABLED);
+            MOVED_TO_GLOBAL.add(Settings.Global.NETSTATS_GLOBAL_ALERT_BYTES);
+            MOVED_TO_GLOBAL.add(Settings.Global.NETSTATS_POLL_INTERVAL);
+            MOVED_TO_GLOBAL.add(Settings.Global.NETSTATS_REPORT_XT_OVER_DEV);
+            MOVED_TO_GLOBAL.add(Settings.Global.NETSTATS_SAMPLE_ENABLED);
+            MOVED_TO_GLOBAL.add(Settings.Global.NETSTATS_TIME_CACHE_MAX_AGE);
+            MOVED_TO_GLOBAL.add(Settings.Global.NETSTATS_UID_BUCKET_DURATION);
+            MOVED_TO_GLOBAL.add(Settings.Global.NETSTATS_UID_DELETE_AGE);
+            MOVED_TO_GLOBAL.add(Settings.Global.NETSTATS_UID_PERSIST_BYTES);
+            MOVED_TO_GLOBAL.add(Settings.Global.NETSTATS_UID_ROTATE_AGE);
+            MOVED_TO_GLOBAL.add(Settings.Global.NETSTATS_UID_TAG_BUCKET_DURATION);
+            MOVED_TO_GLOBAL.add(Settings.Global.NETSTATS_UID_TAG_DELETE_AGE);
+            MOVED_TO_GLOBAL.add(Settings.Global.NETSTATS_UID_TAG_PERSIST_BYTES);
+            MOVED_TO_GLOBAL.add(Settings.Global.NETSTATS_UID_TAG_ROTATE_AGE);
+            MOVED_TO_GLOBAL.add(Settings.Global.NETWORK_PREFERENCE);
+            MOVED_TO_GLOBAL.add(Settings.Global.NITZ_UPDATE_DIFF);
+            MOVED_TO_GLOBAL.add(Settings.Global.NITZ_UPDATE_SPACING);
+            MOVED_TO_GLOBAL.add(Settings.Global.NTP_SERVER);
+            MOVED_TO_GLOBAL.add(Settings.Global.NTP_TIMEOUT);
+            MOVED_TO_GLOBAL.add(Settings.Global.PDP_WATCHDOG_ERROR_POLL_COUNT);
+            MOVED_TO_GLOBAL.add(Settings.Global.PDP_WATCHDOG_LONG_POLL_INTERVAL_MS);
+            MOVED_TO_GLOBAL.add(Settings.Global.PDP_WATCHDOG_MAX_PDP_RESET_FAIL_COUNT);
+            MOVED_TO_GLOBAL.add(Settings.Global.PDP_WATCHDOG_POLL_INTERVAL_MS);
+            MOVED_TO_GLOBAL.add(Settings.Global.PDP_WATCHDOG_TRIGGER_PACKET_COUNT);
+            MOVED_TO_GLOBAL.add(Settings.Global.SAMPLING_PROFILER_MS);
+            MOVED_TO_GLOBAL.add(Settings.Global.SETUP_PREPAID_DATA_SERVICE_URL);
+            MOVED_TO_GLOBAL.add(Settings.Global.SETUP_PREPAID_DETECTION_REDIR_HOST);
+            MOVED_TO_GLOBAL.add(Settings.Global.SETUP_PREPAID_DETECTION_TARGET_URL);
+            MOVED_TO_GLOBAL.add(Settings.Global.TETHER_DUN_APN);
+            MOVED_TO_GLOBAL.add(Settings.Global.TETHER_DUN_REQUIRED);
+            MOVED_TO_GLOBAL.add(Settings.Global.TETHER_SUPPORTED);
+            MOVED_TO_GLOBAL.add(Settings.Global.THROTTLE_HELP_URI);
+            MOVED_TO_GLOBAL.add(Settings.Global.THROTTLE_MAX_NTP_CACHE_AGE_SEC);
+            MOVED_TO_GLOBAL.add(Settings.Global.THROTTLE_NOTIFICATION_TYPE);
+            MOVED_TO_GLOBAL.add(Settings.Global.THROTTLE_POLLING_SEC);
+            MOVED_TO_GLOBAL.add(Settings.Global.THROTTLE_RESET_DAY);
+            MOVED_TO_GLOBAL.add(Settings.Global.THROTTLE_THRESHOLD_BYTES);
+            MOVED_TO_GLOBAL.add(Settings.Global.THROTTLE_VALUE_KBITSPS);
+            MOVED_TO_GLOBAL.add(Settings.Global.USB_MASS_STORAGE_ENABLED);
+            MOVED_TO_GLOBAL.add(Settings.Global.USE_GOOGLE_MAIL);
+            MOVED_TO_GLOBAL.add(Settings.Global.WEB_AUTOFILL_QUERY_URL);
+            MOVED_TO_GLOBAL.add(Settings.Global.WIFI_COUNTRY_CODE);
+            MOVED_TO_GLOBAL.add(Settings.Global.WIFI_FRAMEWORK_SCAN_INTERVAL_MS);
+            MOVED_TO_GLOBAL.add(Settings.Global.WIFI_FREQUENCY_BAND);
+            MOVED_TO_GLOBAL.add(Settings.Global.WIFI_IDLE_MS);
+            MOVED_TO_GLOBAL.add(Settings.Global.WIFI_MAX_DHCP_RETRY_COUNT);
+            MOVED_TO_GLOBAL.add(Settings.Global.WIFI_MOBILE_DATA_TRANSITION_WAKELOCK_TIMEOUT_MS);
+            MOVED_TO_GLOBAL.add(Settings.Global.WIFI_NETWORKS_AVAILABLE_NOTIFICATION_ON);
+            MOVED_TO_GLOBAL.add(Settings.Global.WIFI_NETWORKS_AVAILABLE_REPEAT_DELAY);
+            MOVED_TO_GLOBAL.add(Settings.Global.WIFI_NUM_OPEN_NETWORKS_KEPT);
+            MOVED_TO_GLOBAL.add(Settings.Global.WIFI_ON);
+            MOVED_TO_GLOBAL.add(Settings.Global.WIFI_P2P_DEVICE_NAME);
+            MOVED_TO_GLOBAL.add(Settings.Global.WIFI_SAVED_STATE);
+            MOVED_TO_GLOBAL.add(Settings.Global.WIFI_SUPPLICANT_SCAN_INTERVAL_MS);
+            MOVED_TO_GLOBAL.add(Settings.Global.WIFI_SUSPEND_OPTIMIZATIONS_ENABLED);
+            MOVED_TO_GLOBAL.add(Settings.Global.WIFI_WATCHDOG_NUM_ARP_PINGS);
+            MOVED_TO_GLOBAL.add(Settings.Global.WIFI_WATCHDOG_ON);
+            MOVED_TO_GLOBAL.add(Settings.Global.WIFI_WATCHDOG_POOR_NETWORK_TEST_ENABLED);
+            MOVED_TO_GLOBAL.add(Settings.Global.WIFI_WATCHDOG_RSSI_FETCH_INTERVAL_MS);
+            MOVED_TO_GLOBAL.add(Settings.Global.WIMAX_NETWORKS_AVAILABLE_NOTIFICATION_ON);
+            MOVED_TO_GLOBAL.add(Settings.Global.WTF_IS_FATAL);
+        }
+
+        private static void lazyInitCache() {
+            if (sNameValueCache == null) {
+                sNameValueCache = new NameValueCache(
+                        SYS_PROP_SETTING_VERSION + '_' + UserHandle.myUserId(),
+                        CONTENT_URI,
+                        CALL_METHOD_GET_SECURE,
+                        CALL_METHOD_PUT_SECURE);
+            }
         }
 
         /**
@@ -2324,9 +2635,16 @@
          * @return the corresponding value, or null if not present
          */
         public synchronized static String getString(ContentResolver resolver, String name) {
-            if (sNameValueCache == null) {
-                sNameValueCache = new NameValueCache(SYS_PROP_SETTING_VERSION, CONTENT_URI,
-                                                     CALL_METHOD_GET_SECURE);
+            return getStringForUser(resolver, name, UserHandle.myUserId());
+        }
+
+        /** @hide */
+        public synchronized static String getStringForUser(ContentResolver resolver, String name,
+                int userHandle) {
+            if (MOVED_TO_GLOBAL.contains(name)) {
+                Log.w(TAG, "Setting " + name + " has moved from android.provider.Settings.Secure"
+                        + " to android.provider.Settings.Global.");
+                return Global.getStringForUser(resolver, name, userHandle);
             }
 
             if (sLockSettings == null) {
@@ -2337,13 +2655,14 @@
             if (sLockSettings != null && !sIsSystemProcess
                     && MOVED_TO_LOCK_SETTINGS.contains(name)) {
                 try {
-                    return sLockSettings.getString(name, "0", UserHandle.getCallingUserId());
+                    return sLockSettings.getString(name, "0", userHandle);
                 } catch (RemoteException re) {
                     // Fall through
                 }
             }
 
-            return sNameValueCache.getString(resolver, name);
+            lazyInitCache();
+            return sNameValueCache.getStringForUser(resolver, name, userHandle);
         }
 
         /**
@@ -2353,9 +2672,20 @@
          * @param value to associate with the name
          * @return true if the value was set, false on database errors
          */
-        public static boolean putString(ContentResolver resolver,
-                String name, String value) {
-            return putString(resolver, CONTENT_URI, name, value);
+        public static boolean putString(ContentResolver resolver, String name, String value) {
+            return putStringForUser(resolver, name, value, UserHandle.myUserId());
+        }
+
+        /** @hide */
+        public static boolean putStringForUser(ContentResolver resolver, String name, String value,
+                int userHandle) {
+            if (MOVED_TO_GLOBAL.contains(name)) {
+                Log.w(TAG, "Setting " + name + " has moved from android.provider.Settings.System"
+                        + " to android.provider.Settings.Global");
+                return Global.putStringForUser(resolver, name, value, userHandle);
+            }
+            lazyInitCache();
+            return sNameValueCache.putStringForUser(resolver, name, value, userHandle);
         }
 
         /**
@@ -2365,6 +2695,11 @@
          * @return the corresponding content URI, or null if not present
          */
         public static Uri getUriFor(String name) {
+            if (MOVED_TO_GLOBAL.contains(name)) {
+                Log.w(TAG, "Setting " + name + " has moved from android.provider.Settings.Secure"
+                        + " to android.provider.Settings.Global, returning global URI.");
+                return Global.getUriFor(Global.CONTENT_URI, name);
+            }
             return getUriFor(CONTENT_URI, name);
         }
 
@@ -2383,7 +2718,12 @@
          * or not a valid integer.
          */
         public static int getInt(ContentResolver cr, String name, int def) {
-            String v = getString(cr, name);
+            return getIntForUser(cr, name, def, UserHandle.myUserId());
+        }
+
+        /** @hide */
+        public static int getIntForUser(ContentResolver cr, String name, int def, int userHandle) {
+            String v = getStringForUser(cr, name, userHandle);
             try {
                 return v != null ? Integer.parseInt(v) : def;
             } catch (NumberFormatException e) {
@@ -2411,7 +2751,13 @@
          */
         public static int getInt(ContentResolver cr, String name)
                 throws SettingNotFoundException {
-            String v = getString(cr, name);
+            return getIntForUser(cr, name, UserHandle.myUserId());
+        }
+
+        /** @hide */
+        public static int getIntForUser(ContentResolver cr, String name, int userHandle)
+                throws SettingNotFoundException {
+            String v = getStringForUser(cr, name, userHandle);
             try {
                 return Integer.parseInt(v);
             } catch (NumberFormatException e) {
@@ -2433,7 +2779,13 @@
          * @return true if the value was set, false on database errors
          */
         public static boolean putInt(ContentResolver cr, String name, int value) {
-            return putString(cr, name, Integer.toString(value));
+            return putIntForUser(cr, name, value, UserHandle.myUserId());
+        }
+
+        /** @hide */
+        public static boolean putIntForUser(ContentResolver cr, String name, int value,
+                int userHandle) {
+            return putStringForUser(cr, name, Integer.toString(value), userHandle);
         }
 
         /**
@@ -2451,7 +2803,13 @@
          * or not a valid {@code long}.
          */
         public static long getLong(ContentResolver cr, String name, long def) {
-            String valString = getString(cr, name);
+            return getLongForUser(cr, name, def, UserHandle.myUserId());
+        }
+
+        /** @hide */
+        public static long getLongForUser(ContentResolver cr, String name, long def,
+                int userHandle) {
+            String valString = getStringForUser(cr, name, userHandle);
             long value;
             try {
                 value = valString != null ? Long.parseLong(valString) : def;
@@ -2480,7 +2838,13 @@
          */
         public static long getLong(ContentResolver cr, String name)
                 throws SettingNotFoundException {
-            String valString = getString(cr, name);
+            return getLongForUser(cr, name, UserHandle.myUserId());
+        }
+
+        /** @hide */
+        public static long getLongForUser(ContentResolver cr, String name, int userHandle)
+                throws SettingNotFoundException {
+            String valString = getStringForUser(cr, name, userHandle);
             try {
                 return Long.parseLong(valString);
             } catch (NumberFormatException e) {
@@ -2502,7 +2866,13 @@
          * @return true if the value was set, false on database errors
          */
         public static boolean putLong(ContentResolver cr, String name, long value) {
-            return putString(cr, name, Long.toString(value));
+            return putLongForUser(cr, name, value, UserHandle.myUserId());
+        }
+
+        /** @hide */
+        public static boolean putLongForUser(ContentResolver cr, String name, long value,
+                int userHandle) {
+            return putStringForUser(cr, name, Long.toString(value), userHandle);
         }
 
         /**
@@ -2520,7 +2890,13 @@
          * or not a valid float.
          */
         public static float getFloat(ContentResolver cr, String name, float def) {
-            String v = getString(cr, name);
+            return getFloatForUser(cr, name, def, UserHandle.myUserId());
+        }
+
+        /** @hide */
+        public static float getFloatForUser(ContentResolver cr, String name, float def,
+                int userHandle) {
+            String v = getStringForUser(cr, name, userHandle);
             try {
                 return v != null ? Float.parseFloat(v) : def;
             } catch (NumberFormatException e) {
@@ -2548,7 +2924,13 @@
          */
         public static float getFloat(ContentResolver cr, String name)
                 throws SettingNotFoundException {
-            String v = getString(cr, name);
+            return getFloatForUser(cr, name, UserHandle.myUserId());
+        }
+
+        /** @hide */
+        public static float getFloatForUser(ContentResolver cr, String name, int userHandle)
+                throws SettingNotFoundException {
+            String v = getStringForUser(cr, name, userHandle);
             if (v == null) {
                 throw new SettingNotFoundException(name);
             }
@@ -2573,7 +2955,13 @@
          * @return true if the value was set, false on database errors
          */
         public static boolean putFloat(ContentResolver cr, String name, float value) {
-            return putString(cr, name, Float.toString(value));
+            return putFloatForUser(cr, name, value, UserHandle.myUserId());
+        }
+
+        /** @hide */
+        public static boolean putFloatForUser(ContentResolver cr, String name, float value,
+                int userHandle) {
+            return putStringForUser(cr, name, Float.toString(value), userHandle);
         }
 
         /**
@@ -2583,9 +2971,12 @@
             Uri.parse("content://" + AUTHORITY + "/secure");
 
         /**
-         * Whether user has enabled development settings.
+         * @deprecated Use {@link android.provider.Settings.Global#DEVELOPMENT_SETTINGS_ENABLED}
+         * instead
          */
-        public static final String DEVELOPMENT_SETTINGS_ENABLED = "development_settings_enabled";
+        @Deprecated
+        public static final String DEVELOPMENT_SETTINGS_ENABLED =
+                Global.DEVELOPMENT_SETTINGS_ENABLED;
 
         /**
          * When the user has enable the option to have a "bug report" command
@@ -2595,9 +2986,10 @@
         public static final String BUGREPORT_IN_POWER_MENU = "bugreport_in_power_menu";
 
         /**
-         * Whether ADB is enabled.
+         * @deprecated Use {@link android.provider.Settings.Global#ADB_ENABLED} instead
          */
-        public static final String ADB_ENABLED = "adb_enabled";
+        @Deprecated
+        public static final String ADB_ENABLED = Global.ADB_ENABLED;
 
         /**
          * Setting to allow mock locations and location provider status to be injected into the
@@ -2616,10 +3008,10 @@
         public static final String ANDROID_ID = "android_id";
 
         /**
-         * Whether bluetooth is enabled/disabled
-         * 0=disabled. 1=enabled.
+         * @deprecated Use {@link android.provider.Settings.Global#BLUETOOTH_ON} instead
          */
-        public static final String BLUETOOTH_ON = "bluetooth_on";
+        @Deprecated
+        public static final String BLUETOOTH_ON = Global.BLUETOOTH_ON;
 
         /**
          * Get the key that retrieves a bluetooth headset's priority.
@@ -2646,9 +3038,9 @@
         }
 
         /**
-         * Whether or not data roaming is enabled. (0 = false, 1 = true)
+         * @deprecated Use {@link android.provider.Settings.Global#DATA_ROAMING} instead
          */
-        public static final String DATA_ROAMING = "data_roaming";
+        public static final String DATA_ROAMING = Global.DATA_ROAMING;
 
         /**
          * Setting to record the input method used by default, holding the ID
@@ -2678,9 +3070,10 @@
                 "input_method_selector_visibility";
 
         /**
-         * Whether the device has been provisioned (0 = false, 1 = true)
+         * @deprecated Use {@link android.provider.Settings.Global#DEVICE_PROVISIONED} instead
          */
-        public static final String DEVICE_PROVISIONED = "device_provisioned";
+        @Deprecated
+        public static final String DEVICE_PROVISIONED = Global.DEVICE_PROVISIONED;
 
         /**
          * List of input methods that are currently enabled.  This is a string
@@ -2739,13 +3132,10 @@
         public static final String DEFAULT_DNS_SERVER = "default_dns_server";
 
         /**
-         * Whether the package installer should allow installation of apps downloaded from
-         * sources other than Google Play.
-         *
-         * 1 = allow installing from other sources
-         * 0 = only allow installing from Google Play
+         * @deprecated Use {@link android.provider.Settings.Global#INSTALL_NON_MARKET_APPS} instead
          */
-        public static final String INSTALL_NON_MARKET_APPS = "install_non_market_apps";
+        @Deprecated
+        public static final String INSTALL_NON_MARKET_APPS = Global.INSTALL_NON_MARKET_APPS;
 
         /**
          * Comma-separated list of location providers that activities may access.
@@ -2797,24 +3187,25 @@
             "lock_screen_owner_info_enabled";
 
         /**
-         * The saved value for WindowManagerService.setForcedDisplaySize().
-         * Two integers separated by a comma.  If unset, then use the real display size.
+         * @deprecated Use {@link android.provider.Settings.Global#DISPLAY_SIZE_FORCED} instead
          * @hide
          */
-        public static final String DISPLAY_SIZE_FORCED = "display_size_forced";
+        @Deprecated
+        public static final String DISPLAY_SIZE_FORCED = Global.DISPLAY_SIZE_FORCED;
 
         /**
-         * The saved value for WindowManagerService.setForcedDisplayDensity().
-         * One integer in dpi.  If unset, then use the real display density.
+         * @deprecated Use {@link android.provider.Settings.Global#DISPLAY_DENSITY_FORCED} instead
          * @hide
          */
-        public static final String DISPLAY_DENSITY_FORCED = "display_density_forced";
+        @Deprecated
+        public static final String DISPLAY_DENSITY_FORCED = Global.DISPLAY_DENSITY_FORCED;
 
         /**
-         * Whether assisted GPS should be enabled or not.
+         * @deprecated Use {@link android.provider.Settings.Global#ASSISTED_GPS_ENABLE} instead
          * @hide
          */
-        public static final String ASSISTED_GPS_ENABLED = "assisted_gps_enabled";
+        @Deprecated
+        public static final String ASSISTED_GPS_ENABLED = Global.ASSISTED_GPS_ENABLED;
 
         /**
          * The Logging ID (a unique 64-bit value) as a hex string.
@@ -2826,57 +3217,48 @@
         public static final String LOGGING_ID = "logging_id";
 
         /**
-         * User preference for which network(s) should be used. Only the
-         * connectivity service should touch this.
+         * @deprecated Use {@link android.provider.Settings.Global#NETWORK_PREFERENCE} instead
          */
-        public static final String NETWORK_PREFERENCE = "network_preference";
+        @Deprecated
+        public static final String NETWORK_PREFERENCE = Global.NETWORK_PREFERENCE;
 
         /**
-         * Used to disable Tethering on a device - defaults to true
+         * @deprecated Use {@link android.provider.Settings.Global#TETHER_SUPPORTED} instead
          * @hide
          */
-        public static final String TETHER_SUPPORTED = "tether_supported";
+        @Deprecated
+        public static final String TETHER_SUPPORTED = Global.TETHER_SUPPORTED;
 
         /**
-         * Used to require DUN APN on the device or not - defaults to a build config value
-         * which defaults to false
+         * @deprecated Use {@link android.provider.Settings.Global#TETHER_DUN_REQUIRED} instead
          * @hide
          */
-        public static final String TETHER_DUN_REQUIRED = "tether_dun_required";
+        @Deprecated
+        public static final String TETHER_DUN_REQUIRED = Global.TETHER_DUN_REQUIRED;
 
         /**
-         * Used to hold a gservices-provisioned apn value for DUN.  If set, or the
-         * corresponding build config values are set it will override the APN DB
-         * values.
-         * Consists of a comma seperated list of strings:
-         * "name,apn,proxy,port,username,password,server,mmsc,mmsproxy,mmsport,mcc,mnc,auth,type"
-         * note that empty fields can be ommitted: "name,apn,,,,,,,,,310,260,,DUN"
+         * @deprecated Use {@link android.provider.Settings.Global#TETHER_DUN_REQUIRED} instead
          * @hide
          */
-        public static final String TETHER_DUN_APN = "tether_dun_apn";
+        @Deprecated
+        public static final String TETHER_DUN_APN = Global.TETHER_DUN_APN;
 
-        /** Inactivity timeout to track mobile data activity.
-         *
-         * If set to a positive integer, it indicates the inactivity timeout value in seconds to
-         * infer the data activity of mobile network. After a period of no activity on mobile
-         * networks with length specified by the timeout, an {@code ACTION_DATA_ACTIVITY_CHANGE}
-         * intent is fired to indicate a transition of network status from "active" to "idle". Any
-         * subsequent activity on mobile networks triggers the firing of {@code
-         * ACTION_DATA_ACTIVITY_CHANGE} intent indicating transition from "idle" to "active".
-         *
-         * Network activity refers to transmitting or receiving data on the network interfaces.
-         *
-         * Tracking is disabled if set to zero or negative value.
-         *
+        /**
+         * @deprecated Use {@link android.provider.Settings.Global#DATA_ACTIVITY_TIMEOUT_MOBILE}
+         * instead
          * @hide
          */
-        public static final String DATA_ACTIVITY_TIMEOUT_MOBILE = "data_activity_timeout_mobile";
+        @Deprecated
+        public static final String DATA_ACTIVITY_TIMEOUT_MOBILE =
+            Global.DATA_ACTIVITY_TIMEOUT_MOBILE;
 
-        /** Timeout to tracking Wifi data activity. Same as {@code DATA_ACTIVITY_TIMEOUT_MOBILE}
-         * but for Wifi network.
+        /**
+         * @deprecated Use {@link android.provider.Settings.Global#DATA_ACTIVITY_TIMEOUT_MOBILE}
+         * instead
          * @hide
          */
-        public static final String DATA_ACTIVITY_TIMEOUT_WIFI = "data_activity_timeout_wifi";
+        @Deprecated
+        public static final String DATA_ACTIVITY_TIMEOUT_WIFI = Global.DATA_ACTIVITY_TIMEOUT_WIFI;
 
         /**
          * No longer supported.
@@ -2894,13 +3276,11 @@
         public static final String PARENTAL_CONTROL_REDIRECT_URL = "parental_control_redirect_url";
 
         /**
-         * A positive value indicates how often the SamplingProfiler
-         * should take snapshots. Zero value means SamplingProfiler
-         * is disabled.
-         *
+         * @deprecated Use {@link android.provider.Settings.Global#SAMPLING_PROFILER_MS} instead
          * @hide
          */
-        public static final String SAMPLING_PROFILER_MS = "sampling_profiler_ms";
+        @Deprecated
+        public static final String SAMPLING_PROFILER_MS = Global.SAMPLING_PROFILER_MS;
 
         /**
          * Settings classname to launch when Settings is clicked from All
@@ -2911,15 +3291,16 @@
         public static final String SETTINGS_CLASSNAME = "settings_classname";
 
         /**
-         * USB Mass Storage Enabled
+         * @deprecated Use {@link android.provider.Settings.Global#USB_MASS_STORAGE_ENABLED} instead
          */
-        public static final String USB_MASS_STORAGE_ENABLED = "usb_mass_storage_enabled";
+        @Deprecated
+        public static final String USB_MASS_STORAGE_ENABLED = Global.USB_MASS_STORAGE_ENABLED;
 
         /**
-         * If this setting is set (to anything), then all references
-         * to Gmail on the device must change to Google Mail.
+         * @deprecated Use {@link android.provider.Settings.Global#USE_GOOGLE_MAIL} instead
          */
-        public static final String USE_GOOGLE_MAIL = "use_google_mail";
+        @Deprecated
+        public static final String USE_GOOGLE_MAIL = Global.USE_GOOGLE_MAIL;
 
         /**
          * If accessibility is enabled.
@@ -3022,6 +3403,46 @@
             "accessibility_web_content_key_bindings";
 
         /**
+         * Setting that specifies whether the display magnification is enabled.
+         * Display magnifications allows the user to zoom in the display content
+         * and is targeted to low vision users. The current magnification scale
+         * is controlled by {@link #ACCESSIBILITY_DISPLAY_MAGNIFICATION_SCALE}.
+         *
+         * @hide
+         */
+        public static final String ACCESSIBILITY_DISPLAY_MAGNIFICATION_ENABLED =
+                "accessibility_display_magnification_enabled";
+
+        /**
+         * Setting that specifies what the display magnification scale is.
+         * Display magnifications allows the user to zoom in the display
+         * content and is targeted to low vision users. Whether a display
+         * magnification is performed is controlled by
+         * {@link #ACCESSIBILITY_DISPLAY_MAGNIFICATION_ENABLED}
+         *
+         * @hide
+         */
+        public static final String ACCESSIBILITY_DISPLAY_MAGNIFICATION_SCALE =
+                "accessibility_display_magnification_scale";
+
+        /**
+         * Setting that specifies whether the display magnification should be
+         * automatically updated. If this fearture is enabled the system will
+         * exit magnification mode or pan the viewport when a context change
+         * occurs. For example, on staring a new activity or rotating the screen,
+         * the system may zoom out so the user can see the new context he is in.
+         * Another example is on showing a window that is not visible in the
+         * magnified viewport the system may pan the viewport to make the window
+         * the has popped up so the user knows that the context has changed.
+         * Whether a screen magnification is performed is controlled by
+         * {@link #ACCESSIBILITY_DISPLAY_MAGNIFICATION_ENABLED}
+         *
+         * @hide
+         */
+        public static final String ACCESSIBILITY_DISPLAY_MAGNIFICATION_AUTO_UPDATE =
+                "accessibility_display_magnification_auto_update";
+
+        /**
          * The timout for considering a press to be a long press in milliseconds.
          * @hide
          */
@@ -3315,11 +3736,11 @@
                 "wifi_suspend_optimizations_enabled";
 
         /**
-         * The maximum number of times we will retry a connection to an access
-         * point for which we have failed in acquiring an IP address from DHCP.
-         * A value of N means that we will make N+1 connection attempts in all.
+         * @deprecated Use
+         * {@link android.provider.Settings.Global#WIFI_MAX_DHCP_RETRY_COUNT} instead
          */
-        public static final String WIFI_MAX_DHCP_RETRY_COUNT = "wifi_max_dhcp_retry_count";
+        @Deprecated
+        public static final String WIFI_MAX_DHCP_RETRY_COUNT = Global.WIFI_MAX_DHCP_RETRY_COUNT;
 
         /**
          * The operational wifi frequency band
@@ -3380,26 +3801,25 @@
                 = "allowed_geolocation_origins";
 
         /**
-         * Whether mobile data connections are allowed by the user.  See
-         * ConnectivityManager for more info.
+         * @deprecated Use {@link android.provider.Settings.Global#MOBILE_DATA} instead
          * @hide
          */
-        public static final String MOBILE_DATA = "mobile_data";
+        @Deprecated
+        public static final String MOBILE_DATA = Global.MOBILE_DATA;
 
         /**
-         * The CDMA roaming mode 0 = Home Networks, CDMA default
-         *                       1 = Roaming on Affiliated networks
-         *                       2 = Roaming on any networks
+         * @deprecated Use {@link android.provider.Settings.Global#CDMA_ROAMING_MODE} instead
          * @hide
          */
-        public static final String CDMA_ROAMING_MODE = "roaming_settings";
+        @Deprecated
+        public static final String CDMA_ROAMING_MODE = Global.CDMA_ROAMING_MODE;
 
         /**
-         * The CDMA subscription mode 0 = RUIM/SIM (default)
-         *                                1 = NV
+         * @deprecated Use {@link android.provider.Settings.Global#CDMA_ROAMING_MODE} instead
          * @hide
          */
-        public static final String CDMA_SUBSCRIPTION_MODE = "subscription_mode";
+        @Deprecated
+        public static final String CDMA_SUBSCRIPTION_MODE = Global.CDMA_SUBSCRIPTION_MODE;
 
         /**
          * The preferred network mode   7 = Global
@@ -3427,13 +3847,11 @@
 
 
         /**
-         * CDMA Cell Broadcast SMS
-         *                            0 = CDMA Cell Broadcast SMS disabled
-         *                            1 = CDMA Cell Broadcast SMS enabled
+         * @deprecated Use {@link android.provider.Settings.Global#CDMA_CELL_BROADCAST_SMS} instead
          * @hide
          */
-        public static final String CDMA_CELL_BROADCAST_SMS =
-                "cdma_cell_broadcast_sms";
+        @Deprecated
+        public static final String CDMA_CELL_BROADCAST_SMS = Global.CDMA_CELL_BROADCAST_SMS;
 
         /**
          * The cdma subscription 0 = Subscription from RUIM, when available
@@ -3653,10 +4071,11 @@
         public static final String SEND_ACTION_APP_ERROR = "send_action_app_error";
 
         /**
-         * Nonzero causes Log.wtf() to crash.
+         * @deprecated Use {@link android.provider.Settings.Global#WTF_IS_FATAL} instead
          * @hide
          */
-        public static final String WTF_IS_FATAL = "wtf_is_fatal";
+        @Deprecated
+        public static final String WTF_IS_FATAL = Global.WTF_IS_FATAL;
 
         /**
          * Maximum age of entries kept by {@link com.android.internal.os.IDropBoxManagerService}.
@@ -3786,57 +4205,52 @@
                 "wifi_supplicant_scan_interval_ms";
 
         /**
-         * The interval in milliseconds at which to check packet counts on the
-         * mobile data interface when screen is on, to detect possible data
-         * connection problems.
+         * @deprecated Moved to Settings.Global
          * @hide
          */
+        @Deprecated
         public static final String PDP_WATCHDOG_POLL_INTERVAL_MS =
-                "pdp_watchdog_poll_interval_ms";
+                Global.PDP_WATCHDOG_POLL_INTERVAL_MS;
 
         /**
-         * The interval in milliseconds at which to check packet counts on the
-         * mobile data interface when screen is off, to detect possible data
-         * connection problems.
+         * @deprecated Moved to Settings.Global
          * @hide
          */
+        @Deprecated
         public static final String PDP_WATCHDOG_LONG_POLL_INTERVAL_MS =
-                "pdp_watchdog_long_poll_interval_ms";
+                Global.PDP_WATCHDOG_LONG_POLL_INTERVAL_MS;
 
         /**
-         * The interval in milliseconds at which to check packet counts on the
-         * mobile data interface after {@link #PDP_WATCHDOG_TRIGGER_PACKET_COUNT}
-         * outgoing packets has been reached without incoming packets.
+         * @deprecated Moved to Settings.Global
          * @hide
          */
+        @Deprecated
         public static final String PDP_WATCHDOG_ERROR_POLL_INTERVAL_MS =
-                "pdp_watchdog_error_poll_interval_ms";
+                Global.PDP_WATCHDOG_ERROR_POLL_INTERVAL_MS;
 
         /**
-         * The number of outgoing packets sent without seeing an incoming packet
-         * that triggers a countdown (of {@link #PDP_WATCHDOG_ERROR_POLL_COUNT}
-         * device is logged to the event log
+         * @deprecated Moved to Settings.Global
          * @hide
          */
+        @Deprecated
         public static final String PDP_WATCHDOG_TRIGGER_PACKET_COUNT =
-                "pdp_watchdog_trigger_packet_count";
+                Global.PDP_WATCHDOG_TRIGGER_PACKET_COUNT;
 
         /**
-         * The number of polls to perform (at {@link #PDP_WATCHDOG_ERROR_POLL_INTERVAL_MS})
-         * after hitting {@link #PDP_WATCHDOG_TRIGGER_PACKET_COUNT} before
-         * attempting data connection recovery.
+         * @deprecated Moved to Settings.Global
          * @hide
          */
+        @Deprecated
         public static final String PDP_WATCHDOG_ERROR_POLL_COUNT =
-                "pdp_watchdog_error_poll_count";
+                Global.PDP_WATCHDOG_ERROR_POLL_COUNT;
 
         /**
-         * The number of failed PDP reset attempts before moving to something more
-         * drastic: re-registering to the network.
+         * @deprecated Moved to Settings.Global
          * @hide
          */
+        @Deprecated
         public static final String PDP_WATCHDOG_MAX_PDP_RESET_FAIL_COUNT =
-                "pdp_watchdog_max_pdp_reset_fail_count";
+                Global.PDP_WATCHDOG_MAX_PDP_RESET_FAIL_COUNT;
 
         /**
          * The number of milliseconds to delay when checking for data stalls during
@@ -3865,19 +4279,16 @@
                 "gprs_register_check_period_ms";
 
         /**
-         * The length of time in milli-seconds that automatic small adjustments to
-         * SystemClock are ignored if NITZ_UPDATE_DIFF is not exceeded.
+         * @deprecated Use {@link android.provider.Settings.Global#NITZ_UPDATE_SPACING} instead
          * @hide
          */
-        public static final String NITZ_UPDATE_SPACING = "nitz_update_spacing";
+        public static final String NITZ_UPDATE_SPACING = Global.NITZ_UPDATE_SPACING;
 
         /**
-         * If the NITZ_UPDATE_DIFF time is exceeded then an automatic adjustment
-         * to SystemClock will be allowed even if NITZ_UPDATE_SPACING has not been
-         * exceeded.
+         * @deprecated Use {@link android.provider.Settings.Global#NITZ_UPDATE_SPACING} instead
          * @hide
          */
-        public static final String NITZ_UPDATE_DIFF = "nitz_update_diff";
+        public static final String NITZ_UPDATE_DIFF = Global.NITZ_UPDATE_DIFF;
 
         /**
          * The maximum reconnect delay for short network outages or when the network is suspended
@@ -4139,65 +4550,70 @@
         public static final String DEFAULT_INSTALL_LOCATION = "default_install_location";
 
         /**
-         * The bandwidth throttle polling freqency in seconds
+         * @deprecated Use {@link android.provider.Settings.Global#THROTTLE_POLLING_SEC} instead
          * @hide
          */
-        public static final String THROTTLE_POLLING_SEC = "throttle_polling_sec";
+        @Deprecated
+        public static final String THROTTLE_POLLING_SEC = Global.THROTTLE_POLLING_SEC;
 
         /**
-         * The bandwidth throttle threshold (long)
+         * @deprecated Use {@link android.provider.Settings.Global#THROTTLE_THRESHOLD_BYTES} instead
          * @hide
          */
-        public static final String THROTTLE_THRESHOLD_BYTES = "throttle_threshold_bytes";
+        @Deprecated
+        public static final String THROTTLE_THRESHOLD_BYTES = Global.THROTTLE_THRESHOLD_BYTES;
 
         /**
-         * The bandwidth throttle value (kbps)
+         * @deprecated Use {@link android.provider.Settings.Global#THROTTLE_VALUE_KBITSPS} instead
          * @hide
          */
-        public static final String THROTTLE_VALUE_KBITSPS = "throttle_value_kbitsps";
+        @Deprecated
+        public static final String THROTTLE_VALUE_KBITSPS = Global.THROTTLE_VALUE_KBITSPS;
 
         /**
-         * The bandwidth throttle reset calendar day (1-28)
+         * @deprecated Use {@link android.provider.Settings.Global#THROTTLE_VALUE_KBITSPS} instead
          * @hide
          */
-        public static final String THROTTLE_RESET_DAY = "throttle_reset_day";
+        @Deprecated
+        public static final String THROTTLE_RESET_DAY = Global.THROTTLE_RESET_DAY;
 
         /**
-         * The throttling notifications we should send
+         * @deprecated Use {@link android.provider.Settings.Global#THROTTLE_NOTIFICATION_TYPE} instead
          * @hide
          */
-        public static final String THROTTLE_NOTIFICATION_TYPE = "throttle_notification_type";
+        @Deprecated
+        public static final String THROTTLE_NOTIFICATION_TYPE = Global.THROTTLE_NOTIFICATION_TYPE;
 
         /**
-         * Help URI for data throttling policy
+         * @deprecated Use {@link android.provider.Settings.Global#THROTTLE_HELP_URI} instead
          * @hide
          */
-        public static final String THROTTLE_HELP_URI = "throttle_help_uri";
+        @Deprecated
+        public static final String THROTTLE_HELP_URI = Global.THROTTLE_HELP_URI;
 
         /**
-         * The length of time in Sec that we allow our notion of NTP time
-         * to be cached before we refresh it
+         * @deprecated Use {@link android.provider.Settings.Global#THROTTLE_MAX_NTP_CACHE_AGE_SEC} instead
          * @hide
          */
+        @Deprecated
         public static final String THROTTLE_MAX_NTP_CACHE_AGE_SEC =
-                "throttle_max_ntp_cache_age_sec";
+                Global.THROTTLE_MAX_NTP_CACHE_AGE_SEC;
 
         /**
-         * The maximum size, in bytes, of a download that the download manager will transfer over
-         * a non-wifi connection.
+         * @deprecated Use {@link android.provider.Settings.Global#DOWNLOAD_MAX_BYTES_OVER_MOBILE} instead
          * @hide
          */
+        @Deprecated
         public static final String DOWNLOAD_MAX_BYTES_OVER_MOBILE =
-                "download_manager_max_bytes_over_mobile";
+                Global.DOWNLOAD_MAX_BYTES_OVER_MOBILE;
 
         /**
-         * The recommended maximum size, in bytes, of a download that the download manager should
-         * transfer over a non-wifi connection. Over this size, the use will be warned, but will
-         * have the option to start the download over the mobile connection anyway.
+         * @deprecated Use {@link android.provider.Settings.Global#DOWNLOAD_RECOMMENDED_MAX_BYTES_OVER_MOBILE} instead
          * @hide
          */
+        @Deprecated
         public static final String DOWNLOAD_RECOMMENDED_MAX_BYTES_OVER_MOBILE =
-                "download_manager_recommended_max_bytes_over_mobile";
+                Global.DOWNLOAD_RECOMMENDED_MAX_BYTES_OVER_MOBILE;
 
         /**
          * ms during which to consume extra events related to Inet connection condition
@@ -4216,27 +4632,28 @@
                 "inet_condition_debounce_down_delay";
 
         /**
-         * URL to open browser on to allow user to manage a prepay account
+         * @deprecated Use {@link android.provider.Settings.Global#SETUP_PREPAID_DATA_SERVICE_URL} instead
          * @hide
          */
+        @Deprecated
         public static final String SETUP_PREPAID_DATA_SERVICE_URL =
-                "setup_prepaid_data_service_url";
+                Global.SETUP_PREPAID_DATA_SERVICE_URL;
 
         /**
-         * URL to attempt a GET on to see if this is a prepay device
+         * @deprecated Use {@link android.provider.Settings.Global#SETUP_PREPAID_DETECTION_TARGET_URL} instead
          * @hide
          */
+        @Deprecated
         public static final String SETUP_PREPAID_DETECTION_TARGET_URL =
-                "setup_prepaid_detection_target_url";
+                Global.SETUP_PREPAID_DETECTION_TARGET_URL;
 
         /**
-         * Host to check for a redirect to after an attempt to GET
-         * SETUP_PREPAID_DETECTION_TARGET_URL. (If we redirected there,
-         * this is a prepaid device with zero balance.)
+         * @deprecated Use {@link android.provider.Settings.Global#SETUP_PREPAID_DETECTION_REDIR_HOST} instead
          * @hide
          */
+        @Deprecated
         public static final String SETUP_PREPAID_DETECTION_REDIR_HOST =
-                "setup_prepaid_detection_redir_host";
+                Global.SETUP_PREPAID_DETECTION_REDIR_HOST;
 
         /**
          * Whether screensavers are enabled.
@@ -4273,62 +4690,116 @@
          */
         public static final String SCREENSAVER_DEFAULT_COMPONENT = "screensaver_default_component";
 
-        /** {@hide} */
-        public static final String NETSTATS_ENABLED = "netstats_enabled";
-        /** {@hide} */
-        public static final String NETSTATS_POLL_INTERVAL = "netstats_poll_interval";
-        /** {@hide} */
-        public static final String NETSTATS_TIME_CACHE_MAX_AGE = "netstats_time_cache_max_age";
-        /** {@hide} */
-        public static final String NETSTATS_GLOBAL_ALERT_BYTES = "netstats_global_alert_bytes";
-        /** {@hide} */
-        public static final String NETSTATS_SAMPLE_ENABLED = "netstats_sample_enabled";
-        /** {@hide} */
-        public static final String NETSTATS_REPORT_XT_OVER_DEV = "netstats_report_xt_over_dev";
+        /** @deprecated The NETSTATS_* symbols live in Settings.Global.* now
+         * {@hide} */
+        @Deprecated
+        public static final String NETSTATS_ENABLED = Global.NETSTATS_ENABLED;
+        /** @deprecated The NETSTATS_* symbols live in Settings.Global.* now
+         * {@hide} */
+        @Deprecated
+        public static final String NETSTATS_POLL_INTERVAL = Global.NETSTATS_POLL_INTERVAL;
+        /** @deprecated The NETSTATS_* symbols live in Settings.Global.* now
+         * {@hide} */
+        @Deprecated
+        public static final String NETSTATS_TIME_CACHE_MAX_AGE = Global.NETSTATS_TIME_CACHE_MAX_AGE;
+        /** @deprecated The NETSTATS_* symbols live in Settings.Global.* now
+         * {@hide} */
+        @Deprecated
+        public static final String NETSTATS_GLOBAL_ALERT_BYTES = Global.NETSTATS_GLOBAL_ALERT_BYTES;
+        /** @deprecated The NETSTATS_* symbols live in Settings.Global.* now
+         * {@hide} */
+        @Deprecated
+        public static final String NETSTATS_SAMPLE_ENABLED = Global.NETSTATS_SAMPLE_ENABLED;
+        /** @deprecated The NETSTATS_* symbols live in Settings.Global.* now
+         * {@hide} */
+        @Deprecated
+        public static final String NETSTATS_REPORT_XT_OVER_DEV = Global.NETSTATS_REPORT_XT_OVER_DEV;
 
-        /** {@hide} */
-        public static final String NETSTATS_DEV_BUCKET_DURATION = "netstats_dev_bucket_duration";
-        /** {@hide} */
-        public static final String NETSTATS_DEV_PERSIST_BYTES = "netstats_dev_persist_bytes";
-        /** {@hide} */
-        public static final String NETSTATS_DEV_ROTATE_AGE = "netstats_dev_rotate_age";
-        /** {@hide} */
-        public static final String NETSTATS_DEV_DELETE_AGE = "netstats_dev_delete_age";
+        /** @deprecated The NETSTATS_* symbols live in Settings.Global.* now
+         * {@hide} */
+        @Deprecated
+        public static final String NETSTATS_DEV_BUCKET_DURATION = Global.NETSTATS_DEV_BUCKET_DURATION;
+        /** @deprecated The NETSTATS_* symbols live in Settings.Global.* now
+         * {@hide} */
+        @Deprecated
+        public static final String NETSTATS_DEV_PERSIST_BYTES = Global.NETSTATS_DEV_PERSIST_BYTES;
+        /** @deprecated The NETSTATS_* symbols live in Settings.Global.* now
+         * {@hide} */
+        @Deprecated
+        public static final String NETSTATS_DEV_ROTATE_AGE = Global.NETSTATS_DEV_ROTATE_AGE;
+        /** @deprecated The NETSTATS_* symbols live in Settings.Global.* now
+         * {@hide} */
+        @Deprecated
+        public static final String NETSTATS_DEV_DELETE_AGE = Global.NETSTATS_DEV_DELETE_AGE;
 
-        /** {@hide} */
-        public static final String NETSTATS_UID_BUCKET_DURATION = "netstats_uid_bucket_duration";
-        /** {@hide} */
-        public static final String NETSTATS_UID_PERSIST_BYTES = "netstats_uid_persist_bytes";
-        /** {@hide} */
-        public static final String NETSTATS_UID_ROTATE_AGE = "netstats_uid_rotate_age";
-        /** {@hide} */
-        public static final String NETSTATS_UID_DELETE_AGE = "netstats_uid_delete_age";
+        /** @deprecated The NETSTATS_* symbols live in Settings.Global.* now
+         * {@hide} */
+        @Deprecated
+        public static final String NETSTATS_UID_BUCKET_DURATION = Global.NETSTATS_UID_BUCKET_DURATION;
+        /** @deprecated The NETSTATS_* symbols live in Settings.Global.* now
+         * {@hide} */
+        @Deprecated
+        public static final String NETSTATS_UID_PERSIST_BYTES = Global.NETSTATS_UID_PERSIST_BYTES;
+        /** @deprecated The NETSTATS_* symbols live in Settings.Global.* now
+         * {@hide} */
+        @Deprecated
+        public static final String NETSTATS_UID_ROTATE_AGE = Global.NETSTATS_UID_ROTATE_AGE;
+        /** @deprecated The NETSTATS_* symbols live in Settings.Global.* now
+         * {@hide} */
+        @Deprecated
+        public static final String NETSTATS_UID_DELETE_AGE = Global.NETSTATS_UID_DELETE_AGE;
 
-        /** {@hide} */
-        public static final String NETSTATS_UID_TAG_BUCKET_DURATION = "netstats_uid_tag_bucket_duration";
-        /** {@hide} */
-        public static final String NETSTATS_UID_TAG_PERSIST_BYTES = "netstats_uid_tag_persist_bytes";
-        /** {@hide} */
-        public static final String NETSTATS_UID_TAG_ROTATE_AGE = "netstats_uid_tag_rotate_age";
-        /** {@hide} */
-        public static final String NETSTATS_UID_TAG_DELETE_AGE = "netstats_uid_tag_delete_age";
+        /** @deprecated The NETSTATS_* symbols live in Settings.Global.* now
+         * {@hide} */
+        @Deprecated
+        public static final String NETSTATS_UID_TAG_BUCKET_DURATION = Global.NETSTATS_UID_TAG_BUCKET_DURATION;
+        /** @deprecated The NETSTATS_* symbols live in Settings.Global.* now
+         * {@hide} */
+        @Deprecated
+        public static final String NETSTATS_UID_TAG_PERSIST_BYTES = Global.NETSTATS_UID_TAG_PERSIST_BYTES;
+        /** @deprecated The NETSTATS_* symbols live in Settings.Global.* now
+         * {@hide} */
+        @Deprecated
+        public static final String NETSTATS_UID_TAG_ROTATE_AGE = Global.NETSTATS_UID_TAG_ROTATE_AGE;
+        /** @deprecated The NETSTATS_* symbols live in Settings.Global.* now
+         * {@hide} */
+        @Deprecated
+        public static final String NETSTATS_UID_TAG_DELETE_AGE = Global.NETSTATS_UID_TAG_DELETE_AGE;
 
-        /** Preferred NTP server. {@hide} */
-        public static final String NTP_SERVER = "ntp_server";
-        /** Timeout in milliseconds to wait for NTP server. {@hide} */
-        public static final String NTP_TIMEOUT = "ntp_timeout";
+        /** Preferred NTP server. {@hide}
+         * @deprecated moved to Settings.Global */
+        public static final String NTP_SERVER = Global.NTP_SERVER;
 
-        /** Autofill server address (Used in WebView/browser). {@hide} */
-        public static final String WEB_AUTOFILL_QUERY_URL =
-            "web_autofill_query_url";
+        /** Timeout in milliseconds to wait for NTP server. {@hide}
+         * @deprecated moved to Settings.Global */
+        public static final String NTP_TIMEOUT = Global.NTP_TIMEOUT;
 
-        /** Whether package verification is enabled. {@hide} */
-        public static final String PACKAGE_VERIFIER_ENABLE = "verifier_enable";
+        /** Autofill server address (Used in WebView/browser).
+         * @deprecated moved to Settings.Global
+         * {@hide} */
+        public static final String WEB_AUTOFILL_QUERY_URL = Global.WEB_AUTOFILL_QUERY_URL;
 
-        /** Timeout for package verification. {@hide} */
+        /**
+         * Whether the package manager should send package verification broadcasts for verifiers to
+         * review apps prior to installation.
+         * @deprecated moved to Settings.Global
+         * 1 = request apps to be verified prior to installation, if a verifier exists.
+         * 0 = do not verify apps before installation
+         * {@hide}
+         */
+        @Deprecated
+        public static final String PACKAGE_VERIFIER_ENABLE = "package_verifier_enable";
+
+        /** Timeout for package verification.
+         * @deprecated moved to Settings.Global
+         * {@hide} */
+        @Deprecated
         public static final String PACKAGE_VERIFIER_TIMEOUT = "verifier_timeout";
 
-        /** Default response code for package verification. {@hide} */
+        /** Default response code for package verification.
+         * @deprecated moved to Settings.Global
+         * {@hide} */
+        @Deprecated
         public static final String PACKAGE_VERIFIER_DEFAULT_RESPONSE = "verifier_default_response";
 
         /** {@hide} */
@@ -4385,6 +4856,9 @@
             PARENTAL_CONTROL_ENABLED,
             PARENTAL_CONTROL_REDIRECT_URL,
             USB_MASS_STORAGE_ENABLED,
+            ACCESSIBILITY_DISPLAY_MAGNIFICATION_ENABLED,
+            ACCESSIBILITY_DISPLAY_MAGNIFICATION_SCALE,
+            ACCESSIBILITY_DISPLAY_MAGNIFICATION_AUTO_UPDATE,
             ACCESSIBILITY_SCRIPT_INJECTION,
             BACKUP_AUTO_RESTORE,
             ENABLED_ACCESSIBILITY_SERVICES,
@@ -4444,6 +4918,972 @@
     }
 
     /**
+     * Global system settings, containing preferences that always apply identically
+     * to all defined users.  Applications can read these but are not allowed to write;
+     * like the "Secure" settings, these are for preferences that the user must
+     * explicitly modify through the system UI or specialized APIs for those values.
+     */
+    public static final class Global extends NameValueTable {
+        public static final String SYS_PROP_SETTING_VERSION = "sys.settings_global_version";
+
+        /**
+         * The content:// style URL for global secure settings items.  Not public.
+         */
+        public static final Uri CONTENT_URI = Uri.parse("content://" + AUTHORITY + "/global");
+
+        /**
+         * Whether Airplane Mode is on.
+         */
+        public static final String AIRPLANE_MODE_ON = "airplane_mode_on";
+
+        /**
+         * Constant for use in AIRPLANE_MODE_RADIOS to specify Bluetooth radio.
+         */
+        public static final String RADIO_BLUETOOTH = "bluetooth";
+
+        /**
+         * Constant for use in AIRPLANE_MODE_RADIOS to specify Wi-Fi radio.
+         */
+        public static final String RADIO_WIFI = "wifi";
+
+        /**
+         * {@hide}
+         */
+        public static final String RADIO_WIMAX = "wimax";
+        /**
+         * Constant for use in AIRPLANE_MODE_RADIOS to specify Cellular radio.
+         */
+        public static final String RADIO_CELL = "cell";
+
+        /**
+         * Constant for use in AIRPLANE_MODE_RADIOS to specify NFC radio.
+         */
+        public static final String RADIO_NFC = "nfc";
+
+        /**
+         * A comma separated list of radios that need to be disabled when airplane mode
+         * is on. This overrides WIFI_ON and BLUETOOTH_ON, if Wi-Fi and bluetooth are
+         * included in the comma separated list.
+         */
+        public static final String AIRPLANE_MODE_RADIOS = "airplane_mode_radios";
+
+        /**
+         * A comma separated list of radios that should to be disabled when airplane mode
+         * is on, but can be manually reenabled by the user.  For example, if RADIO_WIFI is
+         * added to both AIRPLANE_MODE_RADIOS and AIRPLANE_MODE_TOGGLEABLE_RADIOS, then Wifi
+         * will be turned off when entering airplane mode, but the user will be able to reenable
+         * Wifi in the Settings app.
+         *
+         * {@hide}
+         */
+        public static final String AIRPLANE_MODE_TOGGLEABLE_RADIOS = "airplane_mode_toggleable_radios";
+
+        /**
+         * The policy for deciding when Wi-Fi should go to sleep (which will in
+         * turn switch to using the mobile data as an Internet connection).
+         * <p>
+         * Set to one of {@link #WIFI_SLEEP_POLICY_DEFAULT},
+         * {@link #WIFI_SLEEP_POLICY_NEVER_WHILE_PLUGGED}, or
+         * {@link #WIFI_SLEEP_POLICY_NEVER}.
+         */
+        public static final String WIFI_SLEEP_POLICY = "wifi_sleep_policy";
+
+        /**
+         * Value for {@link #WIFI_SLEEP_POLICY} to use the default Wi-Fi sleep
+         * policy, which is to sleep shortly after the turning off
+         * according to the {@link #STAY_ON_WHILE_PLUGGED_IN} setting.
+         */
+        public static final int WIFI_SLEEP_POLICY_DEFAULT = 0;
+
+        /**
+         * Value for {@link #WIFI_SLEEP_POLICY} to use the default policy when
+         * the device is on battery, and never go to sleep when the device is
+         * plugged in.
+         */
+        public static final int WIFI_SLEEP_POLICY_NEVER_WHILE_PLUGGED = 1;
+
+        /**
+         * Value for {@link #WIFI_SLEEP_POLICY} to never go to sleep.
+         */
+        public static final int WIFI_SLEEP_POLICY_NEVER = 2;
+
+        /**
+         * Value to specify if the user prefers the date, time and time zone
+         * to be automatically fetched from the network (NITZ). 1=yes, 0=no
+         */
+        public static final String AUTO_TIME = "auto_time";
+
+        /**
+         * Value to specify if the user prefers the time zone
+         * to be automatically fetched from the network (NITZ). 1=yes, 0=no
+         */
+        public static final String AUTO_TIME_ZONE = "auto_time_zone";
+
+        /**
+         * URI for the car dock "in" event sound.
+         * @hide
+         */
+        public static final String CAR_DOCK_SOUND = "car_dock_sound";
+
+        /**
+         * URI for the car dock "out" event sound.
+         * @hide
+         */
+        public static final String CAR_UNDOCK_SOUND = "car_undock_sound";
+
+        /**
+         * URI for the desk dock "in" event sound.
+         * @hide
+         */
+        public static final String DESK_DOCK_SOUND = "desk_dock_sound";
+
+        /**
+         * URI for the desk dock "out" event sound.
+         * @hide
+         */
+        public static final String DESK_UNDOCK_SOUND = "desk_undock_sound";
+
+        /**
+         * Whether to play a sound for dock events.
+         * @hide
+         */
+        public static final String DOCK_SOUNDS_ENABLED = "dock_sounds_enabled";
+
+        /**
+         * URI for the "device locked" (keyguard shown) sound.
+         * @hide
+         */
+        public static final String LOCK_SOUND = "lock_sound";
+
+        /**
+         * URI for the "device unlocked" sound.
+         * @hide
+         */
+        public static final String UNLOCK_SOUND = "unlock_sound";
+
+        /**
+         * URI for the low battery sound file.
+         * @hide
+         */
+        public static final String LOW_BATTERY_SOUND = "low_battery_sound";
+
+        /**
+         * Whether to play a sound for low-battery alerts.
+         * @hide
+         */
+        public static final String POWER_SOUNDS_ENABLED = "power_sounds_enabled";
+
+        /**
+         * Whether we keep the device on while the device is plugged in.
+         * Supported values are:
+         * <ul>
+         * <li>{@code 0} to never stay on while plugged in</li>
+         * <li>{@link BatteryManager#BATTERY_PLUGGED_AC} to stay on for AC charger</li>
+         * <li>{@link BatteryManager#BATTERY_PLUGGED_USB} to stay on for USB charger</li>
+         * <li>{@link BatteryManager#BATTERY_PLUGGED_WIRELESS} to stay on for wireless charger</li>
+         * </ul>
+         * These values can be OR-ed together.
+         */
+        public static final String STAY_ON_WHILE_PLUGGED_IN = "stay_on_while_plugged_in";
+
+        /**
+         * Whether ADB is enabled.
+         */
+        public static final String ADB_ENABLED = "adb_enabled";
+
+        /**
+         * Whether assisted GPS should be enabled or not.
+         * @hide
+         */
+        public static final String ASSISTED_GPS_ENABLED = "assisted_gps_enabled";
+
+        /**
+         * Whether bluetooth is enabled/disabled
+         * 0=disabled. 1=enabled.
+         */
+        public static final String BLUETOOTH_ON = "bluetooth_on";
+
+        /**
+         * CDMA Cell Broadcast SMS
+         *                            0 = CDMA Cell Broadcast SMS disabled
+         *                            1 = CDMA Cell Broadcast SMS enabled
+         * @hide
+         */
+        public static final String CDMA_CELL_BROADCAST_SMS =
+                "cdma_cell_broadcast_sms";
+
+        /**
+         * The CDMA roaming mode 0 = Home Networks, CDMA default
+         *                       1 = Roaming on Affiliated networks
+         *                       2 = Roaming on any networks
+         * @hide
+         */
+        public static final String CDMA_ROAMING_MODE = "roaming_settings";
+
+        /**
+         * The CDMA subscription mode 0 = RUIM/SIM (default)
+         *                                1 = NV
+         * @hide
+         */
+        public static final String CDMA_SUBSCRIPTION_MODE = "subscription_mode";
+
+        /** Inactivity timeout to track mobile data activity.
+        *
+        * If set to a positive integer, it indicates the inactivity timeout value in seconds to
+        * infer the data activity of mobile network. After a period of no activity on mobile
+        * networks with length specified by the timeout, an {@code ACTION_DATA_ACTIVITY_CHANGE}
+        * intent is fired to indicate a transition of network status from "active" to "idle". Any
+        * subsequent activity on mobile networks triggers the firing of {@code
+        * ACTION_DATA_ACTIVITY_CHANGE} intent indicating transition from "idle" to "active".
+        *
+        * Network activity refers to transmitting or receiving data on the network interfaces.
+        *
+        * Tracking is disabled if set to zero or negative value.
+        *
+        * @hide
+        */
+       public static final String DATA_ACTIVITY_TIMEOUT_MOBILE = "data_activity_timeout_mobile";
+
+       /** Timeout to tracking Wifi data activity. Same as {@code DATA_ACTIVITY_TIMEOUT_MOBILE}
+        * but for Wifi network.
+        * @hide
+        */
+       public static final String DATA_ACTIVITY_TIMEOUT_WIFI = "data_activity_timeout_wifi";
+
+       /**
+        * Whether or not data roaming is enabled. (0 = false, 1 = true)
+        */
+       public static final String DATA_ROAMING = "data_roaming";
+
+       /**
+        * Whether user has enabled development settings.
+        */
+       public static final String DEVELOPMENT_SETTINGS_ENABLED = "development_settings_enabled";
+
+       /**
+        * Whether the device has been provisioned (0 = false, 1 = true)
+        */
+       public static final String DEVICE_PROVISIONED = "device_provisioned";
+
+       /**
+        * The saved value for WindowManagerService.setForcedDisplayDensity().
+        * One integer in dpi.  If unset, then use the real display density.
+        * @hide
+        */
+       public static final String DISPLAY_DENSITY_FORCED = "display_density_forced";
+
+       /**
+        * The saved value for WindowManagerService.setForcedDisplaySize().
+        * Two integers separated by a comma.  If unset, then use the real display size.
+        * @hide
+        */
+       public static final String DISPLAY_SIZE_FORCED = "display_size_forced";
+
+       /**
+        * The maximum size, in bytes, of a download that the download manager will transfer over
+        * a non-wifi connection.
+        * @hide
+        */
+       public static final String DOWNLOAD_MAX_BYTES_OVER_MOBILE =
+               "download_manager_max_bytes_over_mobile";
+
+       /**
+        * The recommended maximum size, in bytes, of a download that the download manager should
+        * transfer over a non-wifi connection. Over this size, the use will be warned, but will
+        * have the option to start the download over the mobile connection anyway.
+        * @hide
+        */
+       public static final String DOWNLOAD_RECOMMENDED_MAX_BYTES_OVER_MOBILE =
+               "download_manager_recommended_max_bytes_over_mobile";
+
+       /**
+        * Whether the package installer should allow installation of apps downloaded from
+        * sources other than Google Play.
+        *
+        * 1 = allow installing from other sources
+        * 0 = only allow installing from Google Play
+        */
+       public static final String INSTALL_NON_MARKET_APPS = "install_non_market_apps";
+
+       /**
+        * Whether mobile data connections are allowed by the user.  See
+        * ConnectivityManager for more info.
+        * @hide
+        */
+       public static final String MOBILE_DATA = "mobile_data";
+
+       /** {@hide} */
+       public static final String NETSTATS_ENABLED = "netstats_enabled";
+       /** {@hide} */
+       public static final String NETSTATS_POLL_INTERVAL = "netstats_poll_interval";
+       /** {@hide} */
+       public static final String NETSTATS_TIME_CACHE_MAX_AGE = "netstats_time_cache_max_age";
+       /** {@hide} */
+       public static final String NETSTATS_GLOBAL_ALERT_BYTES = "netstats_global_alert_bytes";
+       /** {@hide} */
+       public static final String NETSTATS_SAMPLE_ENABLED = "netstats_sample_enabled";
+       /** {@hide} */
+       public static final String NETSTATS_REPORT_XT_OVER_DEV = "netstats_report_xt_over_dev";
+
+       /** {@hide} */
+       public static final String NETSTATS_DEV_BUCKET_DURATION = "netstats_dev_bucket_duration";
+       /** {@hide} */
+       public static final String NETSTATS_DEV_PERSIST_BYTES = "netstats_dev_persist_bytes";
+       /** {@hide} */
+       public static final String NETSTATS_DEV_ROTATE_AGE = "netstats_dev_rotate_age";
+       /** {@hide} */
+       public static final String NETSTATS_DEV_DELETE_AGE = "netstats_dev_delete_age";
+
+       /** {@hide} */
+       public static final String NETSTATS_UID_BUCKET_DURATION = "netstats_uid_bucket_duration";
+       /** {@hide} */
+       public static final String NETSTATS_UID_PERSIST_BYTES = "netstats_uid_persist_bytes";
+       /** {@hide} */
+       public static final String NETSTATS_UID_ROTATE_AGE = "netstats_uid_rotate_age";
+       /** {@hide} */
+       public static final String NETSTATS_UID_DELETE_AGE = "netstats_uid_delete_age";
+
+       /** {@hide} */
+       public static final String NETSTATS_UID_TAG_BUCKET_DURATION = "netstats_uid_tag_bucket_duration";
+       /** {@hide} */
+       public static final String NETSTATS_UID_TAG_PERSIST_BYTES = "netstats_uid_tag_persist_bytes";
+       /** {@hide} */
+       public static final String NETSTATS_UID_TAG_ROTATE_AGE = "netstats_uid_tag_rotate_age";
+       /** {@hide} */
+       public static final String NETSTATS_UID_TAG_DELETE_AGE = "netstats_uid_tag_delete_age";
+
+       /**
+        * User preference for which network(s) should be used. Only the
+        * connectivity service should touch this.
+        */
+       public static final String NETWORK_PREFERENCE = "network_preference";
+
+       /**
+        * If the NITZ_UPDATE_DIFF time is exceeded then an automatic adjustment
+        * to SystemClock will be allowed even if NITZ_UPDATE_SPACING has not been
+        * exceeded.
+        * @hide
+        */
+       public static final String NITZ_UPDATE_DIFF = "nitz_update_diff";
+
+       /**
+        * The length of time in milli-seconds that automatic small adjustments to
+        * SystemClock are ignored if NITZ_UPDATE_DIFF is not exceeded.
+        * @hide
+        */
+       public static final String NITZ_UPDATE_SPACING = "nitz_update_spacing";
+
+       /** Preferred NTP server. {@hide} */
+       public static final String NTP_SERVER = "ntp_server";
+       /** Timeout in milliseconds to wait for NTP server. {@hide} */
+       public static final String NTP_TIMEOUT = "ntp_timeout";
+
+       /**
+        * Whether the package manager should send package verification broadcasts for verifiers to
+        * review apps prior to installation.
+        * 1 = request apps to be verified prior to installation, if a verifier exists.
+        * 0 = do not verify apps before installation
+        * {@hide}
+        */
+       public static final String PACKAGE_VERIFIER_ENABLE = "package_verifier_enable";
+
+       /** Timeout for package verification.
+        * {@hide} */
+       public static final String PACKAGE_VERIFIER_TIMEOUT = "verifier_timeout";
+
+       /** Default response code for package verification.
+        * {@hide} */
+       public static final String PACKAGE_VERIFIER_DEFAULT_RESPONSE = "verifier_default_response";
+
+       /**
+        * The interval in milliseconds at which to check packet counts on the
+        * mobile data interface when screen is on, to detect possible data
+        * connection problems.
+        * @hide
+        */
+       public static final String PDP_WATCHDOG_POLL_INTERVAL_MS =
+               "pdp_watchdog_poll_interval_ms";
+
+       /**
+        * The interval in milliseconds at which to check packet counts on the
+        * mobile data interface when screen is off, to detect possible data
+        * connection problems.
+        * @hide
+        */
+       public static final String PDP_WATCHDOG_LONG_POLL_INTERVAL_MS =
+               "pdp_watchdog_long_poll_interval_ms";
+
+       /**
+        * The interval in milliseconds at which to check packet counts on the
+        * mobile data interface after {@link #PDP_WATCHDOG_TRIGGER_PACKET_COUNT}
+        * outgoing packets has been reached without incoming packets.
+        * @hide
+        */
+       public static final String PDP_WATCHDOG_ERROR_POLL_INTERVAL_MS =
+               "pdp_watchdog_error_poll_interval_ms";
+
+       /**
+        * The number of outgoing packets sent without seeing an incoming packet
+        * that triggers a countdown (of {@link #PDP_WATCHDOG_ERROR_POLL_COUNT}
+        * device is logged to the event log
+        * @hide
+        */
+       public static final String PDP_WATCHDOG_TRIGGER_PACKET_COUNT =
+               "pdp_watchdog_trigger_packet_count";
+
+       /**
+        * The number of polls to perform (at {@link #PDP_WATCHDOG_ERROR_POLL_INTERVAL_MS})
+        * after hitting {@link #PDP_WATCHDOG_TRIGGER_PACKET_COUNT} before
+        * attempting data connection recovery.
+        * @hide
+        */
+       public static final String PDP_WATCHDOG_ERROR_POLL_COUNT =
+               "pdp_watchdog_error_poll_count";
+
+       /**
+        * The number of failed PDP reset attempts before moving to something more
+        * drastic: re-registering to the network.
+        * @hide
+        */
+       public static final String PDP_WATCHDOG_MAX_PDP_RESET_FAIL_COUNT =
+               "pdp_watchdog_max_pdp_reset_fail_count";
+
+       /**
+        * A positive value indicates how often the SamplingProfiler
+        * should take snapshots. Zero value means SamplingProfiler
+        * is disabled.
+        *
+        * @hide
+        */
+       public static final String SAMPLING_PROFILER_MS = "sampling_profiler_ms";
+
+       /**
+        * URL to open browser on to allow user to manage a prepay account
+        * @hide
+        */
+       public static final String SETUP_PREPAID_DATA_SERVICE_URL =
+               "setup_prepaid_data_service_url";
+
+       /**
+        * URL to attempt a GET on to see if this is a prepay device
+        * @hide
+        */
+       public static final String SETUP_PREPAID_DETECTION_TARGET_URL =
+               "setup_prepaid_detection_target_url";
+
+       /**
+        * Host to check for a redirect to after an attempt to GET
+        * SETUP_PREPAID_DETECTION_TARGET_URL. (If we redirected there,
+        * this is a prepaid device with zero balance.)
+        * @hide
+        */
+       public static final String SETUP_PREPAID_DETECTION_REDIR_HOST =
+               "setup_prepaid_detection_redir_host";
+
+       /**
+        * Used to disable Tethering on a device - defaults to true
+        * @hide
+        */
+       public static final String TETHER_SUPPORTED = "tether_supported";
+
+       /**
+        * Used to require DUN APN on the device or not - defaults to a build config value
+        * which defaults to false
+        * @hide
+        */
+       public static final String TETHER_DUN_REQUIRED = "tether_dun_required";
+
+       /**
+        * Used to hold a gservices-provisioned apn value for DUN.  If set, or the
+        * corresponding build config values are set it will override the APN DB
+        * values.
+        * Consists of a comma seperated list of strings:
+        * "name,apn,proxy,port,username,password,server,mmsc,mmsproxy,mmsport,mcc,mnc,auth,type"
+        * note that empty fields can be ommitted: "name,apn,,,,,,,,,310,260,,DUN"
+        * @hide
+        */
+       public static final String TETHER_DUN_APN = "tether_dun_apn";
+
+       /**
+        * The bandwidth throttle polling freqency in seconds
+        * @hide
+        */
+       public static final String THROTTLE_POLLING_SEC = "throttle_polling_sec";
+
+       /**
+        * The bandwidth throttle threshold (long)
+        * @hide
+        */
+       public static final String THROTTLE_THRESHOLD_BYTES = "throttle_threshold_bytes";
+
+       /**
+        * The bandwidth throttle value (kbps)
+        * @hide
+        */
+       public static final String THROTTLE_VALUE_KBITSPS = "throttle_value_kbitsps";
+
+       /**
+        * The bandwidth throttle reset calendar day (1-28)
+        * @hide
+        */
+       public static final String THROTTLE_RESET_DAY = "throttle_reset_day";
+
+       /**
+        * The throttling notifications we should send
+        * @hide
+        */
+       public static final String THROTTLE_NOTIFICATION_TYPE = "throttle_notification_type";
+
+       /**
+        * Help URI for data throttling policy
+        * @hide
+        */
+       public static final String THROTTLE_HELP_URI = "throttle_help_uri";
+
+       /**
+        * The length of time in Sec that we allow our notion of NTP time
+        * to be cached before we refresh it
+        * @hide
+        */
+       public static final String THROTTLE_MAX_NTP_CACHE_AGE_SEC =
+               "throttle_max_ntp_cache_age_sec";
+
+       /**
+        * USB Mass Storage Enabled
+        */
+       public static final String USB_MASS_STORAGE_ENABLED = "usb_mass_storage_enabled";
+
+       /**
+        * If this setting is set (to anything), then all references
+        * to Gmail on the device must change to Google Mail.
+        */
+       public static final String USE_GOOGLE_MAIL = "use_google_mail";
+
+       /** Autofill server address (Used in WebView/browser).
+        * {@hide} */
+       public static final String WEB_AUTOFILL_QUERY_URL =
+           "web_autofill_query_url";
+
+       /**
+        * Whether to notify the user of open networks.
+        * <p>
+        * If not connected and the scan results have an open network, we will
+        * put this notification up. If we attempt to connect to a network or
+        * the open network(s) disappear, we remove the notification. When we
+        * show the notification, we will not show it again for
+        * {@link android.provider.Settings.Secure#WIFI_NETWORKS_AVAILABLE_REPEAT_DELAY} time.
+        */
+       public static final String WIFI_NETWORKS_AVAILABLE_NOTIFICATION_ON =
+               "wifi_networks_available_notification_on";
+       /**
+        * {@hide}
+        */
+       public static final String WIMAX_NETWORKS_AVAILABLE_NOTIFICATION_ON =
+               "wimax_networks_available_notification_on";
+
+       /**
+        * Delay (in seconds) before repeating the Wi-Fi networks available notification.
+        * Connecting to a network will reset the timer.
+        */
+       public static final String WIFI_NETWORKS_AVAILABLE_REPEAT_DELAY =
+               "wifi_networks_available_repeat_delay";
+
+       /**
+        * 802.11 country code in ISO 3166 format
+        * @hide
+        */
+       public static final String WIFI_COUNTRY_CODE = "wifi_country_code";
+
+       /**
+        * The interval in milliseconds to issue wake up scans when wifi needs
+        * to connect. This is necessary to connect to an access point when
+        * device is on the move and the screen is off.
+        * @hide
+        */
+       public static final String WIFI_FRAMEWORK_SCAN_INTERVAL_MS =
+               "wifi_framework_scan_interval_ms";
+
+       /**
+        * The interval in milliseconds after which Wi-Fi is considered idle.
+        * When idle, it is possible for the device to be switched from Wi-Fi to
+        * the mobile data network.
+        * @hide
+        */
+       public static final String WIFI_IDLE_MS = "wifi_idle_ms";
+
+       /**
+        * When the number of open networks exceeds this number, the
+        * least-recently-used excess networks will be removed.
+        */
+       public static final String WIFI_NUM_OPEN_NETWORKS_KEPT = "wifi_num_open_networks_kept";
+
+       /**
+        * Whether the Wi-Fi should be on.  Only the Wi-Fi service should touch this.
+        */
+       public static final String WIFI_ON = "wifi_on";
+
+       /**
+        * Used to save the Wifi_ON state prior to tethering.
+        * This state will be checked to restore Wifi after
+        * the user turns off tethering.
+        *
+        * @hide
+        */
+       public static final String WIFI_SAVED_STATE = "wifi_saved_state";
+
+       /**
+        * The interval in milliseconds to scan as used by the wifi supplicant
+        * @hide
+        */
+       public static final String WIFI_SUPPLICANT_SCAN_INTERVAL_MS =
+               "wifi_supplicant_scan_interval_ms";
+
+       /**
+        * Whether the Wi-Fi watchdog is enabled.
+        */
+       public static final String WIFI_WATCHDOG_ON = "wifi_watchdog_on";
+
+       /**
+        * ms delay interval between rssi polling when the signal is known to be weak
+        * @hide
+        */
+       public static final String WIFI_WATCHDOG_RSSI_FETCH_INTERVAL_MS =
+               "wifi_watchdog_rssi_fetch_interval_ms";
+
+       /**
+        * Number of ARP pings per check.
+        * @hide
+        */
+       public static final String WIFI_WATCHDOG_NUM_ARP_PINGS = "wifi_watchdog_num_arp_pings";
+
+       /**
+        * Setting to turn off poor network avoidance on Wi-Fi. Feature is enabled by default and
+        * the setting needs to be set to 0 to disable it.
+        * @hide
+        */
+       public static final String WIFI_WATCHDOG_POOR_NETWORK_TEST_ENABLED =
+               "wifi_watchdog_poor_network_test_enabled";
+
+       /**
+        * Setting to turn on suspend optimizations at screen off on Wi-Fi. Enabled by default and
+        * needs to be set to 0 to disable it.
+        * @hide
+        */
+       public static final String WIFI_SUSPEND_OPTIMIZATIONS_ENABLED =
+               "wifi_suspend_optimizations_enabled";
+
+       /**
+        * The maximum number of times we will retry a connection to an access
+        * point for which we have failed in acquiring an IP address from DHCP.
+        * A value of N means that we will make N+1 connection attempts in all.
+        */
+       public static final String WIFI_MAX_DHCP_RETRY_COUNT = "wifi_max_dhcp_retry_count";
+
+       /**
+        * Maximum amount of time in milliseconds to hold a wakelock while waiting for mobile
+        * data connectivity to be established after a disconnect from Wi-Fi.
+        */
+       public static final String WIFI_MOBILE_DATA_TRANSITION_WAKELOCK_TIMEOUT_MS =
+           "wifi_mobile_data_transition_wakelock_timeout_ms";
+
+       /**
+        * The operational wifi frequency band
+        * Set to one of {@link WifiManager#WIFI_FREQUENCY_BAND_AUTO},
+        * {@link WifiManager#WIFI_FREQUENCY_BAND_5GHZ} or
+        * {@link WifiManager#WIFI_FREQUENCY_BAND_2GHZ}
+        *
+        * @hide
+        */
+       public static final String WIFI_FREQUENCY_BAND = "wifi_frequency_band";
+
+       /**
+        * The Wi-Fi peer-to-peer device name
+        * @hide
+        */
+       public static final String WIFI_P2P_DEVICE_NAME = "wifi_p2p_device_name";
+
+       /**
+        * Nonzero causes Log.wtf() to crash.
+        * @hide
+        */
+       public static final String WTF_IS_FATAL = "wtf_is_fatal";
+
+
+
+
+        // Populated lazily, guarded by class object:
+        private static NameValueCache sNameValueCache = null;
+
+        private static void lazyInitCache() {
+            if (sNameValueCache == null) {
+                sNameValueCache = new NameValueCache(
+                        SYS_PROP_SETTING_VERSION,
+                        CONTENT_URI,
+                        CALL_METHOD_GET_GLOBAL,
+                        CALL_METHOD_PUT_GLOBAL);
+            }
+        }
+
+        /**
+         * Look up a name in the database.
+         * @param resolver to access the database with
+         * @param name to look up in the table
+         * @return the corresponding value, or null if not present
+         */
+        public synchronized static String getString(ContentResolver resolver, String name) {
+            return getStringForUser(resolver, name, UserHandle.myUserId());
+        }
+
+        /** @hide */
+        public synchronized static String getStringForUser(ContentResolver resolver, String name,
+                int userHandle) {
+            lazyInitCache();
+            return sNameValueCache.getStringForUser(resolver, name, userHandle);
+        }
+
+        /**
+         * Store a name/value pair into the database.
+         * @param resolver to access the database with
+         * @param name to store
+         * @param value to associate with the name
+         * @return true if the value was set, false on database errors
+         */
+        public static boolean putString(ContentResolver resolver,
+                String name, String value) {
+            return putStringForUser(resolver, name, value, UserHandle.myUserId());
+        }
+
+        /** @hide */
+        public static boolean putStringForUser(ContentResolver resolver,
+                String name, String value, int userHandle) {
+            lazyInitCache();
+            if (LOCAL_LOGV) {
+                Log.v(TAG, "Global.putString(name=" + name + ", value=" + value
+                        + " for " + userHandle);
+            }
+            return sNameValueCache.putStringForUser(resolver, name, value, userHandle);
+        }
+
+        /**
+         * Construct the content URI for a particular name/value pair,
+         * useful for monitoring changes with a ContentObserver.
+         * @param name to look up in the table
+         * @return the corresponding content URI, or null if not present
+         */
+        public static Uri getUriFor(String name) {
+            return getUriFor(CONTENT_URI, name);
+        }
+
+        /**
+         * Convenience function for retrieving a single secure settings value
+         * as an integer.  Note that internally setting values are always
+         * stored as strings; this function converts the string to an integer
+         * for you.  The default value will be returned if the setting is
+         * not defined or not an integer.
+         *
+         * @param cr The ContentResolver to access.
+         * @param name The name of the setting to retrieve.
+         * @param def Value to return if the setting is not defined.
+         *
+         * @return The setting's current value, or 'def' if it is not defined
+         * or not a valid integer.
+         */
+        public static int getInt(ContentResolver cr, String name, int def) {
+            String v = getString(cr, name);
+            try {
+                return v != null ? Integer.parseInt(v) : def;
+            } catch (NumberFormatException e) {
+                return def;
+            }
+        }
+
+        /**
+         * Convenience function for retrieving a single secure settings value
+         * as an integer.  Note that internally setting values are always
+         * stored as strings; this function converts the string to an integer
+         * for you.
+         * <p>
+         * This version does not take a default value.  If the setting has not
+         * been set, or the string value is not a number,
+         * it throws {@link SettingNotFoundException}.
+         *
+         * @param cr The ContentResolver to access.
+         * @param name The name of the setting to retrieve.
+         *
+         * @throws SettingNotFoundException Thrown if a setting by the given
+         * name can't be found or the setting value is not an integer.
+         *
+         * @return The setting's current value.
+         */
+        public static int getInt(ContentResolver cr, String name)
+                throws SettingNotFoundException {
+            String v = getString(cr, name);
+            try {
+                return Integer.parseInt(v);
+            } catch (NumberFormatException e) {
+                throw new SettingNotFoundException(name);
+            }
+        }
+
+        /**
+         * Convenience function for updating a single settings value as an
+         * integer. This will either create a new entry in the table if the
+         * given name does not exist, or modify the value of the existing row
+         * with that name.  Note that internally setting values are always
+         * stored as strings, so this function converts the given value to a
+         * string before storing it.
+         *
+         * @param cr The ContentResolver to access.
+         * @param name The name of the setting to modify.
+         * @param value The new value for the setting.
+         * @return true if the value was set, false on database errors
+         */
+        public static boolean putInt(ContentResolver cr, String name, int value) {
+            return putString(cr, name, Integer.toString(value));
+        }
+
+        /**
+         * Convenience function for retrieving a single secure settings value
+         * as a {@code long}.  Note that internally setting values are always
+         * stored as strings; this function converts the string to a {@code long}
+         * for you.  The default value will be returned if the setting is
+         * not defined or not a {@code long}.
+         *
+         * @param cr The ContentResolver to access.
+         * @param name The name of the setting to retrieve.
+         * @param def Value to return if the setting is not defined.
+         *
+         * @return The setting's current value, or 'def' if it is not defined
+         * or not a valid {@code long}.
+         */
+        public static long getLong(ContentResolver cr, String name, long def) {
+            String valString = getString(cr, name);
+            long value;
+            try {
+                value = valString != null ? Long.parseLong(valString) : def;
+            } catch (NumberFormatException e) {
+                value = def;
+            }
+            return value;
+        }
+
+        /**
+         * Convenience function for retrieving a single secure settings value
+         * as a {@code long}.  Note that internally setting values are always
+         * stored as strings; this function converts the string to a {@code long}
+         * for you.
+         * <p>
+         * This version does not take a default value.  If the setting has not
+         * been set, or the string value is not a number,
+         * it throws {@link SettingNotFoundException}.
+         *
+         * @param cr The ContentResolver to access.
+         * @param name The name of the setting to retrieve.
+         *
+         * @return The setting's current value.
+         * @throws SettingNotFoundException Thrown if a setting by the given
+         * name can't be found or the setting value is not an integer.
+         */
+        public static long getLong(ContentResolver cr, String name)
+                throws SettingNotFoundException {
+            String valString = getString(cr, name);
+            try {
+                return Long.parseLong(valString);
+            } catch (NumberFormatException e) {
+                throw new SettingNotFoundException(name);
+            }
+        }
+
+        /**
+         * Convenience function for updating a secure settings value as a long
+         * integer. This will either create a new entry in the table if the
+         * given name does not exist, or modify the value of the existing row
+         * with that name.  Note that internally setting values are always
+         * stored as strings, so this function converts the given value to a
+         * string before storing it.
+         *
+         * @param cr The ContentResolver to access.
+         * @param name The name of the setting to modify.
+         * @param value The new value for the setting.
+         * @return true if the value was set, false on database errors
+         */
+        public static boolean putLong(ContentResolver cr, String name, long value) {
+            return putString(cr, name, Long.toString(value));
+        }
+
+        /**
+         * Convenience function for retrieving a single secure settings value
+         * as a floating point number.  Note that internally setting values are
+         * always stored as strings; this function converts the string to an
+         * float for you. The default value will be returned if the setting
+         * is not defined or not a valid float.
+         *
+         * @param cr The ContentResolver to access.
+         * @param name The name of the setting to retrieve.
+         * @param def Value to return if the setting is not defined.
+         *
+         * @return The setting's current value, or 'def' if it is not defined
+         * or not a valid float.
+         */
+        public static float getFloat(ContentResolver cr, String name, float def) {
+            String v = getString(cr, name);
+            try {
+                return v != null ? Float.parseFloat(v) : def;
+            } catch (NumberFormatException e) {
+                return def;
+            }
+        }
+
+        /**
+         * Convenience function for retrieving a single secure settings value
+         * as a float.  Note that internally setting values are always
+         * stored as strings; this function converts the string to a float
+         * for you.
+         * <p>
+         * This version does not take a default value.  If the setting has not
+         * been set, or the string value is not a number,
+         * it throws {@link SettingNotFoundException}.
+         *
+         * @param cr The ContentResolver to access.
+         * @param name The name of the setting to retrieve.
+         *
+         * @throws SettingNotFoundException Thrown if a setting by the given
+         * name can't be found or the setting value is not a float.
+         *
+         * @return The setting's current value.
+         */
+        public static float getFloat(ContentResolver cr, String name)
+                throws SettingNotFoundException {
+            String v = getString(cr, name);
+            if (v == null) {
+                throw new SettingNotFoundException(name);
+            }
+            try {
+                return Float.parseFloat(v);
+            } catch (NumberFormatException e) {
+                throw new SettingNotFoundException(name);
+            }
+        }
+
+        /**
+         * Convenience function for updating a single settings value as a
+         * floating point number. This will either create a new entry in the
+         * table if the given name does not exist, or modify the value of the
+         * existing row with that name.  Note that internally setting values
+         * are always stored as strings, so this function converts the given
+         * value to a string before storing it.
+         *
+         * @param cr The ContentResolver to access.
+         * @param name The name of the setting to modify.
+         * @param value The new value for the setting.
+         * @return true if the value was set, false on database errors
+         */
+        public static boolean putFloat(ContentResolver cr, String name, float value) {
+            return putString(cr, name, Float.toString(value));
+        }
+    }
+
+    /**
      * User-defined bookmarks and shortcuts.  The target of each bookmark is an
      * Intent URL, allowing it to be either a web page or a particular
      * application activity.
diff --git a/core/java/android/text/format/Time.java b/core/java/android/text/format/Time.java
index e9b0d32..b0b18da 100644
--- a/core/java/android/text/format/Time.java
+++ b/core/java/android/text/format/Time.java
@@ -437,6 +437,9 @@
      * @throws android.util.TimeFormatException if s cannot be parsed.
      */
     public boolean parse(String s) {
+        if (s == null) {
+            throw new NullPointerException("time string is null");
+        }
         if (nativeParse(s)) {
             timezone = TIMEZONE_UTC;
             return true;
diff --git a/core/java/android/util/Pair.java b/core/java/android/util/Pair.java
index bf25306..6027d08 100644
--- a/core/java/android/util/Pair.java
+++ b/core/java/android/util/Pair.java
@@ -16,6 +16,8 @@
 
 package android.util;
 
+import libcore.util.Objects;
+
 /**
  * Container to ease passing around a tuple of two objects. This object provides a sensible
  * implementation of equals(), returning true if equals() is true on each of the contained
@@ -26,8 +28,8 @@
     public final S second;
 
     /**
-     * Constructor for a Pair. If either are null then equals() and hashCode() will throw
-     * a NullPointerException.
+     * Constructor for a Pair.
+     *
      * @param first the first object in the Pair
      * @param second the second object in the pair
      */
@@ -37,31 +39,30 @@
     }
 
     /**
-     * Checks the two objects for equality by delegating to their respective equals() methods.
-     * @param o the Pair to which this one is to be checked for equality
-     * @return true if the underlying objects of the Pair are both considered equals()
+     * Checks the two objects for equality by delegating to their respective
+     * {@link Object#equals(Object)} methods.
+     *
+     * @param o the {@link Pair} to which this one is to be checked for equality
+     * @return true if the underlying objects of the Pair are both considered
+     *         equal
      */
+    @Override
     public boolean equals(Object o) {
-        if (o == this) return true;
-        if (!(o instanceof Pair)) return false;
-        final Pair<F, S> other;
-        try {
-            other = (Pair<F, S>) o;
-        } catch (ClassCastException e) {
+        if (!(o instanceof Pair)) {
             return false;
         }
-        return first.equals(other.first) && second.equals(other.second);
+        Pair<?, ?> p = (Pair<?, ?>) o;
+        return Objects.equal(p.first, first) && Objects.equal(p.second, second);
     }
 
     /**
      * Compute a hash code using the hash codes of the underlying objects
+     *
      * @return a hashcode of the Pair
      */
+    @Override
     public int hashCode() {
-        int result = 17;
-        result = 31 * result + first.hashCode();
-        result = 31 * result + second.hashCode();
-        return result;
+        return (first == null ? 0 : first.hashCode()) ^ (second == null ? 0 : second.hashCode());
     }
 
     /**
diff --git a/core/java/android/view/GLES20Canvas.java b/core/java/android/view/GLES20Canvas.java
index f4ab133..869cd00 100644
--- a/core/java/android/view/GLES20Canvas.java
+++ b/core/java/android/view/GLES20Canvas.java
@@ -152,6 +152,8 @@
     static native int nCreateLayer(int width, int height, boolean isOpaque, int[] layerInfo);
     static native void nResizeLayer(int layerId, int width, int height, int[] layerInfo);
     static native void nSetOpaqueLayer(int layerId, boolean isOpaque);
+    static native void nSetLayerPaint(int layerId, int nativePaint);
+    static native void nSetLayerColorFilter(int layerId, int nativeColorFilter);
     static native void nUpdateTextureLayer(int layerId, int width, int height, boolean opaque,
             SurfaceTexture surface);
     static native void nSetTextureLayerTransform(int layerId, int matrix);
@@ -394,13 +396,8 @@
     
     void drawHardwareLayer(HardwareLayer layer, float x, float y, Paint paint) {
         final GLES20Layer glLayer = (GLES20Layer) layer;
-        int modifier = paint != null ? setupColorFilter(paint) : MODIFIER_NONE;
-        try {
-            final int nativePaint = paint == null ? 0 : paint.mNativePaint;
-            nDrawLayer(mRenderer, glLayer.getLayer(), x, y, nativePaint);
-        } finally {
-            if (modifier != MODIFIER_NONE) nResetModifiers(mRenderer, modifier);
-        }
+        final int nativePaint = paint == null ? 0 : paint.mNativePaint;
+        nDrawLayer(mRenderer, glLayer.getLayer(), x, y, nativePaint);
     }
 
     private static native void nDrawLayer(int renderer, int layer, float x, float y, int paint);
diff --git a/core/java/android/view/GLES20Layer.java b/core/java/android/view/GLES20Layer.java
index a0ae379..a462ed6 100644
--- a/core/java/android/view/GLES20Layer.java
+++ b/core/java/android/view/GLES20Layer.java
@@ -18,6 +18,7 @@
 package android.view;
 
 import android.graphics.Bitmap;
+import android.graphics.Paint;
 
 /**
  * An OpenGL ES 2.0 implementation of {@link HardwareLayer}.
@@ -43,6 +44,15 @@
     }
 
     @Override
+    void setLayerPaint(Paint paint) {
+        if (paint != null) {
+            GLES20Canvas.nSetLayerPaint(mLayer, paint.mNativePaint);
+            GLES20Canvas.nSetLayerColorFilter(mLayer, paint.getColorFilter() != null ?
+                    paint.getColorFilter().nativeColorFilter : 0);
+        }
+    }
+
+    @Override
     boolean copyInto(Bitmap bitmap) {
         return GLES20Canvas.nCopyLayer(mLayer, bitmap.mNativeBitmap);
     }
diff --git a/core/java/android/view/HardwareLayer.java b/core/java/android/view/HardwareLayer.java
index 06c6e7c..6e763b2 100644
--- a/core/java/android/view/HardwareLayer.java
+++ b/core/java/android/view/HardwareLayer.java
@@ -19,6 +19,7 @@
 import android.graphics.Bitmap;
 import android.graphics.Canvas;
 import android.graphics.Matrix;
+import android.graphics.Paint;
 import android.graphics.Rect;
 
 /**
@@ -62,6 +63,14 @@
     }
 
     /**
+     * Update the paint used when drawing this layer.
+     *
+     * @param paint The paint used when the layer is drawn into the destination canvas.
+     * @see View#setLayerPaint(android.graphics.Paint)
+     */
+    void setLayerPaint(Paint paint) {}
+
+    /**
      * Returns the minimum width of the layer.
      * 
      * @return The minimum desired width of the hardware layer 
diff --git a/core/java/android/view/IDisplayContentChangeListener.aidl b/core/java/android/view/IDisplayContentChangeListener.aidl
new file mode 100644
index 0000000..8f23ff6
--- /dev/null
+++ b/core/java/android/view/IDisplayContentChangeListener.aidl
@@ -0,0 +1,32 @@
+/*
+** Copyright 2012, 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.view;
+
+import android.os.IBinder;
+import android.view.WindowInfo;
+import android.graphics.Rect;
+
+/**
+ * Interface for observing content changes on a display.
+ *
+ * {@hide}
+ */
+oneway interface IDisplayContentChangeListener {
+    void onWindowTransition(int displayId, int transition, in WindowInfo info);
+    void onRectangleOnScreenRequested(int displayId, in Rect rectangle, boolean immediate);
+    void onRotationChanged(int rotation);
+}
diff --git a/core/java/android/view/IWindowManager.aidl b/core/java/android/view/IWindowManager.aidl
index 7f2de50..b9f3942 100644
--- a/core/java/android/view/IWindowManager.aidl
+++ b/core/java/android/view/IWindowManager.aidl
@@ -26,6 +26,7 @@
 import android.graphics.Rect;
 import android.os.IRemoteCallback;
 import android.view.IApplicationToken;
+import android.view.IDisplayContentChangeListener;
 import android.view.IOnKeyguardExitResult;
 import android.view.IRotationWatcher;
 import android.view.IWindowSession;
@@ -34,7 +35,8 @@
 import android.view.MotionEvent;
 import android.view.InputChannel;
 import android.view.InputDevice;
-import  android.view.IInputFilter;
+import android.view.IInputFilter;
+import android.view.WindowInfo;
 
 /**
  * System private interface to the window manager.
@@ -214,11 +216,6 @@
     IBinder getFocusedWindowToken();
 
     /**
-     * Gets the frame on the screen of the window given its token.
-     */
-    boolean getWindowFrame(IBinder token, out Rect outBounds);
-
-    /**
      * Gets the compatibility scale of e window given its token.
      */
     float getWindowCompatibilityScale(IBinder windowToken);
@@ -227,4 +224,29 @@
      * Sets an input filter for manipulating the input event stream.
      */
     void setInputFilter(in IInputFilter filter);
+
+    /**
+     * Sets the scale and offset for implementing accessibility magnification.
+     */
+    void magnifyDisplay(int dipslayId, float scale, float offsetX, float offsetY);
+
+    /**
+     * Adds a listener for display content changes.
+     */
+    void addDisplayContentChangeListener(int displayId, IDisplayContentChangeListener listener);
+
+    /**
+     * Removes a listener for display content changes.
+     */
+    void removeDisplayContentChangeListener(int displayId, IDisplayContentChangeListener listener);
+
+    /**
+     * Gets the info for a window given its token.
+     */
+    WindowInfo getWindowInfo(IBinder token);
+
+    /**
+     * Gets the infos for all visible windows.
+     */
+    void getVisibleWindowsForDisplay(int displayId, out List<WindowInfo> outInfos);
 }
diff --git a/core/java/android/view/IWindowSession.aidl b/core/java/android/view/IWindowSession.aidl
index c5d9255..ff9dcce 100644
--- a/core/java/android/view/IWindowSession.aidl
+++ b/core/java/android/view/IWindowSession.aidl
@@ -180,4 +180,9 @@
 
     void setUniverseTransform(IBinder window, float alpha, float offx, float offy,
             float dsdx, float dtdx, float dsdy, float dtdy);
+
+    /**
+     * Notifies that a rectangle on the screen has been requested.
+     */
+    void onRectangleOnScreenRequested(IBinder token, in Rect rectangle, boolean immediate);
 }
diff --git a/core/java/android/view/Surface.java b/core/java/android/view/Surface.java
index db05e10..8f4626f 100644
--- a/core/java/android/view/Surface.java
+++ b/core/java/android/view/Surface.java
@@ -259,7 +259,7 @@
     private static native IBinder nativeGetBuiltInDisplay(int physicalDisplayId);
     private static native IBinder nativeCreateDisplay(String name);
     private static native void nativeSetDisplaySurface(
-            IBinder displayToken, SurfaceTexture surfaceTexture);
+            IBinder displayToken, Surface surface);
     private static native void nativeSetDisplayLayerStack(
             IBinder displayToken, int layerStack);
     private static native void nativeSetDisplayProjection(
@@ -597,11 +597,11 @@
     }
 
     /** @hide */
-    public static void setDisplaySurface(IBinder displayToken, SurfaceTexture surfaceTexture) {
+    public static void setDisplaySurface(IBinder displayToken, Surface surface) {
         if (displayToken == null) {
             throw new IllegalArgumentException("displayToken must not be null");
         }
-        nativeSetDisplaySurface(displayToken, surfaceTexture);
+        nativeSetDisplaySurface(displayToken, surface);
     }
 
     /** @hide */
diff --git a/core/java/android/view/SurfaceView.java b/core/java/android/view/SurfaceView.java
index fdf1c22..973c7f6 100644
--- a/core/java/android/view/SurfaceView.java
+++ b/core/java/android/view/SurfaceView.java
@@ -615,21 +615,22 @@
             mSurfaceView = new WeakReference<SurfaceView>(surfaceView);
         }
 
-        public void resized(int w, int h, Rect contentInsets,
+        @Override
+        public void resized(Rect frame, Rect contentInsets,
                 Rect visibleInsets, boolean reportDraw, Configuration newConfig) {
             SurfaceView surfaceView = mSurfaceView.get();
             if (surfaceView != null) {
                 if (DEBUG) Log.v(
-                        "SurfaceView", surfaceView + " got resized: w=" +
-                                w + " h=" + h + ", cur w=" + mCurWidth + " h=" + mCurHeight);
+                        "SurfaceView", surfaceView + " got resized: w=" + frame.width()
+                        + " h=" + frame.height() + ", cur w=" + mCurWidth + " h=" + mCurHeight);
                 surfaceView.mSurfaceLock.lock();
                 try {
                     if (reportDraw) {
                         surfaceView.mUpdateWindowNeeded = true;
                         surfaceView.mReportDrawNeeded = true;
                         surfaceView.mHandler.sendEmptyMessage(UPDATE_WINDOW_MSG);
-                    } else if (surfaceView.mWinFrame.width() != w
-                            || surfaceView.mWinFrame.height() != h) {
+                    } else if (surfaceView.mWinFrame.width() != frame.width()
+                            || surfaceView.mWinFrame.height() != frame.height()) {
                         surfaceView.mUpdateWindowNeeded = true;
                         surfaceView.mHandler.sendEmptyMessage(UPDATE_WINDOW_MSG);
                     }
diff --git a/core/java/android/view/TextureView.java b/core/java/android/view/TextureView.java
index fe14c88..7e335f0 100644
--- a/core/java/android/view/TextureView.java
+++ b/core/java/android/view/TextureView.java
@@ -367,6 +367,7 @@
             if (mListener != null && !mUpdateSurface) {
                 mListener.onSurfaceTextureAvailable(mSurface, getWidth(), getHeight());
             }
+            mLayer.setLayerPaint(mLayerPaint);
         }
 
         if (mUpdateSurface) {
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index b6f07fa..236adab 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -6259,6 +6259,11 @@
             if (viewRootImpl != null) {
                 viewRootImpl.setAccessibilityFocus(this, null);
             }
+            if (mAttachInfo != null) {
+                Rect rectangle = mAttachInfo.mTmpInvalRect;
+                getDrawingRect(rectangle);
+                requestRectangleOnScreen(rectangle);
+            }
             invalidate();
             sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_ACCESSIBILITY_FOCUSED);
             notifyAccessibilityStateChanged();
@@ -6805,7 +6810,7 @@
      * @hide
      */
     public CharSequence getIterableTextForAccessibility() {
-        return mContentDescription;
+        return getContentDescription();
     }
 
     /**
@@ -11359,6 +11364,7 @@
         resolveLayoutParams();
         resolveTextDirection();
         resolveTextAlignment();
+        resolveDrawables();
     }
 
     /**
@@ -11926,13 +11932,13 @@
      * {@link #setAlpha(float)}, the alpha value of the layer's paint is replaced by
      * this view's alpha value. Calling {@link #setAlpha(float)} is therefore
      * equivalent to setting a hardware layer on this view and providing a paint with
-     * the desired alpha value.<p>
+     * the desired alpha value.</p>
      *
      * <p>Refer to the documentation of {@link #LAYER_TYPE_NONE disabled},
      * {@link #LAYER_TYPE_SOFTWARE software} and {@link #LAYER_TYPE_HARDWARE hardware}
      * for more information on when and how to use layers.</p>
      *
-     * @param layerType The ype of layer to use with this view, must be one of
+     * @param layerType The type of layer to use with this view, must be one of
      *        {@link #LAYER_TYPE_NONE}, {@link #LAYER_TYPE_SOFTWARE} or
      *        {@link #LAYER_TYPE_HARDWARE}
      * @param paint The paint used to compose the layer. This argument is optional
@@ -11984,6 +11990,50 @@
     }
 
     /**
+     * Updates the {@link Paint} object used with the current layer (used only if the current
+     * layer type is not set to {@link #LAYER_TYPE_NONE}). Changed properties of the Paint
+     * provided to {@link #setLayerType(int, android.graphics.Paint)} will be used the next time
+     * the View is redrawn, but {@link #setLayerPaint(android.graphics.Paint)} must be called to
+     * ensure that the view gets redrawn immediately.
+     *
+     * <p>A layer is associated with an optional {@link android.graphics.Paint}
+     * instance that controls how the layer is composed on screen. The following
+     * properties of the paint are taken into account when composing the layer:</p>
+     * <ul>
+     * <li>{@link android.graphics.Paint#getAlpha() Translucency (alpha)}</li>
+     * <li>{@link android.graphics.Paint#getXfermode() Blending mode}</li>
+     * <li>{@link android.graphics.Paint#getColorFilter() Color filter}</li>
+     * </ul>
+     *
+     * <p>If this view has an alpha value set to < 1.0 by calling
+     * {@link #setAlpha(float)}, the alpha value of the layer's paint is replaced by
+     * this view's alpha value. Calling {@link #setAlpha(float)} is therefore
+     * equivalent to setting a hardware layer on this view and providing a paint with
+     * the desired alpha value.</p>
+     *
+     * @param paint The paint used to compose the layer. This argument is optional
+     *        and can be null. It is ignored when the layer type is
+     *        {@link #LAYER_TYPE_NONE}
+     *
+     * @see #setLayerType(int, android.graphics.Paint)
+     */
+    public void setLayerPaint(Paint paint) {
+        int layerType = getLayerType();
+        if (layerType != LAYER_TYPE_NONE) {
+            mLayerPaint = paint == null ? new Paint() : paint;
+            if (layerType == LAYER_TYPE_HARDWARE) {
+                HardwareLayer layer = getHardwareLayer();
+                if (layer != null) {
+                    layer.setLayerPaint(paint);
+                }
+                invalidateViewProperty(false, false);
+            } else {
+                invalidate();
+            }
+        }
+    }
+
+    /**
      * Indicates whether this view has a static layer. A view with layer type
      * {@link #LAYER_TYPE_NONE} is a static layer. Other types of layers are
      * dynamic.
@@ -12095,6 +12145,7 @@
             if (!mHardwareLayer.isValid()) {
                 return null;
             }
+            mHardwareLayer.setLayerPaint(mLayerPaint);
 
             mHardwareLayer.redraw(getHardwareLayerDisplayList(mHardwareLayer), mLocalDirtyRect);
             mLocalDirtyRect.setEmpty();
@@ -12537,10 +12588,15 @@
             final boolean opaque = drawingCacheBackgroundColor != 0 || isOpaque();
             final boolean use32BitCache = attachInfo != null && attachInfo.mUse32BitDrawingCache;
 
-            if (width <= 0 || height <= 0 ||
-                     // Projected bitmap size in bytes
-                    (width * height * (opaque && !use32BitCache ? 2 : 4) >
-                            ViewConfiguration.get(mContext).getScaledMaximumDrawingCacheSize())) {
+            final int projectedBitmapSize = width * height * (opaque && !use32BitCache ? 2 : 4);
+            final int drawingCacheSize =
+                    ViewConfiguration.get(mContext).getScaledMaximumDrawingCacheSize();
+            if (width <= 0 || height <= 0 || projectedBitmapSize > drawingCacheSize) {
+                if (width > 0 && height > 0) {
+                    Log.w(VIEW_LOG_TAG, "View too large to fit into drawing cache, needs "
+                            + projectedBitmapSize + " bytes, only "
+                            + drawingCacheSize + " available");
+                }
                 destroyDrawingCache();
                 mCachingFailed = true;
                 return;
@@ -14107,7 +14163,7 @@
     @RemotableViewMethod
     public void setBackgroundColor(int color) {
         if (mBackground instanceof ColorDrawable) {
-            ((ColorDrawable) mBackground).setColor(color);
+            ((ColorDrawable) mBackground.mutate()).setColor(color);
             computeOpaqueFlags();
         } else {
             setBackground(new ColorDrawable(color));
diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java
index ffd495e..a4c0235 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -4649,9 +4649,19 @@
         // ViewAncestor never intercepts touch event, so this can be a no-op
     }
 
-    public boolean requestChildRectangleOnScreen(View child, Rect rectangle,
-            boolean immediate) {
-        return scrollToRectOrFocus(rectangle, immediate);
+    public boolean requestChildRectangleOnScreen(View child, Rect rectangle, boolean immediate) {
+        final boolean scrolled = scrollToRectOrFocus(rectangle, immediate);
+        if (rectangle != null) {
+            mTempRect.set(rectangle);
+            mTempRect.offset(0, -mCurScrollY);
+            mTempRect.offset(mAttachInfo.mWindowLeft, mAttachInfo.mWindowTop);
+            try {
+                mWindowSession.onRectangleOnScreenRequested(mWindow, mTempRect, immediate);
+            } catch (RemoteException re) {
+                /* ignore */
+            }
+        }
+        return scrolled;
     }
 
     public void childHasTransientStateChanged(View child, boolean hasTransientState) {
diff --git a/core/java/android/view/WindowInfo.aidl b/core/java/android/view/WindowInfo.aidl
new file mode 100644
index 0000000..23e927a
--- /dev/null
+++ b/core/java/android/view/WindowInfo.aidl
@@ -0,0 +1,20 @@
+/*
+**
+** Copyright 2012, 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.view;
+
+parcelable WindowInfo;
diff --git a/core/java/android/view/WindowInfo.java b/core/java/android/view/WindowInfo.java
new file mode 100644
index 0000000..00875ae
--- /dev/null
+++ b/core/java/android/view/WindowInfo.java
@@ -0,0 +1,153 @@
+/*
+ * Copyright (C) 2012 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.view;
+
+import android.graphics.Rect;
+import android.os.IBinder;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+/**
+ * Information the state of a window.
+ *
+ * @hide
+ */
+public class WindowInfo implements Parcelable {
+
+    private static final int MAX_POOL_SIZE = 20;
+
+    private static int UNDEFINED = -1;
+
+    private static Object sPoolLock = new Object();
+    private static WindowInfo sPool;
+    private static int sPoolSize;
+
+    private WindowInfo mNext;
+    private boolean mInPool;
+
+    public IBinder token;
+
+    public final Rect frame = new Rect();
+
+    public final Rect touchableRegion = new Rect();
+
+    public int type;
+
+    public float compatibilityScale;
+
+    public boolean visible;
+
+    public int displayId;
+
+    private WindowInfo() {
+        /* do nothing - reduce visibility */
+    }
+
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    @Override
+    public void writeToParcel(Parcel parcel, int flags) {
+        parcel.writeStrongBinder(token);
+        parcel.writeParcelable(frame, 0);
+        parcel.writeParcelable(touchableRegion, 0);
+        parcel.writeInt(type);
+        parcel.writeFloat(compatibilityScale);
+        parcel.writeInt(visible ? 1 : 0);
+        parcel.writeInt(displayId);
+        recycle();
+    }
+
+    private void initFromParcel(Parcel parcel) {
+        token = parcel.readStrongBinder();
+        frame.set((Rect) parcel.readParcelable(null));
+        touchableRegion.set((Rect) parcel.readParcelable(null));
+        type = parcel.readInt();
+        compatibilityScale = parcel.readFloat();
+        visible = (parcel.readInt() == 1);
+        displayId = parcel.readInt();
+    }
+
+    public static WindowInfo obtain(WindowInfo other) {
+        WindowInfo info = obtain();
+        info.token = other.token;
+        info.frame.set(other.frame);
+        info.touchableRegion.set(other.touchableRegion);
+        info.type = other.type;
+        info.displayId = other.displayId;
+        info.compatibilityScale = other.compatibilityScale;
+        info.visible = other.visible;
+        return info;
+    }
+
+    public static WindowInfo obtain() {
+        synchronized (sPoolLock) {
+            if (sPoolSize > 0) {
+                WindowInfo info = sPool;
+                sPool = info.mNext;
+                info.mNext = null;
+                info.mInPool = false;
+                sPoolSize--;
+                return info;
+            } else {
+                return new WindowInfo();
+            }
+        }
+    }
+
+    public void recycle() {
+        if (mInPool) {
+            throw new IllegalStateException("Already recycled.");
+        }
+        clear();
+        synchronized (sPoolLock) {
+            if (sPoolSize < MAX_POOL_SIZE) {
+                mNext = sPool;
+                sPool = this;
+                mInPool = true;
+                sPoolSize++;
+            }
+        }
+    }
+
+    private void clear() {
+        token = null;
+        frame.setEmpty();
+        touchableRegion.setEmpty();
+        type = UNDEFINED;
+        displayId = UNDEFINED;
+        visible = false;
+    }
+
+    /**
+     * @see Parcelable.Creator
+     */
+    public static final Parcelable.Creator<WindowInfo> CREATOR =
+            new Parcelable.Creator<WindowInfo>() {
+        public WindowInfo createFromParcel(Parcel parcel) {
+            WindowInfo info = WindowInfo.obtain();
+            info.initFromParcel(parcel);
+            return info;
+        }
+
+        public WindowInfo[] newArray(int size) {
+            return new WindowInfo[size];
+        }
+    };
+}
diff --git a/core/java/android/view/WindowManager.java b/core/java/android/view/WindowManager.java
index 7412f39..fa2d4e8 100644
--- a/core/java/android/view/WindowManager.java
+++ b/core/java/android/view/WindowManager.java
@@ -205,7 +205,8 @@
             @ViewDebug.IntToString(from = TYPE_HIDDEN_NAV_CONSUMER, to = "TYPE_HIDDEN_NAV_CONSUMER"),
             @ViewDebug.IntToString(from = TYPE_DREAM, to = "TYPE_DREAM"),
             @ViewDebug.IntToString(from = TYPE_NAVIGATION_BAR_PANEL, to = "TYPE_NAVIGATION_BAR_PANEL"),
-            @ViewDebug.IntToString(from = TYPE_DISPLAY_OVERLAY, to = "TYPE_DISPLAY_OVERLAY")
+            @ViewDebug.IntToString(from = TYPE_DISPLAY_OVERLAY, to = "TYPE_DISPLAY_OVERLAY"),
+            @ViewDebug.IntToString(from = TYPE_MAGNIFICATION_OVERLAY, to = "TYPE_MAGNIFICATION_OVERLAY")
         })
         public int type;
     
@@ -467,6 +468,13 @@
         public static final int TYPE_DISPLAY_OVERLAY = FIRST_SYSTEM_WINDOW+26;
 
         /**
+         * Window type: Magnification overlay window. Used to highlight the magnified
+         * portion of a display when accessibility magnification is enabled.
+         * @hide
+         */
+        public static final int TYPE_MAGNIFICATION_OVERLAY = FIRST_SYSTEM_WINDOW+27;
+
+        /**
          * End of types of system windows.
          */
         public static final int LAST_SYSTEM_WINDOW      = 2999;
diff --git a/core/java/android/view/WindowManagerPolicy.java b/core/java/android/view/WindowManagerPolicy.java
index 05838f9..75554da 100644
--- a/core/java/android/view/WindowManagerPolicy.java
+++ b/core/java/android/view/WindowManagerPolicy.java
@@ -123,7 +123,7 @@
     /**
      * This key event should put the device to sleep (and engage keyguard if necessary)
      * To be returned from {@link #interceptKeyBeforeQueueing}.
-     * Do not return this and {@link #ACTION_POKE_USER_ACTIVITY} or {@link #ACTION_PASS_TO_USER}.
+     * Do not return this and {@link #ACTION_WAKE_UP} or {@link #ACTION_PASS_TO_USER}.
      */
     public final static int ACTION_GO_TO_SLEEP = 0x00000004;
 
@@ -338,6 +338,12 @@
          * Check whether the process hosting this window is currently alive.
          */
         public boolean isAlive();
+
+        /**
+         * Check if window is on {@link Display#DEFAULT_DISPLAY}.
+         * @return true if window is on default display.
+         */
+        public boolean isDefaultDisplay();
     }
 
     /**
@@ -707,7 +713,7 @@
      * @param isScreenOn True if the screen is already on
      *
      * @return The bitwise or of the {@link #ACTION_PASS_TO_USER},
-     *          {@link #ACTION_POKE_USER_ACTIVITY} and {@link #ACTION_GO_TO_SLEEP} flags.
+     *      {@link #ACTION_WAKE_UP} and {@link #ACTION_GO_TO_SLEEP} flags.
      */
     public int interceptKeyBeforeQueueing(KeyEvent event, int policyFlags, boolean isScreenOn);
 
@@ -721,7 +727,7 @@
      * @param policyFlags The policy flags associated with the motion.
      *
      * @return The bitwise or of the {@link #ACTION_PASS_TO_USER},
-     *          {@link #ACTION_POKE_USER_ACTIVITY} and {@link #ACTION_GO_TO_SLEEP} flags.
+     *      {@link #ACTION_WAKE_UP} and {@link #ACTION_GO_TO_SLEEP} flags.
      */
     public int interceptMotionBeforeQueueingWhenScreenOff(int policyFlags);
 
@@ -762,12 +768,14 @@
     /**
      * Called when layout of the windows is about to start.
      * 
+     * @param isDefaultDisplay true if window is on {@link Display#DEFAULT_DISPLAY}.
      * @param displayWidth The current full width of the screen.
      * @param displayHeight The current full height of the screen.
      * @param displayRotation The current rotation being applied to the base
      * window.
      */
-    public void beginLayoutLw(int displayWidth, int displayHeight, int displayRotation);
+    public void beginLayoutLw(boolean isDefaultDisplay, int displayWidth, int displayHeight,
+                              int displayRotation);
 
     /**
      * Return the rectangle of the screen currently covered by system decorations.
@@ -1066,9 +1074,9 @@
      * Inform the policy that the user has chosen a preferred orientation ("rotation lock"). 
      *
      * @param mode One of {@link WindowManagerPolicy#USER_ROTATION_LOCKED} or
-     *             {@link * WindowManagerPolicy#USER_ROTATION_FREE}. 
+     *             {@link WindowManagerPolicy#USER_ROTATION_FREE}. 
      * @param rotation One of {@link Surface#ROTATION_0}, {@link Surface#ROTATION_90},
-     *                 {@link Surface#ROTATION_180}, {@link Surface#ROTATION_270}. 
+     *                 {@link Surface#ROTATION_180}, {@link Surface#ROTATION_270}.
      */
     public void setUserRotationMode(int mode, int rotation);
 
@@ -1098,6 +1106,14 @@
     public void setLastInputMethodWindowLw(WindowState ime, WindowState target);
 
     /**
+     * Returns whether magnification can be applied to the given window type.
+     *
+     * @param attrs The window's LayoutParams.
+     * @return Whether magnification can be applied.
+     */
+    public boolean canMagnifyWindow(WindowManager.LayoutParams attrs);
+
+    /**
      * Print the WindowManagerPolicy's state into the given stream.
      *
      * @param prefix Text to print at the front of each line.
diff --git a/core/java/android/webkit/HTML5VideoFullScreen.java b/core/java/android/webkit/HTML5VideoFullScreen.java
index 76ec374..9b93805 100644
--- a/core/java/android/webkit/HTML5VideoFullScreen.java
+++ b/core/java/android/webkit/HTML5VideoFullScreen.java
@@ -93,6 +93,7 @@
     private boolean mPlayingWhenDestroyed = false;
     SurfaceHolder.Callback mSHCallback = new SurfaceHolder.Callback()
     {
+        @Override
         public void surfaceChanged(SurfaceHolder holder, int format,
                                     int w, int h)
         {
@@ -106,6 +107,7 @@
             }
         }
 
+        @Override
         public void surfaceCreated(SurfaceHolder holder)
         {
             mSurfaceHolder = holder;
@@ -114,6 +116,7 @@
             prepareForFullScreen();
         }
 
+        @Override
         public void surfaceDestroyed(SurfaceHolder holder)
         {
             mPlayingWhenDestroyed = mPlayer.isPlaying();
@@ -233,12 +236,14 @@
 
     }
 
+    @Override
     public boolean fullScreenExited() {
         return (mLayout == null);
     }
 
     private final WebChromeClient.CustomViewCallback mCallback =
         new WebChromeClient.CustomViewCallback() {
+            @Override
             public void onCustomViewHidden() {
                 // It listens to SurfaceHolder.Callback.SurfaceDestroyed event
                 // which happens when the video view is detached from its parent
@@ -274,7 +279,7 @@
         mVideoSurfaceView.setFocusable(true);
         mVideoSurfaceView.setFocusableInTouchMode(true);
         mVideoSurfaceView.requestFocus();
-
+        mVideoSurfaceView.setOnKeyListener(mProxy);
         // Create a FrameLayout that will contain the VideoView and the
         // progress view (if any).
         mLayout = new FrameLayout(mProxy.getContext());
@@ -306,6 +311,7 @@
      * @return true when we are in full screen mode, even the surface not fully
      * created.
      */
+    @Override
     public boolean isFullScreenMode() {
         return true;
     }
@@ -344,6 +350,7 @@
     // Other listeners functions:
     private MediaPlayer.OnBufferingUpdateListener mBufferingUpdateListener =
         new MediaPlayer.OnBufferingUpdateListener() {
+        @Override
         public void onBufferingUpdate(MediaPlayer mp, int percent) {
             mCurrentBufferPercentage = percent;
         }
diff --git a/core/java/android/webkit/HTML5VideoInline.java b/core/java/android/webkit/HTML5VideoInline.java
index 96240ef..2ab2ab9 100644
--- a/core/java/android/webkit/HTML5VideoInline.java
+++ b/core/java/android/webkit/HTML5VideoInline.java
@@ -19,7 +19,6 @@
 import android.Manifest.permission;
 import android.content.pm.PackageManager;
 import android.graphics.SurfaceTexture;
-import android.media.MediaPlayer;
 import android.webkit.HTML5VideoView;
 import android.webkit.HTML5VideoViewProxy;
 import android.view.Surface;
diff --git a/core/java/android/webkit/HTML5VideoView.java b/core/java/android/webkit/HTML5VideoView.java
index 8f9f8eb..0e8a5db 100644
--- a/core/java/android/webkit/HTML5VideoView.java
+++ b/core/java/android/webkit/HTML5VideoView.java
@@ -16,11 +16,8 @@
 
 package android.webkit;
 
-import android.graphics.SurfaceTexture;
 import android.media.MediaPlayer;
 import android.net.Uri;
-import android.util.Log;
-import android.view.SurfaceView;
 import android.webkit.HTML5VideoViewProxy;
 import java.io.IOException;
 import java.util.HashMap;
diff --git a/core/java/android/webkit/HTML5VideoViewProxy.java b/core/java/android/webkit/HTML5VideoViewProxy.java
index 701ef35..a3d62ae 100644
--- a/core/java/android/webkit/HTML5VideoViewProxy.java
+++ b/core/java/android/webkit/HTML5VideoViewProxy.java
@@ -31,6 +31,8 @@
 import android.os.Looper;
 import android.os.Message;
 import android.util.Log;
+import android.view.KeyEvent;
+import android.view.View;
 
 import java.io.ByteArrayOutputStream;
 import java.io.IOException;
@@ -47,7 +49,8 @@
                           MediaPlayer.OnCompletionListener,
                           MediaPlayer.OnErrorListener,
                           MediaPlayer.OnInfoListener,
-                          SurfaceTexture.OnFrameAvailableListener {
+                          SurfaceTexture.OnFrameAvailableListener,
+                          View.OnKeyListener {
     // Logging tag.
     private static final String LOGTAG = "HTML5VideoViewProxy";
 
@@ -94,9 +97,6 @@
         private static HTML5VideoView mHTML5VideoView;
 
         private static boolean isVideoSelfEnded = false;
-        // By using the baseLayer and the current video Layer ID, we can
-        // identify the exact layer on the UI thread to use the SurfaceTexture.
-        private static int mBaseLayer = 0;
 
         private static void setPlayerBuffering(boolean playerBuffering) {
             mHTML5VideoView.setPlayerBuffering(playerBuffering);
@@ -106,7 +106,6 @@
         // When we found the Video layer, then we set the Surface Texture to it.
         // Otherwise, we may want to delete the Surface Texture to save memory.
         public static void setBaseLayer(int layer) {
-            mBaseLayer = layer;
             // Don't do this for full screen mode.
             if (mHTML5VideoView != null
                 && !mHTML5VideoView.isFullScreenMode()
@@ -303,6 +302,7 @@
 
     // A bunch event listeners for our VideoView
     // MediaPlayer.OnPreparedListener
+    @Override
     public void onPrepared(MediaPlayer mp) {
         VideoPlayer.onPrepared();
         Message msg = Message.obtain(mWebCoreHandler, PREPARED);
@@ -315,6 +315,7 @@
     }
 
     // MediaPlayer.OnCompletionListener;
+    @Override
     public void onCompletion(MediaPlayer mp) {
         // The video ended by itself, so we need to
         // send a message to the UI thread to dismiss
@@ -324,6 +325,7 @@
     }
 
     // MediaPlayer.OnErrorListener
+    @Override
     public boolean onError(MediaPlayer mp, int what, int extra) {
         sendMessage(obtainMessage(ERROR));
         return false;
@@ -489,6 +491,7 @@
             releaseQueue();
         }
         // EventHandler methods. Executed on the network thread.
+        @Override
         public void status(int major_version,
                 int minor_version,
                 int code,
@@ -496,10 +499,12 @@
             mStatusCode = code;
         }
 
+        @Override
         public void headers(Headers headers) {
             mHeaders = headers;
         }
 
+        @Override
         public void data(byte[] data, int len) {
             if (mPosterBytes == null) {
                 mPosterBytes = new ByteArrayOutputStream();
@@ -507,6 +512,7 @@
             mPosterBytes.write(data, 0, len);
         }
 
+        @Override
         public void endData() {
             if (mStatusCode == 200) {
                 if (mPosterBytes.size() > 0) {
@@ -524,6 +530,7 @@
                 }
                 if (mUrl != null) {
                     mHandler.post(new Runnable() {
+                       @Override
                        public void run() {
                            if (mRequestHandle != null) {
                                mRequestHandle.setupRedirect(mUrl.toString(), mStatusCode,
@@ -535,14 +542,17 @@
             }
         }
 
+        @Override
         public void certificate(SslCertificate certificate) {
             // Don't care.
         }
 
+        @Override
         public void error(int id, String description) {
             cleanup();
         }
 
+        @Override
         public boolean handleSslErrorRequest(SslError error) {
             // Don't care. If this happens, data() will never be called so
             // mPosterBytes will never be created, so no need to call cleanup.
@@ -794,4 +804,17 @@
         }
         return false;
     }
+
+    @Override
+    public boolean onKey(View v, int keyCode, KeyEvent event) {
+        if (keyCode == KeyEvent.KEYCODE_BACK) {
+            if (event.getAction() == KeyEvent.ACTION_DOWN) {
+                return true;
+            } else if (event.getAction() == KeyEvent.ACTION_UP && !event.isCanceled()) {
+                VideoPlayer.exitFullScreenVideo(this, mWebView);
+                return true;
+            }
+        }
+        return false;
+    }
 }
diff --git a/core/java/android/widget/AbsSeekBar.java b/core/java/android/widget/AbsSeekBar.java
index e217e4f..34f78c6 100644
--- a/core/java/android/widget/AbsSeekBar.java
+++ b/core/java/android/widget/AbsSeekBar.java
@@ -107,6 +107,9 @@
         }
         if (thumb != null) {
             thumb.setCallback(this);
+            if (canResolveLayoutDirection()) {
+                thumb.setLayoutDirection(getResolvedLayoutDirection());
+            }
 
             // Assuming the thumb drawable is symmetric, set the thumb offset
             // such that the thumb will hang halfway off either edge of the
@@ -303,7 +306,16 @@
         // Canvas will be translated, so 0,0 is where we start drawing
         thumb.setBounds(thumbPos, topBound, thumbPos + thumbWidth, bottomBound);
     }
-    
+
+    @Override
+    public void onResolveDrawables(int layoutDirection) {
+        super.onResolveDrawables(layoutDirection);
+
+        if (mThumb != null) {
+            mThumb.setLayoutDirection(layoutDirection);
+        }
+    }
+
     @Override
     protected synchronized void onDraw(Canvas canvas) {
         super.onDraw(canvas);
@@ -409,15 +421,25 @@
         int x = (int)event.getX();
         float scale;
         float progress = 0;
-        if (x < mPaddingLeft) {
-            scale = 0.0f;
-        } else if (x > width - mPaddingRight) {
-            scale = 1.0f;
+        if (isLayoutRtl()) {
+            if (x > width - mPaddingRight) {
+                scale = 0.0f;
+            } else if (x < mPaddingLeft) {
+                scale = 1.0f;
+            } else {
+                scale = (float)(available - x + mPaddingLeft) / (float)available;
+                progress = mTouchProgressOffset;
+            }
         } else {
-            scale = (float)(x - mPaddingLeft) / (float)available;
-            progress = mTouchProgressOffset;
+            if (x < mPaddingLeft) {
+                scale = 0.0f;
+            } else if (x > width - mPaddingRight) {
+                scale = 1.0f;
+            } else {
+                scale = (float)(x - mPaddingLeft) / (float)available;
+                progress = mTouchProgressOffset;
+            }
         }
-        
         final int max = getMax();
         progress += scale * max;
         
diff --git a/core/java/android/widget/ListView.java b/core/java/android/widget/ListView.java
index e011c13..938979a 100644
--- a/core/java/android/widget/ListView.java
+++ b/core/java/android/widget/ListView.java
@@ -29,6 +29,7 @@
 import android.graphics.Rect;
 import android.graphics.drawable.Drawable;
 import android.util.AttributeSet;
+import android.util.MathUtils;
 import android.util.SparseBooleanArray;
 import android.view.FocusFinder;
 import android.view.KeyEvent;
@@ -1490,6 +1491,10 @@
 
             View focusLayoutRestoreView = null;
 
+            AccessibilityNodeInfo accessibilityFocusLayoutRestoreNode = null;
+            View accessibilityFocusLayoutRestoreView = null;
+            int accessibilityFocusPosition = INVALID_POSITION;
+
             // Remember stuff we will need down below
             switch (mLayoutMode) {
             case LAYOUT_SET_SELECTION:
@@ -1584,6 +1589,25 @@
                 requestFocus();
             }
 
+            // Remember which child, if any, had accessibility focus.
+            final View accessFocusedView = getViewRootImpl().getAccessibilityFocusedHost();
+            if (accessFocusedView != null) {
+                final View accessFocusedChild = findAccessibilityFocusedChild(accessFocusedView);
+                if (accessFocusedChild != null) {
+                    if (!dataChanged || isDirectChildHeaderOrFooter(accessFocusedChild)) {
+                        // If the views won't be changing, try to maintain focus
+                        // on the current view host and (if applicable) its
+                        // virtual view.
+                        accessibilityFocusLayoutRestoreView = accessFocusedView;
+                        accessibilityFocusLayoutRestoreNode = getViewRootImpl()
+                                .getAccessibilityFocusedVirtualView();
+                    } else {
+                        // Otherwise, try to maintain focus at the same position.
+                        accessibilityFocusPosition = getPositionForView(accessFocusedChild);
+                    }
+                }
+            }
+
             // Clear out old views
             detachAllViewsFromParent();
             recycleBin.removeSkippedScrap();
@@ -1682,6 +1706,22 @@
                 }
             }
 
+            // Attempt to restore accessibility focus.
+            if (accessibilityFocusLayoutRestoreNode != null) {
+                accessibilityFocusLayoutRestoreNode.performAction(
+                        AccessibilityNodeInfo.ACTION_ACCESSIBILITY_FOCUS);
+            } else if (accessibilityFocusLayoutRestoreView != null) {
+                accessibilityFocusLayoutRestoreView.requestAccessibilityFocus();
+            } else if (accessibilityFocusPosition != INVALID_POSITION) {
+                // Bound the position within the visible children.
+                final int position = MathUtils.constrain(
+                        (accessibilityFocusPosition - mFirstPosition), 0, (getChildCount() - 1));
+                final View restoreView = getChildAt(position);
+                if (restoreView != null) {
+                    restoreView.requestAccessibilityFocus();
+                }
+            }
+
             // tell focus view we are done mucking with it, if it is still in
             // our view hierarchy.
             if (focusLayoutRestoreView != null
@@ -1713,6 +1753,22 @@
     }
 
     /**
+     * @param focusedView the view that has accessibility focus.
+     * @return the direct child that contains accessibility focus.
+     */
+    private View findAccessibilityFocusedChild(View focusedView) {
+        ViewParent viewParent = focusedView.getParent();
+        while ((viewParent instanceof View) && (viewParent != this)) {
+            focusedView = (View) viewParent;
+            viewParent = viewParent.getParent();
+        }
+        if (!(viewParent instanceof View)) {
+            return null;
+        }
+        return focusedView;
+    }
+
+    /**
      * @param child a direct child of this list.
      * @return Whether child is a header or footer view.
      */
diff --git a/core/java/android/widget/NumberPicker.java b/core/java/android/widget/NumberPicker.java
index eabcb80..dbc777e 100644
--- a/core/java/android/widget/NumberPicker.java
+++ b/core/java/android/widget/NumberPicker.java
@@ -2305,22 +2305,26 @@
         }
 
         private void sendAccessibilityEventForVirtualText(int eventType) {
-            AccessibilityEvent event = AccessibilityEvent.obtain(eventType);
-            mInputText.onInitializeAccessibilityEvent(event);
-            mInputText.onPopulateAccessibilityEvent(event);
-            event.setSource(NumberPicker.this, VIRTUAL_VIEW_ID_INPUT);
-            requestSendAccessibilityEvent(NumberPicker.this, event);
+            if (AccessibilityManager.getInstance(mContext).isEnabled()) {
+                AccessibilityEvent event = AccessibilityEvent.obtain(eventType);
+                mInputText.onInitializeAccessibilityEvent(event);
+                mInputText.onPopulateAccessibilityEvent(event);
+                event.setSource(NumberPicker.this, VIRTUAL_VIEW_ID_INPUT);
+                requestSendAccessibilityEvent(NumberPicker.this, event);
+            }
         }
 
         private void sendAccessibilityEventForVirtualButton(int virtualViewId, int eventType,
                 String text) {
-            AccessibilityEvent event = AccessibilityEvent.obtain(eventType);
-            event.setClassName(Button.class.getName());
-            event.setPackageName(mContext.getPackageName());
-            event.getText().add(text);
-            event.setEnabled(NumberPicker.this.isEnabled());
-            event.setSource(NumberPicker.this, virtualViewId);
-            requestSendAccessibilityEvent(NumberPicker.this, event);
+            if (AccessibilityManager.getInstance(mContext).isEnabled()) {
+                AccessibilityEvent event = AccessibilityEvent.obtain(eventType);
+                event.setClassName(Button.class.getName());
+                event.setPackageName(mContext.getPackageName());
+                event.getText().add(text);
+                event.setEnabled(NumberPicker.this.isEnabled());
+                event.setSource(NumberPicker.this, virtualViewId);
+                requestSendAccessibilityEvent(NumberPicker.this, event);
+            }
         }
 
         private void findAccessibilityNodeInfosByTextInChild(String searchedLowerCase,
diff --git a/core/java/android/widget/ProgressBar.java b/core/java/android/widget/ProgressBar.java
index 860e583..b6d0995 100644
--- a/core/java/android/widget/ProgressBar.java
+++ b/core/java/android/widget/ProgressBar.java
@@ -478,8 +478,8 @@
             d.setCallback(this);
         }
         mIndeterminateDrawable = d;
-        if (mIndeterminateDrawable != null) {
-            mIndeterminateDrawable.setLayoutDirection(getLayoutDirection());
+        if (mIndeterminateDrawable != null && canResolveLayoutDirection()) {
+            mIndeterminateDrawable.setLayoutDirection(getResolvedLayoutDirection());
         }
         if (mIndeterminate) {
             mCurrentDrawable = d;
@@ -520,7 +520,9 @@
 
         if (d != null) {
             d.setCallback(this);
-            d.setLayoutDirection(getLayoutDirection());
+            if (canResolveLayoutDirection()) {
+                d.setLayoutDirection(getResolvedLayoutDirection());
+            }
 
             // Make sure the ProgressBar is always tall enough
             int drawableHeight = d.getMinimumHeight();
@@ -564,6 +566,20 @@
     }
 
     @Override
+    public void onResolveDrawables(int layoutDirection) {
+        final Drawable d = mCurrentDrawable;
+        if (d != null) {
+            d.setLayoutDirection(layoutDirection);
+        }
+        if (mIndeterminateDrawable != null) {
+            mIndeterminateDrawable.setLayoutDirection(layoutDirection);
+        }
+        if (mProgressDrawable != null) {
+            mProgressDrawable.setLayoutDirection(layoutDirection);
+        }
+    }
+
+    @Override
     public void postInvalidate() {
         if (!mNoInvalidate) {
             super.postInvalidate();
@@ -652,6 +668,9 @@
 
             if (d instanceof LayerDrawable) {
                 progressDrawable = ((LayerDrawable) d).findDrawableByLayerId(id);
+                if (progressDrawable != null && canResolveLayoutDirection()) {
+                    progressDrawable.setLayoutDirection(getResolvedLayoutDirection());
+                }
             }
 
             final int level = (int) (scale * MAX_LEVEL);
diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java
index c9688c8..dd2ff35 100644
--- a/core/java/android/widget/TextView.java
+++ b/core/java/android/widget/TextView.java
@@ -4463,9 +4463,6 @@
 
         mTemporaryDetach = false;
 
-        // Resolve drawables as the layout direction has been resolved
-        resolveDrawables();
-
         if (mEditor != null) mEditor.onAttachedToWindow();
     }
 
@@ -8355,7 +8352,7 @@
      */
     @Override
     public CharSequence getIterableTextForAccessibility() {
-        if (getContentDescription() == null) {
+        if (!TextUtils.isEmpty(mText)) {
             if (!(mText instanceof Spannable)) {
                 setText(mText, BufferType.SPANNABLE);
             }
diff --git a/core/java/com/android/internal/util/DumpUtils.java b/core/java/com/android/internal/util/DumpUtils.java
new file mode 100644
index 0000000..7b8c582
--- /dev/null
+++ b/core/java/com/android/internal/util/DumpUtils.java
@@ -0,0 +1,57 @@
+/*
+ * Copyright (C) 2012 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.internal.util;
+
+import android.os.Handler;
+
+import java.io.PrintWriter;
+import java.io.StringWriter;
+
+/**
+ * Helper functions for dumping the state of system services.
+ */
+public final class DumpUtils {
+    private DumpUtils() {
+    }
+
+    /**
+     * Helper for dumping state owned by a handler thread.
+     *
+     * Because the caller might be holding an important lock that the handler is
+     * trying to acquire, we use a short timeout to avoid deadlocks.  The process
+     * is inelegant but this function is only used for debugging purposes.
+     */
+    public static void dumpAsync(Handler handler, final Dump dump, PrintWriter pw, long timeout) {
+        final StringWriter sw = new StringWriter();
+        if (handler.runWithScissors(new Runnable() {
+            @Override
+            public void run() {
+                PrintWriter lpw = new PrintWriter(sw);
+                dump.dump(lpw);
+                lpw.close();
+            }
+        }, timeout)) {
+            pw.print(sw.toString());
+        } else {
+            pw.println("... timed out");
+        }
+    }
+
+    public interface Dump {
+        void dump(PrintWriter pw);
+    }
+}
diff --git a/core/java/com/android/internal/util/IndentingPrintWriter.java b/core/java/com/android/internal/util/IndentingPrintWriter.java
index 699e9b3..dd5918b 100644
--- a/core/java/com/android/internal/util/IndentingPrintWriter.java
+++ b/core/java/com/android/internal/util/IndentingPrintWriter.java
@@ -28,7 +28,7 @@
     private final String mIndent;
 
     private StringBuilder mBuilder = new StringBuilder();
-    private String mCurrent = new String();
+    private char[] mCurrent;
     private boolean mEmptyLine = true;
 
     public IndentingPrintWriter(Writer writer, String indent) {
@@ -38,12 +38,12 @@
 
     public void increaseIndent() {
         mBuilder.append(mIndent);
-        mCurrent = mBuilder.toString();
+        mCurrent = null;
     }
 
     public void decreaseIndent() {
         mBuilder.delete(0, mIndent.length());
-        mCurrent = mBuilder.toString();
+        mCurrent = null;
     }
 
     public void printPair(String key, Object value) {
@@ -51,17 +51,35 @@
     }
 
     @Override
-    public void println() {
-        super.println();
-        mEmptyLine = true;
+    public void write(char[] buf, int offset, int count) {
+        final int bufferEnd = offset + count;
+        int lineStart = offset;
+        int lineEnd = offset;
+        while (lineEnd < bufferEnd) {
+            char ch = buf[lineEnd++];
+            if (ch == '\n') {
+                writeIndent();
+                super.write(buf, lineStart, lineEnd - lineStart);
+                lineStart = lineEnd;
+                mEmptyLine = true;
+            }
+        }
+
+        if (lineStart != lineEnd) {
+            writeIndent();
+            super.write(buf, lineStart, lineEnd - lineStart);
+        }
     }
 
-    @Override
-    public void write(char[] buf, int offset, int count) {
+    private void writeIndent() {
         if (mEmptyLine) {
             mEmptyLine = false;
-            super.print(mCurrent);
+            if (mBuilder.length() != 0) {
+                if (mCurrent == null) {
+                    mCurrent = mBuilder.toString().toCharArray();
+                }
+                super.write(mCurrent, 0, mCurrent.length);
+            }
         }
-        super.write(buf, offset, count);
     }
 }
diff --git a/core/jni/Android.mk b/core/jni/Android.mk
index 9d45479..5f6042d 100644
--- a/core/jni/Android.mk
+++ b/core/jni/Android.mk
@@ -126,6 +126,7 @@
 	android_media_AudioSystem.cpp \
 	android_media_AudioTrack.cpp \
 	android_media_JetPlayer.cpp \
+	android_media_RemoteDisplay.cpp \
 	android_media_ToneGenerator.cpp \
 	android_hardware_Camera.cpp \
 	android_hardware_SensorManager.cpp \
diff --git a/core/jni/AndroidRuntime.cpp b/core/jni/AndroidRuntime.cpp
index 55563a8..27684d7 100644
--- a/core/jni/AndroidRuntime.cpp
+++ b/core/jni/AndroidRuntime.cpp
@@ -160,6 +160,7 @@
 extern int register_android_app_backup_FullBackup(JNIEnv *env);
 extern int register_android_app_ActivityThread(JNIEnv *env);
 extern int register_android_app_NativeActivity(JNIEnv *env);
+extern int register_android_media_RemoteDisplay(JNIEnv *env);
 extern int register_android_view_InputChannel(JNIEnv* env);
 extern int register_android_view_InputDevice(JNIEnv* env);
 extern int register_android_view_InputEventReceiver(JNIEnv* env);
@@ -1161,6 +1162,7 @@
     REG_JNI(register_android_media_AudioSystem),
     REG_JNI(register_android_media_AudioTrack),
     REG_JNI(register_android_media_JetPlayer),
+    REG_JNI(register_android_media_RemoteDisplay),
     REG_JNI(register_android_media_ToneGenerator),
 
     REG_JNI(register_android_opengl_classes),
diff --git a/core/jni/android_media_RemoteDisplay.cpp b/core/jni/android_media_RemoteDisplay.cpp
new file mode 100644
index 0000000..5d24f61
--- /dev/null
+++ b/core/jni/android_media_RemoteDisplay.cpp
@@ -0,0 +1,182 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "RemoteDisplay"
+
+#include "jni.h"
+#include "JNIHelp.h"
+
+#include "android_os_Parcel.h"
+#include "android_util_Binder.h"
+
+#include <android_runtime/AndroidRuntime.h>
+#include <android_runtime/android_view_Surface.h>
+
+#include <binder/IServiceManager.h>
+
+#include <gui/ISurfaceTexture.h>
+
+#include <media/IMediaPlayerService.h>
+#include <media/IRemoteDisplay.h>
+#include <media/IRemoteDisplayClient.h>
+
+#include <utils/Log.h>
+
+#include <ScopedUtfChars.h>
+
+namespace android {
+
+static struct {
+    jmethodID notifyDisplayConnected;
+    jmethodID notifyDisplayDisconnected;
+    jmethodID notifyDisplayError;
+} gRemoteDisplayClassInfo;
+
+// ----------------------------------------------------------------------------
+
+class NativeRemoteDisplayClient : public BnRemoteDisplayClient {
+public:
+    NativeRemoteDisplayClient(JNIEnv* env, jobject remoteDisplayObj) :
+            mRemoteDisplayObjGlobal(env->NewGlobalRef(remoteDisplayObj)) {
+    }
+
+protected:
+    ~NativeRemoteDisplayClient() {
+        JNIEnv* env = AndroidRuntime::getJNIEnv();
+        env->DeleteGlobalRef(mRemoteDisplayObjGlobal);
+    }
+
+public:
+    virtual void onDisplayConnected(const sp<ISurfaceTexture>& surfaceTexture,
+            uint32_t width, uint32_t height, uint32_t flags) {
+        JNIEnv* env = AndroidRuntime::getJNIEnv();
+
+        jobject surfaceObj = android_view_Surface_createFromISurfaceTexture(env, surfaceTexture);
+        if (surfaceObj == NULL) {
+            ALOGE("Could not create Surface from surface texture %p provided by media server.",
+                    surfaceTexture.get());
+            return;
+        }
+
+        env->CallVoidMethod(mRemoteDisplayObjGlobal,
+                gRemoteDisplayClassInfo.notifyDisplayConnected,
+                surfaceObj, width, height, flags);
+        env->DeleteLocalRef(surfaceObj);
+        checkAndClearExceptionFromCallback(env, "notifyDisplayConnected");
+    }
+
+    virtual void onDisplayDisconnected() {
+        JNIEnv* env = AndroidRuntime::getJNIEnv();
+
+        env->CallVoidMethod(mRemoteDisplayObjGlobal,
+                gRemoteDisplayClassInfo.notifyDisplayDisconnected);
+        checkAndClearExceptionFromCallback(env, "notifyDisplayDisconnected");
+    }
+
+    virtual void onDisplayError(int32_t error) {
+        JNIEnv* env = AndroidRuntime::getJNIEnv();
+
+        env->CallVoidMethod(mRemoteDisplayObjGlobal,
+                gRemoteDisplayClassInfo.notifyDisplayError, error);
+        checkAndClearExceptionFromCallback(env, "notifyDisplayError");
+    }
+
+private:
+    jobject mRemoteDisplayObjGlobal;
+
+    static void checkAndClearExceptionFromCallback(JNIEnv* env, const char* methodName) {
+        if (env->ExceptionCheck()) {
+            ALOGE("An exception was thrown by callback '%s'.", methodName);
+            LOGE_EX(env);
+            env->ExceptionClear();
+        }
+    }
+};
+
+class NativeRemoteDisplay {
+public:
+    NativeRemoteDisplay(const sp<IRemoteDisplay>& display,
+            const sp<NativeRemoteDisplayClient>& client) :
+            mDisplay(display), mClient(client) {
+    }
+
+    ~NativeRemoteDisplay() {
+        mDisplay->dispose();
+    }
+
+private:
+    sp<IRemoteDisplay> mDisplay;
+    sp<NativeRemoteDisplayClient> mClient;
+};
+
+
+// ----------------------------------------------------------------------------
+
+static jint nativeListen(JNIEnv* env, jobject remoteDisplayObj, jstring ifaceStr) {
+    ScopedUtfChars iface(env, ifaceStr);
+
+    sp<IServiceManager> sm = defaultServiceManager();
+    sp<IMediaPlayerService> service = interface_cast<IMediaPlayerService>(
+            sm->getService(String16("media.player")));
+    if (service == NULL) {
+        ALOGE("Could not obtain IMediaPlayerService from service manager");
+        return 0;
+    }
+
+    sp<NativeRemoteDisplayClient> client(new NativeRemoteDisplayClient(env, remoteDisplayObj));
+    sp<IRemoteDisplay> display = service->listenForRemoteDisplay(
+            client, String8(iface.c_str()));
+    if (display == NULL) {
+        ALOGE("Media player service rejected request to listen for remote display '%s'.",
+                iface.c_str());
+        return 0;
+    }
+
+    NativeRemoteDisplay* wrapper = new NativeRemoteDisplay(display, client);
+    return reinterpret_cast<jint>(wrapper);
+}
+
+static void nativeDispose(JNIEnv* env, jobject remoteDisplayObj, jint ptr) {
+    NativeRemoteDisplay* wrapper = reinterpret_cast<NativeRemoteDisplay*>(ptr);
+    delete wrapper;
+}
+
+// ----------------------------------------------------------------------------
+
+static JNINativeMethod gMethods[] = {
+    {"nativeListen", "(Ljava/lang/String;)I",
+            (void*)nativeListen },
+    {"nativeDispose", "(I)V",
+            (void*)nativeDispose },
+};
+
+int register_android_media_RemoteDisplay(JNIEnv* env)
+{
+    int err = AndroidRuntime::registerNativeMethods(env, "android/media/RemoteDisplay",
+            gMethods, NELEM(gMethods));
+
+    jclass clazz = env->FindClass("android/media/RemoteDisplay");
+    gRemoteDisplayClassInfo.notifyDisplayConnected =
+            env->GetMethodID(clazz, "notifyDisplayConnected",
+                    "(Landroid/view/Surface;III)V");
+    gRemoteDisplayClassInfo.notifyDisplayDisconnected =
+            env->GetMethodID(clazz, "notifyDisplayDisconnected", "()V");
+    gRemoteDisplayClassInfo.notifyDisplayError =
+            env->GetMethodID(clazz, "notifyDisplayError", "(I)V");
+    return err;
+}
+
+};
diff --git a/core/jni/android_text_format_Time.cpp b/core/jni/android_text_format_Time.cpp
index 776733c..bb09421 100644
--- a/core/jni/android_text_format_Time.cpp
+++ b/core/jni/android_text_format_Time.cpp
@@ -23,6 +23,7 @@
 #include "jni.h"
 #include "utils/misc.h"
 #include "android_runtime/AndroidRuntime.h"
+#include "ScopedStringChars.h"
 #include "TimeUtils.h"
 #include <nativehelper/JNIHelp.h>
 #include <cutils/tztime.h>
@@ -71,11 +72,10 @@
     t->t.tm_gmtoff = env->GetLongField(o, g_gmtoffField);
     bool allDay = env->GetBooleanField(o, g_allDayField);
     if (allDay &&
-	((t->t.tm_sec !=0) || (t->t.tm_min != 0) || (t->t.tm_hour != 0))) {
-        char msg[100];
-	sprintf(msg, "allDay is true but sec, min, hour are not 0.");
-	jniThrowException(env, "java/lang/IllegalArgumentException", msg);
-	return false;
+       ((t->t.tm_sec !=0) || (t->t.tm_min != 0) || (t->t.tm_hour != 0))) {
+        jniThrowException(env, "java/lang/IllegalArgumentException",
+                          "allDay is true but sec, min, hour are not 0.");
+        return false;
     }
     return true;
 }
@@ -308,7 +308,7 @@
 static jstring android_text_format_Time_toString(JNIEnv* env, jobject This)
 {
     Time t;
-    if (!java2time(env, &t, This)) return env->NewStringUTF("");;
+    if (!java2time(env, &t, This)) return env->NewStringUTF("");
     ACQUIRE_TIMEZONE(This, t)
 
     String8 r = t.toString();
@@ -360,32 +360,30 @@
 // ============================================================================
 // Just do this here because it's not worth recreating the strings
 
-static int get_char(JNIEnv* env, const jchar *s, int spos, int mul,
-                    bool *thrown)
+static int get_char(JNIEnv* env, const ScopedStringChars& s, int spos, int mul,
+                    bool* thrown)
 {
     jchar c = s[spos];
     if (c >= '0' && c <= '9') {
         return (c - '0') * mul;
     } else {
         if (!*thrown) {
-            char msg[100];
-            sprintf(msg, "Parse error at pos=%d", spos);
-            jniThrowException(env, "android/util/TimeFormatException", msg);
+            jniThrowExceptionFmt(env, "android/util/TimeFormatException",
+                                 "Parse error at pos=%d", spos);
             *thrown = true;
         }
         return 0;
     }
 }
 
-static bool check_char(JNIEnv* env, const jchar *s, int spos, jchar expected)
+static bool check_char(JNIEnv* env, const ScopedStringChars& s, int spos, jchar expected)
 {
     jchar c = s[spos];
     if (c != expected) {
-        char msg[100];
-	sprintf(msg, "Unexpected character 0x%02x at pos=%d.  Expected %c.", c, spos,
-		expected);
-	jniThrowException(env, "android/util/TimeFormatException", msg);
-	return false;
+        jniThrowExceptionFmt(env, "android/util/TimeFormatException",
+                             "Unexpected character 0x%02x at pos=%d.  Expected %c.",
+                             c, spos, expected);
+        return false;
     }
     return true;
 }
@@ -394,20 +392,19 @@
 static jboolean android_text_format_Time_parse(JNIEnv* env, jobject This, jstring strObj)
 {
     jsize len = env->GetStringLength(strObj);
-    const jchar *s = env->GetStringChars(strObj, NULL);
-
-    bool thrown = false;
-    int n;
-    jboolean inUtc = false;
-
     if (len < 8) {
-        char msg[100];
-        sprintf(msg, "String too short -- expected at least 8 characters.");
-	jniThrowException(env, "android/util/TimeFormatException", msg);
-	return false;
+        jniThrowException(env, "android/util/TimeFormatException",
+                          "String too short -- expected at least 8 characters.");
+        return false;
     }
 
+    jboolean inUtc = false;
+
+    ScopedStringChars s(env, strObj);
+
     // year
+    int n;
+    bool thrown = false;
     n = get_char(env, s, 0, 1000, &thrown);
     n += get_char(env, s, 1, 100, &thrown);
     n += get_char(env, s, 2, 10, &thrown);
@@ -454,7 +451,7 @@
         if (len > 15) {
             // Z
             if (!check_char(env, s, 15, 'Z')) return false;
-	    inUtc = true;
+            inUtc = true;
         }
     } else {
         env->SetBooleanField(This, g_allDayField, JNI_TRUE);
@@ -467,8 +464,7 @@
     env->SetIntField(This, g_ydayField, 0);
     env->SetIntField(This, g_isdstField, -1);
     env->SetLongField(This, g_gmtoffField, 0);
-    
-    env->ReleaseStringChars(strObj, s);
+
     return inUtc;
 }
 
@@ -477,19 +473,19 @@
                                            jstring strObj)
 {
     jsize len = env->GetStringLength(strObj);
-    const jchar *s = env->GetStringChars(strObj, NULL);
-
-    bool thrown = false;
-    int n;
-    jboolean inUtc = false;
-
     if (len < 10) {
         jniThrowException(env, "android/util/TimeFormatException",
-                "Time input is too short; must be at least 10 characters");
+                          "String too short --- expected at least 10 characters.");
         return false;
     }
 
+    jboolean inUtc = false;
+
+    ScopedStringChars s(env, strObj);
+
     // year
+    int n;
+    bool thrown = false;
     n = get_char(env, s, 0, 1000, &thrown);    
     n += get_char(env, s, 1, 100, &thrown);
     n += get_char(env, s, 2, 10, &thrown);
@@ -520,28 +516,28 @@
         // T
         if (!check_char(env, s, 10, 'T')) return false;
 
-	env->SetBooleanField(This, g_allDayField, JNI_FALSE);
+        env->SetBooleanField(This, g_allDayField, JNI_FALSE);
         // hour
         n = get_char(env, s, 11, 10, &thrown);
         n += get_char(env, s, 12, 1, &thrown);
         if (thrown) return false;
-	int hour = n;
+        int hour = n;
         // env->SetIntField(This, g_hourField, n);
-	
-	// :
-	if (!check_char(env, s, 13, ':')) return false;
 
-	// minute
+        // :
+        if (!check_char(env, s, 13, ':')) return false;
+
+        // minute
         n = get_char(env, s, 14, 10, &thrown);
         n += get_char(env, s, 15, 1, &thrown);
         if (thrown) return false;
-	int minute = n;
+        int minute = n;
         // env->SetIntField(This, g_minField, n);
 
-	// :
-	if (!check_char(env, s, 16, ':')) return false;
+        // :
+        if (!check_char(env, s, 16, ':')) return false;
 
-	// second
+        // second
         n = get_char(env, s, 17, 10, &thrown);
         n += get_char(env, s, 18, 1, &thrown);
         if (thrown) return false;
@@ -561,64 +557,63 @@
         if (len > tz_index) {
             char c = s[tz_index];
 
-	    // NOTE: the offset is meant to be subtracted to get from local time
-	    // to UTC.  we therefore use 1 for '-' and -1 for '+'.
-	    switch (c) {
-	    case 'Z':
-	        // Zulu time -- UTC
-	        offset = 0;
-		break;
-	    case '-': 
+            // NOTE: the offset is meant to be subtracted to get from local time
+            // to UTC.  we therefore use 1 for '-' and -1 for '+'.
+            switch (c) {
+            case 'Z':
+                // Zulu time -- UTC
+                offset = 0;
+                break;
+            case '-': 
                 offset = 1;
-	        break;
-	    case '+': 
+                break;
+            case '+': 
                 offset = -1;
-	        break;
-	    default:
-	        char msg[100];
-	        sprintf(msg, "Unexpected character 0x%02x at position %d.  Expected + or -",
-			c, tz_index);
-	        jniThrowException(env, "android/util/TimeFormatException", msg);
-	        return false;
-	    }
+                break;
+            default:
+                jniThrowExceptionFmt(env, "android/util/TimeFormatException",
+                                     "Unexpected character 0x%02x at position %d.  Expected + or -",
+                                     c, tz_index);
+                return false;
+            }
             inUtc = true;
 
-	    if (offset != 0) {
-	        if (len < tz_index + 6) {
-	            char msg[100];
-	            sprintf(msg, "Unexpected length; should be %d characters", tz_index + 6);
-	            jniThrowException(env, "android/util/TimeFormatException", msg);
-	            return false;
-	        }
+            if (offset != 0) {
+                if (len < tz_index + 6) {
+                    jniThrowExceptionFmt(env, "android/util/TimeFormatException",
+                                         "Unexpected length; should be %d characters",
+                                         tz_index + 6);
+                    return false;
+                }
 
-	        // hour
-	        n = get_char(env, s, tz_index + 1, 10, &thrown);
-		n += get_char(env, s, tz_index + 2, 1, &thrown);
-		if (thrown) return false;
-		n *= offset;
-		hour += n;
+                // hour
+                n = get_char(env, s, tz_index + 1, 10, &thrown);
+                n += get_char(env, s, tz_index + 2, 1, &thrown);
+                if (thrown) return false;
+                n *= offset;
+                hour += n;
 
-		// :
-		if (!check_char(env, s, tz_index + 3, ':')) return false;
-	    
-		// minute
-		n = get_char(env, s, tz_index + 4, 10, &thrown);
-		n += get_char(env, s, tz_index + 5, 1, &thrown);
-		if (thrown) return false;
-		n *= offset;
-		minute += n;
-	    }
-	}
-	env->SetIntField(This, g_hourField, hour);
+                // :
+                if (!check_char(env, s, tz_index + 3, ':')) return false;
+            
+                // minute
+                n = get_char(env, s, tz_index + 4, 10, &thrown);
+                n += get_char(env, s, tz_index + 5, 1, &thrown);
+                if (thrown) return false;
+                n *= offset;
+                minute += n;
+            }
+        }
+        env->SetIntField(This, g_hourField, hour);
         env->SetIntField(This, g_minField, minute);
 
-	if (offset != 0) {
-	    // we need to normalize after applying the hour and minute offsets
-	    android_text_format_Time_normalize(env, This, false /* use isdst */);
-	    // The timezone is set to UTC in the calling Java code.
-	}
+        if (offset != 0) {
+            // we need to normalize after applying the hour and minute offsets
+            android_text_format_Time_normalize(env, This, false /* use isdst */);
+            // The timezone is set to UTC in the calling Java code.
+        }
     } else {
-	env->SetBooleanField(This, g_allDayField, JNI_TRUE);
+        env->SetBooleanField(This, g_allDayField, JNI_TRUE);
         env->SetIntField(This, g_hourField, 0);
         env->SetIntField(This, g_minField, 0);
         env->SetIntField(This, g_secField, 0);
@@ -628,8 +623,7 @@
     env->SetIntField(This, g_ydayField, 0);
     env->SetIntField(This, g_isdstField, -1);
     env->SetLongField(This, g_gmtoffField, 0);
-    
-    env->ReleaseStringChars(strObj, s);
+
     return inUtc;
 }
 
diff --git a/core/jni/android_view_GLES20Canvas.cpp b/core/jni/android_view_GLES20Canvas.cpp
index 3538fef..7dbf9ec 100644
--- a/core/jni/android_view_GLES20Canvas.cpp
+++ b/core/jni/android_view_GLES20Canvas.cpp
@@ -776,6 +776,20 @@
     env->ReleaseIntArrayElements(layerInfo, storage, 0);
 }
 
+static void android_view_GLES20Canvas_setLayerPaint(JNIEnv* env, jobject clazz,
+        Layer* layer, SkPaint* paint) {
+    if (layer) {
+        layer->setPaint(paint);
+    }
+}
+
+static void android_view_GLES20Canvas_setLayerColorFilter(JNIEnv* env, jobject clazz,
+        Layer* layer, SkiaColorFilter* colorFilter) {
+    if (layer) {
+        layer->setColorFilter(colorFilter);
+    }
+}
+
 static void android_view_GLES20Canvas_setOpaqueLayer(JNIEnv* env, jobject clazz,
         Layer* layer, jboolean isOpaque) {
     if (layer) {
@@ -979,6 +993,8 @@
     { "nCreateLayerRenderer",    "(I)I",       (void*) android_view_GLES20Canvas_createLayerRenderer },
     { "nCreateLayer",            "(IIZ[I)I",   (void*) android_view_GLES20Canvas_createLayer },
     { "nResizeLayer",            "(III[I)V" ,  (void*) android_view_GLES20Canvas_resizeLayer },
+    { "nSetLayerPaint",          "(II)V",      (void*) android_view_GLES20Canvas_setLayerPaint },
+    { "nSetLayerColorFilter",    "(II)V",      (void*) android_view_GLES20Canvas_setLayerColorFilter },
     { "nSetOpaqueLayer",         "(IZ)V",      (void*) android_view_GLES20Canvas_setOpaqueLayer },
     { "nCreateTextureLayer",     "(Z[I)I",     (void*) android_view_GLES20Canvas_createTextureLayer },
     { "nUpdateTextureLayer",     "(IIIZLandroid/graphics/SurfaceTexture;)V",
diff --git a/core/jni/android_view_Surface.cpp b/core/jni/android_view_Surface.cpp
index 4fbfab6..90e85e6 100644
--- a/core/jni/android_view_Surface.cpp
+++ b/core/jni/android_view_Surface.cpp
@@ -66,6 +66,7 @@
     jfieldID mGenerationId;
     jfieldID mCanvas;
     jfieldID mCanvasSaveCount;
+    jmethodID ctor;
 } gSurfaceClassInfo;
 
 static struct {
@@ -231,6 +232,42 @@
     }
 }
 
+static sp<ISurfaceTexture> getISurfaceTexture(JNIEnv* env, jobject surfaceObj) {
+    if (surfaceObj) {
+        sp<Surface> surface(getSurface(env, surfaceObj));
+        if (surface != NULL) {
+            return surface->getSurfaceTexture();
+        }
+    }
+    return NULL;
+}
+
+jobject android_view_Surface_createFromISurfaceTexture(JNIEnv* env,
+        const sp<ISurfaceTexture>& surfaceTexture) {
+    if (surfaceTexture == NULL) {
+        return NULL;
+    }
+
+    sp<Surface> surface(new Surface(surfaceTexture));
+    if (surface == NULL) {
+        return NULL;
+    }
+
+    jobject surfaceObj = env->NewObject(gSurfaceClassInfo.clazz, gSurfaceClassInfo.ctor);
+    if (surfaceObj == NULL) {
+        if (env->ExceptionCheck()) {
+            ALOGE("Could not create instance of Surface from ISurfaceTexture.");
+            LOGE_EX(env);
+            env->ExceptionClear();
+        }
+        return NULL;
+    }
+
+    setSurface(env, surfaceObj, surface);
+    return surfaceObj;
+}
+
+
 // ----------------------------------------------------------------------------
 
 static void nativeCreate(JNIEnv* env, jobject surfaceObj, jobject sessionObj,
@@ -619,24 +656,12 @@
 }
 
 static void nativeSetDisplaySurface(JNIEnv* env, jclass clazz,
-        jobject tokenObj, jobject surfaceTextureObj) {
+        jobject tokenObj, jobject surfaceObj) {
     sp<IBinder> token(ibinderForJavaObject(env, tokenObj));
     if (token == NULL) return;
 
-    if (!surfaceTextureObj) {
-        SurfaceComposerClient::setDisplaySurface(token, NULL);
-        return;
-    }
-
-    sp<SurfaceTexture> st(SurfaceTexture_getSurfaceTexture(env, surfaceTextureObj));
-    if (st == NULL) {
-        jniThrowException(env, "java/lang/IllegalArgumentException",
-                "SurfaceTexture has already been released");
-        return;
-    }
-
-    sp<ISurfaceTexture> bq = st->getBufferQueue();
-    SurfaceComposerClient::setDisplaySurface(token, bq);
+    sp<ISurfaceTexture> surfaceTexture(getISurfaceTexture(env, surfaceObj));
+    SurfaceComposerClient::setDisplaySurface(token, surfaceTexture);
 }
 
 static void nativeSetDisplayLayerStack(JNIEnv* env, jclass clazz,
@@ -648,23 +673,23 @@
 }
 
 static void nativeSetDisplayProjection(JNIEnv* env, jclass clazz,
-        jobject tokenObj, jint orientation, jobject rect1Obj, jobject rect2Obj) {
+        jobject tokenObj, jint orientation, jobject layerStackRectObj, jobject displayRectObj) {
     sp<IBinder> token(ibinderForJavaObject(env, tokenObj));
     if (token == NULL) return;
 
-    Rect rect1;
-    rect1.left = env->GetIntField(rect1Obj, gRectClassInfo.left);
-    rect1.top = env->GetIntField(rect1Obj, gRectClassInfo.top);
-    rect1.right = env->GetIntField(rect1Obj, gRectClassInfo.right);
-    rect1.bottom = env->GetIntField(rect1Obj, gRectClassInfo.bottom);
+    Rect layerStackRect;
+    layerStackRect.left = env->GetIntField(layerStackRectObj, gRectClassInfo.left);
+    layerStackRect.top = env->GetIntField(layerStackRectObj, gRectClassInfo.top);
+    layerStackRect.right = env->GetIntField(layerStackRectObj, gRectClassInfo.right);
+    layerStackRect.bottom = env->GetIntField(layerStackRectObj, gRectClassInfo.bottom);
 
-    Rect rect2;
-    rect2.left = env->GetIntField(rect2Obj, gRectClassInfo.left);
-    rect2.top = env->GetIntField(rect2Obj, gRectClassInfo.top);
-    rect2.right = env->GetIntField(rect2Obj, gRectClassInfo.right);
-    rect2.bottom = env->GetIntField(rect2Obj, gRectClassInfo.bottom);
+    Rect displayRect;
+    displayRect.left = env->GetIntField(displayRectObj, gRectClassInfo.left);
+    displayRect.top = env->GetIntField(displayRectObj, gRectClassInfo.top);
+    displayRect.right = env->GetIntField(displayRectObj, gRectClassInfo.right);
+    displayRect.bottom = env->GetIntField(displayRectObj, gRectClassInfo.bottom);
 
-    SurfaceComposerClient::setDisplayProjection(token, orientation, rect1, rect2);
+    SurfaceComposerClient::setDisplayProjection(token, orientation, layerStackRect, displayRect);
 }
 
 static jboolean nativeGetDisplayInfo(JNIEnv* env, jclass clazz,
@@ -800,7 +825,7 @@
             (void*)nativeGetBuiltInDisplay },
     {"nativeCreateDisplay", "(Ljava/lang/String;)Landroid/os/IBinder;",
             (void*)nativeCreateDisplay },
-    {"nativeSetDisplaySurface", "(Landroid/os/IBinder;Landroid/graphics/SurfaceTexture;)V",
+    {"nativeSetDisplaySurface", "(Landroid/os/IBinder;Landroid/view/Surface;)V",
             (void*)nativeSetDisplaySurface },
     {"nativeSetDisplayLayerStack", "(Landroid/os/IBinder;I)V",
             (void*)nativeSetDisplayLayerStack },
@@ -835,6 +860,7 @@
             env->GetFieldID(gSurfaceClassInfo.clazz, "mCanvas", "Landroid/graphics/Canvas;");
     gSurfaceClassInfo.mCanvasSaveCount =
             env->GetFieldID(gSurfaceClassInfo.clazz, "mCanvasSaveCount", "I");
+    gSurfaceClassInfo.ctor = env->GetMethodID(gSurfaceClassInfo.clazz, "<init>", "()V");
 
     clazz = env->FindClass("android/graphics/Canvas");
     gCanvasClassInfo.mNativeCanvas = env->GetFieldID(clazz, "mNativeCanvas", "I");
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index f5f1109..560021d 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -108,6 +108,8 @@
     <protected-broadcast
         android:name="android.bluetooth.pan.profile.action.CONNECTION_STATE_CHANGED" />
 
+    <protected-broadcast android:name="android.hardware.display.action.WIFI_DISPLAY_STATUS_CHANGED" />
+
     <protected-broadcast android:name="android.hardware.usb.action.USB_STATE" />
     <protected-broadcast android:name="android.hardware.usb.action.USB_ACCESSORY_ATTACHED" />
     <protected-broadcast android:name="android.hardware.usb.action.USB_ACCESSORY_ATTACHED" />
@@ -1285,6 +1287,12 @@
         android:description="@string/permdesc_retrieve_window_info"
         android:protectionLevel="signature" />
 
+    <!-- @hide Allows an application to magnify the content of a display. -->
+    <permission android:name="android.permission.MAGNIFY_DISPLAY"
+        android:label="@string/permlab_magnify_display"
+        android:description="@string/permdesc_magnify_display"
+        android:protectionLevel="signature" />
+
     <!-- Allows an application to watch and control how activities are
          started globally in the system.  Only for is in debugging
          (usually the monkey command). -->
@@ -1440,6 +1448,22 @@
         android:description="@string/permdesc_readFrameBuffer"
         android:protectionLevel="signature|system" />
 
+    <!-- Allows an application to configure and connect to Wifi displays
+         @hide -->
+    <permission android:name="android.permission.CONFIGURE_WIFI_DISPLAY"
+        android:label="@string/permlab_configureWifiDisplay"
+        android:description="@string/permdesc_configureWifiDisplay"
+        android:protectionLevel="signature" />
+
+    <!-- Allows an application to control low-level features of Wifi displays
+         such as opening an RTSP socket.  This permission should only be used
+         by the display manager.
+         @hide -->
+    <permission android:name="android.permission.CONTROL_WIFI_DISPLAY"
+        android:label="@string/permlab_controlWifiDisplay"
+        android:description="@string/permdesc_controlWifiDisplay"
+        android:protectionLevel="signature" />
+
     <!-- Required to be able to disable the device (very dangerous!). -->
     <permission android:name="android.permission.BRICK"
         android:label="@string/permlab_brick"
diff --git a/core/res/res/drawable-nodpi/magnified_region_frame.9.png b/core/res/res/drawable-nodpi/magnified_region_frame.9.png
new file mode 100644
index 0000000..4cadefb
--- /dev/null
+++ b/core/res/res/drawable-nodpi/magnified_region_frame.9.png
Binary files differ
diff --git a/core/res/res/drawable/progress_horizontal_holo_dark.xml b/core/res/res/drawable/progress_horizontal_holo_dark.xml
index ff270b3..bc1ecf3 100644
--- a/core/res/res/drawable/progress_horizontal_holo_dark.xml
+++ b/core/res/res/drawable/progress_horizontal_holo_dark.xml
@@ -21,11 +21,13 @@
 
     <item android:id="@android:id/secondaryProgress">
         <scale android:scaleWidth="100%"
+               android:scaleGravity="start"
                android:drawable="@android:drawable/progress_secondary_holo_dark" />
     </item>
 
     <item android:id="@android:id/progress">
         <scale android:scaleWidth="100%"
+               android:scaleGravity="start"
                android:drawable="@android:drawable/progress_primary_holo_dark" />
     </item>
 
diff --git a/core/res/res/drawable/progress_horizontal_holo_light.xml b/core/res/res/drawable/progress_horizontal_holo_light.xml
index 4935185..ee9b629 100644
--- a/core/res/res/drawable/progress_horizontal_holo_light.xml
+++ b/core/res/res/drawable/progress_horizontal_holo_light.xml
@@ -21,11 +21,13 @@
 
     <item android:id="@android:id/secondaryProgress">
         <scale android:scaleWidth="100%"
+               android:scaleGravity="start"
                android:drawable="@android:drawable/progress_secondary_holo_light" />
     </item>
 
     <item android:id="@android:id/progress">
         <scale android:scaleWidth="100%"
+               android:scaleGravity="start"
                android:drawable="@android:drawable/progress_primary_holo_light" />
     </item>
 
diff --git a/core/res/res/drawable/scrubber_progress_horizontal_holo_dark.xml b/core/res/res/drawable/scrubber_progress_horizontal_holo_dark.xml
index b117bb8..4d83191 100644
--- a/core/res/res/drawable/scrubber_progress_horizontal_holo_dark.xml
+++ b/core/res/res/drawable/scrubber_progress_horizontal_holo_dark.xml
@@ -19,10 +19,12 @@
             android:drawable="@android:drawable/scrubber_track_holo_dark" />
     <item android:id="@android:id/secondaryProgress">
         <scale android:scaleWidth="100%"
-                android:drawable="@android:drawable/scrubber_secondary_holo" />
+               android:scaleGravity="start"
+               android:drawable="@android:drawable/scrubber_secondary_holo" />
     </item>
     <item android:id="@android:id/progress">
         <scale android:scaleWidth="100%"
-                android:drawable="@android:drawable/scrubber_primary_holo" />
+               android:scaleGravity="start"
+               android:drawable="@android:drawable/scrubber_primary_holo" />
     </item>
 </layer-list>
diff --git a/core/res/res/drawable/scrubber_progress_horizontal_holo_light.xml b/core/res/res/drawable/scrubber_progress_horizontal_holo_light.xml
index 6cd08ea..a3461fa 100644
--- a/core/res/res/drawable/scrubber_progress_horizontal_holo_light.xml
+++ b/core/res/res/drawable/scrubber_progress_horizontal_holo_light.xml
@@ -19,10 +19,12 @@
             android:drawable="@android:drawable/scrubber_track_holo_light" />
     <item android:id="@android:id/secondaryProgress">
         <scale android:scaleWidth="100%"
-                android:drawable="@android:drawable/scrubber_secondary_holo" />
+               android:scaleGravity="start"
+               android:drawable="@android:drawable/scrubber_secondary_holo" />
     </item>
     <item android:id="@android:id/progress">
         <scale android:scaleWidth="100%"
-                android:drawable="@android:drawable/scrubber_primary_holo" />
+               android:scaleGravity="start"
+               android:drawable="@android:drawable/scrubber_primary_holo" />
     </item>
 </layer-list>
diff --git a/core/res/res/layout-land/keyguard_host_view.xml b/core/res/res/layout-land/keyguard_host_view.xml
index b404155..0028a54 100644
--- a/core/res/res/layout-land/keyguard_host_view.xml
+++ b/core/res/res/layout-land/keyguard_host_view.xml
@@ -45,13 +45,8 @@
         android:layout_weight="1"
         android:gravity="center">
 
+        <!-- SelectorView is always used, so add it here. The rest are loaded dynamically -->
         <include layout="@layout/keyguard_selector_view"/>
-        <include layout="@layout/keyguard_account_view"/>
-        <include layout="@layout/keyguard_pattern_view"/>
-        <include layout="@layout/keyguard_password_view"/>
-        <include layout="@layout/keyguard_sim_pin_view"/>
-        <include layout="@layout/keyguard_sim_puk_view"/>
-        <include layout="@layout/keyguard_face_unlock_view"/>
 
     </ViewFlipper>
 
diff --git a/core/res/res/layout-port/keyguard_host_view.xml b/core/res/res/layout-port/keyguard_host_view.xml
index 5dc2225..5e467d1 100644
--- a/core/res/res/layout-port/keyguard_host_view.xml
+++ b/core/res/res/layout-port/keyguard_host_view.xml
@@ -33,13 +33,8 @@
         android:layout_height="match_parent"
         android:gravity="center">
 
+        <!-- SelectorView is always used, so add it here. The rest are loaded dynamically -->
         <include layout="@layout/keyguard_selector_view"/>
-        <include layout="@layout/keyguard_account_view"/>
-        <include layout="@layout/keyguard_pattern_view"/>
-        <include layout="@layout/keyguard_password_view"/>
-        <include layout="@layout/keyguard_sim_pin_view"/>
-        <include layout="@layout/keyguard_sim_puk_view"/>
-        <include layout="@layout/keyguard_face_unlock_view"/>
 
     </ViewFlipper>
 
diff --git a/core/res/res/layout-sw600dp-land/keyguard_host_view.xml b/core/res/res/layout-sw600dp-land/keyguard_host_view.xml
index e77f584..5b6bb2f 100644
--- a/core/res/res/layout-sw600dp-land/keyguard_host_view.xml
+++ b/core/res/res/layout-sw600dp-land/keyguard_host_view.xml
@@ -52,13 +52,8 @@
             android:layout_weight="1"
             android:gravity="center">
 
+            <!-- SelectorView is always used, so add it here. The rest are loaded dynamically -->
             <include layout="@layout/keyguard_selector_view"/>
-            <include layout="@layout/keyguard_account_view"/>
-            <include layout="@layout/keyguard_pattern_view"/>
-            <include layout="@layout/keyguard_password_view"/>
-            <include layout="@layout/keyguard_sim_pin_view"/>
-            <include layout="@layout/keyguard_sim_puk_view"/>
-            <include layout="@layout/keyguard_face_unlock_view"/>
 
         </ViewFlipper>
 
diff --git a/core/res/res/layout-sw600dp-port/keyguard_host_view.xml b/core/res/res/layout-sw600dp-port/keyguard_host_view.xml
index 50636f1..397b881 100644
--- a/core/res/res/layout-sw600dp-port/keyguard_host_view.xml
+++ b/core/res/res/layout-sw600dp-port/keyguard_host_view.xml
@@ -32,7 +32,7 @@
         android:id="@+id/app_widget_container"
         android:layout_width="match_parent"
         android:layout_height="0dip"
-        android:layout_weight="1"
+        android:layout_weight="0.4"
         android:visibility="gone">
 
         <!-- TODO: Remove this once supported as a widget -->
@@ -44,16 +44,11 @@
         android:id="@+id/view_flipper"
         android:layout_width="@dimen/kg_security_view_width"
         android:layout_height="0dip"
-        android:layout_weight="1"
+        android:layout_weight="0.6"
         android:layout_gravity="center">
 
+        <!-- SelectorView is always used, so add it here. The rest are loaded dynamically -->
         <include layout="@layout/keyguard_selector_view"/>
-        <include layout="@layout/keyguard_account_view"/>
-        <include layout="@layout/keyguard_pattern_view"/>
-        <include layout="@layout/keyguard_password_view"/>
-        <include layout="@layout/keyguard_sim_pin_view"/>
-        <include layout="@layout/keyguard_sim_puk_view"/>
-        <include layout="@layout/keyguard_face_unlock_view"/>
 
     </ViewFlipper>
 
diff --git a/core/res/res/layout/keyguard_multi_user_avatar.xml b/core/res/res/layout/keyguard_multi_user_avatar.xml
new file mode 100644
index 0000000..9999177
--- /dev/null
+++ b/core/res/res/layout/keyguard_multi_user_avatar.xml
@@ -0,0 +1,40 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+**
+** Copyright 2009, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License")
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+-->
+
+<!-- This is a view that shows general status information in Keyguard. -->
+<com.android.internal.policy.impl.keyguard.KeyguardMultiUserAvatar
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="125dp"
+    android:layout_height="125dp"
+    android:background="#550000ff"
+    android:gravity="center_horizontal">
+    <ImageView
+        android:id="@+id/keyguard_user_avatar"
+        android:layout_width="match_parent"
+        android:layout_height="match_parent"
+        android:layout_gravity="center"/>
+    <TextView
+        android:id="@+id/keyguard_user_name"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_gravity="bottom|right"
+        android:textSize="12sp"
+        android:background="#99FFFFFF"
+        android:textColor="#ff000000"/>
+</com.android.internal.policy.impl.keyguard.KeyguardMultiUserAvatar>
\ No newline at end of file
diff --git a/core/res/res/layout/keyguard_multi_user_selector.xml b/core/res/res/layout/keyguard_multi_user_selector.xml
new file mode 100644
index 0000000..3ed9103
--- /dev/null
+++ b/core/res/res/layout/keyguard_multi_user_selector.xml
@@ -0,0 +1,41 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+**
+** Copyright 2009, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License")
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+-->
+<com.android.internal.policy.impl.keyguard.KeyguardMultiUserSelectorView
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:orientation="horizontal"
+    android:layout_width="375dp"
+    android:layout_height="wrap_content"
+    android:layout_gravity="center">
+
+    <include
+        android:id="@+id/keyguard_active_user"
+        android:layout_width="250dp"
+        android:layout_height="250dp"
+        layout="@layout/keyguard_multi_user_avatar"/>
+
+    <ScrollView
+        android:layout_width="125dp"
+        android:layout_height="250dp">
+        <LinearLayout
+            android:id="@+id/keyguard_inactive_users"
+            android:orientation="vertical"
+            layout_width="match_parent"
+            layout_height="wrap_content"/>
+    </ScrollView>
+</com.android.internal.policy.impl.keyguard.KeyguardMultiUserSelectorView>
\ No newline at end of file
diff --git a/core/res/res/layout/keyguard_multi_user_selector_widget.xml b/core/res/res/layout/keyguard_multi_user_selector_widget.xml
new file mode 100644
index 0000000..c00089c
--- /dev/null
+++ b/core/res/res/layout/keyguard_multi_user_selector_widget.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+**
+** Copyright 2009, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License")
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+-->
+
+<!-- This is a view that shows general status information in Keyguard. -->
+<com.android.internal.policy.impl.keyguard.KeyguardWidgetFrame
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent">
+
+    <include layout="@layout/keyguard_multi_user_selector"/>
+
+</com.android.internal.policy.impl.keyguard.KeyguardWidgetFrame>
\ No newline at end of file
diff --git a/core/res/res/layout/keyguard_selector_view.xml b/core/res/res/layout/keyguard_selector_view.xml
index d516369..d7f98f9 100644
--- a/core/res/res/layout/keyguard_selector_view.xml
+++ b/core/res/res/layout/keyguard_selector_view.xml
@@ -32,7 +32,7 @@
         android:layout_height="0dip"
         android:layout_weight="1"
         android:visibility="gone">
-            <!-- TODO: Remove this once supported as a widget -->
+            <!-- TODO: Remove this when supported as a widget -->
             <include layout="@layout/keyguard_status_view"/>
     </com.android.internal.policy.impl.keyguard.KeyguardWidgetPager>
 
diff --git a/core/res/res/values-af/strings.xml b/core/res/res/values-af/strings.xml
index 2eaf87a..01d440a 100644
--- a/core/res/res/values-af/strings.xml
+++ b/core/res/res/values-af/strings.xml
@@ -547,10 +547,8 @@
     <string name="permdesc_sdcardWrite" product="default" msgid="4337417790936632090">"Laat die program toe om na die SD-kaart te skryf."</string>
     <string name="permlab_mediaStorageWrite" product="default" msgid="6859839199706879015">"verander/vee uit interne mediabergingsinhoud"</string>
     <string name="permdesc_mediaStorageWrite" product="default" msgid="8189160597698529185">"Laat die program toe om die inhoud van die interne mediaberging te verander."</string>
-    <!-- no translation found for permlab_sdcardAccessAll (8150613823900460576) -->
-    <skip />
-    <!-- no translation found for permdesc_sdcardAccessAll (3215208357415891320) -->
-    <skip />
+    <string name="permlab_sdcardAccessAll" msgid="8150613823900460576">"verkry toegang tot alle gebruikers se eksterne berging"</string>
+    <string name="permdesc_sdcardAccessAll" msgid="3215208357415891320">"Laat die program toe om toegang tot eksterne berging vir alle gebruikers te verkry."</string>
     <string name="permlab_cache_filesystem" msgid="5656487264819669824">"lees die kaslêerstelsel"</string>
     <string name="permdesc_cache_filesystem" msgid="5578967642265550955">"Laat die program toe om die kaslêerstelsel te lees en skryf."</string>
     <string name="permlab_use_sip" msgid="5986952362795870502">"maak/ontvang internetoproepe"</string>
@@ -581,6 +579,10 @@
     <string name="policydesc_encryptedStorage" msgid="2637732115325316992">"Vereis dat gestoorde programdata geënkripteer word."</string>
     <string name="policylab_disableCamera" msgid="6395301023152297826">"Deaktiveer kameras"</string>
     <string name="policydesc_disableCamera" msgid="2306349042834754597">"Voorkom die gebruik van alle toestelkameras."</string>
+    <!-- no translation found for policylab_disableKeyguardWidgets (1794894613389073926) -->
+    <skip />
+    <!-- no translation found for policydesc_disableKeyguardWidgets (7254624892984033592) -->
+    <skip />
   <string-array name="phoneTypes">
     <item msgid="8901098336658710359">"Tuis"</item>
     <item msgid="869923650527136615">"Mobiel"</item>
@@ -1173,7 +1175,7 @@
     <string name="vpn_text_long" msgid="6407351006249174473">"Gekoppel aan <xliff:g id="SESSION">%s</xliff:g>. Raak om die netwerk te bestuur."</string>
     <string name="vpn_lockdown_connecting" msgid="6443438964440960745">"Altydaan-VPN koppel tans..."</string>
     <string name="vpn_lockdown_connected" msgid="8202679674819213931">"Altydaan-VPN gekoppel"</string>
-    <string name="vpn_lockdown_error" msgid="6009249814034708175">"Altydaan-VPN se fout"</string>
+    <string name="vpn_lockdown_error" msgid="6009249814034708175">"Altydaan-VPN-fout"</string>
     <string name="vpn_lockdown_reset" msgid="5365010427963548932">"Raak om verbinding terug te stel"</string>
     <string name="upload_file" msgid="2897957172366730416">"Kies lêer"</string>
     <string name="no_file_chosen" msgid="6363648562170759465">"Geen lêer gekies nie"</string>
@@ -1319,64 +1321,46 @@
     <string name="bluetooth_a2dp_audio_route_name" msgid="8575624030406771015">"Bluetooth-oudio"</string>
     <string name="media_route_chooser_grouping_done" msgid="7966438307723317169">"Klaar"</string>
     <string name="media_route_button_content_description" msgid="5758553567065145276">"Media-uitvoer"</string>
-    <!-- no translation found for display_manager_built_in_display_name (2583134294292563941) -->
+    <string name="display_manager_built_in_display_name" msgid="2583134294292563941">"Ingeboude skerm"</string>
+    <!-- no translation found for display_manager_hdmi_display_name (1555264559227470109) -->
     <skip />
-    <!-- no translation found for display_manager_overlay_display_name (5142365982271620716) -->
+    <string name="display_manager_overlay_display_name" msgid="5142365982271620716">"Oorlegger #<xliff:g id="ID">%1$d</xliff:g>"</string>
+    <!-- no translation found for display_manager_overlay_display_title (652124517672257172) -->
     <skip />
-    <!-- no translation found for display_manager_overlay_display_title (8186674340178573982) -->
-    <skip />
-    <!-- no translation found for kg_emergency_call_label (684946192523830531) -->
-    <skip />
-    <!-- no translation found for kg_forgot_pattern_button_text (8852021467868220608) -->
-    <skip />
-    <!-- no translation found for kg_wrong_pattern (1850806070801358830) -->
-    <skip />
-    <!-- no translation found for kg_wrong_password (2333281762128113157) -->
-    <skip />
-    <!-- no translation found for kg_wrong_pin (1131306510833563801) -->
-    <skip />
-    <!-- no translation found for kg_too_many_failed_attempts_countdown (353963338189371686) -->
-    <skip />
-    <!-- no translation found for kg_pattern_instructions (398978611683075868) -->
-    <skip />
-    <!-- no translation found for kg_sim_pin_instructions (2319508550934557331) -->
-    <skip />
-    <!-- no translation found for kg_pin_instructions (2377242233495111557) -->
-    <skip />
-    <!-- no translation found for kg_password_instructions (5753646556186936819) -->
-    <skip />
-    <!-- no translation found for kg_puk_enter_puk_hint (5183097160254244459) -->
-    <skip />
-    <!-- no translation found for kg_puk_enter_pin_hint (597821135578014901) -->
-    <skip />
-    <!-- no translation found for kg_sim_unlock_progress_dialog_message (8950398016976865762) -->
-    <skip />
-    <!-- no translation found for kg_password_wrong_pin_code (1139324887413846912) -->
-    <skip />
-    <!-- no translation found for kg_invalid_sim_pin_hint (8795159358110620001) -->
-    <skip />
-    <!-- no translation found for kg_invalid_sim_puk_hint (5216603185442368307) -->
-    <skip />
-    <!-- no translation found for kg_sim_puk_recovery_hint (5577753137718442566) -->
-    <skip />
-    <!-- no translation found for kg_invalid_puk (5809955359950817326) -->
-    <skip />
-    <!-- no translation found for kg_login_too_many_attempts (6486842094005698475) -->
-    <skip />
-    <!-- no translation found for kg_login_instructions (1100551261265506448) -->
-    <skip />
-    <!-- no translation found for kg_login_username_hint (5718534272070920364) -->
-    <skip />
-    <!-- no translation found for kg_login_password_hint (9057289103827298549) -->
-    <skip />
-    <!-- no translation found for kg_login_submit_button (5355904582674054702) -->
-    <skip />
-    <!-- no translation found for kg_login_invalid_input (5754664119319872197) -->
-    <skip />
-    <!-- no translation found for kg_login_account_recovery_hint (5690709132841752974) -->
-    <skip />
-    <!-- no translation found for kg_login_checking_password (8849589033659332457) -->
-    <skip />
-    <!-- no translation found for kg_temp_back_string (5812983904056640466) -->
-    <skip />
+    <string name="kg_emergency_call_label" msgid="684946192523830531">"Noodoproep"</string>
+    <string name="kg_forgot_pattern_button_text" msgid="8852021467868220608">"Het jy die patroon vergeet?"</string>
+    <string name="kg_wrong_pattern" msgid="1850806070801358830">"Verkeerde patroon"</string>
+    <string name="kg_wrong_password" msgid="2333281762128113157">"Verkeerde wagwoord"</string>
+    <string name="kg_wrong_pin" msgid="1131306510833563801">"Verkeerde PIN"</string>
+    <string name="kg_too_many_failed_attempts_countdown" msgid="6358110221603297548">"Probeer weer in <xliff:g id="NUMBER">%d</xliff:g> sekondes."</string>
+    <string name="kg_pattern_instructions" msgid="398978611683075868">"Teken jou patroon"</string>
+    <string name="kg_sim_pin_instructions" msgid="2319508550934557331">"Voer SIM-PIN in"</string>
+    <string name="kg_pin_instructions" msgid="2377242233495111557">"Voer PIN in"</string>
+    <string name="kg_password_instructions" msgid="5753646556186936819">"Voer wagwoord in"</string>
+    <string name="kg_puk_enter_puk_hint" msgid="5183097160254244459">"PUK-kode"</string>
+    <string name="kg_puk_enter_pin_hint" msgid="597821135578014901">"Nuwe PIN-kode"</string>
+    <string name="kg_sim_unlock_progress_dialog_message" msgid="8950398016976865762">"Ontsluit tans SIM-kaart…"</string>
+    <string name="kg_password_wrong_pin_code" msgid="1139324887413846912">"Verkeerde PIN-kode."</string>
+    <string name="kg_invalid_sim_pin_hint" msgid="8795159358110620001">"Tik \'n PIN in wat 4 tot 8 nommers lank is."</string>
+    <string name="kg_invalid_sim_puk_hint" msgid="5216603185442368307">"Tik \'n PUK in wat 8 nommers of meer is."</string>
+    <string name="kg_sim_puk_recovery_hint" msgid="5577753137718442566">"Voer PUK en nuwe PIN-kode in"</string>
+    <string name="kg_invalid_puk" msgid="5809955359950817326">"Jy het die verkeerde PUK getik."</string>
+    <string name="kg_login_too_many_attempts" msgid="6486842094005698475">"Te veel patroonpogings"</string>
+    <string name="kg_login_instructions" msgid="1100551261265506448">"Om te ontsluit, meld met jou Google-rekening aan."</string>
+    <string name="kg_login_username_hint" msgid="5718534272070920364">"Gebruikernaam (e-pos)"</string>
+    <string name="kg_login_password_hint" msgid="9057289103827298549">"Wagwoord"</string>
+    <string name="kg_login_submit_button" msgid="5355904582674054702">"Meld aan"</string>
+    <string name="kg_login_invalid_input" msgid="5754664119319872197">"Ongeldige gebruikernaam of wagwoord."</string>
+    <string name="kg_login_account_recovery_hint" msgid="5690709132841752974">"Het jy jou gebruikernaam of wagwoord vergeet?"\n"Besoek"<b>"google.com/accounts/recovery"</b>"."</string>
+    <string name="kg_login_checking_password" msgid="8849589033659332457">"Kontroleer tans..."</string>
+    <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="8276745642049502550">"Jy het jou PIN <xliff:g id="NUMBER_0">%d</xliff:g> keer verkeerd ingetik. "\n\n"Probeer weer in <xliff:g id="NUMBER_1">%d</xliff:g> sekondes."</string>
+    <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="7813713389422226531">"Jy het <xliff:g id="NUMBER_0">%d</xliff:g> keer jou wagwoord verkeerdelik getik. "\n\n"Probeer weer in <xliff:g id="NUMBER_1">%d</xliff:g> sekondes."</string>
+    <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="74089475965050805">"Jy het jou ontsluitpatroon <xliff:g id="NUMBER_0">%d</xliff:g> keer verkeerdelik geteken. "\n\n"Probeer weer in <xliff:g id="NUMBER_1">%d</xliff:g> sekondes."</string>
+    <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="1575557200627128949">"Jy het <xliff:g id="NUMBER_0">%d</xliff:g> keer verkeerdelik gepoog om die tablet te ontsluit. Na nog<xliff:g id="NUMBER_1">%d</xliff:g> onsuksesvolle pogings, sal die tablet na die fabrieksverstek teruggestel word en al die gebruikerdata sal verlore wees."</string>
+    <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="4051015943038199910">"Jy het <xliff:g id="NUMBER_0">%d</xliff:g> keer verkeerdelik gepoog om die foon te ontsluit. Na nog<xliff:g id="NUMBER_1">%d</xliff:g> onsuksesvolle pogings, sal die foon na die fabrieksverstek teruggestel word en al die gebruikerdata sal verlore wees."</string>
+    <string name="kg_failed_attempts_now_wiping" product="tablet" msgid="2072996269148483637">"Jy het <xliff:g id="NUMBER">%d</xliff:g> keer verkeerdelik gepoog om die tablet te ontsluit. Die tablet sal nou na fabrieksverstek teruggestel word."</string>
+    <string name="kg_failed_attempts_now_wiping" product="default" msgid="4817627474419471518">"Jy het <xliff:g id="NUMBER">%d</xliff:g> keer verkeerdelik gepoog om die foon te ontsluit. Die foon sal nou na fabrieksverstek teruggestel word."</string>
+    <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"Jy het jou ontsluitpatroon <xliff:g id="NUMBER_0">%d</xliff:g> keer verkeerdelik geteken. Na nog <xliff:g id="NUMBER_1">%d</xliff:g> onsuksesvolle pogings, sal jy gevra word om jou tablet te ontsluit deur \'n e-posrekening te gebruik."\n\n" Probeer weer in <xliff:g id="NUMBER_2">%d</xliff:g> sekondes."</string>
+    <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"Jy het jou ontsluitpatroon <xliff:g id="NUMBER_0">%d</xliff:g> keer verkeerdelik geteken. Na nog <xliff:g id="NUMBER_1">%d</xliff:g> onsuksesvolle pogings, sal jy gevra word om jou foon te ontsluit deur \'n e-posrekening te gebruik."\n\n" Probeer weer in <xliff:g id="NUMBER_2">%d</xliff:g> sekondes."</string>
+    <string name="kg_temp_back_string" msgid="5812983904056640466">"&lt;"</string>
 </resources>
diff --git a/core/res/res/values-am/strings.xml b/core/res/res/values-am/strings.xml
index bbe666a..9d06464 100644
--- a/core/res/res/values-am/strings.xml
+++ b/core/res/res/values-am/strings.xml
@@ -547,10 +547,8 @@
     <string name="permdesc_sdcardWrite" product="default" msgid="4337417790936632090">"መተግበሪያውን ወደ SD ካርድ ለመፃፍ ይፈቅዳል።"</string>
     <string name="permlab_mediaStorageWrite" product="default" msgid="6859839199706879015">"የውስጥ ማህደረ መረጃ ማከማቻ ይዘቶችን ቀይር/ሰርዝ"</string>
     <string name="permdesc_mediaStorageWrite" product="default" msgid="8189160597698529185">"የውስጥ ማህደረ መረጃ ማከማቻ ይዘትን ለመቀየር ለመተግበሪያው ይፈቅዳሉ፡፡"</string>
-    <!-- no translation found for permlab_sdcardAccessAll (8150613823900460576) -->
-    <skip />
-    <!-- no translation found for permdesc_sdcardAccessAll (3215208357415891320) -->
-    <skip />
+    <string name="permlab_sdcardAccessAll" msgid="8150613823900460576">"የሁሉም ተጠቃሚዎች ውጫዊ ማከማቻውን ይደርስበታል"</string>
+    <string name="permdesc_sdcardAccessAll" msgid="3215208357415891320">"መተግበሪያውን የሁሉም ተጠቃሚዎች ውጫዊ ማከማቻውን እንዲደርስ ይፈቅድለታል።"</string>
     <string name="permlab_cache_filesystem" msgid="5656487264819669824">"የመሸጎጫ ስርዓተ ፋይል ድረስ"</string>
     <string name="permdesc_cache_filesystem" msgid="5578967642265550955">"መሸጎጫ ስርዓተ ፋይል ለማንበብ እና ለመፃፍ ለመተግበሪያው ይፈቅዳሉ።"</string>
     <string name="permlab_use_sip" msgid="5986952362795870502">"የበይነ መረብ ጥሪዎች አድርግ/ተቀበል"</string>
@@ -581,6 +579,10 @@
     <string name="policydesc_encryptedStorage" msgid="2637732115325316992">"የተከማቸ ትግበራ ውሂብ የተመሰጠረ እንዲሆን ጠይቅ።"</string>
     <string name="policylab_disableCamera" msgid="6395301023152297826">"ካሜራዎችን አቦዝን"</string>
     <string name="policydesc_disableCamera" msgid="2306349042834754597">"የሁሉንም መሣሪያ ካሜራዎች መጠቀም ከልክል።"</string>
+    <!-- no translation found for policylab_disableKeyguardWidgets (1794894613389073926) -->
+    <skip />
+    <!-- no translation found for policydesc_disableKeyguardWidgets (7254624892984033592) -->
+    <skip />
   <string-array name="phoneTypes">
     <item msgid="8901098336658710359">"መነሻ"</item>
     <item msgid="869923650527136615">"ተንቀሳቃሽ"</item>
@@ -1319,64 +1321,46 @@
     <string name="bluetooth_a2dp_audio_route_name" msgid="8575624030406771015">"የብሉቱዝ ድምጽ"</string>
     <string name="media_route_chooser_grouping_done" msgid="7966438307723317169">"ተከናውኗል"</string>
     <string name="media_route_button_content_description" msgid="5758553567065145276">"የሚዲያ ውጽዓት"</string>
-    <!-- no translation found for display_manager_built_in_display_name (2583134294292563941) -->
+    <string name="display_manager_built_in_display_name" msgid="2583134294292563941">"ውስጥ የተሰራ ማያ ገጽ"</string>
+    <!-- no translation found for display_manager_hdmi_display_name (1555264559227470109) -->
     <skip />
-    <!-- no translation found for display_manager_overlay_display_name (5142365982271620716) -->
+    <string name="display_manager_overlay_display_name" msgid="5142365982271620716">"ተደራቢ #<xliff:g id="ID">%1$d</xliff:g>"</string>
+    <!-- no translation found for display_manager_overlay_display_title (652124517672257172) -->
     <skip />
-    <!-- no translation found for display_manager_overlay_display_title (8186674340178573982) -->
-    <skip />
-    <!-- no translation found for kg_emergency_call_label (684946192523830531) -->
-    <skip />
-    <!-- no translation found for kg_forgot_pattern_button_text (8852021467868220608) -->
-    <skip />
-    <!-- no translation found for kg_wrong_pattern (1850806070801358830) -->
-    <skip />
-    <!-- no translation found for kg_wrong_password (2333281762128113157) -->
-    <skip />
-    <!-- no translation found for kg_wrong_pin (1131306510833563801) -->
-    <skip />
-    <!-- no translation found for kg_too_many_failed_attempts_countdown (353963338189371686) -->
-    <skip />
-    <!-- no translation found for kg_pattern_instructions (398978611683075868) -->
-    <skip />
-    <!-- no translation found for kg_sim_pin_instructions (2319508550934557331) -->
-    <skip />
-    <!-- no translation found for kg_pin_instructions (2377242233495111557) -->
-    <skip />
-    <!-- no translation found for kg_password_instructions (5753646556186936819) -->
-    <skip />
-    <!-- no translation found for kg_puk_enter_puk_hint (5183097160254244459) -->
-    <skip />
-    <!-- no translation found for kg_puk_enter_pin_hint (597821135578014901) -->
-    <skip />
-    <!-- no translation found for kg_sim_unlock_progress_dialog_message (8950398016976865762) -->
-    <skip />
-    <!-- no translation found for kg_password_wrong_pin_code (1139324887413846912) -->
-    <skip />
-    <!-- no translation found for kg_invalid_sim_pin_hint (8795159358110620001) -->
-    <skip />
-    <!-- no translation found for kg_invalid_sim_puk_hint (5216603185442368307) -->
-    <skip />
-    <!-- no translation found for kg_sim_puk_recovery_hint (5577753137718442566) -->
-    <skip />
-    <!-- no translation found for kg_invalid_puk (5809955359950817326) -->
-    <skip />
-    <!-- no translation found for kg_login_too_many_attempts (6486842094005698475) -->
-    <skip />
-    <!-- no translation found for kg_login_instructions (1100551261265506448) -->
-    <skip />
-    <!-- no translation found for kg_login_username_hint (5718534272070920364) -->
-    <skip />
-    <!-- no translation found for kg_login_password_hint (9057289103827298549) -->
-    <skip />
-    <!-- no translation found for kg_login_submit_button (5355904582674054702) -->
-    <skip />
-    <!-- no translation found for kg_login_invalid_input (5754664119319872197) -->
-    <skip />
-    <!-- no translation found for kg_login_account_recovery_hint (5690709132841752974) -->
-    <skip />
-    <!-- no translation found for kg_login_checking_password (8849589033659332457) -->
-    <skip />
-    <!-- no translation found for kg_temp_back_string (5812983904056640466) -->
-    <skip />
+    <string name="kg_emergency_call_label" msgid="684946192523830531">"የአደጋ ጊዜ ጥሪ"</string>
+    <string name="kg_forgot_pattern_button_text" msgid="8852021467868220608">"ስርዓተ ጥለቱን እርሳ"</string>
+    <string name="kg_wrong_pattern" msgid="1850806070801358830">"የተሳሳተ ስርዓተ ጥለት"</string>
+    <string name="kg_wrong_password" msgid="2333281762128113157">"የተሳሳተ ይለፍ ቃል"</string>
+    <string name="kg_wrong_pin" msgid="1131306510833563801">"የተሳሳተ ፒን"</string>
+    <string name="kg_too_many_failed_attempts_countdown" msgid="6358110221603297548">"በ<xliff:g id="NUMBER">%d</xliff:g> ሰከንዶች ውስጥ እንደገና ይሞክሩ።"</string>
+    <string name="kg_pattern_instructions" msgid="398978611683075868">"ስርዓተ ጥለትዎን ይሳሉ"</string>
+    <string name="kg_sim_pin_instructions" msgid="2319508550934557331">"የሲም ፒን ያስገቡ"</string>
+    <string name="kg_pin_instructions" msgid="2377242233495111557">"ፒን ያስገቡ"</string>
+    <string name="kg_password_instructions" msgid="5753646556186936819">"የይለፍ ቃል ያስገቡ"</string>
+    <string name="kg_puk_enter_puk_hint" msgid="5183097160254244459">"የPUK ኮድ"</string>
+    <string name="kg_puk_enter_pin_hint" msgid="597821135578014901">"አዲስ ፒን ኮድ"</string>
+    <string name="kg_sim_unlock_progress_dialog_message" msgid="8950398016976865762">"ሲም ካርዱን በመክፈት ላይ…"</string>
+    <string name="kg_password_wrong_pin_code" msgid="1139324887413846912">"ትክክል ያልሆነ ፒን ኮድ።"</string>
+    <string name="kg_invalid_sim_pin_hint" msgid="8795159358110620001">"ከ4 እስከ 8 ቁጥሮች የያዘ ፒን ይተይቡ"</string>
+    <string name="kg_invalid_sim_puk_hint" msgid="5216603185442368307">"8 ወይም ከዚያ በላይ ቁጥሮችን የሆነ PUK ይተይቡ።"</string>
+    <string name="kg_sim_puk_recovery_hint" msgid="5577753137718442566">"PUK እና አዲስ ፒን ይተይቡ"</string>
+    <string name="kg_invalid_puk" msgid="5809955359950817326">"የተየቡት PUK ትክክል  አይደለም።"</string>
+    <string name="kg_login_too_many_attempts" msgid="6486842094005698475">"በጣም ብዙ የስርዓተ ጥለት ሙከራዎች"</string>
+    <string name="kg_login_instructions" msgid="1100551261265506448">"ለመክፈት በGoogle መለያዎ ይግቡ።"</string>
+    <string name="kg_login_username_hint" msgid="5718534272070920364">"የተጠቃሚ ስም (ኢሜይል)"</string>
+    <string name="kg_login_password_hint" msgid="9057289103827298549">"የይለፍ ቃል"</string>
+    <string name="kg_login_submit_button" msgid="5355904582674054702">"ግባ"</string>
+    <string name="kg_login_invalid_input" msgid="5754664119319872197">"ልክ ያልሆነ የተጠቃሚ ስም ወይም የይለፍ ቃል።"</string>
+    <string name="kg_login_account_recovery_hint" msgid="5690709132841752974">"የተጠቃሚ ስምዎን ወይም የይለፍ ቃልዎን ረሱት?"\n<b>"google.com/accounts/recovery"</b>"ይጎብኙ።"</string>
+    <string name="kg_login_checking_password" msgid="8849589033659332457">"በማረጋገጥ ላይ…"</string>
+    <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="8276745642049502550">"ፒንዎን <xliff:g id="NUMBER_0">%d</xliff:g> ጊዜ በትክክል አልተየቡም። "\n\n"በ<xliff:g id="NUMBER_1">%d</xliff:g> ሰኮንዶች ውስጥ እንደገና ይሞክሩ።"</string>
+    <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="7813713389422226531">"የይለፍ ቃልዎን <xliff:g id="NUMBER_0">%d</xliff:g> ጊዜ ትክክል ባልሆነ መንገድ ተይበዋል።"\n\n"በ<xliff:g id="NUMBER_1">%d</xliff:g> ሰኮንዶች ውስጥ እንደገና ይሞክሩ።"</string>
+    <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="74089475965050805">"የመክፈቻ ስርዓተ ጥለትዎን <xliff:g id="NUMBER_0">%d</xliff:g> ጊዜ በትክክል አልሳሉትም። "\n\n" ከ<xliff:g id="NUMBER_1">%d</xliff:g> ሰከንዶች በኋላ እንደገና ይሞክሩ።"</string>
+    <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="1575557200627128949">"ጡባዊ ቱኮውን <xliff:g id="NUMBER_0">%d</xliff:g> ጊዜ ትክክል ባልሆነ መንገድ ለመክፈት ሞክረዋል። ከ<xliff:g id="NUMBER_1">%d</xliff:g> ተጨማሪ ያልተሳኩ ሙከራዎች በኋላ ጡባዊ ቱኮው በፋብሪካ ነባሪ ቅንብር ዳግም ይጀመርና ሁሉም ሁሉም የተጠቃሚ ውሂብ ይጠፋል።"</string>
+    <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="4051015943038199910">"ስልኩን <xliff:g id="NUMBER_0">%d</xliff:g> ጊዜ ትክክል ባልሆነ መንገድ ለመክፈት ሞክረዋል። ከ<xliff:g id="NUMBER_1">%d</xliff:g> ተጨማሪ ያልተሳኩ ሙከራዎች በኋላ ስልኩ በፋብሪካ ነባሪ ቅንብር ዳግም ይጀመርና ሁሉም ሁሉም የተጠቃሚ ውሂብ ይጠፋል።"</string>
+    <string name="kg_failed_attempts_now_wiping" product="tablet" msgid="2072996269148483637">"ጡባዊ ቱኮዎን <xliff:g id="NUMBER">%d</xliff:g> ጊዜ ትክክል ባልሆነ መንገድ ለመክፈት ሞክረዋል። ስልኩን አሁን በፋብሪካ ነባሪ ቅንብር ዳግም ይጀመራል።"</string>
+    <string name="kg_failed_attempts_now_wiping" product="default" msgid="4817627474419471518">"ስልኩን <xliff:g id="NUMBER">%d</xliff:g> ጊዜ ትክክል ባልሆነ መንገድ ለመክፈት ሞክረዋል። ስልኩን አሁን በፋብሪካ ነባሪ ቅንብር ዳግም ይጀመራል።"</string>
+    <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"የመክፈቻ ስርዓተ ጥለቱን <xliff:g id="NUMBER_0">%d</xliff:g> ጊዜ በትክክል አልሳሉትም። ከ<xliff:g id="NUMBER_1">%d</xliff:g> ተጨማሪ ያልተሳኩ ሙከራዎች በኋላ የኢሜይል መለያ ተጠቅመው ጡባዊ ቱኮዎን እንዲከፍቱ ይጠየቃሉ።"\n\n" ከ<xliff:g id="NUMBER_2">%d</xliff:g> ከሰከንዶች በኋላ እንደገና ይሞክሩ።"</string>
+    <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"የመክፈቻ ስርዓተ ጥለቱን <xliff:g id="NUMBER_0">%d</xliff:g> ጊዜ በትክክል አልሳሉትም። ከ<xliff:g id="NUMBER_1">%d</xliff:g> ተጨማሪ ያልተሳኩ ሙከራዎች በኋላ የኢሜይል መለያ ተጠቅመው ስልክዎን እንዲከፍቱ ይጠየቃሉ።"\n\n"እባክዎ ከ<xliff:g id="NUMBER_2">%d</xliff:g> ሰከንዶች በኋላ እንደገና ይሞክሩ።"</string>
+    <string name="kg_temp_back_string" msgid="5812983904056640466">"&lt;"</string>
 </resources>
diff --git a/core/res/res/values-ar/strings.xml b/core/res/res/values-ar/strings.xml
index 9b44dcd..a9093a7 100644
--- a/core/res/res/values-ar/strings.xml
+++ b/core/res/res/values-ar/strings.xml
@@ -547,10 +547,8 @@
     <string name="permdesc_sdcardWrite" product="default" msgid="4337417790936632090">"للسماح للتطبيق بالكتابة إلى بطاقة SD."</string>
     <string name="permlab_mediaStorageWrite" product="default" msgid="6859839199706879015">"تعديل/حذف محتويات وحدة تخزين الوسائط الداخلية"</string>
     <string name="permdesc_mediaStorageWrite" product="default" msgid="8189160597698529185">"للسماح للتطبيق بتعديل محتويات وحدة تخزين الوسائط الداخلية."</string>
-    <!-- no translation found for permlab_sdcardAccessAll (8150613823900460576) -->
-    <skip />
-    <!-- no translation found for permdesc_sdcardAccessAll (3215208357415891320) -->
-    <skip />
+    <string name="permlab_sdcardAccessAll" msgid="8150613823900460576">"الدخول إلى سعة التخزين الخارجية لجميع المستخدمين"</string>
+    <string name="permdesc_sdcardAccessAll" msgid="3215208357415891320">"للسماح للتطبيق بالدخول إلى سعة التخزين الخارجية لجميع المستخدمين."</string>
     <string name="permlab_cache_filesystem" msgid="5656487264819669824">"الدخول إلى نظام ملفات ذاكرة التخزين المؤقت"</string>
     <string name="permdesc_cache_filesystem" msgid="5578967642265550955">"للسماح للتطبيق بقراءة نظام ملفات ذاكرة التخزين المؤقت والكتابة به."</string>
     <string name="permlab_use_sip" msgid="5986952362795870502">"إجراء/تلقي مكالمات عبر الإنترنت"</string>
@@ -581,6 +579,10 @@
     <string name="policydesc_encryptedStorage" msgid="2637732115325316992">"يمكنك طلب تشفير بيانات التطبيق المخزنة."</string>
     <string name="policylab_disableCamera" msgid="6395301023152297826">"تعطيل الكاميرات"</string>
     <string name="policydesc_disableCamera" msgid="2306349042834754597">"يمكنك منح استخدام جميع كاميرات الجهاز."</string>
+    <!-- no translation found for policylab_disableKeyguardWidgets (1794894613389073926) -->
+    <skip />
+    <!-- no translation found for policydesc_disableKeyguardWidgets (7254624892984033592) -->
+    <skip />
   <string-array name="phoneTypes">
     <item msgid="8901098336658710359">"الرئيسية"</item>
     <item msgid="869923650527136615">"الجوال"</item>
@@ -1319,64 +1321,46 @@
     <string name="bluetooth_a2dp_audio_route_name" msgid="8575624030406771015">"صوت بلوتوث"</string>
     <string name="media_route_chooser_grouping_done" msgid="7966438307723317169">"تم"</string>
     <string name="media_route_button_content_description" msgid="5758553567065145276">"المنفذ الإعلامي"</string>
-    <!-- no translation found for display_manager_built_in_display_name (2583134294292563941) -->
+    <string name="display_manager_built_in_display_name" msgid="2583134294292563941">"شاشة مدمجة"</string>
+    <!-- no translation found for display_manager_hdmi_display_name (1555264559227470109) -->
     <skip />
-    <!-- no translation found for display_manager_overlay_display_name (5142365982271620716) -->
+    <string name="display_manager_overlay_display_name" msgid="5142365982271620716">"المركب #<xliff:g id="ID">%1$d</xliff:g>"</string>
+    <!-- no translation found for display_manager_overlay_display_title (652124517672257172) -->
     <skip />
-    <!-- no translation found for display_manager_overlay_display_title (8186674340178573982) -->
-    <skip />
-    <!-- no translation found for kg_emergency_call_label (684946192523830531) -->
-    <skip />
-    <!-- no translation found for kg_forgot_pattern_button_text (8852021467868220608) -->
-    <skip />
-    <!-- no translation found for kg_wrong_pattern (1850806070801358830) -->
-    <skip />
-    <!-- no translation found for kg_wrong_password (2333281762128113157) -->
-    <skip />
-    <!-- no translation found for kg_wrong_pin (1131306510833563801) -->
-    <skip />
-    <!-- no translation found for kg_too_many_failed_attempts_countdown (353963338189371686) -->
-    <skip />
-    <!-- no translation found for kg_pattern_instructions (398978611683075868) -->
-    <skip />
-    <!-- no translation found for kg_sim_pin_instructions (2319508550934557331) -->
-    <skip />
-    <!-- no translation found for kg_pin_instructions (2377242233495111557) -->
-    <skip />
-    <!-- no translation found for kg_password_instructions (5753646556186936819) -->
-    <skip />
-    <!-- no translation found for kg_puk_enter_puk_hint (5183097160254244459) -->
-    <skip />
-    <!-- no translation found for kg_puk_enter_pin_hint (597821135578014901) -->
-    <skip />
-    <!-- no translation found for kg_sim_unlock_progress_dialog_message (8950398016976865762) -->
-    <skip />
-    <!-- no translation found for kg_password_wrong_pin_code (1139324887413846912) -->
-    <skip />
-    <!-- no translation found for kg_invalid_sim_pin_hint (8795159358110620001) -->
-    <skip />
-    <!-- no translation found for kg_invalid_sim_puk_hint (5216603185442368307) -->
-    <skip />
-    <!-- no translation found for kg_sim_puk_recovery_hint (5577753137718442566) -->
-    <skip />
-    <!-- no translation found for kg_invalid_puk (5809955359950817326) -->
-    <skip />
-    <!-- no translation found for kg_login_too_many_attempts (6486842094005698475) -->
-    <skip />
-    <!-- no translation found for kg_login_instructions (1100551261265506448) -->
-    <skip />
-    <!-- no translation found for kg_login_username_hint (5718534272070920364) -->
-    <skip />
-    <!-- no translation found for kg_login_password_hint (9057289103827298549) -->
-    <skip />
-    <!-- no translation found for kg_login_submit_button (5355904582674054702) -->
-    <skip />
-    <!-- no translation found for kg_login_invalid_input (5754664119319872197) -->
-    <skip />
-    <!-- no translation found for kg_login_account_recovery_hint (5690709132841752974) -->
-    <skip />
-    <!-- no translation found for kg_login_checking_password (8849589033659332457) -->
-    <skip />
-    <!-- no translation found for kg_temp_back_string (5812983904056640466) -->
-    <skip />
+    <string name="kg_emergency_call_label" msgid="684946192523830531">"الاتصال بالطوارئ"</string>
+    <string name="kg_forgot_pattern_button_text" msgid="8852021467868220608">"نسيت النقش"</string>
+    <string name="kg_wrong_pattern" msgid="1850806070801358830">"نقش خاطئ"</string>
+    <string name="kg_wrong_password" msgid="2333281762128113157">"كلمة مرور خاطئة"</string>
+    <string name="kg_wrong_pin" msgid="1131306510833563801">"رقم تعريف شخصي خاطئ"</string>
+    <string name="kg_too_many_failed_attempts_countdown" msgid="6358110221603297548">"حاول مرة أخرى خلال <xliff:g id="NUMBER">%d</xliff:g> ثانية."</string>
+    <string name="kg_pattern_instructions" msgid="398978611683075868">"ارسم نقشك"</string>
+    <string name="kg_sim_pin_instructions" msgid="2319508550934557331">"أدخل رقم التعريف الشخصي لبطاقة SIM"</string>
+    <string name="kg_pin_instructions" msgid="2377242233495111557">"أدخل رقم التعريف الشخصي"</string>
+    <string name="kg_password_instructions" msgid="5753646556186936819">"أدخل كلمة المرور"</string>
+    <string name="kg_puk_enter_puk_hint" msgid="5183097160254244459">"رمز PUK"</string>
+    <string name="kg_puk_enter_pin_hint" msgid="597821135578014901">"رمز رقم التعريف الشخصي الجديد"</string>
+    <string name="kg_sim_unlock_progress_dialog_message" msgid="8950398016976865762">"جارٍ إلغاء تأمين بطاقة SIM…"</string>
+    <string name="kg_password_wrong_pin_code" msgid="1139324887413846912">"رقم التعريف الشخصي غير صحيح."</string>
+    <string name="kg_invalid_sim_pin_hint" msgid="8795159358110620001">"اكتب رقم التعريف الشخصي المكون من 4 إلى 8 أرقام."</string>
+    <string name="kg_invalid_sim_puk_hint" msgid="5216603185442368307">"اكتب رمز PUK المكون من 8 أرقام أو أكثر."</string>
+    <string name="kg_sim_puk_recovery_hint" msgid="5577753137718442566">"اكتب رمز PUK ورمز رقم التعريف الشخصي الجديد"</string>
+    <string name="kg_invalid_puk" msgid="5809955359950817326">"رمز PUK الذي كتبته غير صحيح."</string>
+    <string name="kg_login_too_many_attempts" msgid="6486842094005698475">"محاولات النقش كثيرة جدًا"</string>
+    <string name="kg_login_instructions" msgid="1100551261265506448">"لإلغاء التأمين، سجّل الدخول بحسابك في Google."</string>
+    <string name="kg_login_username_hint" msgid="5718534272070920364">"اسم المستخدم (البريد إلكتروني)"</string>
+    <string name="kg_login_password_hint" msgid="9057289103827298549">"كلمة المرور"</string>
+    <string name="kg_login_submit_button" msgid="5355904582674054702">"تسجيل الدخول"</string>
+    <string name="kg_login_invalid_input" msgid="5754664119319872197">"اسم مستخدم غير صحيح أو كلمة مرور غير صالحة."</string>
+    <string name="kg_login_account_recovery_hint" msgid="5690709132841752974">"هل نسيت اسم المستخدم أو كلمة المرور؟"\n"انتقل إلى "<b>"google.com/accounts/recovery"</b>"."</string>
+    <string name="kg_login_checking_password" msgid="8849589033659332457">"جارٍ التحقق…"</string>
+    <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="8276745642049502550">"لقد كتبت رقم التعريف الشخصي بشكل غير صحيح <xliff:g id="NUMBER_0">%d</xliff:g> مرة. "\n\n"أعد المحاولة خلال <xliff:g id="NUMBER_1">%d</xliff:g> ثانية."</string>
+    <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="7813713389422226531">"لقد كتبت كلمة المرور بشكل غير صحيح <xliff:g id="NUMBER_0">%d</xliff:g> مرة. "\n\n"أعد المحاولة خلال <xliff:g id="NUMBER_1">%d</xliff:g> ثانية."</string>
+    <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="74089475965050805">"لقد رسمت نقش إلغاء التأمين بطريقة غير صحيحة <xliff:g id="NUMBER_0">%d</xliff:g> مرة. "\n\n"أعد المحاولة خلال <xliff:g id="NUMBER_1">%d</xliff:g> ثانية."</string>
+    <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="1575557200627128949">"لقد حاولت إلغاء تأمين الجهاز اللوحي بشكل غير صحيح <xliff:g id="NUMBER_0">%d</xliff:g> مرة. بعد <xliff:g id="NUMBER_1">%d</xliff:g> من المحاولات غير الناجحة الأخرى، ستتم إعادة تعيين الجهاز اللوحي على الإعدادات الافتراضية للمصنع وسيتم فقد جميع بيانات المستخدم."</string>
+    <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="4051015943038199910">"لقد حاولت إلغاء تأمين الهاتف بشكل غير صحيح <xliff:g id="NUMBER_0">%d</xliff:g> مرة. بعد <xliff:g id="NUMBER_1">%d</xliff:g> من المحاولات غير الناجحة الأخرى، ستتم إعادة تعيين الهاتف على الإعدادات الافتراضية للمصنع وسيتم فقد جميع بيانات المستخدم."</string>
+    <string name="kg_failed_attempts_now_wiping" product="tablet" msgid="2072996269148483637">"لقد حاولت إلغاء تأمين الجهاز اللوحي بشكل غير صحيح <xliff:g id="NUMBER">%d</xliff:g> مرة. سيتم الآن إعادة تعيين الجهاز اللوحي على الإعدادات الافتراضية للمصنع."</string>
+    <string name="kg_failed_attempts_now_wiping" product="default" msgid="4817627474419471518">"لقد حاولت إلغاء تأمين الهاتف بشكل غير صحيح <xliff:g id="NUMBER">%d</xliff:g> مرة. سيتم الآن إعادة تعيين الهاتف على الإعدادات الافتراضية للمصنع."</string>
+    <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"لقد رسمت نقش إلغاء التأمين بشكل غير صحيح <xliff:g id="NUMBER_0">%d</xliff:g> مرة. بعد <xliff:g id="NUMBER_1">%d</xliff:g> من المحاولات غير الناجحة الأخرى، ستطالَب بإلغاء تأمين الجهاز اللوحي باستخدام معلومات حساب بريد إلكتروني."\n\n" أعد المحاولة خلال <xliff:g id="NUMBER_2">%d</xliff:g> ثانية."</string>
+    <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"لقد رسمت نقش إلغاء التأمين بشكل غير صحيح <xliff:g id="NUMBER_0">%d</xliff:g> مرة. بعد <xliff:g id="NUMBER_1">%d</xliff:g> من المحاولات غير الناجحة الأخرى، ستُطالب بإلغاء تأمين الهاتف باستخدام حساب بريد إلكتروني لإلغاء تأمين الهاتف."\n\n" أعد المحاولة خلال <xliff:g id="NUMBER_2">%d</xliff:g> ثانية."</string>
+    <string name="kg_temp_back_string" msgid="5812983904056640466">"&lt;"</string>
 </resources>
diff --git a/core/res/res/values-be/strings.xml b/core/res/res/values-be/strings.xml
index 7d8c3f3..cb25685 100644
--- a/core/res/res/values-be/strings.xml
+++ b/core/res/res/values-be/strings.xml
@@ -547,10 +547,8 @@
     <string name="permdesc_sdcardWrite" product="default" msgid="4337417790936632090">"Дазваляе прыкладанням запісваць на SD-карту."</string>
     <string name="permlab_mediaStorageWrite" product="default" msgid="6859839199706879015">"змяніць/выдаліць унутраныя носьбіты змесціва"</string>
     <string name="permdesc_mediaStorageWrite" product="default" msgid="8189160597698529185">"Дазваляе прыкладанням змяняць змесціва ўнутранай памяці."</string>
-    <!-- no translation found for permlab_sdcardAccessAll (8150613823900460576) -->
-    <skip />
-    <!-- no translation found for permdesc_sdcardAccessAll (3215208357415891320) -->
-    <skip />
+    <string name="permlab_sdcardAccessAll" msgid="8150613823900460576">"доступ да знешніх захоўвання для ўсіх карыстальнікаў"</string>
+    <string name="permdesc_sdcardAccessAll" msgid="3215208357415891320">"Дазваляе ўсiм карыстальнiкам прыкладання атрымлiваць доступ да знешнега сховiшча"</string>
     <string name="permlab_cache_filesystem" msgid="5656487264819669824">"доступ да файлавай сістэмы кэша"</string>
     <string name="permdesc_cache_filesystem" msgid="5578967642265550955">"Дазваляе прыкладанню счытваць і выконваць запіс у файлавую сістэму кэш-памяці."</string>
     <string name="permlab_use_sip" msgid="5986952362795870502">"рабіць/прымаць iнтэрнэт-выклікі"</string>
@@ -581,6 +579,10 @@
     <string name="policydesc_encryptedStorage" msgid="2637732115325316992">"Запыт на шыфраванне захаваных дадзеных прыкладанняў."</string>
     <string name="policylab_disableCamera" msgid="6395301023152297826">"Адключыць камеры"</string>
     <string name="policydesc_disableCamera" msgid="2306349042834754597">"Забараніць выкарыстанне ўсіх камер прылады."</string>
+    <!-- no translation found for policylab_disableKeyguardWidgets (1794894613389073926) -->
+    <skip />
+    <!-- no translation found for policydesc_disableKeyguardWidgets (7254624892984033592) -->
+    <skip />
   <string-array name="phoneTypes">
     <item msgid="8901098336658710359">"Галоўная старонка"</item>
     <item msgid="869923650527136615">"Мабільны"</item>
@@ -1319,64 +1321,46 @@
     <string name="bluetooth_a2dp_audio_route_name" msgid="8575624030406771015">"Bluetooth-аўдыё"</string>
     <string name="media_route_chooser_grouping_done" msgid="7966438307723317169">"Гатова"</string>
     <string name="media_route_button_content_description" msgid="5758553567065145276">"Мультымедыйны выхад"</string>
-    <!-- no translation found for display_manager_built_in_display_name (2583134294292563941) -->
+    <string name="display_manager_built_in_display_name" msgid="2583134294292563941">"Убудаваны экран"</string>
+    <!-- no translation found for display_manager_hdmi_display_name (1555264559227470109) -->
     <skip />
-    <!-- no translation found for display_manager_overlay_display_name (5142365982271620716) -->
+    <string name="display_manager_overlay_display_name" msgid="5142365982271620716">"Оверлей # <xliff:g id="ID">%1$d</xliff:g>"</string>
+    <!-- no translation found for display_manager_overlay_display_title (652124517672257172) -->
     <skip />
-    <!-- no translation found for display_manager_overlay_display_title (8186674340178573982) -->
-    <skip />
-    <!-- no translation found for kg_emergency_call_label (684946192523830531) -->
-    <skip />
-    <!-- no translation found for kg_forgot_pattern_button_text (8852021467868220608) -->
-    <skip />
-    <!-- no translation found for kg_wrong_pattern (1850806070801358830) -->
-    <skip />
-    <!-- no translation found for kg_wrong_password (2333281762128113157) -->
-    <skip />
-    <!-- no translation found for kg_wrong_pin (1131306510833563801) -->
-    <skip />
-    <!-- no translation found for kg_too_many_failed_attempts_countdown (353963338189371686) -->
-    <skip />
-    <!-- no translation found for kg_pattern_instructions (398978611683075868) -->
-    <skip />
-    <!-- no translation found for kg_sim_pin_instructions (2319508550934557331) -->
-    <skip />
-    <!-- no translation found for kg_pin_instructions (2377242233495111557) -->
-    <skip />
-    <!-- no translation found for kg_password_instructions (5753646556186936819) -->
-    <skip />
-    <!-- no translation found for kg_puk_enter_puk_hint (5183097160254244459) -->
-    <skip />
-    <!-- no translation found for kg_puk_enter_pin_hint (597821135578014901) -->
-    <skip />
-    <!-- no translation found for kg_sim_unlock_progress_dialog_message (8950398016976865762) -->
-    <skip />
-    <!-- no translation found for kg_password_wrong_pin_code (1139324887413846912) -->
-    <skip />
-    <!-- no translation found for kg_invalid_sim_pin_hint (8795159358110620001) -->
-    <skip />
-    <!-- no translation found for kg_invalid_sim_puk_hint (5216603185442368307) -->
-    <skip />
-    <!-- no translation found for kg_sim_puk_recovery_hint (5577753137718442566) -->
-    <skip />
-    <!-- no translation found for kg_invalid_puk (5809955359950817326) -->
-    <skip />
-    <!-- no translation found for kg_login_too_many_attempts (6486842094005698475) -->
-    <skip />
-    <!-- no translation found for kg_login_instructions (1100551261265506448) -->
-    <skip />
-    <!-- no translation found for kg_login_username_hint (5718534272070920364) -->
-    <skip />
-    <!-- no translation found for kg_login_password_hint (9057289103827298549) -->
-    <skip />
-    <!-- no translation found for kg_login_submit_button (5355904582674054702) -->
-    <skip />
-    <!-- no translation found for kg_login_invalid_input (5754664119319872197) -->
-    <skip />
-    <!-- no translation found for kg_login_account_recovery_hint (5690709132841752974) -->
-    <skip />
-    <!-- no translation found for kg_login_checking_password (8849589033659332457) -->
-    <skip />
-    <!-- no translation found for kg_temp_back_string (5812983904056640466) -->
-    <skip />
+    <string name="kg_emergency_call_label" msgid="684946192523830531">"Экстранны выклік"</string>
+    <string name="kg_forgot_pattern_button_text" msgid="8852021467868220608">"Забылі ключ"</string>
+    <string name="kg_wrong_pattern" msgid="1850806070801358830">"Няправільна ключ"</string>
+    <string name="kg_wrong_password" msgid="2333281762128113157">"Няправiльны пароль"</string>
+    <string name="kg_wrong_pin" msgid="1131306510833563801">"Няправільны PIN-код"</string>
+    <string name="kg_too_many_failed_attempts_countdown" msgid="6358110221603297548">"Паўтарыце спробу праз <xliff:g id="NUMBER">%d</xliff:g> с."</string>
+    <string name="kg_pattern_instructions" msgid="398978611683075868">"Намалюйце ключ"</string>
+    <string name="kg_sim_pin_instructions" msgid="2319508550934557331">"Увядзіце PIN-код SIM-карты"</string>
+    <string name="kg_pin_instructions" msgid="2377242233495111557">"Увядзіце PIN-код"</string>
+    <string name="kg_password_instructions" msgid="5753646556186936819">"Увядзіце пароль"</string>
+    <string name="kg_puk_enter_puk_hint" msgid="5183097160254244459">"PUK"</string>
+    <string name="kg_puk_enter_pin_hint" msgid="597821135578014901">"Новы PIN-код"</string>
+    <string name="kg_sim_unlock_progress_dialog_message" msgid="8950398016976865762">"Разблакiроўка SIM-карты..."</string>
+    <string name="kg_password_wrong_pin_code" msgid="1139324887413846912">"Няправільны PIN-код."</string>
+    <string name="kg_invalid_sim_pin_hint" msgid="8795159358110620001">"Увядзіце PIN-код, які змяшчае ад 4 да 8 лічбаў."</string>
+    <string name="kg_invalid_sim_puk_hint" msgid="5216603185442368307">"Увядзіце PUK з 8 лічбаў ці больш."</string>
+    <string name="kg_sim_puk_recovery_hint" msgid="5577753137718442566">"Увядзіце PUK-код і новы PIN-код"</string>
+    <string name="kg_invalid_puk" msgid="5809955359950817326">"Няправільны PUK-код."</string>
+    <string name="kg_login_too_many_attempts" msgid="6486842094005698475">"Занадта шмат спроб паўтарыць шаблон!"</string>
+    <string name="kg_login_instructions" msgid="1100551261265506448">"Каб разблакiраваць, увайдзіце ў свой уліковы запіс Google."</string>
+    <string name="kg_login_username_hint" msgid="5718534272070920364">"Імя карыстальніка (электронная пошта)"</string>
+    <string name="kg_login_password_hint" msgid="9057289103827298549">"Пароль"</string>
+    <string name="kg_login_submit_button" msgid="5355904582674054702">"Увайсцi"</string>
+    <string name="kg_login_invalid_input" msgid="5754664119319872197">"Няправільнае імя карыстальніка ці пароль."</string>
+    <string name="kg_login_account_recovery_hint" msgid="5690709132841752974">"Забыліся на імя карыстальніка або пароль?"\n"Наведайце "<b>"google.com/accounts/recovery"</b></string>
+    <string name="kg_login_checking_password" msgid="8849589033659332457">"Праверка..."</string>
+    <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="8276745642049502550">"Вы няправільна ўвялі PIN-код пэўную колькасць разоў: <xliff:g id="NUMBER_0">%d</xliff:g>. "\n\n"Паўтарыце спробу праз <xliff:g id="NUMBER_1">%d</xliff:g> с."</string>
+    <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="7813713389422226531">"Вы няправільна ўвялі пароль пэўную колькасць разоў: <xliff:g id="NUMBER_0">%d</xliff:g>. "\n\n"Паўтарыце спробу праз <xliff:g id="NUMBER_1">%d</xliff:g> с."</string>
+    <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="74089475965050805">"Вы няправільна ўвялі графічны ключ разблакiроўкi пэўную колькасць разоў: <xliff:g id="NUMBER_0">%d</xliff:g>. "\n\n"Паўтарыце спробу праз <xliff:g id="NUMBER_1">%d</xliff:g> с."</string>
+    <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="1575557200627128949">"Вы няправільна спрабавалі разблакiраваць планшэт некалькi разоў (<xliff:g id="NUMBER_0">%d</xliff:g>). Пасля яшчэ некалькiх спроб (<xliff:g id="NUMBER_1">%d</xliff:g>) ён будзе скінуты да заводскіх налад i карыстальнiцкiя дадзеныя будуць згубленыя."</string>
+    <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="4051015943038199910">"Вы няправільна спрабавалі разблакiраваць планшэт некалькi разоў (<xliff:g id="NUMBER_0">%d</xliff:g>). Пасля яшчэ некалькiх спроб (<xliff:g id="NUMBER_1">%d</xliff:g>) ён будзе скінуты да завадскіх налад i карыстальнiцкiя дадзеныя будуць згубленыя."</string>
+    <string name="kg_failed_attempts_now_wiping" product="tablet" msgid="2072996269148483637">"Вы няправільна спрабавалі разблакiраваць планшэт некалькi разоў (<xliff:g id="NUMBER">%d</xliff:g>). Цяпер ён будзе скінуты да завадскіх налад."</string>
+    <string name="kg_failed_attempts_now_wiping" product="default" msgid="4817627474419471518">"Вы няправільна спрабавалі разблакiраваць тэлефон некалькi разоў (<xliff:g id="NUMBER">%d</xliff:g>). Цяпер ён будзе скінуты да завадскіх налад."</string>
+    <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"Вы няправільна ўвялі графічны ключ разблакiроўкi пэўную колькасць разоў: <xliff:g id="NUMBER_0">%d</xliff:g>. Пасля яшчэ некалькiх няўдалых спроб (<xliff:g id="NUMBER_1">%d</xliff:g>) вам будзе прапанавана разблакiраваць тэлефон, увайшоўшы ў Google."\n\n" Паўтарыце спробу праз <xliff:g id="NUMBER_2">%d</xliff:g> с."</string>
+    <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"Вы няправільна ўвялі графічны ключ разблакiроўкi пэўную колькасць разоў: <xliff:g id="NUMBER_0">%d</xliff:g>. Пасля яшчэ некалькiх няўдалых спроб (<xliff:g id="NUMBER_1">%d</xliff:g>) вам будзе прапанавана разблакiраваць тэлефон, увайшоўшы ў Google."\n\n" Паўтарыце спробу праз <xliff:g id="NUMBER_2">%d</xliff:g> с."</string>
+    <string name="kg_temp_back_string" msgid="5812983904056640466">"&lt;"</string>
 </resources>
diff --git a/core/res/res/values-bg/strings.xml b/core/res/res/values-bg/strings.xml
index 85a2c9e..5deffde 100644
--- a/core/res/res/values-bg/strings.xml
+++ b/core/res/res/values-bg/strings.xml
@@ -547,10 +547,8 @@
     <string name="permdesc_sdcardWrite" product="default" msgid="4337417790936632090">"Разрешава на приложението да записва върху SD картата."</string>
     <string name="permlab_mediaStorageWrite" product="default" msgid="6859839199706879015">"пром./изтр. на съдърж. на вътр. мултим. хранил."</string>
     <string name="permdesc_mediaStorageWrite" product="default" msgid="8189160597698529185">"Разрешава на приложението да променя съдържанието на вътрешното мултимедийно хранилище."</string>
-    <!-- no translation found for permlab_sdcardAccessAll (8150613823900460576) -->
-    <skip />
-    <!-- no translation found for permdesc_sdcardAccessAll (3215208357415891320) -->
-    <skip />
+    <string name="permlab_sdcardAccessAll" msgid="8150613823900460576">"достъп до външ. хранилище за всички потребители"</string>
+    <string name="permdesc_sdcardAccessAll" msgid="3215208357415891320">"Разрешава на приложението достъп до външното хранилище за всички потребители."</string>
     <string name="permlab_cache_filesystem" msgid="5656487264819669824">"достъп до файловата система на кеша"</string>
     <string name="permdesc_cache_filesystem" msgid="5578967642265550955">"Разрешава на приложението да чете и записва във файловата система на кеша."</string>
     <string name="permlab_use_sip" msgid="5986952362795870502">"извършване/получаване на интернет обаждания"</string>
@@ -581,6 +579,10 @@
     <string name="policydesc_encryptedStorage" msgid="2637732115325316992">"Изисква съхраняваните данни за приложенията да бъдат шифровани."</string>
     <string name="policylab_disableCamera" msgid="6395301023152297826">"Деактивиране на камерите"</string>
     <string name="policydesc_disableCamera" msgid="2306349042834754597">"Предотвратява употребата на камерите на всички устройства."</string>
+    <!-- no translation found for policylab_disableKeyguardWidgets (1794894613389073926) -->
+    <skip />
+    <!-- no translation found for policydesc_disableKeyguardWidgets (7254624892984033592) -->
+    <skip />
   <string-array name="phoneTypes">
     <item msgid="8901098336658710359">"Домашен"</item>
     <item msgid="869923650527136615">"Мобилен"</item>
@@ -1319,64 +1321,46 @@
     <string name="bluetooth_a2dp_audio_route_name" msgid="8575624030406771015">"Звук през Bluetooth"</string>
     <string name="media_route_chooser_grouping_done" msgid="7966438307723317169">"Готово"</string>
     <string name="media_route_button_content_description" msgid="5758553567065145276">"Изходяща мултимедия"</string>
-    <!-- no translation found for display_manager_built_in_display_name (2583134294292563941) -->
+    <string name="display_manager_built_in_display_name" msgid="2583134294292563941">"Вграден екран"</string>
+    <!-- no translation found for display_manager_hdmi_display_name (1555264559227470109) -->
     <skip />
-    <!-- no translation found for display_manager_overlay_display_name (5142365982271620716) -->
+    <string name="display_manager_overlay_display_name" msgid="5142365982271620716">"Наслагване №<xliff:g id="ID">%1$d</xliff:g>"</string>
+    <!-- no translation found for display_manager_overlay_display_title (652124517672257172) -->
     <skip />
-    <!-- no translation found for display_manager_overlay_display_title (8186674340178573982) -->
-    <skip />
-    <!-- no translation found for kg_emergency_call_label (684946192523830531) -->
-    <skip />
-    <!-- no translation found for kg_forgot_pattern_button_text (8852021467868220608) -->
-    <skip />
-    <!-- no translation found for kg_wrong_pattern (1850806070801358830) -->
-    <skip />
-    <!-- no translation found for kg_wrong_password (2333281762128113157) -->
-    <skip />
-    <!-- no translation found for kg_wrong_pin (1131306510833563801) -->
-    <skip />
-    <!-- no translation found for kg_too_many_failed_attempts_countdown (353963338189371686) -->
-    <skip />
-    <!-- no translation found for kg_pattern_instructions (398978611683075868) -->
-    <skip />
-    <!-- no translation found for kg_sim_pin_instructions (2319508550934557331) -->
-    <skip />
-    <!-- no translation found for kg_pin_instructions (2377242233495111557) -->
-    <skip />
-    <!-- no translation found for kg_password_instructions (5753646556186936819) -->
-    <skip />
-    <!-- no translation found for kg_puk_enter_puk_hint (5183097160254244459) -->
-    <skip />
-    <!-- no translation found for kg_puk_enter_pin_hint (597821135578014901) -->
-    <skip />
-    <!-- no translation found for kg_sim_unlock_progress_dialog_message (8950398016976865762) -->
-    <skip />
-    <!-- no translation found for kg_password_wrong_pin_code (1139324887413846912) -->
-    <skip />
-    <!-- no translation found for kg_invalid_sim_pin_hint (8795159358110620001) -->
-    <skip />
-    <!-- no translation found for kg_invalid_sim_puk_hint (5216603185442368307) -->
-    <skip />
-    <!-- no translation found for kg_sim_puk_recovery_hint (5577753137718442566) -->
-    <skip />
-    <!-- no translation found for kg_invalid_puk (5809955359950817326) -->
-    <skip />
-    <!-- no translation found for kg_login_too_many_attempts (6486842094005698475) -->
-    <skip />
-    <!-- no translation found for kg_login_instructions (1100551261265506448) -->
-    <skip />
-    <!-- no translation found for kg_login_username_hint (5718534272070920364) -->
-    <skip />
-    <!-- no translation found for kg_login_password_hint (9057289103827298549) -->
-    <skip />
-    <!-- no translation found for kg_login_submit_button (5355904582674054702) -->
-    <skip />
-    <!-- no translation found for kg_login_invalid_input (5754664119319872197) -->
-    <skip />
-    <!-- no translation found for kg_login_account_recovery_hint (5690709132841752974) -->
-    <skip />
-    <!-- no translation found for kg_login_checking_password (8849589033659332457) -->
-    <skip />
-    <!-- no translation found for kg_temp_back_string (5812983904056640466) -->
-    <skip />
+    <string name="kg_emergency_call_label" msgid="684946192523830531">"Спешно обаждане"</string>
+    <string name="kg_forgot_pattern_button_text" msgid="8852021467868220608">"Забравена фигура"</string>
+    <string name="kg_wrong_pattern" msgid="1850806070801358830">"Грешна фигура"</string>
+    <string name="kg_wrong_password" msgid="2333281762128113157">"Грешна парола"</string>
+    <string name="kg_wrong_pin" msgid="1131306510833563801">"Грешен ПИН код"</string>
+    <string name="kg_too_many_failed_attempts_countdown" msgid="6358110221603297548">"Опитайте отново след <xliff:g id="NUMBER">%d</xliff:g> секунди."</string>
+    <string name="kg_pattern_instructions" msgid="398978611683075868">"Начертайте фигурата си"</string>
+    <string name="kg_sim_pin_instructions" msgid="2319508550934557331">"Въведете ПИН кода за SIM картата"</string>
+    <string name="kg_pin_instructions" msgid="2377242233495111557">"Въведете ПИН код"</string>
+    <string name="kg_password_instructions" msgid="5753646556186936819">"Въведете паролата"</string>
+    <string name="kg_puk_enter_puk_hint" msgid="5183097160254244459">"PUK код"</string>
+    <string name="kg_puk_enter_pin_hint" msgid="597821135578014901">"Нов ПИН код"</string>
+    <string name="kg_sim_unlock_progress_dialog_message" msgid="8950398016976865762">"SIM картата се отключва…"</string>
+    <string name="kg_password_wrong_pin_code" msgid="1139324887413846912">"Неправилен ПИН код."</string>
+    <string name="kg_invalid_sim_pin_hint" msgid="8795159358110620001">"Въведете ПИН код с четири до осем цифри."</string>
+    <string name="kg_invalid_sim_puk_hint" msgid="5216603185442368307">"Въведете PUK код с поне осем цифри."</string>
+    <string name="kg_sim_puk_recovery_hint" msgid="5577753137718442566">"Въведете PUK и новия ПИН код"</string>
+    <string name="kg_invalid_puk" msgid="5809955359950817326">"Въведеният от вас PUK код е неправилен."</string>
+    <string name="kg_login_too_many_attempts" msgid="6486842094005698475">"Опитите за фигурата са твърде много"</string>
+    <string name="kg_login_instructions" msgid="1100551261265506448">"За да отключите, влезте с профила си в Google."</string>
+    <string name="kg_login_username_hint" msgid="5718534272070920364">"Потребителско име (имейл)"</string>
+    <string name="kg_login_password_hint" msgid="9057289103827298549">"Парола"</string>
+    <string name="kg_login_submit_button" msgid="5355904582674054702">"Вход"</string>
+    <string name="kg_login_invalid_input" msgid="5754664119319872197">"Невалидно потребителско име или парола."</string>
+    <string name="kg_login_account_recovery_hint" msgid="5690709132841752974">"Забравили сте потребителското име или паролата си?"\n"Посетете "<b>"google.com/accounts/recovery"</b>"."</string>
+    <string name="kg_login_checking_password" msgid="8849589033659332457">"Проверява се…"</string>
+    <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="8276745642049502550">"Въведохте неправилно ПИН кода си <xliff:g id="NUMBER_0">%d</xliff:g> пъти. "\n\n"Опитайте отново след <xliff:g id="NUMBER_1">%d</xliff:g> секунди."</string>
+    <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="7813713389422226531">"Въведохте неправилно паролата си <xliff:g id="NUMBER_0">%d</xliff:g> пъти. "\n\n"Опитайте отново след <xliff:g id="NUMBER_1">%d</xliff:g> секунди."</string>
+    <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="74089475965050805">"Начертахте неправилно фигурата си за отключване <xliff:g id="NUMBER_0">%d</xliff:g> пъти. "\n\n"Опитайте отново след <xliff:g id="NUMBER_1">%d</xliff:g> секунди."</string>
+    <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="1575557200627128949">"Направихте опит да отключите неправилно таблета <xliff:g id="NUMBER_0">%d</xliff:g> пъти. След още <xliff:g id="NUMBER_1">%d</xliff:g> неуспешни опита ще бъдат възстановени стандартните му фабрични настройки и всички потребителски данни ще бъдат заличени."</string>
+    <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="4051015943038199910">"Направихте опит да отключите неправилно телефона <xliff:g id="NUMBER_0">%d</xliff:g> пъти. След още <xliff:g id="NUMBER_1">%d</xliff:g> неуспешни опита ще бъдат възстановени стандартните му фабрични настройки и всички потребителски данни ще бъдат заличени."</string>
+    <string name="kg_failed_attempts_now_wiping" product="tablet" msgid="2072996269148483637">"Направихте опит да отключите неправилно таблета <xliff:g id="NUMBER">%d</xliff:g> пъти. Сега ще бъдат възстановени стандартните му фабрични настройки."</string>
+    <string name="kg_failed_attempts_now_wiping" product="default" msgid="4817627474419471518">"Направихте опит да отключите неправилно телефона <xliff:g id="NUMBER">%d</xliff:g> пъти. Сега ще бъдат възстановени стандартните му фабрични настройки."</string>
+    <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"Начертахте неправилно фигурата си за отключване <xliff:g id="NUMBER_0">%d</xliff:g> пъти. След още <xliff:g id="NUMBER_1">%d</xliff:g> неуспешни опита ще бъдете помолени да отключите таблета посредством имейл адрес."\n\n" Опитайте отново след <xliff:g id="NUMBER_2">%d</xliff:g> секунди."</string>
+    <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"Начертахте неправилно фигурата си за отключване <xliff:g id="NUMBER_0">%d</xliff:g> пъти. След още <xliff:g id="NUMBER_1">%d</xliff:g> неуспешни опита ще бъдете помолени да отключите телефона посредством имейл адрес."\n\n" Опитайте отново след <xliff:g id="NUMBER_2">%d</xliff:g> секунди."</string>
+    <string name="kg_temp_back_string" msgid="5812983904056640466">"&lt;"</string>
 </resources>
diff --git a/core/res/res/values-ca/strings.xml b/core/res/res/values-ca/strings.xml
index 86c9f36..c413943 100644
--- a/core/res/res/values-ca/strings.xml
+++ b/core/res/res/values-ca/strings.xml
@@ -547,10 +547,8 @@
     <string name="permdesc_sdcardWrite" product="default" msgid="4337417790936632090">"Permet a l\'aplicació escriure a la targeta SD."</string>
     <string name="permlab_mediaStorageWrite" product="default" msgid="6859839199706879015">"Canvia/esborra emmagatz. intern"</string>
     <string name="permdesc_mediaStorageWrite" product="default" msgid="8189160597698529185">"Permet que l\'aplicació modifiqui el contingut de l\'emmagatzematge multimèdia intern."</string>
-    <!-- no translation found for permlab_sdcardAccessAll (8150613823900460576) -->
-    <skip />
-    <!-- no translation found for permdesc_sdcardAccessAll (3215208357415891320) -->
-    <skip />
+    <string name="permlab_sdcardAccessAll" msgid="8150613823900460576">"accedeix a l\'emmagatzematge extern per a tots els usuaris"</string>
+    <string name="permdesc_sdcardAccessAll" msgid="3215208357415891320">"Permet que l\'aplicació accedeixi a l\'emmagatzematge extern per a tots els usuaris."</string>
     <string name="permlab_cache_filesystem" msgid="5656487264819669824">"accedir al sistema de fitxers de la memòria cau"</string>
     <string name="permdesc_cache_filesystem" msgid="5578967642265550955">"Permet que l\'aplicació llegeixi el sistema de fitxers de la memòria cau i que hi escrigui."</string>
     <string name="permlab_use_sip" msgid="5986952362795870502">"fer/rebre trucades per Internet"</string>
@@ -581,6 +579,10 @@
     <string name="policydesc_encryptedStorage" msgid="2637732115325316992">"Requereix que les dades de l\'aplicació emmagatzemades estiguin encriptades."</string>
     <string name="policylab_disableCamera" msgid="6395301023152297826">"Desactiva les càmeres"</string>
     <string name="policydesc_disableCamera" msgid="2306349042834754597">"Impedeix l\'ús de totes les càmeres del dispositiu."</string>
+    <!-- no translation found for policylab_disableKeyguardWidgets (1794894613389073926) -->
+    <skip />
+    <!-- no translation found for policydesc_disableKeyguardWidgets (7254624892984033592) -->
+    <skip />
   <string-array name="phoneTypes">
     <item msgid="8901098336658710359">"Casa"</item>
     <item msgid="869923650527136615">"Mòbil"</item>
@@ -1319,64 +1321,46 @@
     <string name="bluetooth_a2dp_audio_route_name" msgid="8575624030406771015">"Àudio per Bluetooth"</string>
     <string name="media_route_chooser_grouping_done" msgid="7966438307723317169">"Fet"</string>
     <string name="media_route_button_content_description" msgid="5758553567065145276">"Sortida de contingut multimèdia"</string>
-    <!-- no translation found for display_manager_built_in_display_name (2583134294292563941) -->
+    <string name="display_manager_built_in_display_name" msgid="2583134294292563941">"Pantalla integrada"</string>
+    <!-- no translation found for display_manager_hdmi_display_name (1555264559227470109) -->
     <skip />
-    <!-- no translation found for display_manager_overlay_display_name (5142365982271620716) -->
+    <string name="display_manager_overlay_display_name" msgid="5142365982271620716">"Superposa #<xliff:g id="ID">%1$d</xliff:g>"</string>
+    <!-- no translation found for display_manager_overlay_display_title (652124517672257172) -->
     <skip />
-    <!-- no translation found for display_manager_overlay_display_title (8186674340178573982) -->
-    <skip />
-    <!-- no translation found for kg_emergency_call_label (684946192523830531) -->
-    <skip />
-    <!-- no translation found for kg_forgot_pattern_button_text (8852021467868220608) -->
-    <skip />
-    <!-- no translation found for kg_wrong_pattern (1850806070801358830) -->
-    <skip />
-    <!-- no translation found for kg_wrong_password (2333281762128113157) -->
-    <skip />
-    <!-- no translation found for kg_wrong_pin (1131306510833563801) -->
-    <skip />
-    <!-- no translation found for kg_too_many_failed_attempts_countdown (353963338189371686) -->
-    <skip />
-    <!-- no translation found for kg_pattern_instructions (398978611683075868) -->
-    <skip />
-    <!-- no translation found for kg_sim_pin_instructions (2319508550934557331) -->
-    <skip />
-    <!-- no translation found for kg_pin_instructions (2377242233495111557) -->
-    <skip />
-    <!-- no translation found for kg_password_instructions (5753646556186936819) -->
-    <skip />
-    <!-- no translation found for kg_puk_enter_puk_hint (5183097160254244459) -->
-    <skip />
-    <!-- no translation found for kg_puk_enter_pin_hint (597821135578014901) -->
-    <skip />
-    <!-- no translation found for kg_sim_unlock_progress_dialog_message (8950398016976865762) -->
-    <skip />
-    <!-- no translation found for kg_password_wrong_pin_code (1139324887413846912) -->
-    <skip />
-    <!-- no translation found for kg_invalid_sim_pin_hint (8795159358110620001) -->
-    <skip />
-    <!-- no translation found for kg_invalid_sim_puk_hint (5216603185442368307) -->
-    <skip />
-    <!-- no translation found for kg_sim_puk_recovery_hint (5577753137718442566) -->
-    <skip />
-    <!-- no translation found for kg_invalid_puk (5809955359950817326) -->
-    <skip />
-    <!-- no translation found for kg_login_too_many_attempts (6486842094005698475) -->
-    <skip />
-    <!-- no translation found for kg_login_instructions (1100551261265506448) -->
-    <skip />
-    <!-- no translation found for kg_login_username_hint (5718534272070920364) -->
-    <skip />
-    <!-- no translation found for kg_login_password_hint (9057289103827298549) -->
-    <skip />
-    <!-- no translation found for kg_login_submit_button (5355904582674054702) -->
-    <skip />
-    <!-- no translation found for kg_login_invalid_input (5754664119319872197) -->
-    <skip />
-    <!-- no translation found for kg_login_account_recovery_hint (5690709132841752974) -->
-    <skip />
-    <!-- no translation found for kg_login_checking_password (8849589033659332457) -->
-    <skip />
-    <!-- no translation found for kg_temp_back_string (5812983904056640466) -->
-    <skip />
+    <string name="kg_emergency_call_label" msgid="684946192523830531">"Trucada d\'emergència"</string>
+    <string name="kg_forgot_pattern_button_text" msgid="8852021467868220608">"Patró oblidat"</string>
+    <string name="kg_wrong_pattern" msgid="1850806070801358830">"Patró incorrecte"</string>
+    <string name="kg_wrong_password" msgid="2333281762128113157">"Contrasenya incorrecta"</string>
+    <string name="kg_wrong_pin" msgid="1131306510833563801">"PIN incorrecte"</string>
+    <string name="kg_too_many_failed_attempts_countdown" msgid="6358110221603297548">"Torna-ho a provar d\'aquí a <xliff:g id="NUMBER">%d</xliff:g> segons."</string>
+    <string name="kg_pattern_instructions" msgid="398978611683075868">"Dibuixa el patró"</string>
+    <string name="kg_sim_pin_instructions" msgid="2319508550934557331">"Introdueix el PIN de la SIM"</string>
+    <string name="kg_pin_instructions" msgid="2377242233495111557">"Introdueix el PIN"</string>
+    <string name="kg_password_instructions" msgid="5753646556186936819">"Introdueix la contrasenya"</string>
+    <string name="kg_puk_enter_puk_hint" msgid="5183097160254244459">"Codi PUK"</string>
+    <string name="kg_puk_enter_pin_hint" msgid="597821135578014901">"Codi PIN nou"</string>
+    <string name="kg_sim_unlock_progress_dialog_message" msgid="8950398016976865762">"S\'està desbloquejant la targeta SIM..."</string>
+    <string name="kg_password_wrong_pin_code" msgid="1139324887413846912">"Codi PIN incorrecte."</string>
+    <string name="kg_invalid_sim_pin_hint" msgid="8795159358110620001">"Escriu un PIN que tingui de 4 a 8 números."</string>
+    <string name="kg_invalid_sim_puk_hint" msgid="5216603185442368307">"Introdueix un PUK que tingui com a mínim 8 números."</string>
+    <string name="kg_sim_puk_recovery_hint" msgid="5577753137718442566">"Introdueix el codi PUK i el codi PIN nou"</string>
+    <string name="kg_invalid_puk" msgid="5809955359950817326">"El PUK que has escrit no és correcte."</string>
+    <string name="kg_login_too_many_attempts" msgid="6486842094005698475">"Massa intents incorrectes"</string>
+    <string name="kg_login_instructions" msgid="1100551261265506448">"Per desbloquejar el telèfon, inicia la sessió amb el compte de Google."</string>
+    <string name="kg_login_username_hint" msgid="5718534272070920364">"Nom d\'usuari (correu electrònic)"</string>
+    <string name="kg_login_password_hint" msgid="9057289103827298549">"Contrasenya"</string>
+    <string name="kg_login_submit_button" msgid="5355904582674054702">"Inicia la sessió"</string>
+    <string name="kg_login_invalid_input" msgid="5754664119319872197">"Nom d\'usuari o contrasenya no vàlids."</string>
+    <string name="kg_login_account_recovery_hint" msgid="5690709132841752974">"Has oblidat el teu nom d\'usuari o la contrasenya?"\n"Visita "<b>"google.com/accounts/recovery"</b>"."</string>
+    <string name="kg_login_checking_password" msgid="8849589033659332457">"S\'està comprovant..."</string>
+    <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="8276745642049502550">"Has escrit malament el PIN <xliff:g id="NUMBER_0">%d</xliff:g> vegades. "\n\n"Torna-ho a provar d\'aquí a <xliff:g id="NUMBER_1">%d</xliff:g> segons."</string>
+    <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="7813713389422226531">"Has escrit malament la contrasenya <xliff:g id="NUMBER_0">%d</xliff:g> vegades. "\n\n"Torna-ho a provar d\'aquí a <xliff:g id="NUMBER_1">%d</xliff:g> segons."</string>
+    <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="74089475965050805">"Has dibuixat el patró de desbloqueig de manera incorrecta <xliff:g id="NUMBER_0">%d</xliff:g> vegades. "\n\n"Torna-ho a provar d\'aquí a <xliff:g id="NUMBER_1">%d</xliff:g> segons."</string>
+    <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="1575557200627128949">"Has provat de desbloquejar la tauleta <xliff:g id="NUMBER_0">%d</xliff:g> vegades de manera incorrecta. D\'aquí a <xliff:g id="NUMBER_1">%d</xliff:g> intents incorrectes més, la tauleta es restablirà a la configuració predeterminada de fàbrica i es perdran totes les dades dels usuaris."</string>
+    <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="4051015943038199910">"Has provat de desbloquejar el telèfon <xliff:g id="NUMBER_0">%d</xliff:g> vegades de manera incorrecta. D\'aquí a <xliff:g id="NUMBER_1">%d</xliff:g> intents incorrectes més, el telèfon es restablirà a la configuració predeterminada de fàbrica i es perdran totes les dades dels usuaris."</string>
+    <string name="kg_failed_attempts_now_wiping" product="tablet" msgid="2072996269148483637">"Has provat de desbloquejar la tauleta <xliff:g id="NUMBER">%d</xliff:g> vegades de manera incorrecta. Ara la tauleta es restablirà a la configuració predeterminada de fàbrica."</string>
+    <string name="kg_failed_attempts_now_wiping" product="default" msgid="4817627474419471518">"Has provat de desbloquejar el telèfon <xliff:g id="NUMBER">%d</xliff:g> vegades de manera incorrecta. Ara el telèfon es restablirà a la configuració predeterminada de fàbrica."</string>
+    <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"Has dibuixat el patró de desbloqueig <xliff:g id="NUMBER_0">%d</xliff:g> vegades de manera incorrecta. Després de <xliff:g id="NUMBER_1">%d</xliff:g> intents incorrectes més, se\'t demanarà que desbloquegis la tauleta amb un compte de correu electrònic."\n\n" Torna-ho a provar d\'aquí a <xliff:g id="NUMBER_2">%d</xliff:g> segons."</string>
+    <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"Has dibuixat el patró de desbloqueig <xliff:g id="NUMBER_0">%d</xliff:g> vegades de manera incorrecta. Després de <xliff:g id="NUMBER_1">%d</xliff:g> intents incorrectes més, se\'t demanarà que desbloquegis el telèfon amb un compte de correu electrònic."\n\n" Torna-ho a provar d\'aquí a <xliff:g id="NUMBER_2">%d</xliff:g> segons."</string>
+    <string name="kg_temp_back_string" msgid="5812983904056640466">"&lt;"</string>
 </resources>
diff --git a/core/res/res/values-cs/strings.xml b/core/res/res/values-cs/strings.xml
index 5264a43..f1dca35 100644
--- a/core/res/res/values-cs/strings.xml
+++ b/core/res/res/values-cs/strings.xml
@@ -547,10 +547,8 @@
     <string name="permdesc_sdcardWrite" product="default" msgid="4337417790936632090">"Umožňuje aplikaci zapisovat na kartu SD."</string>
     <string name="permlab_mediaStorageWrite" product="default" msgid="6859839199706879015">"Upravit/smazat interní úlož."</string>
     <string name="permdesc_mediaStorageWrite" product="default" msgid="8189160597698529185">"Umožňuje aplikaci upravovat obsah interního úložiště médií."</string>
-    <!-- no translation found for permlab_sdcardAccessAll (8150613823900460576) -->
-    <skip />
-    <!-- no translation found for permdesc_sdcardAccessAll (3215208357415891320) -->
-    <skip />
+    <string name="permlab_sdcardAccessAll" msgid="8150613823900460576">"přístup k externímu úložišti všech uživatelů"</string>
+    <string name="permdesc_sdcardAccessAll" msgid="3215208357415891320">"Umožňuje aplikaci přistupovat k externímu úložišti pro všechny uživatele."</string>
     <string name="permlab_cache_filesystem" msgid="5656487264819669824">"přistupovat do souborového systému mezipaměti"</string>
     <string name="permdesc_cache_filesystem" msgid="5578967642265550955">"Umožňuje aplikaci číst a zapisovat do souborového systému mezipaměti."</string>
     <string name="permlab_use_sip" msgid="5986952362795870502">"uskutečňovat a přijímat internetové hovory"</string>
@@ -581,6 +579,10 @@
     <string name="policydesc_encryptedStorage" msgid="2637732115325316992">"Požadovat šifrování uložených dat aplikací."</string>
     <string name="policylab_disableCamera" msgid="6395301023152297826">"Vypnout fotoaparáty"</string>
     <string name="policydesc_disableCamera" msgid="2306349042834754597">"Zakázat používání všech fotoaparátů zařízení."</string>
+    <!-- no translation found for policylab_disableKeyguardWidgets (1794894613389073926) -->
+    <skip />
+    <!-- no translation found for policydesc_disableKeyguardWidgets (7254624892984033592) -->
+    <skip />
   <string-array name="phoneTypes">
     <item msgid="8901098336658710359">"Domů"</item>
     <item msgid="869923650527136615">"Mobil"</item>
@@ -1319,64 +1321,46 @@
     <string name="bluetooth_a2dp_audio_route_name" msgid="8575624030406771015">"Bluetooth Audio"</string>
     <string name="media_route_chooser_grouping_done" msgid="7966438307723317169">"Hotovo"</string>
     <string name="media_route_button_content_description" msgid="5758553567065145276">"Výstup médií"</string>
-    <!-- no translation found for display_manager_built_in_display_name (2583134294292563941) -->
+    <string name="display_manager_built_in_display_name" msgid="2583134294292563941">"Integrovaná obrazovka"</string>
+    <!-- no translation found for display_manager_hdmi_display_name (1555264559227470109) -->
     <skip />
-    <!-- no translation found for display_manager_overlay_display_name (5142365982271620716) -->
+    <string name="display_manager_overlay_display_name" msgid="5142365982271620716">"Překryvná vrstva č. <xliff:g id="ID">%1$d</xliff:g>"</string>
+    <!-- no translation found for display_manager_overlay_display_title (652124517672257172) -->
     <skip />
-    <!-- no translation found for display_manager_overlay_display_title (8186674340178573982) -->
-    <skip />
-    <!-- no translation found for kg_emergency_call_label (684946192523830531) -->
-    <skip />
-    <!-- no translation found for kg_forgot_pattern_button_text (8852021467868220608) -->
-    <skip />
-    <!-- no translation found for kg_wrong_pattern (1850806070801358830) -->
-    <skip />
-    <!-- no translation found for kg_wrong_password (2333281762128113157) -->
-    <skip />
-    <!-- no translation found for kg_wrong_pin (1131306510833563801) -->
-    <skip />
-    <!-- no translation found for kg_too_many_failed_attempts_countdown (353963338189371686) -->
-    <skip />
-    <!-- no translation found for kg_pattern_instructions (398978611683075868) -->
-    <skip />
-    <!-- no translation found for kg_sim_pin_instructions (2319508550934557331) -->
-    <skip />
-    <!-- no translation found for kg_pin_instructions (2377242233495111557) -->
-    <skip />
-    <!-- no translation found for kg_password_instructions (5753646556186936819) -->
-    <skip />
-    <!-- no translation found for kg_puk_enter_puk_hint (5183097160254244459) -->
-    <skip />
-    <!-- no translation found for kg_puk_enter_pin_hint (597821135578014901) -->
-    <skip />
-    <!-- no translation found for kg_sim_unlock_progress_dialog_message (8950398016976865762) -->
-    <skip />
-    <!-- no translation found for kg_password_wrong_pin_code (1139324887413846912) -->
-    <skip />
-    <!-- no translation found for kg_invalid_sim_pin_hint (8795159358110620001) -->
-    <skip />
-    <!-- no translation found for kg_invalid_sim_puk_hint (5216603185442368307) -->
-    <skip />
-    <!-- no translation found for kg_sim_puk_recovery_hint (5577753137718442566) -->
-    <skip />
-    <!-- no translation found for kg_invalid_puk (5809955359950817326) -->
-    <skip />
-    <!-- no translation found for kg_login_too_many_attempts (6486842094005698475) -->
-    <skip />
-    <!-- no translation found for kg_login_instructions (1100551261265506448) -->
-    <skip />
-    <!-- no translation found for kg_login_username_hint (5718534272070920364) -->
-    <skip />
-    <!-- no translation found for kg_login_password_hint (9057289103827298549) -->
-    <skip />
-    <!-- no translation found for kg_login_submit_button (5355904582674054702) -->
-    <skip />
-    <!-- no translation found for kg_login_invalid_input (5754664119319872197) -->
-    <skip />
-    <!-- no translation found for kg_login_account_recovery_hint (5690709132841752974) -->
-    <skip />
-    <!-- no translation found for kg_login_checking_password (8849589033659332457) -->
-    <skip />
-    <!-- no translation found for kg_temp_back_string (5812983904056640466) -->
-    <skip />
+    <string name="kg_emergency_call_label" msgid="684946192523830531">"Tísňové volání"</string>
+    <string name="kg_forgot_pattern_button_text" msgid="8852021467868220608">"Zapomenuté gesto"</string>
+    <string name="kg_wrong_pattern" msgid="1850806070801358830">"Nesprávné gesto"</string>
+    <string name="kg_wrong_password" msgid="2333281762128113157">"Nesprávné heslo"</string>
+    <string name="kg_wrong_pin" msgid="1131306510833563801">"Nesprávný kód PIN"</string>
+    <string name="kg_too_many_failed_attempts_countdown" msgid="6358110221603297548">"Zkuste to znovu za <xliff:g id="NUMBER">%d</xliff:g> s."</string>
+    <string name="kg_pattern_instructions" msgid="398978611683075868">"Nakreslete gesto"</string>
+    <string name="kg_sim_pin_instructions" msgid="2319508550934557331">"Zadejte kód PIN SIM karty"</string>
+    <string name="kg_pin_instructions" msgid="2377242233495111557">"Zadejte kód PIN"</string>
+    <string name="kg_password_instructions" msgid="5753646556186936819">"Zadejte heslo"</string>
+    <string name="kg_puk_enter_puk_hint" msgid="5183097160254244459">"Kód PUK"</string>
+    <string name="kg_puk_enter_pin_hint" msgid="597821135578014901">"Nový kód PIN"</string>
+    <string name="kg_sim_unlock_progress_dialog_message" msgid="8950398016976865762">"Odblokování SIM karty..."</string>
+    <string name="kg_password_wrong_pin_code" msgid="1139324887413846912">"Nesprávný kód PIN."</string>
+    <string name="kg_invalid_sim_pin_hint" msgid="8795159358110620001">"Zadejte kód PIN o délce 4–8 číslic."</string>
+    <string name="kg_invalid_sim_puk_hint" msgid="5216603185442368307">"Zadejte osmimístný nebo delší kód PUK."</string>
+    <string name="kg_sim_puk_recovery_hint" msgid="5577753137718442566">"Zadejte kód PUK a nový kód PIN."</string>
+    <string name="kg_invalid_puk" msgid="5809955359950817326">"Zadali jste nesprávný kód PUK."</string>
+    <string name="kg_login_too_many_attempts" msgid="6486842094005698475">"Příliš mnoho pokusů o nakreslení gesta"</string>
+    <string name="kg_login_instructions" msgid="1100551261265506448">"Chcete-li telefon odemknout, přihlaste se pomocí svého účtu Google."</string>
+    <string name="kg_login_username_hint" msgid="5718534272070920364">"Uživatelské jméno (e-mail)"</string>
+    <string name="kg_login_password_hint" msgid="9057289103827298549">"Heslo"</string>
+    <string name="kg_login_submit_button" msgid="5355904582674054702">"Přihlásit se"</string>
+    <string name="kg_login_invalid_input" msgid="5754664119319872197">"Neplatné uživatelské jméno nebo heslo."</string>
+    <string name="kg_login_account_recovery_hint" msgid="5690709132841752974">"Zapomněli jste uživatelské jméno nebo heslo?"\n"Přejděte na stránku "<b>"google.com/accounts/recovery"</b>"."</string>
+    <string name="kg_login_checking_password" msgid="8849589033659332457">"Kontrola…"</string>
+    <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="8276745642049502550">"Již <xliff:g id="NUMBER_0">%d</xliff:g>krát jste zadali nesprávný kód PIN. "\n\n"Zkuste to znovu za <xliff:g id="NUMBER_1">%d</xliff:g> s."</string>
+    <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="7813713389422226531">"Již <xliff:g id="NUMBER_0">%d</xliff:g>krát jste nesprávně zadali heslo. "\n\n"Zkuste to znovu za <xliff:g id="NUMBER_1">%d</xliff:g> s."</string>
+    <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="74089475965050805">"Již <xliff:g id="NUMBER_0">%d</xliff:g>krát jste zadali nesprávné bezpečnostní gesto. "\n\n"Zkuste to znovu za <xliff:g id="NUMBER_1">%d</xliff:g> s."</string>
+    <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="1575557200627128949">"Již jste se <xliff:g id="NUMBER_0">%d</xliff:g>krát pokusili odemknout tablet nesprávným způsobem. Po <xliff:g id="NUMBER_1">%d</xliff:g> dalších neúspěšných pokusech se v tabletu obnoví tovární nastavení a veškerá uživatelská data budou ztracena."</string>
+    <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="4051015943038199910">"Již jste se <xliff:g id="NUMBER_0">%d</xliff:g>krát pokusili odemknout telefon nesprávným způsobem. Po <xliff:g id="NUMBER_1">%d</xliff:g> dalších neúspěšných pokusech se v telefonu obnoví tovární nastavení a veškerá uživatelská data budou ztracena."</string>
+    <string name="kg_failed_attempts_now_wiping" product="tablet" msgid="2072996269148483637">"Již jste se <xliff:g id="NUMBER">%d</xliff:g>krát pokusili odemknout tablet nesprávným způsobem. V tabletu se nyní obnoví výchozí tovární nastavení."</string>
+    <string name="kg_failed_attempts_now_wiping" product="default" msgid="4817627474419471518">"Již jste se <xliff:g id="NUMBER">%d</xliff:g>krát pokusili odemknout telefon nesprávným způsobem. V telefonu se nyní obnoví výchozí tovární nastavení."</string>
+    <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"Již <xliff:g id="NUMBER_0">%d</xliff:g>krát jste nesprávně nakreslili své heslo odemknutí. Po <xliff:g id="NUMBER_1">%d</xliff:g>dalších neúspěšných pokusech budete požádáni o odemčení tabletu pomocí e-mailového účtu."\n\n" Zkuste to znovu za <xliff:g id="NUMBER_2">%d</xliff:g> s."</string>
+    <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"Již <xliff:g id="NUMBER_0">%d</xliff:g>krát jste nesprávně nakreslili své heslo odemknutí. Po <xliff:g id="NUMBER_1">%d</xliff:g> dalších neúspěšných pokusech budete požádáni o odemčení telefonu pomocí e-mailového účtu."\n\n" Zkuste to znovu za <xliff:g id="NUMBER_2">%d</xliff:g> s."</string>
+    <string name="kg_temp_back_string" msgid="5812983904056640466">"&lt;"</string>
 </resources>
diff --git a/core/res/res/values-da/strings.xml b/core/res/res/values-da/strings.xml
index 0aeef97..2263665 100644
--- a/core/res/res/values-da/strings.xml
+++ b/core/res/res/values-da/strings.xml
@@ -547,10 +547,8 @@
     <string name="permdesc_sdcardWrite" product="default" msgid="4337417790936632090">"Tillader, at appen kan skrive til SD-kortet."</string>
     <string name="permlab_mediaStorageWrite" product="default" msgid="6859839199706879015">"Rediger/slet internt medielagringsindhold"</string>
     <string name="permdesc_mediaStorageWrite" product="default" msgid="8189160597698529185">"Tillader, appen kan ændre indholdet af det interne medielager."</string>
-    <!-- no translation found for permlab_sdcardAccessAll (8150613823900460576) -->
-    <skip />
-    <!-- no translation found for permdesc_sdcardAccessAll (3215208357415891320) -->
-    <skip />
+    <string name="permlab_sdcardAccessAll" msgid="8150613823900460576">"få adgang til alle brugeres eksterne lagre"</string>
+    <string name="permdesc_sdcardAccessAll" msgid="3215208357415891320">"Tillader, at appen får adgang til eksterne lagre for alle brugere."</string>
     <string name="permlab_cache_filesystem" msgid="5656487264819669824">"få adgang til cache-filsystemet"</string>
     <string name="permdesc_cache_filesystem" msgid="5578967642265550955">"Tillader, at appen kan læse og skrive i cachefilsystemet."</string>
     <string name="permlab_use_sip" msgid="5986952362795870502">"foretage/modtage internetopkald"</string>
@@ -581,6 +579,10 @@
     <string name="policydesc_encryptedStorage" msgid="2637732115325316992">"Kræver, at gemte appdata krypteres."</string>
     <string name="policylab_disableCamera" msgid="6395301023152297826">"Deaktiver kameraer"</string>
     <string name="policydesc_disableCamera" msgid="2306349042834754597">"Bloker brug af alle kameraer på enheden."</string>
+    <!-- no translation found for policylab_disableKeyguardWidgets (1794894613389073926) -->
+    <skip />
+    <!-- no translation found for policydesc_disableKeyguardWidgets (7254624892984033592) -->
+    <skip />
   <string-array name="phoneTypes">
     <item msgid="8901098336658710359">"Hjem"</item>
     <item msgid="869923650527136615">"Mobil"</item>
@@ -1319,64 +1321,46 @@
     <string name="bluetooth_a2dp_audio_route_name" msgid="8575624030406771015">"Bluetooth-lyd"</string>
     <string name="media_route_chooser_grouping_done" msgid="7966438307723317169">"Udfør"</string>
     <string name="media_route_button_content_description" msgid="5758553567065145276">"Medieudgang"</string>
-    <!-- no translation found for display_manager_built_in_display_name (2583134294292563941) -->
+    <string name="display_manager_built_in_display_name" msgid="2583134294292563941">"Indbygget skærm"</string>
+    <!-- no translation found for display_manager_hdmi_display_name (1555264559227470109) -->
     <skip />
-    <!-- no translation found for display_manager_overlay_display_name (5142365982271620716) -->
+    <string name="display_manager_overlay_display_name" msgid="5142365982271620716">"Overlejring nr. <xliff:g id="ID">%1$d</xliff:g>"</string>
+    <!-- no translation found for display_manager_overlay_display_title (652124517672257172) -->
     <skip />
-    <!-- no translation found for display_manager_overlay_display_title (8186674340178573982) -->
-    <skip />
-    <!-- no translation found for kg_emergency_call_label (684946192523830531) -->
-    <skip />
-    <!-- no translation found for kg_forgot_pattern_button_text (8852021467868220608) -->
-    <skip />
-    <!-- no translation found for kg_wrong_pattern (1850806070801358830) -->
-    <skip />
-    <!-- no translation found for kg_wrong_password (2333281762128113157) -->
-    <skip />
-    <!-- no translation found for kg_wrong_pin (1131306510833563801) -->
-    <skip />
-    <!-- no translation found for kg_too_many_failed_attempts_countdown (353963338189371686) -->
-    <skip />
-    <!-- no translation found for kg_pattern_instructions (398978611683075868) -->
-    <skip />
-    <!-- no translation found for kg_sim_pin_instructions (2319508550934557331) -->
-    <skip />
-    <!-- no translation found for kg_pin_instructions (2377242233495111557) -->
-    <skip />
-    <!-- no translation found for kg_password_instructions (5753646556186936819) -->
-    <skip />
-    <!-- no translation found for kg_puk_enter_puk_hint (5183097160254244459) -->
-    <skip />
-    <!-- no translation found for kg_puk_enter_pin_hint (597821135578014901) -->
-    <skip />
-    <!-- no translation found for kg_sim_unlock_progress_dialog_message (8950398016976865762) -->
-    <skip />
-    <!-- no translation found for kg_password_wrong_pin_code (1139324887413846912) -->
-    <skip />
-    <!-- no translation found for kg_invalid_sim_pin_hint (8795159358110620001) -->
-    <skip />
-    <!-- no translation found for kg_invalid_sim_puk_hint (5216603185442368307) -->
-    <skip />
-    <!-- no translation found for kg_sim_puk_recovery_hint (5577753137718442566) -->
-    <skip />
-    <!-- no translation found for kg_invalid_puk (5809955359950817326) -->
-    <skip />
-    <!-- no translation found for kg_login_too_many_attempts (6486842094005698475) -->
-    <skip />
-    <!-- no translation found for kg_login_instructions (1100551261265506448) -->
-    <skip />
-    <!-- no translation found for kg_login_username_hint (5718534272070920364) -->
-    <skip />
-    <!-- no translation found for kg_login_password_hint (9057289103827298549) -->
-    <skip />
-    <!-- no translation found for kg_login_submit_button (5355904582674054702) -->
-    <skip />
-    <!-- no translation found for kg_login_invalid_input (5754664119319872197) -->
-    <skip />
-    <!-- no translation found for kg_login_account_recovery_hint (5690709132841752974) -->
-    <skip />
-    <!-- no translation found for kg_login_checking_password (8849589033659332457) -->
-    <skip />
-    <!-- no translation found for kg_temp_back_string (5812983904056640466) -->
-    <skip />
+    <string name="kg_emergency_call_label" msgid="684946192523830531">"Nødopkald"</string>
+    <string name="kg_forgot_pattern_button_text" msgid="8852021467868220608">"Glemt mønster"</string>
+    <string name="kg_wrong_pattern" msgid="1850806070801358830">"Forkert mønster"</string>
+    <string name="kg_wrong_password" msgid="2333281762128113157">"Forkert adgangskode"</string>
+    <string name="kg_wrong_pin" msgid="1131306510833563801">"Forkert pinkode"</string>
+    <string name="kg_too_many_failed_attempts_countdown" msgid="6358110221603297548">"Prøv igen om <xliff:g id="NUMBER">%d</xliff:g> sekunder."</string>
+    <string name="kg_pattern_instructions" msgid="398978611683075868">"Tegn dit mønster"</string>
+    <string name="kg_sim_pin_instructions" msgid="2319508550934557331">"Indtast pinkode til SIM"</string>
+    <string name="kg_pin_instructions" msgid="2377242233495111557">"Indtast pinkode"</string>
+    <string name="kg_password_instructions" msgid="5753646556186936819">"Angiv adgangskode"</string>
+    <string name="kg_puk_enter_puk_hint" msgid="5183097160254244459">"PUK-kode"</string>
+    <string name="kg_puk_enter_pin_hint" msgid="597821135578014901">"Ny pinkode"</string>
+    <string name="kg_sim_unlock_progress_dialog_message" msgid="8950398016976865762">"SIM-kortet låses op…"</string>
+    <string name="kg_password_wrong_pin_code" msgid="1139324887413846912">"Forkert pinkode."</string>
+    <string name="kg_invalid_sim_pin_hint" msgid="8795159358110620001">"Indtast en pinkode på mellem 4 og 8 tal."</string>
+    <string name="kg_invalid_sim_puk_hint" msgid="5216603185442368307">"Angiv en PUK-kode på 8 eller flere cifre."</string>
+    <string name="kg_sim_puk_recovery_hint" msgid="5577753137718442566">"Indtast PUK-koden og den nye pinkode"</string>
+    <string name="kg_invalid_puk" msgid="5809955359950817326">"Den indtastede PUK-kode er forkert."</string>
+    <string name="kg_login_too_many_attempts" msgid="6486842094005698475">"For mange forsøg på at tegne mønstret korrekt"</string>
+    <string name="kg_login_instructions" msgid="1100551261265506448">"Lås op ved at logge ind med din Google-konto."</string>
+    <string name="kg_login_username_hint" msgid="5718534272070920364">"Brugernavn (e-mail)"</string>
+    <string name="kg_login_password_hint" msgid="9057289103827298549">"Adgangskode"</string>
+    <string name="kg_login_submit_button" msgid="5355904582674054702">"Log ind"</string>
+    <string name="kg_login_invalid_input" msgid="5754664119319872197">"Ugyldigt brugernavn eller ugyldig adgangskode."</string>
+    <string name="kg_login_account_recovery_hint" msgid="5690709132841752974">"Har du glemt dit brugernavn eller din adgangskode?"\n"Gå til "<b>"google.com/accounts/recovery"</b>"."</string>
+    <string name="kg_login_checking_password" msgid="8849589033659332457">"Kontrollerer..."</string>
+    <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="8276745642049502550">"Du har indtastet en forkert pinkode <xliff:g id="NUMBER_0">%d</xliff:g> gange. "\n\n"Prøv igen om <xliff:g id="NUMBER_1">%d</xliff:g> sekunder."</string>
+    <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="7813713389422226531">"Du har indtastet din adgangskode forkert <xliff:g id="NUMBER_0">%d</xliff:g> gange. "\n\n"Prøv igen om <xliff:g id="NUMBER_1">%d</xliff:g> sekunder."</string>
+    <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="74089475965050805">"Du har tegnet dit oplåsningsmønster forkert <xliff:g id="NUMBER_0">%d</xliff:g> gange. "\n\n"Prøv igen om <xliff:g id="NUMBER_1">%d</xliff:g> sekunder."</string>
+    <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="1575557200627128949">"Du har forsøgt at låse tabletten op forkert <xliff:g id="NUMBER_0">%d</xliff:g> gange. Efter <xliff:g id="NUMBER_1">%d</xliff:g> yderligere mislykkede forsøg nulstilles tabletten til fabriksindstillingerne, og alle brugerdata mistes."</string>
+    <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="4051015943038199910">"Du har forsøgt at låse telefonen op forkert <xliff:g id="NUMBER_0">%d</xliff:g> gange. Efter <xliff:g id="NUMBER_1">%d</xliff:g> yderligere mislykkede forsøg, nulstilles telefonen til fabriksindstillingerne, og alle brugerdata mistes."</string>
+    <string name="kg_failed_attempts_now_wiping" product="tablet" msgid="2072996269148483637">"Du har forsøgt at låse tabletten op forkert <xliff:g id="NUMBER">%d</xliff:g> gange. Tabletten nulstilles til fabriksindstillingerne."</string>
+    <string name="kg_failed_attempts_now_wiping" product="default" msgid="4817627474419471518">"Du har forsøgt at låse telefonen op forkert <xliff:g id="NUMBER">%d</xliff:g> gange. Telefonen nulstilles til fabriksindstillingerne."</string>
+    <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"Du har tegnet dit oplåsningsmønster forkert <xliff:g id="NUMBER_0">%d</xliff:g> gange. Efter <xliff:g id="NUMBER_1">%d</xliff:g> yderligere mislykkede forsøg vil du blive bedt om at låse din tablet op ved hjælp af en e-mailkonto"\n\n" Prøv igen om <xliff:g id="NUMBER_2">%d</xliff:g> sekunder."</string>
+    <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"Du har tegnet dit oplåsningsmønster forkert <xliff:g id="NUMBER_0">%d</xliff:g> gange. Efter <xliff:g id="NUMBER_1">%d</xliff:g> yderligere mislykkede forsøg til vil du blive bedt om at låse din telefon op ved hjælp af en e-mailkonto."\n\n" Prøv igen om <xliff:g id="NUMBER_2">%d</xliff:g> sekunder."</string>
+    <string name="kg_temp_back_string" msgid="5812983904056640466">"&lt;"</string>
 </resources>
diff --git a/core/res/res/values-de/strings.xml b/core/res/res/values-de/strings.xml
index 8b1e8bd..2d01975 100644
--- a/core/res/res/values-de/strings.xml
+++ b/core/res/res/values-de/strings.xml
@@ -547,10 +547,8 @@
     <string name="permdesc_sdcardWrite" product="default" msgid="4337417790936632090">"Ermöglicht der App, auf die SD-Karte zu schreiben"</string>
     <string name="permlab_mediaStorageWrite" product="default" msgid="6859839199706879015">"Intern. Mediensp. änd./löschen"</string>
     <string name="permdesc_mediaStorageWrite" product="default" msgid="8189160597698529185">"Ermöglicht der App, den Inhalt des internen Medienspeichers zu ändern"</string>
-    <!-- no translation found for permlab_sdcardAccessAll (8150613823900460576) -->
-    <skip />
-    <!-- no translation found for permdesc_sdcardAccessAll (3215208357415891320) -->
-    <skip />
+    <string name="permlab_sdcardAccessAll" msgid="8150613823900460576">"Auf externen Speicher aller Nutzer zugreifen"</string>
+    <string name="permdesc_sdcardAccessAll" msgid="3215208357415891320">"Ermöglicht der App, auf externen Speicher aller Nutzer zuzugreifen."</string>
     <string name="permlab_cache_filesystem" msgid="5656487264819669824">"Zugriff auf das Cache-Dateisystem"</string>
     <string name="permdesc_cache_filesystem" msgid="5578967642265550955">"Ermöglicht der App Lese- und Schreibzugriff auf das Cache-Dateisystem"</string>
     <string name="permlab_use_sip" msgid="5986952362795870502">"Internetanrufe tätigen/annehmen"</string>
@@ -581,6 +579,10 @@
     <string name="policydesc_encryptedStorage" msgid="2637732115325316992">"Anforderung, dass gespeicherte App-Daten verschlüsselt werden"</string>
     <string name="policylab_disableCamera" msgid="6395301023152297826">"Kameras deaktivieren"</string>
     <string name="policydesc_disableCamera" msgid="2306349042834754597">"Nutzung sämtlicher Gerätekameras unterbinden"</string>
+    <!-- no translation found for policylab_disableKeyguardWidgets (1794894613389073926) -->
+    <skip />
+    <!-- no translation found for policydesc_disableKeyguardWidgets (7254624892984033592) -->
+    <skip />
   <string-array name="phoneTypes">
     <item msgid="8901098336658710359">"Privat"</item>
     <item msgid="869923650527136615">"Mobil"</item>
@@ -1172,7 +1174,7 @@
     <string name="vpn_text" msgid="3011306607126450322">"Zum Verwalten des Netzwerks berühren"</string>
     <string name="vpn_text_long" msgid="6407351006249174473">"Verbunden mit <xliff:g id="SESSION">%s</xliff:g>. Zum Verwalten des Netzwerks berühren"</string>
     <string name="vpn_lockdown_connecting" msgid="6443438964440960745">"Verbindung zu durchgehend aktivem VPN wird hergestellt…"</string>
-    <string name="vpn_lockdown_connected" msgid="8202679674819213931">"Durchgehend aktives VPN verbunden"</string>
+    <string name="vpn_lockdown_connected" msgid="8202679674819213931">"Mit durchgehend aktivem VPN verbunden"</string>
     <string name="vpn_lockdown_error" msgid="6009249814034708175">"Durchgehend aktives VPN – Verbindungsfehler"</string>
     <string name="vpn_lockdown_reset" msgid="5365010427963548932">"Zum Zurücksetzen der Verbindung tippen"</string>
     <string name="upload_file" msgid="2897957172366730416">"Datei auswählen"</string>
@@ -1319,64 +1321,46 @@
     <string name="bluetooth_a2dp_audio_route_name" msgid="8575624030406771015">"Bluetooth-Audio"</string>
     <string name="media_route_chooser_grouping_done" msgid="7966438307723317169">"Fertig"</string>
     <string name="media_route_button_content_description" msgid="5758553567065145276">"Medienausgabe"</string>
-    <!-- no translation found for display_manager_built_in_display_name (2583134294292563941) -->
+    <string name="display_manager_built_in_display_name" msgid="2583134294292563941">"Integrierter Bildschirm"</string>
+    <!-- no translation found for display_manager_hdmi_display_name (1555264559227470109) -->
     <skip />
-    <!-- no translation found for display_manager_overlay_display_name (5142365982271620716) -->
+    <string name="display_manager_overlay_display_name" msgid="5142365982271620716">"Overlay-Nr. <xliff:g id="ID">%1$d</xliff:g>"</string>
+    <!-- no translation found for display_manager_overlay_display_title (652124517672257172) -->
     <skip />
-    <!-- no translation found for display_manager_overlay_display_title (8186674340178573982) -->
-    <skip />
-    <!-- no translation found for kg_emergency_call_label (684946192523830531) -->
-    <skip />
-    <!-- no translation found for kg_forgot_pattern_button_text (8852021467868220608) -->
-    <skip />
-    <!-- no translation found for kg_wrong_pattern (1850806070801358830) -->
-    <skip />
-    <!-- no translation found for kg_wrong_password (2333281762128113157) -->
-    <skip />
-    <!-- no translation found for kg_wrong_pin (1131306510833563801) -->
-    <skip />
-    <!-- no translation found for kg_too_many_failed_attempts_countdown (353963338189371686) -->
-    <skip />
-    <!-- no translation found for kg_pattern_instructions (398978611683075868) -->
-    <skip />
-    <!-- no translation found for kg_sim_pin_instructions (2319508550934557331) -->
-    <skip />
-    <!-- no translation found for kg_pin_instructions (2377242233495111557) -->
-    <skip />
-    <!-- no translation found for kg_password_instructions (5753646556186936819) -->
-    <skip />
-    <!-- no translation found for kg_puk_enter_puk_hint (5183097160254244459) -->
-    <skip />
-    <!-- no translation found for kg_puk_enter_pin_hint (597821135578014901) -->
-    <skip />
-    <!-- no translation found for kg_sim_unlock_progress_dialog_message (8950398016976865762) -->
-    <skip />
-    <!-- no translation found for kg_password_wrong_pin_code (1139324887413846912) -->
-    <skip />
-    <!-- no translation found for kg_invalid_sim_pin_hint (8795159358110620001) -->
-    <skip />
-    <!-- no translation found for kg_invalid_sim_puk_hint (5216603185442368307) -->
-    <skip />
-    <!-- no translation found for kg_sim_puk_recovery_hint (5577753137718442566) -->
-    <skip />
-    <!-- no translation found for kg_invalid_puk (5809955359950817326) -->
-    <skip />
-    <!-- no translation found for kg_login_too_many_attempts (6486842094005698475) -->
-    <skip />
-    <!-- no translation found for kg_login_instructions (1100551261265506448) -->
-    <skip />
-    <!-- no translation found for kg_login_username_hint (5718534272070920364) -->
-    <skip />
-    <!-- no translation found for kg_login_password_hint (9057289103827298549) -->
-    <skip />
-    <!-- no translation found for kg_login_submit_button (5355904582674054702) -->
-    <skip />
-    <!-- no translation found for kg_login_invalid_input (5754664119319872197) -->
-    <skip />
-    <!-- no translation found for kg_login_account_recovery_hint (5690709132841752974) -->
-    <skip />
-    <!-- no translation found for kg_login_checking_password (8849589033659332457) -->
-    <skip />
-    <!-- no translation found for kg_temp_back_string (5812983904056640466) -->
-    <skip />
+    <string name="kg_emergency_call_label" msgid="684946192523830531">"Notruf"</string>
+    <string name="kg_forgot_pattern_button_text" msgid="8852021467868220608">"Muster vergessen"</string>
+    <string name="kg_wrong_pattern" msgid="1850806070801358830">"Falsches Muster"</string>
+    <string name="kg_wrong_password" msgid="2333281762128113157">"Falsches Passwort"</string>
+    <string name="kg_wrong_pin" msgid="1131306510833563801">"Falsche PIN"</string>
+    <string name="kg_too_many_failed_attempts_countdown" msgid="6358110221603297548">"Versuchen Sie es in <xliff:g id="NUMBER">%d</xliff:g> Sekunden erneut."</string>
+    <string name="kg_pattern_instructions" msgid="398978611683075868">"Muster zeichnen"</string>
+    <string name="kg_sim_pin_instructions" msgid="2319508550934557331">"SIM-PIN eingeben"</string>
+    <string name="kg_pin_instructions" msgid="2377242233495111557">"PIN eingeben"</string>
+    <string name="kg_password_instructions" msgid="5753646556186936819">"Passwort eingeben"</string>
+    <string name="kg_puk_enter_puk_hint" msgid="5183097160254244459">"PUK-Code"</string>
+    <string name="kg_puk_enter_pin_hint" msgid="597821135578014901">"Neuer PIN-Code"</string>
+    <string name="kg_sim_unlock_progress_dialog_message" msgid="8950398016976865762">"SIM-Karte wird entsperrt…"</string>
+    <string name="kg_password_wrong_pin_code" msgid="1139324887413846912">"Falscher PIN-Code"</string>
+    <string name="kg_invalid_sim_pin_hint" msgid="8795159358110620001">"Geben Sie eine 4- bis 8-stellige PIN ein."</string>
+    <string name="kg_invalid_sim_puk_hint" msgid="5216603185442368307">"Geben Sie eine mindestens 8-stellige PUK ein."</string>
+    <string name="kg_sim_puk_recovery_hint" msgid="5577753137718442566">"PUK und neuen PIN-Code eingeben"</string>
+    <string name="kg_invalid_puk" msgid="5809955359950817326">"Die von Ihnen eingegebene PUK ist nicht korrekt."</string>
+    <string name="kg_login_too_many_attempts" msgid="6486842094005698475">"Zu viele Musterversuche"</string>
+    <string name="kg_login_instructions" msgid="1100551261265506448">"Melden Sie sich zum Entsperren mit Ihrem Google-Konto an."</string>
+    <string name="kg_login_username_hint" msgid="5718534272070920364">"Nutzername (E-Mail)"</string>
+    <string name="kg_login_password_hint" msgid="9057289103827298549">"Passwort"</string>
+    <string name="kg_login_submit_button" msgid="5355904582674054702">"Anmelden"</string>
+    <string name="kg_login_invalid_input" msgid="5754664119319872197">"Ungültiger Nutzername oder ungültiges Passwort"</string>
+    <string name="kg_login_account_recovery_hint" msgid="5690709132841752974">"Nutzernamen oder Passwort vergessen?"\n"Besuchen Sie "<b>"google.com/accounts/recovery"</b>"."</string>
+    <string name="kg_login_checking_password" msgid="8849589033659332457">"Überprüfung…"</string>
+    <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="8276745642049502550">"Sie haben Ihre PIN <xliff:g id="NUMBER_0">%d</xliff:g>-mal falsch eingegeben."\n\n"Versuchen Sie es in <xliff:g id="NUMBER_1">%d</xliff:g> Sekunden erneut."</string>
+    <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="7813713389422226531">"Sie haben Ihr Passwort <xliff:g id="NUMBER_0">%d</xliff:g>-mal falsch eingegeben."\n\n"Versuchen Sie es in <xliff:g id="NUMBER_1">%d</xliff:g> Sekunden erneut."</string>
+    <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="74089475965050805">"Sie haben Ihr Entsperrungsmuster <xliff:g id="NUMBER_0">%d</xliff:g>-mal falsch gezeichnet. "\n\n"Versuchen Sie es in <xliff:g id="NUMBER_1">%d</xliff:g> Sekunden erneut."</string>
+    <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="1575557200627128949">"Sie haben <xliff:g id="NUMBER_0">%d</xliff:g>-mal erfolglos versucht, das Tablet zu entsperren. Nach <xliff:g id="NUMBER_1">%d</xliff:g> weiteren erfolglosen Versuchen wird das Tablet auf die Werkseinstellungen zurückgesetzt und alle Nutzerdaten gehen verloren."</string>
+    <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="4051015943038199910">"Sie haben <xliff:g id="NUMBER_0">%d</xliff:g>-mal erfolglos versucht, das Telefon zu entsperren. Nach <xliff:g id="NUMBER_1">%d</xliff:g> weiteren erfolglosen Versuchen wird das Telefon auf die Werkseinstellungen zurückgesetzt und alle Nutzerdaten gehen verloren."</string>
+    <string name="kg_failed_attempts_now_wiping" product="tablet" msgid="2072996269148483637">"Sie haben <xliff:g id="NUMBER">%d</xliff:g>-mal erfolglos versucht, das Tablet zu entsperren. Das Tablet wird nun auf die Werkseinstellungen zurückgesetzt."</string>
+    <string name="kg_failed_attempts_now_wiping" product="default" msgid="4817627474419471518">"Sie haben <xliff:g id="NUMBER">%d</xliff:g>-mal erfolglos versucht, das Telefon zu entsperren. Das Telefon wird nun auf die Werkseinstellungen zurückgesetzt."</string>
+    <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"Sie haben Ihr Entsperrungsmuster <xliff:g id="NUMBER_0">%d</xliff:g>-mal falsch gezeichnet. Nach <xliff:g id="NUMBER_1">%d</xliff:g> weiteren erfolglosen Versuchen werden Sie aufgefordert, Ihr Tablet mithilfe eines E-Mail-Kontos zu entsperren."\n\n" Versuchen Sie es in <xliff:g id="NUMBER_2">%d</xliff:g> Sekunden erneut."</string>
+    <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"Sie haben Ihr Entsperrungsmuster <xliff:g id="NUMBER_0">%d</xliff:g>-mal falsch gezeichnet. Nach <xliff:g id="NUMBER_1">%d</xliff:g> weiteren erfolglosen Versuchen werden Sie aufgefordert, Ihr Telefon mithilfe eines E-Mail-Kontos zu entsperren."\n\n" Versuchen Sie es in <xliff:g id="NUMBER_2">%d</xliff:g> Sekunden erneut."</string>
+    <string name="kg_temp_back_string" msgid="5812983904056640466">"&lt;"</string>
 </resources>
diff --git a/core/res/res/values-el/strings.xml b/core/res/res/values-el/strings.xml
index a299dab..40ed1bd 100644
--- a/core/res/res/values-el/strings.xml
+++ b/core/res/res/values-el/strings.xml
@@ -547,10 +547,8 @@
     <string name="permdesc_sdcardWrite" product="default" msgid="4337417790936632090">"Επιτρέπει στην εφαρμογή την εγγραφή στην κάρτα SD."</string>
     <string name="permlab_mediaStorageWrite" product="default" msgid="6859839199706879015">"τροπ./διαγ. περ. απ. εσ. μνήμ."</string>
     <string name="permdesc_mediaStorageWrite" product="default" msgid="8189160597698529185">"Επιτρέπει στην εφαρμογή να τροποποιήσει τα περιεχόμενα των εσωτερικών μέσων αποθήκευσης."</string>
-    <!-- no translation found for permlab_sdcardAccessAll (8150613823900460576) -->
-    <skip />
-    <!-- no translation found for permdesc_sdcardAccessAll (3215208357415891320) -->
-    <skip />
+    <string name="permlab_sdcardAccessAll" msgid="8150613823900460576">"πρόσβ.εξωτ.χωρ. αποθ. όλων των χρηστ."</string>
+    <string name="permdesc_sdcardAccessAll" msgid="3215208357415891320">"Επιτρέπει στην εφαρμογή να αποκτήσει πρόσβαση σε εξωτερικό χώρο αποθήκευσης για όλους τους χρήστες."</string>
     <string name="permlab_cache_filesystem" msgid="5656487264819669824">"πρόσβαση στο σύστημα αρχείων προσωρινής μνήμης"</string>
     <string name="permdesc_cache_filesystem" msgid="5578967642265550955">"Επιτρέπει στην εφαρμογή την ανάγνωση και την εγγραφή του συστήματος αρχείων προσωρινής μνήμης."</string>
     <string name="permlab_use_sip" msgid="5986952362795870502">"πραγματοποίηση/λήψη κλήσεων μέσω Διαδικτύου"</string>
@@ -581,6 +579,10 @@
     <string name="policydesc_encryptedStorage" msgid="2637732115325316992">"Να απαιτείται η κρυπτογράφηση των αποθηκευμένων δεδομένων εφαρμογής"</string>
     <string name="policylab_disableCamera" msgid="6395301023152297826">"Απενεργοποίηση φωτογρ. μηχανών"</string>
     <string name="policydesc_disableCamera" msgid="2306349042834754597">"Να αποτρέπεται η χρήση των φωτογραφικών μηχανών της συσκευής."</string>
+    <!-- no translation found for policylab_disableKeyguardWidgets (1794894613389073926) -->
+    <skip />
+    <!-- no translation found for policydesc_disableKeyguardWidgets (7254624892984033592) -->
+    <skip />
   <string-array name="phoneTypes">
     <item msgid="8901098336658710359">"Οικία"</item>
     <item msgid="869923650527136615">"Κινητό"</item>
@@ -1319,64 +1321,46 @@
     <string name="bluetooth_a2dp_audio_route_name" msgid="8575624030406771015">"Ήχος Bluetooth"</string>
     <string name="media_route_chooser_grouping_done" msgid="7966438307723317169">"Τέλος"</string>
     <string name="media_route_button_content_description" msgid="5758553567065145276">"Έξοδος μέσων"</string>
-    <!-- no translation found for display_manager_built_in_display_name (2583134294292563941) -->
+    <string name="display_manager_built_in_display_name" msgid="2583134294292563941">"Ενσωματωμένη οθόνη"</string>
+    <!-- no translation found for display_manager_hdmi_display_name (1555264559227470109) -->
     <skip />
-    <!-- no translation found for display_manager_overlay_display_name (5142365982271620716) -->
+    <string name="display_manager_overlay_display_name" msgid="5142365982271620716">"Επικάλυψη #<xliff:g id="ID">%1$d</xliff:g>"</string>
+    <!-- no translation found for display_manager_overlay_display_title (652124517672257172) -->
     <skip />
-    <!-- no translation found for display_manager_overlay_display_title (8186674340178573982) -->
-    <skip />
-    <!-- no translation found for kg_emergency_call_label (684946192523830531) -->
-    <skip />
-    <!-- no translation found for kg_forgot_pattern_button_text (8852021467868220608) -->
-    <skip />
-    <!-- no translation found for kg_wrong_pattern (1850806070801358830) -->
-    <skip />
-    <!-- no translation found for kg_wrong_password (2333281762128113157) -->
-    <skip />
-    <!-- no translation found for kg_wrong_pin (1131306510833563801) -->
-    <skip />
-    <!-- no translation found for kg_too_many_failed_attempts_countdown (353963338189371686) -->
-    <skip />
-    <!-- no translation found for kg_pattern_instructions (398978611683075868) -->
-    <skip />
-    <!-- no translation found for kg_sim_pin_instructions (2319508550934557331) -->
-    <skip />
-    <!-- no translation found for kg_pin_instructions (2377242233495111557) -->
-    <skip />
-    <!-- no translation found for kg_password_instructions (5753646556186936819) -->
-    <skip />
-    <!-- no translation found for kg_puk_enter_puk_hint (5183097160254244459) -->
-    <skip />
-    <!-- no translation found for kg_puk_enter_pin_hint (597821135578014901) -->
-    <skip />
-    <!-- no translation found for kg_sim_unlock_progress_dialog_message (8950398016976865762) -->
-    <skip />
-    <!-- no translation found for kg_password_wrong_pin_code (1139324887413846912) -->
-    <skip />
-    <!-- no translation found for kg_invalid_sim_pin_hint (8795159358110620001) -->
-    <skip />
-    <!-- no translation found for kg_invalid_sim_puk_hint (5216603185442368307) -->
-    <skip />
-    <!-- no translation found for kg_sim_puk_recovery_hint (5577753137718442566) -->
-    <skip />
-    <!-- no translation found for kg_invalid_puk (5809955359950817326) -->
-    <skip />
-    <!-- no translation found for kg_login_too_many_attempts (6486842094005698475) -->
-    <skip />
-    <!-- no translation found for kg_login_instructions (1100551261265506448) -->
-    <skip />
-    <!-- no translation found for kg_login_username_hint (5718534272070920364) -->
-    <skip />
-    <!-- no translation found for kg_login_password_hint (9057289103827298549) -->
-    <skip />
-    <!-- no translation found for kg_login_submit_button (5355904582674054702) -->
-    <skip />
-    <!-- no translation found for kg_login_invalid_input (5754664119319872197) -->
-    <skip />
-    <!-- no translation found for kg_login_account_recovery_hint (5690709132841752974) -->
-    <skip />
-    <!-- no translation found for kg_login_checking_password (8849589033659332457) -->
-    <skip />
-    <!-- no translation found for kg_temp_back_string (5812983904056640466) -->
-    <skip />
+    <string name="kg_emergency_call_label" msgid="684946192523830531">"Κλήσεις επείγουσας ανάγκης"</string>
+    <string name="kg_forgot_pattern_button_text" msgid="8852021467868220608">"Ξεχάσατε το μοτίβο"</string>
+    <string name="kg_wrong_pattern" msgid="1850806070801358830">"Εσφαλμένο μοτίβο"</string>
+    <string name="kg_wrong_password" msgid="2333281762128113157">"Εσφαλμένος κωδικός πρόσβασης"</string>
+    <string name="kg_wrong_pin" msgid="1131306510833563801">"Εσφαλμένος κωδικός PIN"</string>
+    <string name="kg_too_many_failed_attempts_countdown" msgid="6358110221603297548">"Δοκιμάστε ξανά σε <xliff:g id="NUMBER">%d</xliff:g> δευτερόλεπτα."</string>
+    <string name="kg_pattern_instructions" msgid="398978611683075868">"Σχεδιάστε το μοτίβο σας"</string>
+    <string name="kg_sim_pin_instructions" msgid="2319508550934557331">"Εισαγωγή PIN SIM"</string>
+    <string name="kg_pin_instructions" msgid="2377242233495111557">"Πληκτρολογήστε το PIN"</string>
+    <string name="kg_password_instructions" msgid="5753646556186936819">"Εισαγάγετε κωδικό πρόσβασης"</string>
+    <string name="kg_puk_enter_puk_hint" msgid="5183097160254244459">"Κωδικός PUK"</string>
+    <string name="kg_puk_enter_pin_hint" msgid="597821135578014901">"Νέος κωδικός PIN"</string>
+    <string name="kg_sim_unlock_progress_dialog_message" msgid="8950398016976865762">"Ξεκλείδωμα κάρτας SIM..."</string>
+    <string name="kg_password_wrong_pin_code" msgid="1139324887413846912">"Εσφαλμένος κωδικός PIN."</string>
+    <string name="kg_invalid_sim_pin_hint" msgid="8795159358110620001">"Πληκτρολογήστε έναν αριθμό PIN που να αποτελείται από 4 έως 8 αριθμούς."</string>
+    <string name="kg_invalid_sim_puk_hint" msgid="5216603185442368307">"Πληκτρολογήστε έναν κωδικό PUK με 8 αριθμούς ή περισσότερους."</string>
+    <string name="kg_sim_puk_recovery_hint" msgid="5577753137718442566">"Πληκτρολογήστε τον κωδικό PUK και τον νέο κωδικό PIN"</string>
+    <string name="kg_invalid_puk" msgid="5809955359950817326">"Ο κωδικός PUK που πληκτρολογήσατε είναι εσφαλμένος."</string>
+    <string name="kg_login_too_many_attempts" msgid="6486842094005698475">"Πάρα πολλές προσπάθειες μοτίβου"</string>
+    <string name="kg_login_instructions" msgid="1100551261265506448">"Για ξεκλείδωμα, συνδεθείτε με τον λογαριασμό σας Google."</string>
+    <string name="kg_login_username_hint" msgid="5718534272070920364">"Όνομα χρήστη (διεύθυνση ηλεκτρονικού ταχυδρομείου)"</string>
+    <string name="kg_login_password_hint" msgid="9057289103827298549">"Κωδικός πρόσβασης"</string>
+    <string name="kg_login_submit_button" msgid="5355904582674054702">"Σύνδεση"</string>
+    <string name="kg_login_invalid_input" msgid="5754664119319872197">"Μη έγκυρο όνομα χρήστη ή κωδικός πρόσβασης."</string>
+    <string name="kg_login_account_recovery_hint" msgid="5690709132841752974">"Ξεχάσατε το όνομα χρήστη ή τον κωδικό πρόσβασής σας;"\n"Επισκεφτείτε τη διεύθυνση "<b>"google.com/accounts/recovery"</b>"."</string>
+    <string name="kg_login_checking_password" msgid="8849589033659332457">"Έλεγχος…"</string>
+    <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="8276745642049502550">"Έχετε πληκτρολογήσει εσφαλμένα τον κωδικό σας PIN <xliff:g id="NUMBER_0">%d</xliff:g> φορές. "\n\n"Δοκιμάστε ξανά σε <xliff:g id="NUMBER_1">%d</xliff:g> δευτερόλεπτα."</string>
+    <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="7813713389422226531">"Έχετε πληκτρολογήσει τον κωδικό πρόσβασης εσφαλμένα <xliff:g id="NUMBER_0">%d</xliff:g> φορές. "\n\n"Δοκιμάστε ξανά σε <xliff:g id="NUMBER_1">%d</xliff:g> δευτερόλεπτα."</string>
+    <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="74089475965050805">"Σχεδιάσατε εσφαλμένα το μοτίβο ξεκλειδώματος <xliff:g id="NUMBER_0">%d</xliff:g> φορές. "\n\n"Δοκιμάστε ξανά σε <xliff:g id="NUMBER_1">%d</xliff:g> δευτερόλετπα."</string>
+    <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="1575557200627128949">"Προσπαθήσατε να ξεκλειδώσετε εσφαλμένα το tablet <xliff:g id="NUMBER_0">%d</xliff:g> φορές. Μετά από <xliff:g id="NUMBER_1">%d</xliff:g> προσπάθειες, το tablet θα επαναφερθεί στις εργοστασιακές ρυθμίσεις και όλα τα δεδομένα χρήστη θα χαθούν."</string>
+    <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="4051015943038199910">"Προσπαθήσατε να ξεκλειδώσετε εσφαλμένα το τηλέφωνο <xliff:g id="NUMBER_0">%d</xliff:g> φορές. Μετά από <xliff:g id="NUMBER_1">%d</xliff:g> προσπάθειες, το τηλέφωνο θα επαναφερθεί στις εργοστασιακές ρυθμίσεις και όλα τα δεδομένα χρήστη θα χαθούν."</string>
+    <string name="kg_failed_attempts_now_wiping" product="tablet" msgid="2072996269148483637">"Προσπαθήσατε να ξεκλειδώσετε εσφαλμένα το tablet <xliff:g id="NUMBER">%d</xliff:g> φορές. Το tablet θα επαναφερθεί στις εργοστασιακές ρυθμίσεις."</string>
+    <string name="kg_failed_attempts_now_wiping" product="default" msgid="4817627474419471518">"Προσπαθήσατε να ξεκλειδώσετε εσφαλμένα το τηλέφωνο <xliff:g id="NUMBER">%d</xliff:g> φορές. Το τηλέφωνο θα επαναφερθεί στις εργοστασιακές ρυθμίσεις."</string>
+    <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"Σχεδιάσατε το μοτίβο ξεκλειδώματος εσφαλμένα <xliff:g id="NUMBER_0">%d</xliff:g> φορές. Μετά από <xliff:g id="NUMBER_1">%d</xliff:g> ανεπιτυχείς προσπάθειες ακόμη, θα σας ζητηθεί να ξεκλειδώσετε το tablet σας με τη χρήση ενός λογαριασμού ηλεκτρονικού ταχυδρομείου."\n\n" Δοκιμάστε να συνδεθείτε ξανά σε <xliff:g id="NUMBER_2">%d</xliff:g> δευτερόλεπτα."</string>
+    <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"Σχεδιάσατε το μοτίβο ξεκλειδώματος εσφαλμένα <xliff:g id="NUMBER_0">%d</xliff:g> φορές. Μετά από <xliff:g id="NUMBER_1">%d</xliff:g> ανεπιτυχείς προσπάθειες ακόμη, θα σας ζητηθεί να ξεκλειδώσετε το τηλέφωνό σας με τη χρήση ενός λογαριασμού ηλεκτρονικού ταχυδρομείου."\n\n" Δοκιμάστε ξανά σε <xliff:g id="NUMBER_2">%d</xliff:g> δευτερόλεπτα."</string>
+    <string name="kg_temp_back_string" msgid="5812983904056640466">"&lt;"</string>
 </resources>
diff --git a/core/res/res/values-en-rGB/strings.xml b/core/res/res/values-en-rGB/strings.xml
index 2d96b9a..65f2f77 100644
--- a/core/res/res/values-en-rGB/strings.xml
+++ b/core/res/res/values-en-rGB/strings.xml
@@ -547,10 +547,8 @@
     <string name="permdesc_sdcardWrite" product="default" msgid="4337417790936632090">"Allows the app to write to the SD card."</string>
     <string name="permlab_mediaStorageWrite" product="default" msgid="6859839199706879015">"modify/delete internal media storage contents"</string>
     <string name="permdesc_mediaStorageWrite" product="default" msgid="8189160597698529185">"Allows the app to modify the contents of the internal media storage."</string>
-    <!-- no translation found for permlab_sdcardAccessAll (8150613823900460576) -->
-    <skip />
-    <!-- no translation found for permdesc_sdcardAccessAll (3215208357415891320) -->
-    <skip />
+    <string name="permlab_sdcardAccessAll" msgid="8150613823900460576">"access external storage of all users"</string>
+    <string name="permdesc_sdcardAccessAll" msgid="3215208357415891320">"Allows the app to access external storage for all users."</string>
     <string name="permlab_cache_filesystem" msgid="5656487264819669824">"access the cache file system"</string>
     <string name="permdesc_cache_filesystem" msgid="5578967642265550955">"Allows the app to read and write the cache file system."</string>
     <string name="permlab_use_sip" msgid="5986952362795870502">"make/receive Internet calls"</string>
@@ -581,6 +579,10 @@
     <string name="policydesc_encryptedStorage" msgid="2637732115325316992">"Require that stored app data be encrypted."</string>
     <string name="policylab_disableCamera" msgid="6395301023152297826">"Disable cameras"</string>
     <string name="policydesc_disableCamera" msgid="2306349042834754597">"Prevent use of all device cameras."</string>
+    <!-- no translation found for policylab_disableKeyguardWidgets (1794894613389073926) -->
+    <skip />
+    <!-- no translation found for policydesc_disableKeyguardWidgets (7254624892984033592) -->
+    <skip />
   <string-array name="phoneTypes">
     <item msgid="8901098336658710359">"Home"</item>
     <item msgid="869923650527136615">"Mobile"</item>
@@ -1319,64 +1321,46 @@
     <string name="bluetooth_a2dp_audio_route_name" msgid="8575624030406771015">"Bluetooth audio"</string>
     <string name="media_route_chooser_grouping_done" msgid="7966438307723317169">"Done"</string>
     <string name="media_route_button_content_description" msgid="5758553567065145276">"Media output"</string>
-    <!-- no translation found for display_manager_built_in_display_name (2583134294292563941) -->
+    <string name="display_manager_built_in_display_name" msgid="2583134294292563941">"Built-in Screen"</string>
+    <!-- no translation found for display_manager_hdmi_display_name (1555264559227470109) -->
     <skip />
-    <!-- no translation found for display_manager_overlay_display_name (5142365982271620716) -->
+    <string name="display_manager_overlay_display_name" msgid="5142365982271620716">"Overlay #<xliff:g id="ID">%1$d</xliff:g>"</string>
+    <!-- no translation found for display_manager_overlay_display_title (652124517672257172) -->
     <skip />
-    <!-- no translation found for display_manager_overlay_display_title (8186674340178573982) -->
-    <skip />
-    <!-- no translation found for kg_emergency_call_label (684946192523830531) -->
-    <skip />
-    <!-- no translation found for kg_forgot_pattern_button_text (8852021467868220608) -->
-    <skip />
-    <!-- no translation found for kg_wrong_pattern (1850806070801358830) -->
-    <skip />
-    <!-- no translation found for kg_wrong_password (2333281762128113157) -->
-    <skip />
-    <!-- no translation found for kg_wrong_pin (1131306510833563801) -->
-    <skip />
-    <!-- no translation found for kg_too_many_failed_attempts_countdown (353963338189371686) -->
-    <skip />
-    <!-- no translation found for kg_pattern_instructions (398978611683075868) -->
-    <skip />
-    <!-- no translation found for kg_sim_pin_instructions (2319508550934557331) -->
-    <skip />
-    <!-- no translation found for kg_pin_instructions (2377242233495111557) -->
-    <skip />
-    <!-- no translation found for kg_password_instructions (5753646556186936819) -->
-    <skip />
-    <!-- no translation found for kg_puk_enter_puk_hint (5183097160254244459) -->
-    <skip />
-    <!-- no translation found for kg_puk_enter_pin_hint (597821135578014901) -->
-    <skip />
-    <!-- no translation found for kg_sim_unlock_progress_dialog_message (8950398016976865762) -->
-    <skip />
-    <!-- no translation found for kg_password_wrong_pin_code (1139324887413846912) -->
-    <skip />
-    <!-- no translation found for kg_invalid_sim_pin_hint (8795159358110620001) -->
-    <skip />
-    <!-- no translation found for kg_invalid_sim_puk_hint (5216603185442368307) -->
-    <skip />
-    <!-- no translation found for kg_sim_puk_recovery_hint (5577753137718442566) -->
-    <skip />
-    <!-- no translation found for kg_invalid_puk (5809955359950817326) -->
-    <skip />
-    <!-- no translation found for kg_login_too_many_attempts (6486842094005698475) -->
-    <skip />
-    <!-- no translation found for kg_login_instructions (1100551261265506448) -->
-    <skip />
-    <!-- no translation found for kg_login_username_hint (5718534272070920364) -->
-    <skip />
-    <!-- no translation found for kg_login_password_hint (9057289103827298549) -->
-    <skip />
-    <!-- no translation found for kg_login_submit_button (5355904582674054702) -->
-    <skip />
-    <!-- no translation found for kg_login_invalid_input (5754664119319872197) -->
-    <skip />
-    <!-- no translation found for kg_login_account_recovery_hint (5690709132841752974) -->
-    <skip />
-    <!-- no translation found for kg_login_checking_password (8849589033659332457) -->
-    <skip />
-    <!-- no translation found for kg_temp_back_string (5812983904056640466) -->
-    <skip />
+    <string name="kg_emergency_call_label" msgid="684946192523830531">"Emergency call"</string>
+    <string name="kg_forgot_pattern_button_text" msgid="8852021467868220608">"Forgot Pattern"</string>
+    <string name="kg_wrong_pattern" msgid="1850806070801358830">"Wrong Pattern"</string>
+    <string name="kg_wrong_password" msgid="2333281762128113157">"Wrong Password"</string>
+    <string name="kg_wrong_pin" msgid="1131306510833563801">"Wrong PIN"</string>
+    <string name="kg_too_many_failed_attempts_countdown" msgid="6358110221603297548">"Try again in <xliff:g id="NUMBER">%d</xliff:g> seconds."</string>
+    <string name="kg_pattern_instructions" msgid="398978611683075868">"Draw your pattern"</string>
+    <string name="kg_sim_pin_instructions" msgid="2319508550934557331">"Enter SIM PIN"</string>
+    <string name="kg_pin_instructions" msgid="2377242233495111557">"Enter PIN"</string>
+    <string name="kg_password_instructions" msgid="5753646556186936819">"Enter Password"</string>
+    <string name="kg_puk_enter_puk_hint" msgid="5183097160254244459">"PUK code"</string>
+    <string name="kg_puk_enter_pin_hint" msgid="597821135578014901">"New PIN code"</string>
+    <string name="kg_sim_unlock_progress_dialog_message" msgid="8950398016976865762">"Unlocking SIM card…"</string>
+    <string name="kg_password_wrong_pin_code" msgid="1139324887413846912">"Incorrect PIN code."</string>
+    <string name="kg_invalid_sim_pin_hint" msgid="8795159358110620001">"Type a PIN that is 4 to 8 numbers."</string>
+    <string name="kg_invalid_sim_puk_hint" msgid="5216603185442368307">"Type a PUK that is 8 numbers or longer."</string>
+    <string name="kg_sim_puk_recovery_hint" msgid="5577753137718442566">"Type PUK and new PIN code"</string>
+    <string name="kg_invalid_puk" msgid="5809955359950817326">"The PUK you typed isn\'t correct."</string>
+    <string name="kg_login_too_many_attempts" msgid="6486842094005698475">"Too many pattern attempts"</string>
+    <string name="kg_login_instructions" msgid="1100551261265506448">"To unlock, sign in with your Google account."</string>
+    <string name="kg_login_username_hint" msgid="5718534272070920364">"Username (email)"</string>
+    <string name="kg_login_password_hint" msgid="9057289103827298549">"Password"</string>
+    <string name="kg_login_submit_button" msgid="5355904582674054702">"Sign in"</string>
+    <string name="kg_login_invalid_input" msgid="5754664119319872197">"Invalid username or password."</string>
+    <string name="kg_login_account_recovery_hint" msgid="5690709132841752974">"Forgot your username or password?"\n"Visit "<b>"google.com/accounts/recovery"</b>"."</string>
+    <string name="kg_login_checking_password" msgid="8849589033659332457">"Checking…"</string>
+    <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="8276745642049502550">"You have incorrectly typed your PIN <xliff:g id="NUMBER_0">%d</xliff:g> times. "\n\n"Try again in <xliff:g id="NUMBER_1">%d</xliff:g> seconds."</string>
+    <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="7813713389422226531">"You have incorrectly typed your password <xliff:g id="NUMBER_0">%d</xliff:g> times. "\n\n"Try again in <xliff:g id="NUMBER_1">%d</xliff:g> seconds."</string>
+    <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="74089475965050805">"You have incorrectly drawn your unlock pattern <xliff:g id="NUMBER_0">%d</xliff:g> times. "\n\n"Try again in <xliff:g id="NUMBER_1">%d</xliff:g> seconds."</string>
+    <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="1575557200627128949">"You have incorrectly attempted to unlock the tablet <xliff:g id="NUMBER_0">%d</xliff:g> times. After <xliff:g id="NUMBER_1">%d</xliff:g> more unsuccessful attempts, the tablet will be reset to factory default and all user data will be lost."</string>
+    <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="4051015943038199910">"You have incorrectly attempted to unlock the phone <xliff:g id="NUMBER_0">%d</xliff:g> times. After <xliff:g id="NUMBER_1">%d</xliff:g> more unsuccessful attempts, the phone will be reset to factory default and all user data will be lost."</string>
+    <string name="kg_failed_attempts_now_wiping" product="tablet" msgid="2072996269148483637">"You have incorrectly attempted to unlock the tablet <xliff:g id="NUMBER">%d</xliff:g> times. The tablet will now be reset to factory default."</string>
+    <string name="kg_failed_attempts_now_wiping" product="default" msgid="4817627474419471518">"You have incorrectly attempted to unlock the phone <xliff:g id="NUMBER">%d</xliff:g> times. The phone will now be reset to factory default."</string>
+    <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"You have incorrectly drawn your unlock pattern <xliff:g id="NUMBER_0">%d</xliff:g> times. After <xliff:g id="NUMBER_1">%d</xliff:g> more unsuccessful attempts, you will be asked to unlock your tablet using an email account."\n\n" Try again in <xliff:g id="NUMBER_2">%d</xliff:g> seconds."</string>
+    <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"You have incorrectly drawn your unlock pattern <xliff:g id="NUMBER_0">%d</xliff:g> times. After <xliff:g id="NUMBER_1">%d</xliff:g> more unsuccessful attempts, you will be asked to unlock your phone using an email account."\n\n" Try again in <xliff:g id="NUMBER_2">%d</xliff:g> seconds."</string>
+    <string name="kg_temp_back_string" msgid="5812983904056640466">"&lt;"</string>
 </resources>
diff --git a/core/res/res/values-es-rUS/strings.xml b/core/res/res/values-es-rUS/strings.xml
index bd41ffc..14711ba 100644
--- a/core/res/res/values-es-rUS/strings.xml
+++ b/core/res/res/values-es-rUS/strings.xml
@@ -547,10 +547,8 @@
     <string name="permdesc_sdcardWrite" product="default" msgid="4337417790936632090">"Admite que la aplicación escriba en la tarjeta SD."</string>
     <string name="permlab_mediaStorageWrite" product="default" msgid="6859839199706879015">"modificar/eliminar los contenidos del almacenamientos de medios internos"</string>
     <string name="permdesc_mediaStorageWrite" product="default" msgid="8189160597698529185">"Permite que la aplicación modifique el contenido del almacenamiento de medios interno."</string>
-    <!-- no translation found for permlab_sdcardAccessAll (8150613823900460576) -->
-    <skip />
-    <!-- no translation found for permdesc_sdcardAccessAll (3215208357415891320) -->
-    <skip />
+    <string name="permlab_sdcardAccessAll" msgid="8150613823900460576">"acceder almacenamiento externo"</string>
+    <string name="permdesc_sdcardAccessAll" msgid="3215208357415891320">"Permite que la aplicación acceda al almacenamiento externo de todos los usuarios."</string>
     <string name="permlab_cache_filesystem" msgid="5656487264819669824">"Acceder al sistema de archivos caché"</string>
     <string name="permdesc_cache_filesystem" msgid="5578967642265550955">"Permite que la aplicación lea y escriba el sistema de archivos almacenado en caché."</string>
     <string name="permlab_use_sip" msgid="5986952362795870502">"realizar o recibir llamadas por Internet"</string>
@@ -581,6 +579,10 @@
     <string name="policydesc_encryptedStorage" msgid="2637732115325316992">"Exige que se encripten los datos de la aplicación almacenados."</string>
     <string name="policylab_disableCamera" msgid="6395301023152297826">"Desactivar cámaras"</string>
     <string name="policydesc_disableCamera" msgid="2306349042834754597">"Evita el uso de todas las cámaras del dispositivo."</string>
+    <!-- no translation found for policylab_disableKeyguardWidgets (1794894613389073926) -->
+    <skip />
+    <!-- no translation found for policydesc_disableKeyguardWidgets (7254624892984033592) -->
+    <skip />
   <string-array name="phoneTypes">
     <item msgid="8901098336658710359">"Casa"</item>
     <item msgid="869923650527136615">"Móvil"</item>
@@ -1171,9 +1173,9 @@
     <string name="vpn_title_long" msgid="6400714798049252294">"VPN está activado por <xliff:g id="APP">%s</xliff:g>"</string>
     <string name="vpn_text" msgid="3011306607126450322">"Toca para administrar la red."</string>
     <string name="vpn_text_long" msgid="6407351006249174473">"Conectado a <xliff:g id="SESSION">%s</xliff:g>. Toca para administrar la red."</string>
-    <string name="vpn_lockdown_connecting" msgid="6443438964440960745">"Estableciendo conexión con VPN activada ininterrumpidamente..."</string>
-    <string name="vpn_lockdown_connected" msgid="8202679674819213931">"Se estableció conexión con la VPN activada ininterrumpidamente."</string>
-    <string name="vpn_lockdown_error" msgid="6009249814034708175">"Se produjo un error al establecer conexión con la VPN activada ininterrumpidamente."</string>
+    <string name="vpn_lockdown_connecting" msgid="6443438964440960745">"Estableciendo conexión con la VPN siempre activada..."</string>
+    <string name="vpn_lockdown_connected" msgid="8202679674819213931">"Se estableció conexión con la VPN siempre activada."</string>
+    <string name="vpn_lockdown_error" msgid="6009249814034708175">"Se produjo un error al establecer conexión con la VPN siempre activada."</string>
     <string name="vpn_lockdown_reset" msgid="5365010427963548932">"Toca para restablecer la conexión."</string>
     <string name="upload_file" msgid="2897957172366730416">"Elegir archivo"</string>
     <string name="no_file_chosen" msgid="6363648562170759465">"No se seleccionó un archivo."</string>
@@ -1319,64 +1321,46 @@
     <string name="bluetooth_a2dp_audio_route_name" msgid="8575624030406771015">"Audio Bluetooth"</string>
     <string name="media_route_chooser_grouping_done" msgid="7966438307723317169">"Listo"</string>
     <string name="media_route_button_content_description" msgid="5758553567065145276">"Salida multimedia"</string>
-    <!-- no translation found for display_manager_built_in_display_name (2583134294292563941) -->
+    <string name="display_manager_built_in_display_name" msgid="2583134294292563941">"Pantalla integrada"</string>
+    <!-- no translation found for display_manager_hdmi_display_name (1555264559227470109) -->
     <skip />
-    <!-- no translation found for display_manager_overlay_display_name (5142365982271620716) -->
+    <string name="display_manager_overlay_display_name" msgid="5142365982271620716">"Superposición N.°<xliff:g id="ID">%1$d</xliff:g>"</string>
+    <!-- no translation found for display_manager_overlay_display_title (652124517672257172) -->
     <skip />
-    <!-- no translation found for display_manager_overlay_display_title (8186674340178573982) -->
-    <skip />
-    <!-- no translation found for kg_emergency_call_label (684946192523830531) -->
-    <skip />
-    <!-- no translation found for kg_forgot_pattern_button_text (8852021467868220608) -->
-    <skip />
-    <!-- no translation found for kg_wrong_pattern (1850806070801358830) -->
-    <skip />
-    <!-- no translation found for kg_wrong_password (2333281762128113157) -->
-    <skip />
-    <!-- no translation found for kg_wrong_pin (1131306510833563801) -->
-    <skip />
-    <!-- no translation found for kg_too_many_failed_attempts_countdown (353963338189371686) -->
-    <skip />
-    <!-- no translation found for kg_pattern_instructions (398978611683075868) -->
-    <skip />
-    <!-- no translation found for kg_sim_pin_instructions (2319508550934557331) -->
-    <skip />
-    <!-- no translation found for kg_pin_instructions (2377242233495111557) -->
-    <skip />
-    <!-- no translation found for kg_password_instructions (5753646556186936819) -->
-    <skip />
-    <!-- no translation found for kg_puk_enter_puk_hint (5183097160254244459) -->
-    <skip />
-    <!-- no translation found for kg_puk_enter_pin_hint (597821135578014901) -->
-    <skip />
-    <!-- no translation found for kg_sim_unlock_progress_dialog_message (8950398016976865762) -->
-    <skip />
-    <!-- no translation found for kg_password_wrong_pin_code (1139324887413846912) -->
-    <skip />
-    <!-- no translation found for kg_invalid_sim_pin_hint (8795159358110620001) -->
-    <skip />
-    <!-- no translation found for kg_invalid_sim_puk_hint (5216603185442368307) -->
-    <skip />
-    <!-- no translation found for kg_sim_puk_recovery_hint (5577753137718442566) -->
-    <skip />
-    <!-- no translation found for kg_invalid_puk (5809955359950817326) -->
-    <skip />
-    <!-- no translation found for kg_login_too_many_attempts (6486842094005698475) -->
-    <skip />
-    <!-- no translation found for kg_login_instructions (1100551261265506448) -->
-    <skip />
-    <!-- no translation found for kg_login_username_hint (5718534272070920364) -->
-    <skip />
-    <!-- no translation found for kg_login_password_hint (9057289103827298549) -->
-    <skip />
-    <!-- no translation found for kg_login_submit_button (5355904582674054702) -->
-    <skip />
-    <!-- no translation found for kg_login_invalid_input (5754664119319872197) -->
-    <skip />
-    <!-- no translation found for kg_login_account_recovery_hint (5690709132841752974) -->
-    <skip />
-    <!-- no translation found for kg_login_checking_password (8849589033659332457) -->
-    <skip />
-    <!-- no translation found for kg_temp_back_string (5812983904056640466) -->
-    <skip />
+    <string name="kg_emergency_call_label" msgid="684946192523830531">"Llamada de emergencia"</string>
+    <string name="kg_forgot_pattern_button_text" msgid="8852021467868220608">"¿Olvidaste el patrón?"</string>
+    <string name="kg_wrong_pattern" msgid="1850806070801358830">"Patrón incorrecto"</string>
+    <string name="kg_wrong_password" msgid="2333281762128113157">"Contraseña incorrecta"</string>
+    <string name="kg_wrong_pin" msgid="1131306510833563801">"PIN incorrecto"</string>
+    <string name="kg_too_many_failed_attempts_countdown" msgid="6358110221603297548">"Vuelve a intentarlo en <xliff:g id="NUMBER">%d</xliff:g> segundos."</string>
+    <string name="kg_pattern_instructions" msgid="398978611683075868">"Dibuja tu patrón."</string>
+    <string name="kg_sim_pin_instructions" msgid="2319508550934557331">"Ingresa el PIN de la tarjeta SIM."</string>
+    <string name="kg_pin_instructions" msgid="2377242233495111557">"Ingresa el PIN."</string>
+    <string name="kg_password_instructions" msgid="5753646556186936819">"Ingresa tu contraseña."</string>
+    <string name="kg_puk_enter_puk_hint" msgid="5183097160254244459">"Código PUK"</string>
+    <string name="kg_puk_enter_pin_hint" msgid="597821135578014901">"Nuevo código PIN"</string>
+    <string name="kg_sim_unlock_progress_dialog_message" msgid="8950398016976865762">"Desbloqueando tarjeta SIM…"</string>
+    <string name="kg_password_wrong_pin_code" msgid="1139324887413846912">"Código PIN incorrecto"</string>
+    <string name="kg_invalid_sim_pin_hint" msgid="8795159358110620001">"Escribe un PIN que tenga de 4 a 8 números."</string>
+    <string name="kg_invalid_sim_puk_hint" msgid="5216603185442368307">"Ingresa un código PUK de ocho números o más."</string>
+    <string name="kg_sim_puk_recovery_hint" msgid="5577753137718442566">"Escribe el código PUK y un nuevo código PIN."</string>
+    <string name="kg_invalid_puk" msgid="5809955359950817326">"El código PUK que escribiste es incorrecto."</string>
+    <string name="kg_login_too_many_attempts" msgid="6486842094005698475">"Demasiados intentos incorrectos para ingresar el patrón"</string>
+    <string name="kg_login_instructions" msgid="1100551261265506448">"Para desbloquear, inicia sesión en tu cuenta de Google."</string>
+    <string name="kg_login_username_hint" msgid="5718534272070920364">"Nombre de usuario (correo electrónico)"</string>
+    <string name="kg_login_password_hint" msgid="9057289103827298549">"Contraseña"</string>
+    <string name="kg_login_submit_button" msgid="5355904582674054702">"Acceder"</string>
+    <string name="kg_login_invalid_input" msgid="5754664119319872197">"Nombre de usuario o contraseña incorrectos"</string>
+    <string name="kg_login_account_recovery_hint" msgid="5690709132841752974">"¿Olvidaste tu nombre de usuario o contraseña?"\n"Accede a "<b>"google.com/accounts/recovery"</b>"."</string>
+    <string name="kg_login_checking_password" msgid="8849589033659332457">"Comprobando..."</string>
+    <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="8276745642049502550">"Escribiste incorrectamente tu PIN <xliff:g id="NUMBER_0">%d</xliff:g> veces. "\n\n"Vuelve a intentarlo en <xliff:g id="NUMBER_1">%d</xliff:g> segundos."</string>
+    <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="7813713389422226531">"Escribiste incorrectamente tu contraseña <xliff:g id="NUMBER_0">%d</xliff:g> veces. "\n\n"Vuelve a intentarlo en <xliff:g id="NUMBER_1">%d</xliff:g> segundos."</string>
+    <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="74089475965050805">"Dibujaste incorrectamente tu patrón de desbloqueo <xliff:g id="NUMBER_0">%d</xliff:g> veces. "\n\n"Vuelve a intentarlo en <xliff:g id="NUMBER_1">%d</xliff:g> segundos."</string>
+    <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="1575557200627128949">"Intentaste desbloquear la tableta <xliff:g id="NUMBER_0">%d</xliff:g> veces, pero no lo lograste. Puedes intentarlo <xliff:g id="NUMBER_1">%d</xliff:g> veces más antes de que se restablezcan los valores predeterminados de fábrica de la tableta y se pierdan todos los datos de usuario."</string>
+    <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="4051015943038199910">"Intentaste desbloquear el dispositivo <xliff:g id="NUMBER_0">%d</xliff:g> veces, pero no lo lograste. Puedes intentarlo <xliff:g id="NUMBER_1">%d</xliff:g> veces más antes de que se restablezcan los valores predeterminados de fábrica del dispositivo y se pierdan todos los datos de usuario."</string>
+    <string name="kg_failed_attempts_now_wiping" product="tablet" msgid="2072996269148483637">"Intentaste desbloquear la tableta <xliff:g id="NUMBER">%d</xliff:g> veces, pero no lo lograste. Se restablecerán los valores predeterminados de fábrica de la tableta."</string>
+    <string name="kg_failed_attempts_now_wiping" product="default" msgid="4817627474419471518">"Intentaste desbloquear el dispositivo <xliff:g id="NUMBER">%d</xliff:g> veces, pero no lo lograste. Se restablecerán los valores predeterminados de fábrica del dispositivo."</string>
+    <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"Dibujaste incorrectamente tu patrón de desbloqueo <xliff:g id="NUMBER_0">%d</xliff:g> veces. Luego de <xliff:g id="NUMBER_1">%d</xliff:g> intentos incorrectos, se te solicitará que desbloquees tu tableta mediante el uso de una cuenta de correo electrónico."\n\n" Vuelve a intentarlo en <xliff:g id="NUMBER_2">%d</xliff:g> segundos."</string>
+    <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"Dibujaste incorrectamente tu patrón de desbloqueo <xliff:g id="NUMBER_0">%d</xliff:g> veces. Luego de <xliff:g id="NUMBER_1">%d</xliff:g> intentos incorrectos, se te solicitará que desbloquees tu dispositivo mediante el uso de una cuenta de correo electrónico."\n\n" Vuelve a intentarlo en <xliff:g id="NUMBER_2">%d</xliff:g> segundos."</string>
+    <string name="kg_temp_back_string" msgid="5812983904056640466">"&lt;"</string>
 </resources>
diff --git a/core/res/res/values-es/strings.xml b/core/res/res/values-es/strings.xml
index c962de0..f50c797 100644
--- a/core/res/res/values-es/strings.xml
+++ b/core/res/res/values-es/strings.xml
@@ -547,10 +547,8 @@
     <string name="permdesc_sdcardWrite" product="default" msgid="4337417790936632090">"Permite que la aplicación escriba en la tarjeta SD."</string>
     <string name="permlab_mediaStorageWrite" product="default" msgid="6859839199706879015">"modificar o eliminar el contenido del almacenamiento de medios interno"</string>
     <string name="permdesc_mediaStorageWrite" product="default" msgid="8189160597698529185">"Permite que la aplicación modifique el contenido del almacenamiento multimedia interno."</string>
-    <!-- no translation found for permlab_sdcardAccessAll (8150613823900460576) -->
-    <skip />
-    <!-- no translation found for permdesc_sdcardAccessAll (3215208357415891320) -->
-    <skip />
+    <string name="permlab_sdcardAccessAll" msgid="8150613823900460576">"acceder almacenamiento externo"</string>
+    <string name="permdesc_sdcardAccessAll" msgid="3215208357415891320">"Permite que la aplicación acceda al almacenamiento externo de todos los usuarios."</string>
     <string name="permlab_cache_filesystem" msgid="5656487264819669824">"acceder al sistema de archivos almacenado en caché"</string>
     <string name="permdesc_cache_filesystem" msgid="5578967642265550955">"Permite que la aplicación lea y escriba el sistema de archivos almacenado en caché."</string>
     <string name="permlab_use_sip" msgid="5986952362795870502">"realizar/recibir llamadas por Internet"</string>
@@ -581,6 +579,10 @@
     <string name="policydesc_encryptedStorage" msgid="2637732115325316992">"Exige que se encripten los datos de la aplicación almacenados."</string>
     <string name="policylab_disableCamera" msgid="6395301023152297826">"Inhabilitar cámaras"</string>
     <string name="policydesc_disableCamera" msgid="2306349042834754597">"Evitar el uso de las cámaras del dispositivo"</string>
+    <!-- no translation found for policylab_disableKeyguardWidgets (1794894613389073926) -->
+    <skip />
+    <!-- no translation found for policydesc_disableKeyguardWidgets (7254624892984033592) -->
+    <skip />
   <string-array name="phoneTypes">
     <item msgid="8901098336658710359">"Casa"</item>
     <item msgid="869923650527136615">"Móvil"</item>
@@ -1319,64 +1321,46 @@
     <string name="bluetooth_a2dp_audio_route_name" msgid="8575624030406771015">"Audio Bluetooth"</string>
     <string name="media_route_chooser_grouping_done" msgid="7966438307723317169">"Fin"</string>
     <string name="media_route_button_content_description" msgid="5758553567065145276">"Salida multimedia"</string>
-    <!-- no translation found for display_manager_built_in_display_name (2583134294292563941) -->
+    <string name="display_manager_built_in_display_name" msgid="2583134294292563941">"Pantalla integrada"</string>
+    <!-- no translation found for display_manager_hdmi_display_name (1555264559227470109) -->
     <skip />
-    <!-- no translation found for display_manager_overlay_display_name (5142365982271620716) -->
+    <string name="display_manager_overlay_display_name" msgid="5142365982271620716">"Superposición #<xliff:g id="ID">%1$d</xliff:g>"</string>
+    <!-- no translation found for display_manager_overlay_display_title (652124517672257172) -->
     <skip />
-    <!-- no translation found for display_manager_overlay_display_title (8186674340178573982) -->
-    <skip />
-    <!-- no translation found for kg_emergency_call_label (684946192523830531) -->
-    <skip />
-    <!-- no translation found for kg_forgot_pattern_button_text (8852021467868220608) -->
-    <skip />
-    <!-- no translation found for kg_wrong_pattern (1850806070801358830) -->
-    <skip />
-    <!-- no translation found for kg_wrong_password (2333281762128113157) -->
-    <skip />
-    <!-- no translation found for kg_wrong_pin (1131306510833563801) -->
-    <skip />
-    <!-- no translation found for kg_too_many_failed_attempts_countdown (353963338189371686) -->
-    <skip />
-    <!-- no translation found for kg_pattern_instructions (398978611683075868) -->
-    <skip />
-    <!-- no translation found for kg_sim_pin_instructions (2319508550934557331) -->
-    <skip />
-    <!-- no translation found for kg_pin_instructions (2377242233495111557) -->
-    <skip />
-    <!-- no translation found for kg_password_instructions (5753646556186936819) -->
-    <skip />
-    <!-- no translation found for kg_puk_enter_puk_hint (5183097160254244459) -->
-    <skip />
-    <!-- no translation found for kg_puk_enter_pin_hint (597821135578014901) -->
-    <skip />
-    <!-- no translation found for kg_sim_unlock_progress_dialog_message (8950398016976865762) -->
-    <skip />
-    <!-- no translation found for kg_password_wrong_pin_code (1139324887413846912) -->
-    <skip />
-    <!-- no translation found for kg_invalid_sim_pin_hint (8795159358110620001) -->
-    <skip />
-    <!-- no translation found for kg_invalid_sim_puk_hint (5216603185442368307) -->
-    <skip />
-    <!-- no translation found for kg_sim_puk_recovery_hint (5577753137718442566) -->
-    <skip />
-    <!-- no translation found for kg_invalid_puk (5809955359950817326) -->
-    <skip />
-    <!-- no translation found for kg_login_too_many_attempts (6486842094005698475) -->
-    <skip />
-    <!-- no translation found for kg_login_instructions (1100551261265506448) -->
-    <skip />
-    <!-- no translation found for kg_login_username_hint (5718534272070920364) -->
-    <skip />
-    <!-- no translation found for kg_login_password_hint (9057289103827298549) -->
-    <skip />
-    <!-- no translation found for kg_login_submit_button (5355904582674054702) -->
-    <skip />
-    <!-- no translation found for kg_login_invalid_input (5754664119319872197) -->
-    <skip />
-    <!-- no translation found for kg_login_account_recovery_hint (5690709132841752974) -->
-    <skip />
-    <!-- no translation found for kg_login_checking_password (8849589033659332457) -->
-    <skip />
-    <!-- no translation found for kg_temp_back_string (5812983904056640466) -->
-    <skip />
+    <string name="kg_emergency_call_label" msgid="684946192523830531">"Llamada de emergencia"</string>
+    <string name="kg_forgot_pattern_button_text" msgid="8852021467868220608">"¿Has olvidado el patrón?"</string>
+    <string name="kg_wrong_pattern" msgid="1850806070801358830">"Patrón incorrecto"</string>
+    <string name="kg_wrong_password" msgid="2333281762128113157">"Contraseña incorrecta"</string>
+    <string name="kg_wrong_pin" msgid="1131306510833563801">"PIN incorrecto"</string>
+    <string name="kg_too_many_failed_attempts_countdown" msgid="6358110221603297548">"Inténtalo de nuevo en <xliff:g id="NUMBER">%d</xliff:g> segundos."</string>
+    <string name="kg_pattern_instructions" msgid="398978611683075868">"Dibuja tu patrón."</string>
+    <string name="kg_sim_pin_instructions" msgid="2319508550934557331">"Introduce el PIN de la tarjeta SIM."</string>
+    <string name="kg_pin_instructions" msgid="2377242233495111557">"Introduce el PIN."</string>
+    <string name="kg_password_instructions" msgid="5753646556186936819">"Escribe tu contraseña."</string>
+    <string name="kg_puk_enter_puk_hint" msgid="5183097160254244459">"Código PUK"</string>
+    <string name="kg_puk_enter_pin_hint" msgid="597821135578014901">"Nuevo código PIN"</string>
+    <string name="kg_sim_unlock_progress_dialog_message" msgid="8950398016976865762">"Desbloqueando tarjeta SIM…"</string>
+    <string name="kg_password_wrong_pin_code" msgid="1139324887413846912">"Código PIN incorrecto"</string>
+    <string name="kg_invalid_sim_pin_hint" msgid="8795159358110620001">"Introduce un código PIN con una longitud comprendida entre cuatro y ocho dígitos."</string>
+    <string name="kg_invalid_sim_puk_hint" msgid="5216603185442368307">"Escribe un código PUK de ocho caracteres o más."</string>
+    <string name="kg_sim_puk_recovery_hint" msgid="5577753137718442566">"Introduce el código PUK y un nuevo código PIN."</string>
+    <string name="kg_invalid_puk" msgid="5809955359950817326">"El código PUK que has introducido no es correcto."</string>
+    <string name="kg_login_too_many_attempts" msgid="6486842094005698475">"Demasiados intentos incorrectos de crear el patrón"</string>
+    <string name="kg_login_instructions" msgid="1100551261265506448">"Para desbloquear el teléfono, inicia sesión con tu cuenta de Google."</string>
+    <string name="kg_login_username_hint" msgid="5718534272070920364">"Nombre de usuario (correo electrónico)"</string>
+    <string name="kg_login_password_hint" msgid="9057289103827298549">"Contraseña"</string>
+    <string name="kg_login_submit_button" msgid="5355904582674054702">"Iniciar sesión"</string>
+    <string name="kg_login_invalid_input" msgid="5754664119319872197">"El nombre de usuario o la contraseña no son válidos."</string>
+    <string name="kg_login_account_recovery_hint" msgid="5690709132841752974">"Si has olvidado tu nombre de usuario o tu contraseña,"\n"accede a la página "<b>"google.com/accounts/recovery"</b>"."</string>
+    <string name="kg_login_checking_password" msgid="8849589033659332457">"Comprobando..."</string>
+    <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="8276745642049502550">"Has introducido un código PIN incorrecto <xliff:g id="NUMBER_0">%d</xliff:g> veces. "\n\n"Inténtalo de nuevo en <xliff:g id="NUMBER_1">%d</xliff:g> segundos."</string>
+    <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="7813713389422226531">"Has introducido una contraseña incorrecta <xliff:g id="NUMBER_0">%d</xliff:g> veces. "\n\n"Inténtalo de nuevo en <xliff:g id="NUMBER_1">%d</xliff:g> segundos."</string>
+    <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="74089475965050805">"Has fallado <xliff:g id="NUMBER_0">%d</xliff:g> veces al dibujar tu patrón de desbloqueo. "\n\n"Inténtalo de nuevo en <xliff:g id="NUMBER_1">%d</xliff:g> segundos."</string>
+    <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="1575557200627128949">"Has intentado desbloquear el tablet <xliff:g id="NUMBER_0">%d</xliff:g> veces, pero no lo has conseguido. Si fallas otras <xliff:g id="NUMBER_1">%d</xliff:g> veces, se restablecerán los datos de fábrica y se perderán todos los datos del usuario."</string>
+    <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="4051015943038199910">"Has intentado desbloquear el teléfono <xliff:g id="NUMBER_0">%d</xliff:g> veces, pero no lo has conseguido. Si fallas otras <xliff:g id="NUMBER_1">%d</xliff:g> veces, se restablecerán los datos de fábrica y se perderán todos los datos del usuario."</string>
+    <string name="kg_failed_attempts_now_wiping" product="tablet" msgid="2072996269148483637">"Has intentado desbloquear el tablet <xliff:g id="NUMBER">%d</xliff:g> veces, pero no lo has conseguido. Se restablecerán los datos de fábrica del dispositivo."</string>
+    <string name="kg_failed_attempts_now_wiping" product="default" msgid="4817627474419471518">"Has intentado desbloquear el teléfono <xliff:g id="NUMBER">%d</xliff:g> veces, pero no lo has conseguido. Se restablecerán los datos de fábrica del dispositivo."</string>
+    <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"Has fallado <xliff:g id="NUMBER_0">%d</xliff:g> veces al dibujar el patrón de desbloqueo. Si fallas otras <xliff:g id="NUMBER_1">%d</xliff:g> veces, deberás usar una cuenta de correo electrónico para desbloquear el tablet."\n\n" Inténtalo de nuevo en <xliff:g id="NUMBER_2">%d</xliff:g> segundos."</string>
+    <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"Has fallado <xliff:g id="NUMBER_0">%d</xliff:g> veces al dibujar el patrón de desbloqueo. Si fallas otras <xliff:g id="NUMBER_1">%d</xliff:g> veces, deberás usar una cuenta de correo electrónico para desbloquear el teléfono."\n\n" Inténtalo de nuevo en <xliff:g id="NUMBER_2">%d</xliff:g> segundos."</string>
+    <string name="kg_temp_back_string" msgid="5812983904056640466">"&lt;"</string>
 </resources>
diff --git a/core/res/res/values-et/strings.xml b/core/res/res/values-et/strings.xml
index d8a0ec5..c2693e8 100644
--- a/core/res/res/values-et/strings.xml
+++ b/core/res/res/values-et/strings.xml
@@ -547,10 +547,8 @@
     <string name="permdesc_sdcardWrite" product="default" msgid="4337417790936632090">"Võimaldab rakendusel kirjutada SD-kaardile."</string>
     <string name="permlab_mediaStorageWrite" product="default" msgid="6859839199706879015">"sisemälu sisu muutm./kustut."</string>
     <string name="permdesc_mediaStorageWrite" product="default" msgid="8189160597698529185">"Võimaldab rakendusel muuta sisemise andmekandja sisu."</string>
-    <!-- no translation found for permlab_sdcardAccessAll (8150613823900460576) -->
-    <skip />
-    <!-- no translation found for permdesc_sdcardAccessAll (3215208357415891320) -->
-    <skip />
+    <string name="permlab_sdcardAccessAll" msgid="8150613823900460576">"juurdepääs kõikide kasutajate välismäluseadmele"</string>
+    <string name="permdesc_sdcardAccessAll" msgid="3215208357415891320">"Võimaldab rakenduse kõikidel kasutajatel hankida juurdepääsu välismäluseadmele."</string>
     <string name="permlab_cache_filesystem" msgid="5656487264819669824">"juurdepääs vahemälu failisüsteemile"</string>
     <string name="permdesc_cache_filesystem" msgid="5578967642265550955">"Võimaldab rakendusel vahemälu failisüsteemi lugeda ja kirjutada."</string>
     <string name="permlab_use_sip" msgid="5986952362795870502">"Interneti-kõnede tegemine/vastuvõtmine"</string>
@@ -581,6 +579,10 @@
     <string name="policydesc_encryptedStorage" msgid="2637732115325316992">"Nõua salvestatud rakenduse andmete krüpteerimist."</string>
     <string name="policylab_disableCamera" msgid="6395301023152297826">"Keela kaamerad"</string>
     <string name="policydesc_disableCamera" msgid="2306349042834754597">"Vältige seadme kõigi kaamerate kasutamist."</string>
+    <!-- no translation found for policylab_disableKeyguardWidgets (1794894613389073926) -->
+    <skip />
+    <!-- no translation found for policydesc_disableKeyguardWidgets (7254624892984033592) -->
+    <skip />
   <string-array name="phoneTypes">
     <item msgid="8901098336658710359">"Kodu"</item>
     <item msgid="869923650527136615">"Mobiil"</item>
@@ -1173,7 +1175,7 @@
     <string name="vpn_text_long" msgid="6407351006249174473">"Ühendatud seansiga <xliff:g id="SESSION">%s</xliff:g>. Võrgu haldamiseks puudutage."</string>
     <string name="vpn_lockdown_connecting" msgid="6443438964440960745">"Ühendamine alati sees VPN-iga …"</string>
     <string name="vpn_lockdown_connected" msgid="8202679674819213931">"Ühendatud alati sees VPN-iga"</string>
-    <string name="vpn_lockdown_error" msgid="6009249814034708175">"Alati see VPN-i viga"</string>
+    <string name="vpn_lockdown_error" msgid="6009249814034708175">"Alati sees VPN-i viga"</string>
     <string name="vpn_lockdown_reset" msgid="5365010427963548932">"Ühenduse lähtestamiseks puudutage"</string>
     <string name="upload_file" msgid="2897957172366730416">"Valige fail"</string>
     <string name="no_file_chosen" msgid="6363648562170759465">"Ühtegi faili pole valitud"</string>
@@ -1319,64 +1321,46 @@
     <string name="bluetooth_a2dp_audio_route_name" msgid="8575624030406771015">"Bluetooth-heli"</string>
     <string name="media_route_chooser_grouping_done" msgid="7966438307723317169">"Valmis"</string>
     <string name="media_route_button_content_description" msgid="5758553567065145276">"Meediaväljund"</string>
-    <!-- no translation found for display_manager_built_in_display_name (2583134294292563941) -->
+    <string name="display_manager_built_in_display_name" msgid="2583134294292563941">"Sisseehitatud ekraan"</string>
+    <!-- no translation found for display_manager_hdmi_display_name (1555264559227470109) -->
     <skip />
-    <!-- no translation found for display_manager_overlay_display_name (5142365982271620716) -->
+    <string name="display_manager_overlay_display_name" msgid="5142365982271620716">"Ülekate nr<xliff:g id="ID">%1$d</xliff:g>"</string>
+    <!-- no translation found for display_manager_overlay_display_title (652124517672257172) -->
     <skip />
-    <!-- no translation found for display_manager_overlay_display_title (8186674340178573982) -->
-    <skip />
-    <!-- no translation found for kg_emergency_call_label (684946192523830531) -->
-    <skip />
-    <!-- no translation found for kg_forgot_pattern_button_text (8852021467868220608) -->
-    <skip />
-    <!-- no translation found for kg_wrong_pattern (1850806070801358830) -->
-    <skip />
-    <!-- no translation found for kg_wrong_password (2333281762128113157) -->
-    <skip />
-    <!-- no translation found for kg_wrong_pin (1131306510833563801) -->
-    <skip />
-    <!-- no translation found for kg_too_many_failed_attempts_countdown (353963338189371686) -->
-    <skip />
-    <!-- no translation found for kg_pattern_instructions (398978611683075868) -->
-    <skip />
-    <!-- no translation found for kg_sim_pin_instructions (2319508550934557331) -->
-    <skip />
-    <!-- no translation found for kg_pin_instructions (2377242233495111557) -->
-    <skip />
-    <!-- no translation found for kg_password_instructions (5753646556186936819) -->
-    <skip />
-    <!-- no translation found for kg_puk_enter_puk_hint (5183097160254244459) -->
-    <skip />
-    <!-- no translation found for kg_puk_enter_pin_hint (597821135578014901) -->
-    <skip />
-    <!-- no translation found for kg_sim_unlock_progress_dialog_message (8950398016976865762) -->
-    <skip />
-    <!-- no translation found for kg_password_wrong_pin_code (1139324887413846912) -->
-    <skip />
-    <!-- no translation found for kg_invalid_sim_pin_hint (8795159358110620001) -->
-    <skip />
-    <!-- no translation found for kg_invalid_sim_puk_hint (5216603185442368307) -->
-    <skip />
-    <!-- no translation found for kg_sim_puk_recovery_hint (5577753137718442566) -->
-    <skip />
-    <!-- no translation found for kg_invalid_puk (5809955359950817326) -->
-    <skip />
-    <!-- no translation found for kg_login_too_many_attempts (6486842094005698475) -->
-    <skip />
-    <!-- no translation found for kg_login_instructions (1100551261265506448) -->
-    <skip />
-    <!-- no translation found for kg_login_username_hint (5718534272070920364) -->
-    <skip />
-    <!-- no translation found for kg_login_password_hint (9057289103827298549) -->
-    <skip />
-    <!-- no translation found for kg_login_submit_button (5355904582674054702) -->
-    <skip />
-    <!-- no translation found for kg_login_invalid_input (5754664119319872197) -->
-    <skip />
-    <!-- no translation found for kg_login_account_recovery_hint (5690709132841752974) -->
-    <skip />
-    <!-- no translation found for kg_login_checking_password (8849589033659332457) -->
-    <skip />
-    <!-- no translation found for kg_temp_back_string (5812983904056640466) -->
-    <skip />
+    <string name="kg_emergency_call_label" msgid="684946192523830531">"Hädaabikõne"</string>
+    <string name="kg_forgot_pattern_button_text" msgid="8852021467868220608">"Unustasite mustri"</string>
+    <string name="kg_wrong_pattern" msgid="1850806070801358830">"Vale muster"</string>
+    <string name="kg_wrong_password" msgid="2333281762128113157">"Vale parool"</string>
+    <string name="kg_wrong_pin" msgid="1131306510833563801">"Vale PIN-kood"</string>
+    <string name="kg_too_many_failed_attempts_countdown" msgid="6358110221603297548">"Proovige uuesti <xliff:g id="NUMBER">%d</xliff:g> sekundi pärast."</string>
+    <string name="kg_pattern_instructions" msgid="398978611683075868">"Joonistage oma muster"</string>
+    <string name="kg_sim_pin_instructions" msgid="2319508550934557331">"Sisestage SIM-i PIN-kood"</string>
+    <string name="kg_pin_instructions" msgid="2377242233495111557">"Sisestage PIN-kood"</string>
+    <string name="kg_password_instructions" msgid="5753646556186936819">"Sisestage parool"</string>
+    <string name="kg_puk_enter_puk_hint" msgid="5183097160254244459">"PUK-kood"</string>
+    <string name="kg_puk_enter_pin_hint" msgid="597821135578014901">"Uus PIN-kood"</string>
+    <string name="kg_sim_unlock_progress_dialog_message" msgid="8950398016976865762">"SIM-kaardi avamine ..."</string>
+    <string name="kg_password_wrong_pin_code" msgid="1139324887413846912">"Vale PIN-kood."</string>
+    <string name="kg_invalid_sim_pin_hint" msgid="8795159358110620001">"Sisestage 4–8-numbriline PIN-kood."</string>
+    <string name="kg_invalid_sim_puk_hint" msgid="5216603185442368307">"Sisestage 8-numbriline või pikem PUK-kood."</string>
+    <string name="kg_sim_puk_recovery_hint" msgid="5577753137718442566">"Sisestage PUK-kood ja uus PIN-kood"</string>
+    <string name="kg_invalid_puk" msgid="5809955359950817326">"Sisestatud PUK-kood pole õige."</string>
+    <string name="kg_login_too_many_attempts" msgid="6486842094005698475">"Liiga palju mustrikatseid"</string>
+    <string name="kg_login_instructions" msgid="1100551261265506448">"Avamiseks logige sisse oma Google\'i kontoga."</string>
+    <string name="kg_login_username_hint" msgid="5718534272070920364">"Kasutajanimi (e-post)"</string>
+    <string name="kg_login_password_hint" msgid="9057289103827298549">"Parool"</string>
+    <string name="kg_login_submit_button" msgid="5355904582674054702">"Logi sisse"</string>
+    <string name="kg_login_invalid_input" msgid="5754664119319872197">"Vale kasutajanimi või parool."</string>
+    <string name="kg_login_account_recovery_hint" msgid="5690709132841752974">"Kas unustasite kasutajanime või parooli?"\n"Külastage aadressi "<b>"google.com/accounts/recovery"</b>"."</string>
+    <string name="kg_login_checking_password" msgid="8849589033659332457">"Kontrollimine ..."</string>
+    <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="8276745642049502550">"Olete PIN-koodi <xliff:g id="NUMBER_0">%d</xliff:g> korda valesti sisestanud."\n\n"Proovige <xliff:g id="NUMBER_1">%d</xliff:g> sekundi pärast uuesti."</string>
+    <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="7813713389422226531">"Olete parooli <xliff:g id="NUMBER_0">%d</xliff:g> korda valesti sisestanud. "\n\n"Proovige uuesti <xliff:g id="NUMBER_1">%d</xliff:g> sekundi pärast."</string>
+    <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="74089475965050805">"Joonistasite oma avamismustri <xliff:g id="NUMBER_0">%d</xliff:g> korda valesti."\n\n"Proovige <xliff:g id="NUMBER_1">%d</xliff:g> sekundi pärast uuesti."</string>
+    <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="1575557200627128949">"Olete üritanud <xliff:g id="NUMBER_0">%d</xliff:g> korda tahvelarvutit valesti avada. Pärast veel <xliff:g id="NUMBER_1">%d</xliff:g> ebaõnnestunud katset lähtestatakse tahvelarvuti tehase vaikeseadetele ja kõik kasutajaandmed lähevad kaotsi."</string>
+    <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="4051015943038199910">"Olete üritanud <xliff:g id="NUMBER_0">%d</xliff:g> korda telefoni valesti avada. Pärast veel <xliff:g id="NUMBER_1">%d</xliff:g> ebaõnnestunud katset lähtestatakse telefon tehase vaikeseadetele ja kõik kasutajaandmed lähevad kaotsi."</string>
+    <string name="kg_failed_attempts_now_wiping" product="tablet" msgid="2072996269148483637">"Olete püüdnud tahvelarvutit <xliff:g id="NUMBER">%d</xliff:g> korda valesti avada. Tahvelarvuti lähtestatakse nüüd tehase vaikeseadetele."</string>
+    <string name="kg_failed_attempts_now_wiping" product="default" msgid="4817627474419471518">"Olete püüdnud telefoni <xliff:g id="NUMBER">%d</xliff:g> korda valesti avada. Telefon lähtestatakse nüüd tehase vaikeseadetele."</string>
+    <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"Joonistasite oma avamismustri <xliff:g id="NUMBER_0">%d</xliff:g> korda valesti. Kui olete teinud veel <xliff:g id="NUMBER_1">%d</xliff:g> ebaõnnestunud katset, palutakse teil tahvelarvuti avada meilikontoga."\n\n" Proovige uuesti <xliff:g id="NUMBER_2">%d</xliff:g> sekundi pärast."</string>
+    <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"Joonistasite oma avamismustri <xliff:g id="NUMBER_0">%d</xliff:g> korda valesti. Kui olete teinud veel <xliff:g id="NUMBER_1">%d</xliff:g> ebaõnnestunud katset, palutakse teil telefon avada meilikontoga."\n\n" Proovige uuesti <xliff:g id="NUMBER_2">%d</xliff:g> sekundi pärast."</string>
+    <string name="kg_temp_back_string" msgid="5812983904056640466">"&lt;"</string>
 </resources>
diff --git a/core/res/res/values-fa/strings.xml b/core/res/res/values-fa/strings.xml
index fb9a1ff..da5ff94 100644
--- a/core/res/res/values-fa/strings.xml
+++ b/core/res/res/values-fa/strings.xml
@@ -547,10 +547,8 @@
     <string name="permdesc_sdcardWrite" product="default" msgid="4337417790936632090">"به برنامه اجازه می‎دهد تا در کارت SD بنویسد."</string>
     <string name="permlab_mediaStorageWrite" product="default" msgid="6859839199706879015">"تغییر/حذف محتواهای حافظه رسانه داخلی"</string>
     <string name="permdesc_mediaStorageWrite" product="default" msgid="8189160597698529185">"به برنامه اجازه می‎دهد تا محتویات حافظه رسانه داخلی را تغییر دهد."</string>
-    <!-- no translation found for permlab_sdcardAccessAll (8150613823900460576) -->
-    <skip />
-    <!-- no translation found for permdesc_sdcardAccessAll (3215208357415891320) -->
-    <skip />
+    <string name="permlab_sdcardAccessAll" msgid="8150613823900460576">"دسترسی به دستگاه ذخیره خارجی تمام کاربران"</string>
+    <string name="permdesc_sdcardAccessAll" msgid="3215208357415891320">"به برنامه اجازه می‌دهد به دستگاه ذخیره خارجی برای همه کاربران دسترسی داشته باشد."</string>
     <string name="permlab_cache_filesystem" msgid="5656487264819669824">"دسترسی به سیستم فایل حافظهٔ پنهان"</string>
     <string name="permdesc_cache_filesystem" msgid="5578967642265550955">"به برنامه اجازه می‎دهد تا سیستم فایل حافظهٔ پنهان را بخواند و بنویسد."</string>
     <string name="permlab_use_sip" msgid="5986952362795870502">"علامتگذاری/دریافت تماس‌های اینترنتی"</string>
@@ -581,6 +579,10 @@
     <string name="policydesc_encryptedStorage" msgid="2637732115325316992">"باید اطلاعات ذخیره شده برنامه رمزگذاری شود."</string>
     <string name="policylab_disableCamera" msgid="6395301023152297826">"غیر فعال کردن دوربین ها"</string>
     <string name="policydesc_disableCamera" msgid="2306349042834754597">"از استفاده از تمام دوربین‎های دستگاه جلوگیری کنید."</string>
+    <!-- no translation found for policylab_disableKeyguardWidgets (1794894613389073926) -->
+    <skip />
+    <!-- no translation found for policydesc_disableKeyguardWidgets (7254624892984033592) -->
+    <skip />
   <string-array name="phoneTypes">
     <item msgid="8901098336658710359">"خانه"</item>
     <item msgid="869923650527136615">"تلفن همراه"</item>
@@ -1319,64 +1321,46 @@
     <string name="bluetooth_a2dp_audio_route_name" msgid="8575624030406771015">"بلوتوث‌های صوتی"</string>
     <string name="media_route_chooser_grouping_done" msgid="7966438307723317169">"انجام شد"</string>
     <string name="media_route_button_content_description" msgid="5758553567065145276">"خروجی رسانه"</string>
-    <!-- no translation found for display_manager_built_in_display_name (2583134294292563941) -->
+    <string name="display_manager_built_in_display_name" msgid="2583134294292563941">"صفحه نمایش از خود"</string>
+    <!-- no translation found for display_manager_hdmi_display_name (1555264559227470109) -->
     <skip />
-    <!-- no translation found for display_manager_overlay_display_name (5142365982271620716) -->
+    <string name="display_manager_overlay_display_name" msgid="5142365982271620716">"همپوشانی #<xliff:g id="ID">%1$d</xliff:g>"</string>
+    <!-- no translation found for display_manager_overlay_display_title (652124517672257172) -->
     <skip />
-    <!-- no translation found for display_manager_overlay_display_title (8186674340178573982) -->
-    <skip />
-    <!-- no translation found for kg_emergency_call_label (684946192523830531) -->
-    <skip />
-    <!-- no translation found for kg_forgot_pattern_button_text (8852021467868220608) -->
-    <skip />
-    <!-- no translation found for kg_wrong_pattern (1850806070801358830) -->
-    <skip />
-    <!-- no translation found for kg_wrong_password (2333281762128113157) -->
-    <skip />
-    <!-- no translation found for kg_wrong_pin (1131306510833563801) -->
-    <skip />
-    <!-- no translation found for kg_too_many_failed_attempts_countdown (353963338189371686) -->
-    <skip />
-    <!-- no translation found for kg_pattern_instructions (398978611683075868) -->
-    <skip />
-    <!-- no translation found for kg_sim_pin_instructions (2319508550934557331) -->
-    <skip />
-    <!-- no translation found for kg_pin_instructions (2377242233495111557) -->
-    <skip />
-    <!-- no translation found for kg_password_instructions (5753646556186936819) -->
-    <skip />
-    <!-- no translation found for kg_puk_enter_puk_hint (5183097160254244459) -->
-    <skip />
-    <!-- no translation found for kg_puk_enter_pin_hint (597821135578014901) -->
-    <skip />
-    <!-- no translation found for kg_sim_unlock_progress_dialog_message (8950398016976865762) -->
-    <skip />
-    <!-- no translation found for kg_password_wrong_pin_code (1139324887413846912) -->
-    <skip />
-    <!-- no translation found for kg_invalid_sim_pin_hint (8795159358110620001) -->
-    <skip />
-    <!-- no translation found for kg_invalid_sim_puk_hint (5216603185442368307) -->
-    <skip />
-    <!-- no translation found for kg_sim_puk_recovery_hint (5577753137718442566) -->
-    <skip />
-    <!-- no translation found for kg_invalid_puk (5809955359950817326) -->
-    <skip />
-    <!-- no translation found for kg_login_too_many_attempts (6486842094005698475) -->
-    <skip />
-    <!-- no translation found for kg_login_instructions (1100551261265506448) -->
-    <skip />
-    <!-- no translation found for kg_login_username_hint (5718534272070920364) -->
-    <skip />
-    <!-- no translation found for kg_login_password_hint (9057289103827298549) -->
-    <skip />
-    <!-- no translation found for kg_login_submit_button (5355904582674054702) -->
-    <skip />
-    <!-- no translation found for kg_login_invalid_input (5754664119319872197) -->
-    <skip />
-    <!-- no translation found for kg_login_account_recovery_hint (5690709132841752974) -->
-    <skip />
-    <!-- no translation found for kg_login_checking_password (8849589033659332457) -->
-    <skip />
-    <!-- no translation found for kg_temp_back_string (5812983904056640466) -->
-    <skip />
+    <string name="kg_emergency_call_label" msgid="684946192523830531">"تماس اضطراری"</string>
+    <string name="kg_forgot_pattern_button_text" msgid="8852021467868220608">"الگو را فراموش کرده‌اید"</string>
+    <string name="kg_wrong_pattern" msgid="1850806070801358830">"الگوی اشتباه"</string>
+    <string name="kg_wrong_password" msgid="2333281762128113157">"گذرواژه اشتباه"</string>
+    <string name="kg_wrong_pin" msgid="1131306510833563801">"پین اشتباه"</string>
+    <string name="kg_too_many_failed_attempts_countdown" msgid="6358110221603297548">"پس از <xliff:g id="NUMBER">%d</xliff:g> ثانیه دوباره امتحان کنید."</string>
+    <string name="kg_pattern_instructions" msgid="398978611683075868">"رسم الگوی خود"</string>
+    <string name="kg_sim_pin_instructions" msgid="2319508550934557331">"پین سیم کارت را وارد کنید"</string>
+    <string name="kg_pin_instructions" msgid="2377242233495111557">"پین را وارد کنید"</string>
+    <string name="kg_password_instructions" msgid="5753646556186936819">"گذرواژه را وارد کنید"</string>
+    <string name="kg_puk_enter_puk_hint" msgid="5183097160254244459">"کد PUK"</string>
+    <string name="kg_puk_enter_pin_hint" msgid="597821135578014901">"پین کد جدید"</string>
+    <string name="kg_sim_unlock_progress_dialog_message" msgid="8950398016976865762">"بازگشایی قفل سیم کارت..."</string>
+    <string name="kg_password_wrong_pin_code" msgid="1139324887413846912">"پین کد اشتباه است."</string>
+    <string name="kg_invalid_sim_pin_hint" msgid="8795159358110620001">"یک پین ۴ تا ۸ رقمی را تایپ کنید."</string>
+    <string name="kg_invalid_sim_puk_hint" msgid="5216603185442368307">"یک PUK با ۸ رقم یا بیشتر تایپ کنید."</string>
+    <string name="kg_sim_puk_recovery_hint" msgid="5577753137718442566">"PUK و پین کد جدید را تایپ کنید"</string>
+    <string name="kg_invalid_puk" msgid="5809955359950817326">"PUK که نوشته‌اید صحیح نیست."</string>
+    <string name="kg_login_too_many_attempts" msgid="6486842094005698475">"تلاش‎های زیادی برای کشیدن الگو صورت گرفته است"</string>
+    <string name="kg_login_instructions" msgid="1100551261265506448">"برای بازگشایی قفل، با حساب Google خود وارد سیستم شوید."</string>
+    <string name="kg_login_username_hint" msgid="5718534272070920364">"نام کاربری (ایمیل)"</string>
+    <string name="kg_login_password_hint" msgid="9057289103827298549">"گذرواژه"</string>
+    <string name="kg_login_submit_button" msgid="5355904582674054702">"ورود به سیستم"</string>
+    <string name="kg_login_invalid_input" msgid="5754664119319872197">"نام کاربری و گذرواژه نامعتبر."</string>
+    <string name="kg_login_account_recovery_hint" msgid="5690709132841752974">"نام کاربری یا گذرواژه خود را فراموش کردید؟"\n"از "<b>"google.com/accounts/recovery"</b>" بازدید کنید."</string>
+    <string name="kg_login_checking_password" msgid="8849589033659332457">"در حال بررسی..."</string>
+    <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="8276745642049502550">"پین خود را <xliff:g id="NUMBER_0">%d</xliff:g> بار اشتباه تایپ کردید. "\n\n"پس از <xliff:g id="NUMBER_1">%d</xliff:g> ثانیه دوباره امتحان کنید."</string>
+    <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="7813713389422226531">"گذرواژه خود را <xliff:g id="NUMBER_0">%d</xliff:g> بار اشتباه تایپ کردید. "\n\n"پس از <xliff:g id="NUMBER_1">%d</xliff:g> ثانیه دوباره امتحان کنید."</string>
+    <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="74089475965050805">"الگوی بازگشایی قفل خود را <xliff:g id="NUMBER_0">%d</xliff:g> بار اشتباه کشیدید. "\n\n"لطفاً پس از <xliff:g id="NUMBER_1">%d</xliff:g> ثانیه دوباره امتحان کنید."</string>
+    <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="1575557200627128949">"شما به اشتباه <xliff:g id="NUMBER_0">%d</xliff:g> بار اقدام به باز کردن قفل رایانه لوحی کرده‌اید. پس از <xliff:g id="NUMBER_1">%d</xliff:g> تلاش ناموفق دیگر، رایانهٔ لوحی به پیش‌فرض کارخانه بازنشانی می‌شود و تمام داده‌های کاربر از دست خواهد رفت."</string>
+    <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="4051015943038199910">"شما به اشتباه <xliff:g id="NUMBER_0">%d</xliff:g> بار اقدام به باز کردن قفل تلفن کرده‌اید. پس از <xliff:g id="NUMBER_1">%d</xliff:g> تلاش ناموفق دیگر، تلفن به پیش‌فرض کارخانه بازنشانی می‌شود و تمام داده‌های کاربر از دست خواهد رفت."</string>
+    <string name="kg_failed_attempts_now_wiping" product="tablet" msgid="2072996269148483637">"شما به اشتباه <xliff:g id="NUMBER">%d</xliff:g> بار اقدام به باز کردن قفل رایانه لوحی کرده‌اید. رایانه لوحی اکنون به پیش‌فرض کارخانه بازنشانی می‌شود."</string>
+    <string name="kg_failed_attempts_now_wiping" product="default" msgid="4817627474419471518">"شما به اشتباه <xliff:g id="NUMBER">%d</xliff:g> بار اقدام به باز کردن قفل تلفن کرده‌اید. این تلفن اکنون به پیش‌فرض کارخانه بازنشانی می‌شود."</string>
+    <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"شما الگوی بازگشایی قفل خود را <xliff:g id="NUMBER_0">%d</xliff:g> بار اشتباه کشیده‎اید. بعد از <xliff:g id="NUMBER_1">%d</xliff:g> تلاش ناموفق، از شما خواسته می‎شود که با استفاده از یک حساب ایمیل قفل رایانه لوحی خود را باز کنید."\n\n" لطفاً پس از <xliff:g id="NUMBER_2">%d</xliff:g> ثانیه دوباره امتحان کنید."</string>
+    <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"شما الگوی بازگشایی قفل خود را <xliff:g id="NUMBER_0">%d</xliff:g> بار اشتباه کشیده‌اید. پس از <xliff:g id="NUMBER_1">%d</xliff:g> تلاش ناموفق، از شما خواسته می‎شود که با استفاده از یک حساب ایمیل قفل تلفن خود را باز کنید."\n\n" لطفاً پس از <xliff:g id="NUMBER_2">%d</xliff:g> ثانیه دوباره امتحان کنید."</string>
+    <string name="kg_temp_back_string" msgid="5812983904056640466">"&lt;"</string>
 </resources>
diff --git a/core/res/res/values-fi/strings.xml b/core/res/res/values-fi/strings.xml
index b9d6c06..770297c 100644
--- a/core/res/res/values-fi/strings.xml
+++ b/core/res/res/values-fi/strings.xml
@@ -547,10 +547,8 @@
     <string name="permdesc_sdcardWrite" product="default" msgid="4337417790936632090">"Antaa sovelluksen kirjoittaa SD-kortille."</string>
     <string name="permlab_mediaStorageWrite" product="default" msgid="6859839199706879015">"muokkaa/poista sisäisen säilytystilan sisältöä"</string>
     <string name="permdesc_mediaStorageWrite" product="default" msgid="8189160597698529185">"Antaa sovelluksen muokata sisäisen tallennustilan sisältöä."</string>
-    <!-- no translation found for permlab_sdcardAccessAll (8150613823900460576) -->
-    <skip />
-    <!-- no translation found for permdesc_sdcardAccessAll (3215208357415891320) -->
-    <skip />
+    <string name="permlab_sdcardAccessAll" msgid="8150613823900460576">"käyttää kaikkien käyttäjien ulk. tallennustilaa"</string>
+    <string name="permdesc_sdcardAccessAll" msgid="3215208357415891320">"Sallii sovelluksen käyttää ulkoista tallennustilaa kaikille käyttäjille."</string>
     <string name="permlab_cache_filesystem" msgid="5656487264819669824">"käytä välimuistin tiedostojärjestelmää"</string>
     <string name="permdesc_cache_filesystem" msgid="5578967642265550955">"Antaa sovelluksen lukea välimuistin tiedostojärjestelmää ja kirjoittaa siihen."</string>
     <string name="permlab_use_sip" msgid="5986952362795870502">"soita/vastaanota internetpuheluita"</string>
@@ -581,6 +579,10 @@
     <string name="policydesc_encryptedStorage" msgid="2637732115325316992">"Pakota tallennettujen sovellustietojen salaus."</string>
     <string name="policylab_disableCamera" msgid="6395301023152297826">"Poista kamerat käytöstä"</string>
     <string name="policydesc_disableCamera" msgid="2306349042834754597">"Estä laitteen kaikkien kameroiden käyttö."</string>
+    <!-- no translation found for policylab_disableKeyguardWidgets (1794894613389073926) -->
+    <skip />
+    <!-- no translation found for policydesc_disableKeyguardWidgets (7254624892984033592) -->
+    <skip />
   <string-array name="phoneTypes">
     <item msgid="8901098336658710359">"Puhelinnumero (koti)"</item>
     <item msgid="869923650527136615">"Mobiili"</item>
@@ -1319,64 +1321,46 @@
     <string name="bluetooth_a2dp_audio_route_name" msgid="8575624030406771015">"Bluetooth-ääni"</string>
     <string name="media_route_chooser_grouping_done" msgid="7966438307723317169">"Valmis"</string>
     <string name="media_route_button_content_description" msgid="5758553567065145276">"Median äänentoisto"</string>
-    <!-- no translation found for display_manager_built_in_display_name (2583134294292563941) -->
+    <string name="display_manager_built_in_display_name" msgid="2583134294292563941">"Yhdysrakenteinen näyttö"</string>
+    <!-- no translation found for display_manager_hdmi_display_name (1555264559227470109) -->
     <skip />
-    <!-- no translation found for display_manager_overlay_display_name (5142365982271620716) -->
+    <string name="display_manager_overlay_display_name" msgid="5142365982271620716">"Peittokuva # <xliff:g id="ID">%1$d</xliff:g>"</string>
+    <!-- no translation found for display_manager_overlay_display_title (652124517672257172) -->
     <skip />
-    <!-- no translation found for display_manager_overlay_display_title (8186674340178573982) -->
-    <skip />
-    <!-- no translation found for kg_emergency_call_label (684946192523830531) -->
-    <skip />
-    <!-- no translation found for kg_forgot_pattern_button_text (8852021467868220608) -->
-    <skip />
-    <!-- no translation found for kg_wrong_pattern (1850806070801358830) -->
-    <skip />
-    <!-- no translation found for kg_wrong_password (2333281762128113157) -->
-    <skip />
-    <!-- no translation found for kg_wrong_pin (1131306510833563801) -->
-    <skip />
-    <!-- no translation found for kg_too_many_failed_attempts_countdown (353963338189371686) -->
-    <skip />
-    <!-- no translation found for kg_pattern_instructions (398978611683075868) -->
-    <skip />
-    <!-- no translation found for kg_sim_pin_instructions (2319508550934557331) -->
-    <skip />
-    <!-- no translation found for kg_pin_instructions (2377242233495111557) -->
-    <skip />
-    <!-- no translation found for kg_password_instructions (5753646556186936819) -->
-    <skip />
-    <!-- no translation found for kg_puk_enter_puk_hint (5183097160254244459) -->
-    <skip />
-    <!-- no translation found for kg_puk_enter_pin_hint (597821135578014901) -->
-    <skip />
-    <!-- no translation found for kg_sim_unlock_progress_dialog_message (8950398016976865762) -->
-    <skip />
-    <!-- no translation found for kg_password_wrong_pin_code (1139324887413846912) -->
-    <skip />
-    <!-- no translation found for kg_invalid_sim_pin_hint (8795159358110620001) -->
-    <skip />
-    <!-- no translation found for kg_invalid_sim_puk_hint (5216603185442368307) -->
-    <skip />
-    <!-- no translation found for kg_sim_puk_recovery_hint (5577753137718442566) -->
-    <skip />
-    <!-- no translation found for kg_invalid_puk (5809955359950817326) -->
-    <skip />
-    <!-- no translation found for kg_login_too_many_attempts (6486842094005698475) -->
-    <skip />
-    <!-- no translation found for kg_login_instructions (1100551261265506448) -->
-    <skip />
-    <!-- no translation found for kg_login_username_hint (5718534272070920364) -->
-    <skip />
-    <!-- no translation found for kg_login_password_hint (9057289103827298549) -->
-    <skip />
-    <!-- no translation found for kg_login_submit_button (5355904582674054702) -->
-    <skip />
-    <!-- no translation found for kg_login_invalid_input (5754664119319872197) -->
-    <skip />
-    <!-- no translation found for kg_login_account_recovery_hint (5690709132841752974) -->
-    <skip />
-    <!-- no translation found for kg_login_checking_password (8849589033659332457) -->
-    <skip />
-    <!-- no translation found for kg_temp_back_string (5812983904056640466) -->
-    <skip />
+    <string name="kg_emergency_call_label" msgid="684946192523830531">"Hätäpuhelu"</string>
+    <string name="kg_forgot_pattern_button_text" msgid="8852021467868220608">"Unohtunut kuvio"</string>
+    <string name="kg_wrong_pattern" msgid="1850806070801358830">"Väärä kuvio"</string>
+    <string name="kg_wrong_password" msgid="2333281762128113157">"Väärä salasana"</string>
+    <string name="kg_wrong_pin" msgid="1131306510833563801">"Väärä PIN-koodi"</string>
+    <string name="kg_too_many_failed_attempts_countdown" msgid="6358110221603297548">"Yritä uudelleen <xliff:g id="NUMBER">%d</xliff:g> sekunnin kuluttua."</string>
+    <string name="kg_pattern_instructions" msgid="398978611683075868">"Piirrä kuvio"</string>
+    <string name="kg_sim_pin_instructions" msgid="2319508550934557331">"Anna SIM-kortin PIN-koodi"</string>
+    <string name="kg_pin_instructions" msgid="2377242233495111557">"Anna PIN-koodi"</string>
+    <string name="kg_password_instructions" msgid="5753646556186936819">"Anna salasana"</string>
+    <string name="kg_puk_enter_puk_hint" msgid="5183097160254244459">"PUK-koodi"</string>
+    <string name="kg_puk_enter_pin_hint" msgid="597821135578014901">"Uusi PIN-koodi"</string>
+    <string name="kg_sim_unlock_progress_dialog_message" msgid="8950398016976865762">"SIM-kortin lukitusta poistetaan…"</string>
+    <string name="kg_password_wrong_pin_code" msgid="1139324887413846912">"Virheellinen PIN-koodi."</string>
+    <string name="kg_invalid_sim_pin_hint" msgid="8795159358110620001">"Anna 4–8-numeroinen PIN-koodi."</string>
+    <string name="kg_invalid_sim_puk_hint" msgid="5216603185442368307">"Kirjoita vähintään 8 numeron pituinen PUK-koodi."</string>
+    <string name="kg_sim_puk_recovery_hint" msgid="5577753137718442566">"Anna PUK-koodi ja uusi PIN-koodi"</string>
+    <string name="kg_invalid_puk" msgid="5809955359950817326">"Antamasi PUK-koodi on virheellinen."</string>
+    <string name="kg_login_too_many_attempts" msgid="6486842094005698475">"Liikaa kuvionpiirtoyrityksiä"</string>
+    <string name="kg_login_instructions" msgid="1100551261265506448">"Poista lukitus kirjautumalla sisään Google-tililläsi."</string>
+    <string name="kg_login_username_hint" msgid="5718534272070920364">"Käyttäjänimi (sähköposti)"</string>
+    <string name="kg_login_password_hint" msgid="9057289103827298549">"Salasana"</string>
+    <string name="kg_login_submit_button" msgid="5355904582674054702">"Kirjaudu sisään"</string>
+    <string name="kg_login_invalid_input" msgid="5754664119319872197">"Virheellinen käyttäjänimi tai salasana."</string>
+    <string name="kg_login_account_recovery_hint" msgid="5690709132841752974">"Unohditko käyttäjänimesi tai salasanasi?"\n"Käy osoitteessa "<b>"google.com/accounts/recovery"</b>"."</string>
+    <string name="kg_login_checking_password" msgid="8849589033659332457">"Tarkistetaan..."</string>
+    <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="8276745642049502550">"Olet kirjoittanut PIN-koodin väärin <xliff:g id="NUMBER_0">%d</xliff:g> kertaa. "\n\n"Yritä uudelleen <xliff:g id="NUMBER_1">%d</xliff:g> sekunnin kuluttua."</string>
+    <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="7813713389422226531">"Olet kirjoittanut salasanan väärin <xliff:g id="NUMBER_0">%d</xliff:g> kertaa. "\n\n"Yritä uudelleen <xliff:g id="NUMBER_1">%d</xliff:g> sekunnin kuluttua."</string>
+    <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="74089475965050805">"Olet piirtänyt lukituksenpoistokuvion väärin <xliff:g id="NUMBER_0">%d</xliff:g> kertaa. "\n\n"Yritä uudelleen <xliff:g id="NUMBER_1">%d</xliff:g> sekunnin kuluttua."</string>
+    <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="1575557200627128949">"Tablet-laitteen lukituksen poisto epäonnistui <xliff:g id="NUMBER_0">%d</xliff:g> kertaa. Jos teet vielä <xliff:g id="NUMBER_1">%d</xliff:g> epäonnistunutta yritystä, tablet-laitteeseen palautetaan tehdasasetukset ja kaikki käyttäjätiedot häviävät."</string>
+    <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="4051015943038199910">"Puhelimen lukituksen poisto epäonnistui <xliff:g id="NUMBER_0">%d</xliff:g> kertaa. Jos teet vielä <xliff:g id="NUMBER_1">%d</xliff:g> epäonnistunutta yritystä, puhelimeen palautetaan tehdasasetukset ja kaikki käyttäjätiedot häviävät."</string>
+    <string name="kg_failed_attempts_now_wiping" product="tablet" msgid="2072996269148483637">"Tablet-laitteen lukituksen poisto epäonnistui <xliff:g id="NUMBER">%d</xliff:g> kertaa. Laitteeseen palautetaan nyt tehdasasetukset."</string>
+    <string name="kg_failed_attempts_now_wiping" product="default" msgid="4817627474419471518">"Puhelimen lukituksen poisto epäonnistui <xliff:g id="NUMBER">%d</xliff:g> kertaa. Puhelimeen palautetaan nyt tehdasasetukset."</string>
+    <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"Piirsit lukituksenpoistokuvion väärin <xliff:g id="NUMBER_0">%d</xliff:g> kertaa. Jos piirrät kuvion väärin vielä <xliff:g id="NUMBER_1">%d</xliff:g> kertaa, sinua pyydetään poistamaan tablet-laitteesi lukitus sähköpostitilin avulla."\n\n" Yritä uudelleen <xliff:g id="NUMBER_2">%d</xliff:g> sekunnin kuluttua."</string>
+    <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"Piirsit lukituksenpoistokuvion väärin <xliff:g id="NUMBER_0">%d</xliff:g> kertaa. Jos piirrät kuvion väärin vielä <xliff:g id="NUMBER_1">%d</xliff:g> kertaa, sinua pyydetään poistamaan puhelimesi lukitus sähköpostitilin avulla."\n\n" Yritä uudelleen <xliff:g id="NUMBER_2">%d</xliff:g> sekunnin kuluttua."</string>
+    <string name="kg_temp_back_string" msgid="5812983904056640466">"&lt;"</string>
 </resources>
diff --git a/core/res/res/values-fr/strings.xml b/core/res/res/values-fr/strings.xml
index e5f7978..c23a8e3 100644
--- a/core/res/res/values-fr/strings.xml
+++ b/core/res/res/values-fr/strings.xml
@@ -547,10 +547,8 @@
     <string name="permdesc_sdcardWrite" product="default" msgid="4337417790936632090">"Permet à l\'application de modifier le contenu de la carte SD."</string>
     <string name="permlab_mediaStorageWrite" product="default" msgid="6859839199706879015">"Modifier/Supprimer contenu mémoire interne"</string>
     <string name="permdesc_mediaStorageWrite" product="default" msgid="8189160597698529185">"Permet à l\'application de modifier le contenu de la mémoire de stockage multimédia interne."</string>
-    <!-- no translation found for permlab_sdcardAccessAll (8150613823900460576) -->
-    <skip />
-    <!-- no translation found for permdesc_sdcardAccessAll (3215208357415891320) -->
-    <skip />
+    <string name="permlab_sdcardAccessAll" msgid="8150613823900460576">"Accès stock. ext. tous utilis."</string>
+    <string name="permdesc_sdcardAccessAll" msgid="3215208357415891320">"Permet à l\'application d\'accéder à la mémoire de stockage externe pour tous les utilisateurs."</string>
     <string name="permlab_cache_filesystem" msgid="5656487264819669824">"accéder au système de fichiers en cache"</string>
     <string name="permdesc_cache_filesystem" msgid="5578967642265550955">"Permet à l\'application d\'obtenir des droits en lecture/écriture concernant le système de fichiers du cache."</string>
     <string name="permlab_use_sip" msgid="5986952362795870502">"effectuer/recevoir des appels Internet"</string>
@@ -581,6 +579,10 @@
     <string name="policydesc_encryptedStorage" msgid="2637732115325316992">"Exiger le chiffrement des données d\'application stockées"</string>
     <string name="policylab_disableCamera" msgid="6395301023152297826">"Désactiver les appareils photo"</string>
     <string name="policydesc_disableCamera" msgid="2306349042834754597">"Empêcher l\'utilisation de tous les appareils photos"</string>
+    <!-- no translation found for policylab_disableKeyguardWidgets (1794894613389073926) -->
+    <skip />
+    <!-- no translation found for policydesc_disableKeyguardWidgets (7254624892984033592) -->
+    <skip />
   <string-array name="phoneTypes">
     <item msgid="8901098336658710359">"Domicile"</item>
     <item msgid="869923650527136615">"Mobile"</item>
@@ -1319,64 +1321,46 @@
     <string name="bluetooth_a2dp_audio_route_name" msgid="8575624030406771015">"Audio Bluetooth"</string>
     <string name="media_route_chooser_grouping_done" msgid="7966438307723317169">"OK"</string>
     <string name="media_route_button_content_description" msgid="5758553567065145276">"Sortie multimédia"</string>
-    <!-- no translation found for display_manager_built_in_display_name (2583134294292563941) -->
+    <string name="display_manager_built_in_display_name" msgid="2583134294292563941">"Écran intégré"</string>
+    <!-- no translation found for display_manager_hdmi_display_name (1555264559227470109) -->
     <skip />
-    <!-- no translation found for display_manager_overlay_display_name (5142365982271620716) -->
+    <string name="display_manager_overlay_display_name" msgid="5142365982271620716">"Superposition n° <xliff:g id="ID">%1$d</xliff:g>"</string>
+    <!-- no translation found for display_manager_overlay_display_title (652124517672257172) -->
     <skip />
-    <!-- no translation found for display_manager_overlay_display_title (8186674340178573982) -->
-    <skip />
-    <!-- no translation found for kg_emergency_call_label (684946192523830531) -->
-    <skip />
-    <!-- no translation found for kg_forgot_pattern_button_text (8852021467868220608) -->
-    <skip />
-    <!-- no translation found for kg_wrong_pattern (1850806070801358830) -->
-    <skip />
-    <!-- no translation found for kg_wrong_password (2333281762128113157) -->
-    <skip />
-    <!-- no translation found for kg_wrong_pin (1131306510833563801) -->
-    <skip />
-    <!-- no translation found for kg_too_many_failed_attempts_countdown (353963338189371686) -->
-    <skip />
-    <!-- no translation found for kg_pattern_instructions (398978611683075868) -->
-    <skip />
-    <!-- no translation found for kg_sim_pin_instructions (2319508550934557331) -->
-    <skip />
-    <!-- no translation found for kg_pin_instructions (2377242233495111557) -->
-    <skip />
-    <!-- no translation found for kg_password_instructions (5753646556186936819) -->
-    <skip />
-    <!-- no translation found for kg_puk_enter_puk_hint (5183097160254244459) -->
-    <skip />
-    <!-- no translation found for kg_puk_enter_pin_hint (597821135578014901) -->
-    <skip />
-    <!-- no translation found for kg_sim_unlock_progress_dialog_message (8950398016976865762) -->
-    <skip />
-    <!-- no translation found for kg_password_wrong_pin_code (1139324887413846912) -->
-    <skip />
-    <!-- no translation found for kg_invalid_sim_pin_hint (8795159358110620001) -->
-    <skip />
-    <!-- no translation found for kg_invalid_sim_puk_hint (5216603185442368307) -->
-    <skip />
-    <!-- no translation found for kg_sim_puk_recovery_hint (5577753137718442566) -->
-    <skip />
-    <!-- no translation found for kg_invalid_puk (5809955359950817326) -->
-    <skip />
-    <!-- no translation found for kg_login_too_many_attempts (6486842094005698475) -->
-    <skip />
-    <!-- no translation found for kg_login_instructions (1100551261265506448) -->
-    <skip />
-    <!-- no translation found for kg_login_username_hint (5718534272070920364) -->
-    <skip />
-    <!-- no translation found for kg_login_password_hint (9057289103827298549) -->
-    <skip />
-    <!-- no translation found for kg_login_submit_button (5355904582674054702) -->
-    <skip />
-    <!-- no translation found for kg_login_invalid_input (5754664119319872197) -->
-    <skip />
-    <!-- no translation found for kg_login_account_recovery_hint (5690709132841752974) -->
-    <skip />
-    <!-- no translation found for kg_login_checking_password (8849589033659332457) -->
-    <skip />
-    <!-- no translation found for kg_temp_back_string (5812983904056640466) -->
-    <skip />
+    <string name="kg_emergency_call_label" msgid="684946192523830531">"Appel d\'urgence"</string>
+    <string name="kg_forgot_pattern_button_text" msgid="8852021467868220608">"J\'ai oublié le schéma"</string>
+    <string name="kg_wrong_pattern" msgid="1850806070801358830">"Schéma incorrect."</string>
+    <string name="kg_wrong_password" msgid="2333281762128113157">"Mot de passe incorrect."</string>
+    <string name="kg_wrong_pin" msgid="1131306510833563801">"Code PIN incorrect."</string>
+    <string name="kg_too_many_failed_attempts_countdown" msgid="6358110221603297548">"Réessayez dans <xliff:g id="NUMBER">%d</xliff:g> secondes."</string>
+    <string name="kg_pattern_instructions" msgid="398978611683075868">"Dessinez votre schéma."</string>
+    <string name="kg_sim_pin_instructions" msgid="2319508550934557331">"Saisissez le code PIN de la carte SIM."</string>
+    <string name="kg_pin_instructions" msgid="2377242233495111557">"Saisissez le code PIN."</string>
+    <string name="kg_password_instructions" msgid="5753646556186936819">"Saisissez votre mot de passe."</string>
+    <string name="kg_puk_enter_puk_hint" msgid="5183097160254244459">"Clé PUK"</string>
+    <string name="kg_puk_enter_pin_hint" msgid="597821135578014901">"Nouveau code PIN"</string>
+    <string name="kg_sim_unlock_progress_dialog_message" msgid="8950398016976865762">"Déblocage de la carte SIM en cours…"</string>
+    <string name="kg_password_wrong_pin_code" msgid="1139324887413846912">"Le code PIN est erroné."</string>
+    <string name="kg_invalid_sim_pin_hint" msgid="8795159358110620001">"Saisissez un code PIN comprenant entre quatre et huit chiffres"</string>
+    <string name="kg_invalid_sim_puk_hint" msgid="5216603185442368307">"Saisissez une clé PUK comportant au moins huit chiffres"</string>
+    <string name="kg_sim_puk_recovery_hint" msgid="5577753137718442566">"Saisissez la clé PUK et le nouveau code PIN"</string>
+    <string name="kg_invalid_puk" msgid="5809955359950817326">"La clé PUK saisie est incorrecte."</string>
+    <string name="kg_login_too_many_attempts" msgid="6486842094005698475">"Trop de tentatives."</string>
+    <string name="kg_login_instructions" msgid="1100551261265506448">"Pour déverrouiller le téléphone, veuillez vous connecter avec votre compte Google."</string>
+    <string name="kg_login_username_hint" msgid="5718534272070920364">"Nom d\'utilisateur (e-mail)"</string>
+    <string name="kg_login_password_hint" msgid="9057289103827298549">"Mot de passe"</string>
+    <string name="kg_login_submit_button" msgid="5355904582674054702">"Connexion"</string>
+    <string name="kg_login_invalid_input" msgid="5754664119319872197">"Nom d\'utilisateur ou mot de passe non valide."</string>
+    <string name="kg_login_account_recovery_hint" msgid="5690709132841752974">"Vous avez oublié votre nom d\'utilisateur ou votre mot de passe ?"\n"Rendez-vous sur la page "<b>"google.com/accounts/recovery"</b>"."</string>
+    <string name="kg_login_checking_password" msgid="8849589033659332457">"Vérification en cours…"</string>
+    <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="8276745642049502550">"Vous avez saisi un code PIN incorrect à <xliff:g id="NUMBER_0">%d</xliff:g> reprises. "\n\n"Veuillez réessayer dans <xliff:g id="NUMBER_1">%d</xliff:g> secondes."</string>
+    <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="7813713389422226531">"Vous avez saisi un mot de passe incorrect à <xliff:g id="NUMBER_0">%d</xliff:g> reprises. "\n\n"Veuillez réessayer dans <xliff:g id="NUMBER_1">%d</xliff:g> secondes."</string>
+    <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="74089475965050805">"Vous avez dessiné un schéma de déverrouillage incorrect à <xliff:g id="NUMBER_0">%d</xliff:g> reprises."\n\n"Veuillez réessayer dans <xliff:g id="NUMBER_1">%d</xliff:g> secondes."</string>
+    <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="1575557200627128949">"Vous avez tenté de déverrouiller la tablette de façon incorrecte à <xliff:g id="NUMBER_0">%d</xliff:g> reprises. Si vous échouez encore <xliff:g id="NUMBER_1">%d</xliff:g> fois, sa configuration d\'usine sera rétablie, et toutes les données utilisateur seront perdues."</string>
+    <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="4051015943038199910">"Vous avez tenté de déverrouiller le téléphone de façon incorrecte à <xliff:g id="NUMBER_0">%d</xliff:g> reprises. Si vous échouez encore <xliff:g id="NUMBER_1">%d</xliff:g> fois, sa configuration d\'usine sera rétablie, et toutes les données utilisateur seront perdues."</string>
+    <string name="kg_failed_attempts_now_wiping" product="tablet" msgid="2072996269148483637">"Vous avez tenté de déverrouiller la tablette de façon incorrecte à <xliff:g id="NUMBER">%d</xliff:g> reprises. Sa configuration d\'usine va être rétablie."</string>
+    <string name="kg_failed_attempts_now_wiping" product="default" msgid="4817627474419471518">"Vous avez tenté de déverrouiller le téléphone de façon incorrecte à <xliff:g id="NUMBER">%d</xliff:g> reprises. Sa configuration d\'usine va être rétablie."</string>
+    <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"Vous avez dessiné un schéma de déverrouillage incorrect à <xliff:g id="NUMBER_0">%d</xliff:g> reprises. Au bout de <xliff:g id="NUMBER_1">%d</xliff:g> échecs supplémentaires, vous devrez déverrouiller votre tablette à l\'aide d\'un compte de messagerie électronique."\n\n" Veuillez réessayer dans <xliff:g id="NUMBER_2">%d</xliff:g> secondes."</string>
+    <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"Vous avez dessiné un schéma de déverrouillage incorrect à <xliff:g id="NUMBER_0">%d</xliff:g> reprises. Au bout de <xliff:g id="NUMBER_1">%d</xliff:g> échecs supplémentaires, vous devrez déverrouiller votre téléphone à l\'aide d\'un compte de messagerie électronique."\n\n" Veuillez réessayer dans <xliff:g id="NUMBER_2">%d</xliff:g> secondes."</string>
+    <string name="kg_temp_back_string" msgid="5812983904056640466">"&lt;"</string>
 </resources>
diff --git a/core/res/res/values-hi/strings.xml b/core/res/res/values-hi/strings.xml
index fcb0783..e338c95 100644
--- a/core/res/res/values-hi/strings.xml
+++ b/core/res/res/values-hi/strings.xml
@@ -547,10 +547,8 @@
     <string name="permdesc_sdcardWrite" product="default" msgid="4337417790936632090">"एप्लिकेशन को SD कार्ड पर लिखने देता है."</string>
     <string name="permlab_mediaStorageWrite" product="default" msgid="6859839199706879015">"आंतरिक मीडिया संग्रहण सामग्रियों को बदलें/हटाएं"</string>
     <string name="permdesc_mediaStorageWrite" product="default" msgid="8189160597698529185">"एप्लिकेशन को आंतरिक मीडिया संग्रहण की सामग्री को संशोधित करने देता है."</string>
-    <!-- no translation found for permlab_sdcardAccessAll (8150613823900460576) -->
-    <skip />
-    <!-- no translation found for permdesc_sdcardAccessAll (3215208357415891320) -->
-    <skip />
+    <string name="permlab_sdcardAccessAll" msgid="8150613823900460576">"सभी उपयोगकर्ताओं के बाहरी संग्रहण तक पहुंचें"</string>
+    <string name="permdesc_sdcardAccessAll" msgid="3215208357415891320">"एप्लिकेशन को सभी उपयोगकर्ताओं के बाहरी संग्रहण तक पहुंचने दें."</string>
     <string name="permlab_cache_filesystem" msgid="5656487264819669824">"कैश फ़ाइल सिस्‍टम में पहंचे"</string>
     <string name="permdesc_cache_filesystem" msgid="5578967642265550955">"एप्‍लिकेशन को संचय फ़ाइल सिस्‍टम पढ़ने और लिखने देता है."</string>
     <string name="permlab_use_sip" msgid="5986952362795870502">"इंटरनेट कॉल करें/प्राप्त करें"</string>
@@ -581,6 +579,10 @@
     <string name="policydesc_encryptedStorage" msgid="2637732115325316992">"संग्रहीत एप्‍लिकेशन डेटा को एन्क्रिप्ट किया जाना आवश्‍यक है."</string>
     <string name="policylab_disableCamera" msgid="6395301023152297826">"कैमरों को अक्षम करें"</string>
     <string name="policydesc_disableCamera" msgid="2306349042834754597">"सभी उपकरण कैमरों का उपयोग रोकें."</string>
+    <!-- no translation found for policylab_disableKeyguardWidgets (1794894613389073926) -->
+    <skip />
+    <!-- no translation found for policydesc_disableKeyguardWidgets (7254624892984033592) -->
+    <skip />
   <string-array name="phoneTypes">
     <item msgid="8901098336658710359">"घर"</item>
     <item msgid="869923650527136615">"मोबाइल"</item>
@@ -1319,64 +1321,46 @@
     <string name="bluetooth_a2dp_audio_route_name" msgid="8575624030406771015">"Bluetooth ऑडियो"</string>
     <string name="media_route_chooser_grouping_done" msgid="7966438307723317169">"पूर्ण"</string>
     <string name="media_route_button_content_description" msgid="5758553567065145276">"मीडिया आउटपुट"</string>
-    <!-- no translation found for display_manager_built_in_display_name (2583134294292563941) -->
+    <string name="display_manager_built_in_display_name" msgid="2583134294292563941">"अंतर्निहित स्क्रीन"</string>
+    <!-- no translation found for display_manager_hdmi_display_name (1555264559227470109) -->
     <skip />
-    <!-- no translation found for display_manager_overlay_display_name (5142365982271620716) -->
+    <string name="display_manager_overlay_display_name" msgid="5142365982271620716">"ओवरले #<xliff:g id="ID">%1$d</xliff:g>"</string>
+    <!-- no translation found for display_manager_overlay_display_title (652124517672257172) -->
     <skip />
-    <!-- no translation found for display_manager_overlay_display_title (8186674340178573982) -->
-    <skip />
-    <!-- no translation found for kg_emergency_call_label (684946192523830531) -->
-    <skip />
-    <!-- no translation found for kg_forgot_pattern_button_text (8852021467868220608) -->
-    <skip />
-    <!-- no translation found for kg_wrong_pattern (1850806070801358830) -->
-    <skip />
-    <!-- no translation found for kg_wrong_password (2333281762128113157) -->
-    <skip />
-    <!-- no translation found for kg_wrong_pin (1131306510833563801) -->
-    <skip />
-    <!-- no translation found for kg_too_many_failed_attempts_countdown (353963338189371686) -->
-    <skip />
-    <!-- no translation found for kg_pattern_instructions (398978611683075868) -->
-    <skip />
-    <!-- no translation found for kg_sim_pin_instructions (2319508550934557331) -->
-    <skip />
-    <!-- no translation found for kg_pin_instructions (2377242233495111557) -->
-    <skip />
-    <!-- no translation found for kg_password_instructions (5753646556186936819) -->
-    <skip />
-    <!-- no translation found for kg_puk_enter_puk_hint (5183097160254244459) -->
-    <skip />
-    <!-- no translation found for kg_puk_enter_pin_hint (597821135578014901) -->
-    <skip />
-    <!-- no translation found for kg_sim_unlock_progress_dialog_message (8950398016976865762) -->
-    <skip />
-    <!-- no translation found for kg_password_wrong_pin_code (1139324887413846912) -->
-    <skip />
-    <!-- no translation found for kg_invalid_sim_pin_hint (8795159358110620001) -->
-    <skip />
-    <!-- no translation found for kg_invalid_sim_puk_hint (5216603185442368307) -->
-    <skip />
-    <!-- no translation found for kg_sim_puk_recovery_hint (5577753137718442566) -->
-    <skip />
-    <!-- no translation found for kg_invalid_puk (5809955359950817326) -->
-    <skip />
-    <!-- no translation found for kg_login_too_many_attempts (6486842094005698475) -->
-    <skip />
-    <!-- no translation found for kg_login_instructions (1100551261265506448) -->
-    <skip />
-    <!-- no translation found for kg_login_username_hint (5718534272070920364) -->
-    <skip />
-    <!-- no translation found for kg_login_password_hint (9057289103827298549) -->
-    <skip />
-    <!-- no translation found for kg_login_submit_button (5355904582674054702) -->
-    <skip />
-    <!-- no translation found for kg_login_invalid_input (5754664119319872197) -->
-    <skip />
-    <!-- no translation found for kg_login_account_recovery_hint (5690709132841752974) -->
-    <skip />
-    <!-- no translation found for kg_login_checking_password (8849589033659332457) -->
-    <skip />
-    <!-- no translation found for kg_temp_back_string (5812983904056640466) -->
-    <skip />
+    <string name="kg_emergency_call_label" msgid="684946192523830531">"आपातकालीन कॉल"</string>
+    <string name="kg_forgot_pattern_button_text" msgid="8852021467868220608">"प्रतिमान भूल गए"</string>
+    <string name="kg_wrong_pattern" msgid="1850806070801358830">"गलत प्रतिमान"</string>
+    <string name="kg_wrong_password" msgid="2333281762128113157">"गलत पासवर्ड"</string>
+    <string name="kg_wrong_pin" msgid="1131306510833563801">"गलत PIN"</string>
+    <string name="kg_too_many_failed_attempts_countdown" msgid="6358110221603297548">"<xliff:g id="NUMBER">%d</xliff:g> सेकंड में पुन: प्रयास करें."</string>
+    <string name="kg_pattern_instructions" msgid="398978611683075868">"अपना प्रतिमान आरेखित करें"</string>
+    <string name="kg_sim_pin_instructions" msgid="2319508550934557331">"सिम PIN डालें"</string>
+    <string name="kg_pin_instructions" msgid="2377242233495111557">"PIN डालें"</string>
+    <string name="kg_password_instructions" msgid="5753646556186936819">"पासवर्ड डालें"</string>
+    <string name="kg_puk_enter_puk_hint" msgid="5183097160254244459">"PUK कोड"</string>
+    <string name="kg_puk_enter_pin_hint" msgid="597821135578014901">"नया PIN कोड"</string>
+    <string name="kg_sim_unlock_progress_dialog_message" msgid="8950398016976865762">"सिम कार्ड अनलॉक कर रहा है…"</string>
+    <string name="kg_password_wrong_pin_code" msgid="1139324887413846912">"गलत PIN कोड."</string>
+    <string name="kg_invalid_sim_pin_hint" msgid="8795159358110620001">"ऐसा PIN लिखें, जो 4 से 8 अंकों का हो."</string>
+    <string name="kg_invalid_sim_puk_hint" msgid="5216603185442368307">"ऐसा PUK लिखें जो 8 अंकों या अधिक का हो."</string>
+    <string name="kg_sim_puk_recovery_hint" msgid="5577753137718442566">"PUK और नया PIN कोड लिखें"</string>
+    <string name="kg_invalid_puk" msgid="5809955359950817326">"आपके द्वारा लिखा गया PUK सही नहीं है."</string>
+    <string name="kg_login_too_many_attempts" msgid="6486842094005698475">"बहुत अधिक प्रतिमान प्रयास"</string>
+    <string name="kg_login_instructions" msgid="1100551261265506448">"अनलॉक करने के लिए, अपने Google खाते से साइन इन करें."</string>
+    <string name="kg_login_username_hint" msgid="5718534272070920364">"उपयोगकर्ता नाम (ईमेल)"</string>
+    <string name="kg_login_password_hint" msgid="9057289103827298549">"पासवर्ड"</string>
+    <string name="kg_login_submit_button" msgid="5355904582674054702">"साइन इन करें"</string>
+    <string name="kg_login_invalid_input" msgid="5754664119319872197">"अमान्य उपयोगकर्ता नाम या पासवर्ड."</string>
+    <string name="kg_login_account_recovery_hint" msgid="5690709132841752974">"अपना उपयोगकर्ता या पासवर्ड भूल गए?"\n" "<b>"google.com/accounts/recovery"</b>" पर जाएं."</string>
+    <string name="kg_login_checking_password" msgid="8849589033659332457">"जांच कर रहा है..."</string>
+    <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="8276745642049502550">"आप अपना PIN <xliff:g id="NUMBER_0">%d</xliff:g> बार गलत तरीके से लिख चुके हैं. "\n\n" <xliff:g id="NUMBER_1">%d</xliff:g> सेकंड में पुन: प्रयास करें."</string>
+    <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="7813713389422226531">"आप अपना पासवर्ड <xliff:g id="NUMBER_0">%d</xliff:g> बार गलत तरीके से लिख चुके हैं. "\n\n" <xliff:g id="NUMBER_1">%d</xliff:g> सेकंड में पुन: प्रयास करें."</string>
+    <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="74089475965050805">"आपने अपना अनलॉक प्रतिमान <xliff:g id="NUMBER_0">%d</xliff:g> बार गलत तरीके से आरेखित किया है. "\n\n" <xliff:g id="NUMBER_1">%d</xliff:g> सेकंड में पुन: प्रयास करें."</string>
+    <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="1575557200627128949">"आप टेबलेट को अनलॉक करने के लिए <xliff:g id="NUMBER_0">%d</xliff:g> बार गलत तरीके से प्रयास कर चुके हैं. <xliff:g id="NUMBER_1">%d</xliff:g> और असफल प्रयासों के बाद, टेबलेट फ़ैक्टरी डिफ़ॉल्ट पर रीसेट हो जाएगा और सभी उपयोगकर्ता डेटा खो जाएगा."</string>
+    <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="4051015943038199910">"आप फ़ोन को अनलॉक करने के लिए <xliff:g id="NUMBER_0">%d</xliff:g> बार गलत तरीके से प्रयास कर चुके हैं. <xliff:g id="NUMBER_1">%d</xliff:g> और असफल प्रयासों के बाद, फ़ोन फ़ैक्टरी डिफ़ॉल्ट पर रीसेट हो जाएगा और सभी उपयोगकर्ता डेटा खो जाएगा."</string>
+    <string name="kg_failed_attempts_now_wiping" product="tablet" msgid="2072996269148483637">"आप टेबलेट को अनलॉक करने के लिए <xliff:g id="NUMBER">%d</xliff:g> बार गलत तरीके से प्रयास कर चुके हैं. टेबलेट अब फ़ैक्‍टरी डिफ़ॉल्‍ट पर रीसेट हो जाएगा."</string>
+    <string name="kg_failed_attempts_now_wiping" product="default" msgid="4817627474419471518">"आप फ़ोन को अनलॉक करने के लिए <xliff:g id="NUMBER">%d</xliff:g> बार गलत तरीके से प्रयास कर चुके हैं. फ़ोन अब फ़ैक्टरी डिफ़ॉल्ट पर रीसेट हो जाएगा."</string>
+    <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"आपने अपने अनलॉक प्रतिमान को <xliff:g id="NUMBER_0">%d</xliff:g> बार गलत तरीके से आरेखित किया है. <xliff:g id="NUMBER_1">%d</xliff:g> और असफल प्रयासों के बाद, आपसे अपने टेबलेट को किसी ईमेल खाते के उपयोग से अनलॉक करने के लिए कहा जाएगा."\n\n" <xliff:g id="NUMBER_2">%d</xliff:g> सेकंड में पुन: प्रयास करें."</string>
+    <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"आपने अपने अनलॉक प्रतिमान को <xliff:g id="NUMBER_0">%d</xliff:g> बार गलत तरीके से आरेखित किया है. <xliff:g id="NUMBER_1">%d</xliff:g> और असफल प्रयासों के बाद, आपसे अपने फ़ोन को किसी ईमेल खाते के उपयोग से अनलॉक करने के लिए कहा जाएगा."\n\n" <xliff:g id="NUMBER_2">%d</xliff:g> सेकंड में पुन: प्रयास करें."</string>
+    <string name="kg_temp_back_string" msgid="5812983904056640466">"&lt;"</string>
 </resources>
diff --git a/core/res/res/values-hr/strings.xml b/core/res/res/values-hr/strings.xml
index 01e6557..bf7dc5e 100644
--- a/core/res/res/values-hr/strings.xml
+++ b/core/res/res/values-hr/strings.xml
@@ -547,10 +547,8 @@
     <string name="permdesc_sdcardWrite" product="default" msgid="4337417790936632090">"Aplikaciji omogućuje pisanje na SD karticu."</string>
     <string name="permlab_mediaStorageWrite" product="default" msgid="6859839199706879015">"izmijeni/izbriši sadržaj pohranjen na internim medijima"</string>
     <string name="permdesc_mediaStorageWrite" product="default" msgid="8189160597698529185">"Aplikaciji omogućuje izmjenu sadržaja pohranjenog na internim medijima."</string>
-    <!-- no translation found for permlab_sdcardAccessAll (8150613823900460576) -->
-    <skip />
-    <!-- no translation found for permdesc_sdcardAccessAll (3215208357415891320) -->
-    <skip />
+    <string name="permlab_sdcardAccessAll" msgid="8150613823900460576">"pristup vanjskoj pohrani svima"</string>
+    <string name="permdesc_sdcardAccessAll" msgid="3215208357415891320">"Omogućuje aplikaciji pristup vanjskoj pohrani za sve korisnike."</string>
     <string name="permlab_cache_filesystem" msgid="5656487264819669824">"pristup sustavu datoteka predmemorije"</string>
     <string name="permdesc_cache_filesystem" msgid="5578967642265550955">"Aplikaciji omogućuje čitanje i pisanje u datotečnom sustavu privremene memorije."</string>
     <string name="permlab_use_sip" msgid="5986952362795870502">"zovi/primaj internetske pozive"</string>
@@ -581,6 +579,10 @@
     <string name="policydesc_encryptedStorage" msgid="2637732115325316992">"Zahtijevajte da pohranjeni podaci aplikacije budu šifrirani."</string>
     <string name="policylab_disableCamera" msgid="6395301023152297826">"Onemogući fotoaparate"</string>
     <string name="policydesc_disableCamera" msgid="2306349042834754597">"Spriječite upotrebu svih kamera uređaja."</string>
+    <!-- no translation found for policylab_disableKeyguardWidgets (1794894613389073926) -->
+    <skip />
+    <!-- no translation found for policydesc_disableKeyguardWidgets (7254624892984033592) -->
+    <skip />
   <string-array name="phoneTypes">
     <item msgid="8901098336658710359">"Početna"</item>
     <item msgid="869923650527136615">"Mobilni"</item>
@@ -1319,64 +1321,46 @@
     <string name="bluetooth_a2dp_audio_route_name" msgid="8575624030406771015">"Bluetooth zvuk"</string>
     <string name="media_route_chooser_grouping_done" msgid="7966438307723317169">"Gotovo"</string>
     <string name="media_route_button_content_description" msgid="5758553567065145276">"Medijski izlaz"</string>
-    <!-- no translation found for display_manager_built_in_display_name (2583134294292563941) -->
+    <string name="display_manager_built_in_display_name" msgid="2583134294292563941">"Ugrađeni zaslon"</string>
+    <!-- no translation found for display_manager_hdmi_display_name (1555264559227470109) -->
     <skip />
-    <!-- no translation found for display_manager_overlay_display_name (5142365982271620716) -->
+    <string name="display_manager_overlay_display_name" msgid="5142365982271620716">"Preklapanje br. <xliff:g id="ID">%1$d</xliff:g>"</string>
+    <!-- no translation found for display_manager_overlay_display_title (652124517672257172) -->
     <skip />
-    <!-- no translation found for display_manager_overlay_display_title (8186674340178573982) -->
-    <skip />
-    <!-- no translation found for kg_emergency_call_label (684946192523830531) -->
-    <skip />
-    <!-- no translation found for kg_forgot_pattern_button_text (8852021467868220608) -->
-    <skip />
-    <!-- no translation found for kg_wrong_pattern (1850806070801358830) -->
-    <skip />
-    <!-- no translation found for kg_wrong_password (2333281762128113157) -->
-    <skip />
-    <!-- no translation found for kg_wrong_pin (1131306510833563801) -->
-    <skip />
-    <!-- no translation found for kg_too_many_failed_attempts_countdown (353963338189371686) -->
-    <skip />
-    <!-- no translation found for kg_pattern_instructions (398978611683075868) -->
-    <skip />
-    <!-- no translation found for kg_sim_pin_instructions (2319508550934557331) -->
-    <skip />
-    <!-- no translation found for kg_pin_instructions (2377242233495111557) -->
-    <skip />
-    <!-- no translation found for kg_password_instructions (5753646556186936819) -->
-    <skip />
-    <!-- no translation found for kg_puk_enter_puk_hint (5183097160254244459) -->
-    <skip />
-    <!-- no translation found for kg_puk_enter_pin_hint (597821135578014901) -->
-    <skip />
-    <!-- no translation found for kg_sim_unlock_progress_dialog_message (8950398016976865762) -->
-    <skip />
-    <!-- no translation found for kg_password_wrong_pin_code (1139324887413846912) -->
-    <skip />
-    <!-- no translation found for kg_invalid_sim_pin_hint (8795159358110620001) -->
-    <skip />
-    <!-- no translation found for kg_invalid_sim_puk_hint (5216603185442368307) -->
-    <skip />
-    <!-- no translation found for kg_sim_puk_recovery_hint (5577753137718442566) -->
-    <skip />
-    <!-- no translation found for kg_invalid_puk (5809955359950817326) -->
-    <skip />
-    <!-- no translation found for kg_login_too_many_attempts (6486842094005698475) -->
-    <skip />
-    <!-- no translation found for kg_login_instructions (1100551261265506448) -->
-    <skip />
-    <!-- no translation found for kg_login_username_hint (5718534272070920364) -->
-    <skip />
-    <!-- no translation found for kg_login_password_hint (9057289103827298549) -->
-    <skip />
-    <!-- no translation found for kg_login_submit_button (5355904582674054702) -->
-    <skip />
-    <!-- no translation found for kg_login_invalid_input (5754664119319872197) -->
-    <skip />
-    <!-- no translation found for kg_login_account_recovery_hint (5690709132841752974) -->
-    <skip />
-    <!-- no translation found for kg_login_checking_password (8849589033659332457) -->
-    <skip />
-    <!-- no translation found for kg_temp_back_string (5812983904056640466) -->
-    <skip />
+    <string name="kg_emergency_call_label" msgid="684946192523830531">"Hitan poziv"</string>
+    <string name="kg_forgot_pattern_button_text" msgid="8852021467868220608">"Zaboravili ste obrazac"</string>
+    <string name="kg_wrong_pattern" msgid="1850806070801358830">"Pogrešan obrazac"</string>
+    <string name="kg_wrong_password" msgid="2333281762128113157">"Pogrešna zaporka"</string>
+    <string name="kg_wrong_pin" msgid="1131306510833563801">"Pogrešan PIN"</string>
+    <string name="kg_too_many_failed_attempts_countdown" msgid="6358110221603297548">"Pokušajte ponovo za <xliff:g id="NUMBER">%d</xliff:g> s."</string>
+    <string name="kg_pattern_instructions" msgid="398978611683075868">"Iscrtajte svoj obrazac"</string>
+    <string name="kg_sim_pin_instructions" msgid="2319508550934557331">"Unesite PIN za SIM"</string>
+    <string name="kg_pin_instructions" msgid="2377242233495111557">"Unesite PIN"</string>
+    <string name="kg_password_instructions" msgid="5753646556186936819">"Unesite zaporku"</string>
+    <string name="kg_puk_enter_puk_hint" msgid="5183097160254244459">"PUK kôd"</string>
+    <string name="kg_puk_enter_pin_hint" msgid="597821135578014901">"Novi PIN kôd"</string>
+    <string name="kg_sim_unlock_progress_dialog_message" msgid="8950398016976865762">"Otključavanje SIM kartice…"</string>
+    <string name="kg_password_wrong_pin_code" msgid="1139324887413846912">"Netočan PIN kôd."</string>
+    <string name="kg_invalid_sim_pin_hint" msgid="8795159358110620001">"Unesite PIN koji ima od 4 do 8 brojeva."</string>
+    <string name="kg_invalid_sim_puk_hint" msgid="5216603185442368307">"Upišite PUK koji se sastoji od barem 8 brojeva."</string>
+    <string name="kg_sim_puk_recovery_hint" msgid="5577753137718442566">"Unesite PUK i novi PIN kôd"</string>
+    <string name="kg_invalid_puk" msgid="5809955359950817326">"PUK koji ste unijeli nije točan."</string>
+    <string name="kg_login_too_many_attempts" msgid="6486842094005698475">"Previše pokušaja iscrtavanja obrasca"</string>
+    <string name="kg_login_instructions" msgid="1100551261265506448">"Za otključavanje prijavite se Google računom."</string>
+    <string name="kg_login_username_hint" msgid="5718534272070920364">"Korisničko ime (e-pošta)"</string>
+    <string name="kg_login_password_hint" msgid="9057289103827298549">"Zaporka"</string>
+    <string name="kg_login_submit_button" msgid="5355904582674054702">"Prijava"</string>
+    <string name="kg_login_invalid_input" msgid="5754664119319872197">"Nevažeće korisničko ime ili zaporka."</string>
+    <string name="kg_login_account_recovery_hint" msgid="5690709132841752974">"Zaboravili ste korisničko ime ili zaporku?"\n"Posjetite "<b>"google.com/accounts/recovery"</b>"."</string>
+    <string name="kg_login_checking_password" msgid="8849589033659332457">"Provjeravanje…"</string>
+    <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="8276745642049502550">"Netočno ste napisali PIN <xliff:g id="NUMBER_0">%d</xliff:g> puta. "\n\n"Pokušajte ponovo za <xliff:g id="NUMBER_1">%d</xliff:g> s."</string>
+    <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="7813713389422226531">"Netočno ste napisali zaporku <xliff:g id="NUMBER_0">%d</xliff:g> puta. "\n\n"Pokušajte ponovo za <xliff:g id="NUMBER_1">%d</xliff:g> s."</string>
+    <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="74089475965050805">"Netočno ste iscrtali obrazac za otključavanje <xliff:g id="NUMBER_0">%d</xliff:g> puta. "\n\n"Pokušajte ponovo za <xliff:g id="NUMBER_1">%d</xliff:g> s."</string>
+    <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="1575557200627128949">"Netočno ste pokušali otključati tabletno računalo <xliff:g id="NUMBER_0">%d</xliff:g> puta. Ono će se vratiti na tvorničke postavke i svi korisnički podaci bit će izgubljeni nakon još ovoliko neuspjelih pokušaja: <xliff:g id="NUMBER_1">%d</xliff:g>."</string>
+    <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="4051015943038199910">"Netočno ste pokušali otključati telefon <xliff:g id="NUMBER_0">%d</xliff:g> puta. On će se vratiti na tvorničke postavke i svi korisnički podaci bit će izgubljeni nakon još ovoliko neuspjelih pokušaja: <xliff:g id="NUMBER_1">%d</xliff:g>."</string>
+    <string name="kg_failed_attempts_now_wiping" product="tablet" msgid="2072996269148483637">"Netočno ste pokušali otključati tabletno računalo <xliff:g id="NUMBER">%d</xliff:g> puta. Sada će se vratiti na tvorničke postavke."</string>
+    <string name="kg_failed_attempts_now_wiping" product="default" msgid="4817627474419471518">"Netočno ste pokušali otključati telefon <xliff:g id="NUMBER">%d</xliff:g> puta. Sada će se vratiti na tvorničke postavke."</string>
+    <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"Netočno ste iscrtali obrazac za otključavanje <xliff:g id="NUMBER_0">%d</xliff:g> puta. Nakon još ovoliko neuspješnih pokušaja: <xliff:g id="NUMBER_1">%d</xliff:g> morat ćete otključati tabletno računalo pomoću računa e-pošte."\n\n" Pokušajte ponovo za <xliff:g id="NUMBER_2">%d</xliff:g> s."</string>
+    <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"Netočno ste iscrtali obrazac za otključavanje <xliff:g id="NUMBER_0">%d</xliff:g> puta. Nakon još ovoliko neuspješnih pokušaja: <xliff:g id="NUMBER_1">%d</xliff:g> morat ćete otključati telefon pomoću računa e-pošte."\n\n" Pokušajte ponovo za <xliff:g id="NUMBER_2">%d</xliff:g> s."</string>
+    <string name="kg_temp_back_string" msgid="5812983904056640466">"&lt;"</string>
 </resources>
diff --git a/core/res/res/values-hu/strings.xml b/core/res/res/values-hu/strings.xml
index a48129d..0404e3f 100644
--- a/core/res/res/values-hu/strings.xml
+++ b/core/res/res/values-hu/strings.xml
@@ -547,10 +547,8 @@
     <string name="permdesc_sdcardWrite" product="default" msgid="4337417790936632090">"Lehetővé teszi az alkalmazás számára, hogy írjon az SD-kártyára."</string>
     <string name="permlab_mediaStorageWrite" product="default" msgid="6859839199706879015">"belső tár tartalmának módosítása/törlése"</string>
     <string name="permdesc_mediaStorageWrite" product="default" msgid="8189160597698529185">"Lehetővé teszi az alkalmazás számára, hogy módosítsa a belső háttértár tartalmát."</string>
-    <!-- no translation found for permlab_sdcardAccessAll (8150613823900460576) -->
-    <skip />
-    <!-- no translation found for permdesc_sdcardAccessAll (3215208357415891320) -->
-    <skip />
+    <string name="permlab_sdcardAccessAll" msgid="8150613823900460576">"hozzáf. minden felh. külső tár"</string>
+    <string name="permdesc_sdcardAccessAll" msgid="3215208357415891320">"Minden felhasználó számára lehetővé teszi, hogy az alkalmazás hozzáférjen külső tárolókhoz."</string>
     <string name="permlab_cache_filesystem" msgid="5656487264819669824">"hozzáférés a gyorsítótár fájlrendszeréhez"</string>
     <string name="permdesc_cache_filesystem" msgid="5578967642265550955">"Lehetővé teszi az alkalmazás számára a gyorsítótár-fájlrendszer olvasását és írását."</string>
     <string name="permlab_use_sip" msgid="5986952362795870502">"internetes hívások kezdeményezése és fogadása"</string>
@@ -581,6 +579,10 @@
     <string name="policydesc_encryptedStorage" msgid="2637732115325316992">"Megköveteli a tárolt alkalmazásadatok titkosítását."</string>
     <string name="policylab_disableCamera" msgid="6395301023152297826">"Kamerák letiltása"</string>
     <string name="policydesc_disableCamera" msgid="2306349042834754597">"Az összes eszközkamera használatának megakadályozása."</string>
+    <!-- no translation found for policylab_disableKeyguardWidgets (1794894613389073926) -->
+    <skip />
+    <!-- no translation found for policydesc_disableKeyguardWidgets (7254624892984033592) -->
+    <skip />
   <string-array name="phoneTypes">
     <item msgid="8901098336658710359">"Otthoni"</item>
     <item msgid="869923650527136615">"Mobil"</item>
@@ -1319,64 +1321,46 @@
     <string name="bluetooth_a2dp_audio_route_name" msgid="8575624030406771015">"Bluetooth hang"</string>
     <string name="media_route_chooser_grouping_done" msgid="7966438307723317169">"Kész"</string>
     <string name="media_route_button_content_description" msgid="5758553567065145276">"Médiakimenet"</string>
-    <!-- no translation found for display_manager_built_in_display_name (2583134294292563941) -->
+    <string name="display_manager_built_in_display_name" msgid="2583134294292563941">"Beépített képernyő"</string>
+    <!-- no translation found for display_manager_hdmi_display_name (1555264559227470109) -->
     <skip />
-    <!-- no translation found for display_manager_overlay_display_name (5142365982271620716) -->
+    <string name="display_manager_overlay_display_name" msgid="5142365982271620716">"<xliff:g id="ID">%1$d</xliff:g>. fedvény"</string>
+    <!-- no translation found for display_manager_overlay_display_title (652124517672257172) -->
     <skip />
-    <!-- no translation found for display_manager_overlay_display_title (8186674340178573982) -->
-    <skip />
-    <!-- no translation found for kg_emergency_call_label (684946192523830531) -->
-    <skip />
-    <!-- no translation found for kg_forgot_pattern_button_text (8852021467868220608) -->
-    <skip />
-    <!-- no translation found for kg_wrong_pattern (1850806070801358830) -->
-    <skip />
-    <!-- no translation found for kg_wrong_password (2333281762128113157) -->
-    <skip />
-    <!-- no translation found for kg_wrong_pin (1131306510833563801) -->
-    <skip />
-    <!-- no translation found for kg_too_many_failed_attempts_countdown (353963338189371686) -->
-    <skip />
-    <!-- no translation found for kg_pattern_instructions (398978611683075868) -->
-    <skip />
-    <!-- no translation found for kg_sim_pin_instructions (2319508550934557331) -->
-    <skip />
-    <!-- no translation found for kg_pin_instructions (2377242233495111557) -->
-    <skip />
-    <!-- no translation found for kg_password_instructions (5753646556186936819) -->
-    <skip />
-    <!-- no translation found for kg_puk_enter_puk_hint (5183097160254244459) -->
-    <skip />
-    <!-- no translation found for kg_puk_enter_pin_hint (597821135578014901) -->
-    <skip />
-    <!-- no translation found for kg_sim_unlock_progress_dialog_message (8950398016976865762) -->
-    <skip />
-    <!-- no translation found for kg_password_wrong_pin_code (1139324887413846912) -->
-    <skip />
-    <!-- no translation found for kg_invalid_sim_pin_hint (8795159358110620001) -->
-    <skip />
-    <!-- no translation found for kg_invalid_sim_puk_hint (5216603185442368307) -->
-    <skip />
-    <!-- no translation found for kg_sim_puk_recovery_hint (5577753137718442566) -->
-    <skip />
-    <!-- no translation found for kg_invalid_puk (5809955359950817326) -->
-    <skip />
-    <!-- no translation found for kg_login_too_many_attempts (6486842094005698475) -->
-    <skip />
-    <!-- no translation found for kg_login_instructions (1100551261265506448) -->
-    <skip />
-    <!-- no translation found for kg_login_username_hint (5718534272070920364) -->
-    <skip />
-    <!-- no translation found for kg_login_password_hint (9057289103827298549) -->
-    <skip />
-    <!-- no translation found for kg_login_submit_button (5355904582674054702) -->
-    <skip />
-    <!-- no translation found for kg_login_invalid_input (5754664119319872197) -->
-    <skip />
-    <!-- no translation found for kg_login_account_recovery_hint (5690709132841752974) -->
-    <skip />
-    <!-- no translation found for kg_login_checking_password (8849589033659332457) -->
-    <skip />
-    <!-- no translation found for kg_temp_back_string (5812983904056640466) -->
-    <skip />
+    <string name="kg_emergency_call_label" msgid="684946192523830531">"Segélyhívás"</string>
+    <string name="kg_forgot_pattern_button_text" msgid="8852021467868220608">"Elfelejtett minta"</string>
+    <string name="kg_wrong_pattern" msgid="1850806070801358830">"Helytelen minta"</string>
+    <string name="kg_wrong_password" msgid="2333281762128113157">"Helytelen jelszó"</string>
+    <string name="kg_wrong_pin" msgid="1131306510833563801">"Helytelen PIN kód"</string>
+    <string name="kg_too_many_failed_attempts_countdown" msgid="6358110221603297548">"Próbálkozzon újra <xliff:g id="NUMBER">%d</xliff:g> másodperc múlva."</string>
+    <string name="kg_pattern_instructions" msgid="398978611683075868">"Rajzolja le a mintát"</string>
+    <string name="kg_sim_pin_instructions" msgid="2319508550934557331">"Adja meg a SIM kártya PIN kódját"</string>
+    <string name="kg_pin_instructions" msgid="2377242233495111557">"Adja meg a PIN kódot"</string>
+    <string name="kg_password_instructions" msgid="5753646556186936819">"Írja be a jelszót"</string>
+    <string name="kg_puk_enter_puk_hint" msgid="5183097160254244459">"PUK kód"</string>
+    <string name="kg_puk_enter_pin_hint" msgid="597821135578014901">"Új PIN kód"</string>
+    <string name="kg_sim_unlock_progress_dialog_message" msgid="8950398016976865762">"SIM kártya feloldása..."</string>
+    <string name="kg_password_wrong_pin_code" msgid="1139324887413846912">"Helytelen PIN kód."</string>
+    <string name="kg_invalid_sim_pin_hint" msgid="8795159358110620001">"4–8 számjegyű PIN kódot írjon be."</string>
+    <string name="kg_invalid_sim_puk_hint" msgid="5216603185442368307">"8 számjegyű vagy hosszabb PUK kódot írjon be."</string>
+    <string name="kg_sim_puk_recovery_hint" msgid="5577753137718442566">"Írja be a PUK kódot, majd az új PIN kódot"</string>
+    <string name="kg_invalid_puk" msgid="5809955359950817326">"A megadott PUK kód helytelen."</string>
+    <string name="kg_login_too_many_attempts" msgid="6486842094005698475">"Túl sok mintarajzolási próbálkozás"</string>
+    <string name="kg_login_instructions" msgid="1100551261265506448">"A feloldáshoz jelentkezzen be Google Fiókjával."</string>
+    <string name="kg_login_username_hint" msgid="5718534272070920364">"Felhasználónév (e-mail cím)"</string>
+    <string name="kg_login_password_hint" msgid="9057289103827298549">"Jelszó"</string>
+    <string name="kg_login_submit_button" msgid="5355904582674054702">"Bejelentkezés"</string>
+    <string name="kg_login_invalid_input" msgid="5754664119319872197">"Érvénytelen felhasználónév vagy jelszó."</string>
+    <string name="kg_login_account_recovery_hint" msgid="5690709132841752974">"Elfelejtette a felhasználónevét vagy jelszavát?"\n"Keresse fel a "<b>"google.com/accounts/recovery"</b>" webhelyet."</string>
+    <string name="kg_login_checking_password" msgid="8849589033659332457">"Ellenőrzés..."</string>
+    <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="8276745642049502550">"<xliff:g id="NUMBER_0">%d</xliff:g> alkalommal helytelenül adta meg PIN kódját. "\n\n"Próbálja újra <xliff:g id="NUMBER_1">%d</xliff:g> másodperc múlva."</string>
+    <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="7813713389422226531">"<xliff:g id="NUMBER_0">%d</xliff:g> alkalommal helytelenül adta meg a jelszót. "\n\n" Próbálja újra <xliff:g id="NUMBER_1">%d</xliff:g> másodperc múlva."</string>
+    <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="74089475965050805">"<xliff:g id="NUMBER_0">%d</xliff:g> alkalommal rosszul rajzolta le feloldási mintát. "\n\n"Próbálja újra <xliff:g id="NUMBER_1">%d</xliff:g> másodperc múlva."</string>
+    <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="1575557200627128949">"A táblagépet <xliff:g id="NUMBER_0">%d</xliff:g> alkalommal próbálta meg sikertelenül feloldani. <xliff:g id="NUMBER_1">%d</xliff:g> további sikertelen próbálkozás után a rendszer visszaállítja a táblagép gyári alapértelmezett beállításait, és minden felhasználói adat elvész."</string>
+    <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="4051015943038199910">"A telefont <xliff:g id="NUMBER_0">%d</xliff:g> alkalommal próbálta meg sikertelenül feloldani. <xliff:g id="NUMBER_1">%d</xliff:g> további sikertelen próbálkozás után a rendszer visszaállítja a telefon gyári alapértelmezett beállításait, és minden felhasználói adat elvész."</string>
+    <string name="kg_failed_attempts_now_wiping" product="tablet" msgid="2072996269148483637">"A táblagépet <xliff:g id="NUMBER">%d</xliff:g> alkalommal próbálta meg sikertelenül feloldani. A rendszer visszaállítja a táblagép gyári alapértelmezett beállításait."</string>
+    <string name="kg_failed_attempts_now_wiping" product="default" msgid="4817627474419471518">"A telefont <xliff:g id="NUMBER">%d</xliff:g> alkalommal próbálta meg sikertelenül feloldani. A rendszer visszaállítja a telefon gyári alapértelmezett beállításait."</string>
+    <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"<xliff:g id="NUMBER_0">%d</xliff:g> alkalommal helytelenül rajzolta le a feloldási mintát. További <xliff:g id="NUMBER_1">%d</xliff:g> sikertelen kísérlet után egy e-mail fiók használatával kell feloldania a táblagépét."\n\n" Kérjük, próbálja újra <xliff:g id="NUMBER_2">%d</xliff:g> másodperc múlva."</string>
+    <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"<xliff:g id="NUMBER_0">%d</xliff:g> alkalommal helytelenül rajzolta le a feloldási mintát. További <xliff:g id="NUMBER_1">%d</xliff:g> sikertelen kísérlet után egy e-mail fiók használatával kell feloldania a telefonját."\n\n" Kérjük, próbálja újra <xliff:g id="NUMBER_2">%d</xliff:g> másodperc múlva."</string>
+    <string name="kg_temp_back_string" msgid="5812983904056640466">"&lt;"</string>
 </resources>
diff --git a/core/res/res/values-in/strings.xml b/core/res/res/values-in/strings.xml
index 77333cd..8a2ae29 100644
--- a/core/res/res/values-in/strings.xml
+++ b/core/res/res/values-in/strings.xml
@@ -547,10 +547,8 @@
     <string name="permdesc_sdcardWrite" product="default" msgid="4337417790936632090">"Memungkinkan apl menulis ke kartu SD."</string>
     <string name="permlab_mediaStorageWrite" product="default" msgid="6859839199706879015">"ubah/hapus konten penyimpanan media internal"</string>
     <string name="permdesc_mediaStorageWrite" product="default" msgid="8189160597698529185">"Mengizinkan apl memodifikasi konten penyimpanan media internal."</string>
-    <!-- no translation found for permlab_sdcardAccessAll (8150613823900460576) -->
-    <skip />
-    <!-- no translation found for permdesc_sdcardAccessAll (3215208357415891320) -->
-    <skip />
+    <string name="permlab_sdcardAccessAll" msgid="8150613823900460576">"akses penyimpanan eksternal"</string>
+    <string name="permdesc_sdcardAccessAll" msgid="3215208357415891320">"Izinkan aplikasi mengakses penyimpanan eksternal untuk semua pengguna."</string>
     <string name="permlab_cache_filesystem" msgid="5656487264819669824">"akses sistem file cache."</string>
     <string name="permdesc_cache_filesystem" msgid="5578967642265550955">"Mengizinkan apl membaca dan menulis pada sistem file cache."</string>
     <string name="permlab_use_sip" msgid="5986952362795870502">"lakukan//terima panggilan internet"</string>
@@ -581,6 +579,10 @@
     <string name="policydesc_encryptedStorage" msgid="2637732115325316992">"Mengharuskan data apl yang disimpan untuk dienkripsi."</string>
     <string name="policylab_disableCamera" msgid="6395301023152297826">"Nonaktifkan kamera"</string>
     <string name="policydesc_disableCamera" msgid="2306349042834754597">"Mencegah penggunaan semua kamera perangkat."</string>
+    <!-- no translation found for policylab_disableKeyguardWidgets (1794894613389073926) -->
+    <skip />
+    <!-- no translation found for policydesc_disableKeyguardWidgets (7254624892984033592) -->
+    <skip />
   <string-array name="phoneTypes">
     <item msgid="8901098336658710359">"Rumah"</item>
     <item msgid="869923650527136615">"Seluler"</item>
@@ -1206,7 +1208,7 @@
     <string name="media_bad_removal" msgid="7960864061016603281">"Kartu SD dihapus sebelum dilepas."</string>
     <string name="media_checking" product="nosdcard" msgid="418188720009569693">"Saat ini penyimpanan USB sedang diperiksa."</string>
     <string name="media_checking" product="default" msgid="7334762503904827481">"Kartu SD sedang diperiksa."</string>
-    <string name="media_removed" msgid="7001526905057952097">"Kartu SD telah dihapus."</string>
+    <string name="media_removed" msgid="7001526905057952097">"Kartu SD telah dikeluarkan."</string>
     <string name="media_shared" product="nosdcard" msgid="5830814349250834225">"Saat ini penyimpanan USB sedang digunakan oleh komputer."</string>
     <string name="media_shared" product="default" msgid="5706130568133540435">"Kartu SD sedang digunakan oleh komputer."</string>
     <string name="media_unknown_state" msgid="729192782197290385">"Media eksternal dalam status tidak diketahui."</string>
@@ -1319,64 +1321,46 @@
     <string name="bluetooth_a2dp_audio_route_name" msgid="8575624030406771015">"Audio Bluetooth"</string>
     <string name="media_route_chooser_grouping_done" msgid="7966438307723317169">"Selesai"</string>
     <string name="media_route_button_content_description" msgid="5758553567065145276">"Keluaran media"</string>
-    <!-- no translation found for display_manager_built_in_display_name (2583134294292563941) -->
+    <string name="display_manager_built_in_display_name" msgid="2583134294292563941">"Layar Bawaan"</string>
+    <!-- no translation found for display_manager_hdmi_display_name (1555264559227470109) -->
     <skip />
-    <!-- no translation found for display_manager_overlay_display_name (5142365982271620716) -->
+    <string name="display_manager_overlay_display_name" msgid="5142365982271620716">"Hamparan #<xliff:g id="ID">%1$d</xliff:g>"</string>
+    <!-- no translation found for display_manager_overlay_display_title (652124517672257172) -->
     <skip />
-    <!-- no translation found for display_manager_overlay_display_title (8186674340178573982) -->
-    <skip />
-    <!-- no translation found for kg_emergency_call_label (684946192523830531) -->
-    <skip />
-    <!-- no translation found for kg_forgot_pattern_button_text (8852021467868220608) -->
-    <skip />
-    <!-- no translation found for kg_wrong_pattern (1850806070801358830) -->
-    <skip />
-    <!-- no translation found for kg_wrong_password (2333281762128113157) -->
-    <skip />
-    <!-- no translation found for kg_wrong_pin (1131306510833563801) -->
-    <skip />
-    <!-- no translation found for kg_too_many_failed_attempts_countdown (353963338189371686) -->
-    <skip />
-    <!-- no translation found for kg_pattern_instructions (398978611683075868) -->
-    <skip />
-    <!-- no translation found for kg_sim_pin_instructions (2319508550934557331) -->
-    <skip />
-    <!-- no translation found for kg_pin_instructions (2377242233495111557) -->
-    <skip />
-    <!-- no translation found for kg_password_instructions (5753646556186936819) -->
-    <skip />
-    <!-- no translation found for kg_puk_enter_puk_hint (5183097160254244459) -->
-    <skip />
-    <!-- no translation found for kg_puk_enter_pin_hint (597821135578014901) -->
-    <skip />
-    <!-- no translation found for kg_sim_unlock_progress_dialog_message (8950398016976865762) -->
-    <skip />
-    <!-- no translation found for kg_password_wrong_pin_code (1139324887413846912) -->
-    <skip />
-    <!-- no translation found for kg_invalid_sim_pin_hint (8795159358110620001) -->
-    <skip />
-    <!-- no translation found for kg_invalid_sim_puk_hint (5216603185442368307) -->
-    <skip />
-    <!-- no translation found for kg_sim_puk_recovery_hint (5577753137718442566) -->
-    <skip />
-    <!-- no translation found for kg_invalid_puk (5809955359950817326) -->
-    <skip />
-    <!-- no translation found for kg_login_too_many_attempts (6486842094005698475) -->
-    <skip />
-    <!-- no translation found for kg_login_instructions (1100551261265506448) -->
-    <skip />
-    <!-- no translation found for kg_login_username_hint (5718534272070920364) -->
-    <skip />
-    <!-- no translation found for kg_login_password_hint (9057289103827298549) -->
-    <skip />
-    <!-- no translation found for kg_login_submit_button (5355904582674054702) -->
-    <skip />
-    <!-- no translation found for kg_login_invalid_input (5754664119319872197) -->
-    <skip />
-    <!-- no translation found for kg_login_account_recovery_hint (5690709132841752974) -->
-    <skip />
-    <!-- no translation found for kg_login_checking_password (8849589033659332457) -->
-    <skip />
-    <!-- no translation found for kg_temp_back_string (5812983904056640466) -->
-    <skip />
+    <string name="kg_emergency_call_label" msgid="684946192523830531">"Panggilan darurat"</string>
+    <string name="kg_forgot_pattern_button_text" msgid="8852021467868220608">"Lupa Pola?"</string>
+    <string name="kg_wrong_pattern" msgid="1850806070801358830">"Pola Salah"</string>
+    <string name="kg_wrong_password" msgid="2333281762128113157">"Sandi Salah"</string>
+    <string name="kg_wrong_pin" msgid="1131306510833563801">"PIN Salah"</string>
+    <string name="kg_too_many_failed_attempts_countdown" msgid="6358110221603297548">"Coba lagi dalam <xliff:g id="NUMBER">%d</xliff:g> detik."</string>
+    <string name="kg_pattern_instructions" msgid="398978611683075868">"Gambar pola Anda"</string>
+    <string name="kg_sim_pin_instructions" msgid="2319508550934557331">"Masukkan PIN SIM"</string>
+    <string name="kg_pin_instructions" msgid="2377242233495111557">"Masukkan PIN"</string>
+    <string name="kg_password_instructions" msgid="5753646556186936819">"Masukkan Sandi"</string>
+    <string name="kg_puk_enter_puk_hint" msgid="5183097160254244459">"Kode PUK"</string>
+    <string name="kg_puk_enter_pin_hint" msgid="597821135578014901">"Kode PIN baru"</string>
+    <string name="kg_sim_unlock_progress_dialog_message" msgid="8950398016976865762">"Membuka kunci kartu SIM…"</string>
+    <string name="kg_password_wrong_pin_code" msgid="1139324887413846912">"Kode PIN salah."</string>
+    <string name="kg_invalid_sim_pin_hint" msgid="8795159358110620001">"Ketik PIN yang terdiri dari 4 sampai 8 angka."</string>
+    <string name="kg_invalid_sim_puk_hint" msgid="5216603185442368307">"Ketik PUK yang terdiri dari 8 angka atau lebih."</string>
+    <string name="kg_sim_puk_recovery_hint" msgid="5577753137718442566">"Ketik kode PUK dan PIN baru"</string>
+    <string name="kg_invalid_puk" msgid="5809955359950817326">"PUK yang Anda ketikkan salah."</string>
+    <string name="kg_login_too_many_attempts" msgid="6486842094005698475">"Terlalu banyak upaya pola"</string>
+    <string name="kg_login_instructions" msgid="1100551261265506448">"Untuk membuka kunci, masuk dengan akun Google Anda."</string>
+    <string name="kg_login_username_hint" msgid="5718534272070920364">"Nama pengguna (email)"</string>
+    <string name="kg_login_password_hint" msgid="9057289103827298549">"Sandi"</string>
+    <string name="kg_login_submit_button" msgid="5355904582674054702">"Masuk"</string>
+    <string name="kg_login_invalid_input" msgid="5754664119319872197">"Nama pengguna atau sandi tidak valid."</string>
+    <string name="kg_login_account_recovery_hint" msgid="5690709132841752974">"Lupa nama pengguna atau sandi Anda?"\n"Kunjungi "<b>"google.com/accounts/recovery"</b>"."</string>
+    <string name="kg_login_checking_password" msgid="8849589033659332457">"Memeriksa…"</string>
+    <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="8276745642049502550">"Anda telah <xliff:g id="NUMBER_0">%d</xliff:g> kali salah mengetik PIN. "\n\n"Coba lagi dalam <xliff:g id="NUMBER_1">%d</xliff:g> detik."</string>
+    <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="7813713389422226531">"Anda telah <xliff:g id="NUMBER_0">%d</xliff:g> kali salah mengetik sandi. "\n\n"Coba lagi dalam <xliff:g id="NUMBER_1">%d</xliff:g> detik."</string>
+    <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="74089475965050805">"Anda telah <xliff:g id="NUMBER_0">%d</xliff:g> kali salah menggambar pola pembuka kunci. "\n\n"Coba lagi dalam <xliff:g id="NUMBER_1">%d</xliff:g> detik."</string>
+    <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="1575557200627128949">"Anda telah <xliff:g id="NUMBER_0">%d</xliff:g> kali gagal saat berusaha membuka kunci tablet. Setelah <xliff:g id="NUMBER_1">%d</xliff:g> lagi upaya gagal, tablet akan disetel ulang ke setelan default pabrik dan semua data pengguna akan hilang."</string>
+    <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="4051015943038199910">"Anda telah <xliff:g id="NUMBER_0">%d</xliff:g> kali gagal saat berusaha membuka kunci ponsel. Setelah <xliff:g id="NUMBER_1">%d</xliff:g> lagi upaya gagal, ponsel akan disetel ulang ke setelan default pabrik dan semua data pengguna akan hilang."</string>
+    <string name="kg_failed_attempts_now_wiping" product="tablet" msgid="2072996269148483637">"Anda telah <xliff:g id="NUMBER">%d</xliff:g> kali gagal saat berusaha membuka kunci tablet. Kini tablet akan disetel ulang ke setelan default pabrik."</string>
+    <string name="kg_failed_attempts_now_wiping" product="default" msgid="4817627474419471518">"Anda telah <xliff:g id="NUMBER">%d</xliff:g> kali gagal saat berusaha untuk membuka kunci ponsel. Kini ponsel akan disetel ulang ke setelan default pabrik."</string>
+    <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"Anda telah <xliff:g id="NUMBER_0">%d</xliff:g> kali salah menggambar pola pembuka kunci. Setelah <xliff:g id="NUMBER_1">%d</xliff:g> lagi upaya gagal, Anda akan diminta membuka kunci tablet menggunakan akun email."\n\n"Coba lagi dalam <xliff:g id="NUMBER_2">%d</xliff:g> detik."</string>
+    <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"Anda telah <xliff:g id="NUMBER_0">%d</xliff:g> kali salah menggambar pola pembuka kunci. Setelah <xliff:g id="NUMBER_1">%d</xliff:g> lagi upaya gagal, Anda akan diminta membuka kunci ponsel menggunakan akun email."\n\n"Coba lagi dalam <xliff:g id="NUMBER_2">%d</xliff:g> detik."</string>
+    <string name="kg_temp_back_string" msgid="5812983904056640466">"&lt;"</string>
 </resources>
diff --git a/core/res/res/values-it/strings.xml b/core/res/res/values-it/strings.xml
index 9f1ee1c..3b2f460 100644
--- a/core/res/res/values-it/strings.xml
+++ b/core/res/res/values-it/strings.xml
@@ -547,10 +547,8 @@
     <string name="permdesc_sdcardWrite" product="default" msgid="4337417790936632090">"Consente all\'applicazione di scrivere sulla scheda SD."</string>
     <string name="permlab_mediaStorageWrite" product="default" msgid="6859839199706879015">"modifica/eliminaz. contenuti archivio media int."</string>
     <string name="permdesc_mediaStorageWrite" product="default" msgid="8189160597698529185">"Consente all\'applicazione di modificare i contenuti dell\'archivio media interno."</string>
-    <!-- no translation found for permlab_sdcardAccessAll (8150613823900460576) -->
-    <skip />
-    <!-- no translation found for permdesc_sdcardAccessAll (3215208357415891320) -->
-    <skip />
+    <string name="permlab_sdcardAccessAll" msgid="8150613823900460576">"accesso memoria esterna utenti"</string>
+    <string name="permdesc_sdcardAccessAll" msgid="3215208357415891320">"Consente all\'applicazione di accedere alla memoria esterna di tutti gli utenti."</string>
     <string name="permlab_cache_filesystem" msgid="5656487264819669824">"accesso al filesystem nella cache"</string>
     <string name="permdesc_cache_filesystem" msgid="5578967642265550955">"Consente all\'applicazione di leggere e scrivere il filesystem nella cache."</string>
     <string name="permlab_use_sip" msgid="5986952362795870502">"effettuazione/ricezione chiamate Internet"</string>
@@ -581,6 +579,10 @@
     <string name="policydesc_encryptedStorage" msgid="2637732115325316992">"Richiede la crittografia dei dati applicazione memorizzati."</string>
     <string name="policylab_disableCamera" msgid="6395301023152297826">"Disattiva fotocamere"</string>
     <string name="policydesc_disableCamera" msgid="2306349042834754597">"Impedisci l\'utilizzo di tutte le fotocamere del dispositivo."</string>
+    <!-- no translation found for policylab_disableKeyguardWidgets (1794894613389073926) -->
+    <skip />
+    <!-- no translation found for policydesc_disableKeyguardWidgets (7254624892984033592) -->
+    <skip />
   <string-array name="phoneTypes">
     <item msgid="8901098336658710359">"Casa"</item>
     <item msgid="869923650527136615">"Cellulare"</item>
@@ -1319,64 +1321,46 @@
     <string name="bluetooth_a2dp_audio_route_name" msgid="8575624030406771015">"Audio Bluetooth"</string>
     <string name="media_route_chooser_grouping_done" msgid="7966438307723317169">"Fine"</string>
     <string name="media_route_button_content_description" msgid="5758553567065145276">"Uscita media"</string>
-    <!-- no translation found for display_manager_built_in_display_name (2583134294292563941) -->
+    <string name="display_manager_built_in_display_name" msgid="2583134294292563941">"Schermo incorporato"</string>
+    <!-- no translation found for display_manager_hdmi_display_name (1555264559227470109) -->
     <skip />
-    <!-- no translation found for display_manager_overlay_display_name (5142365982271620716) -->
+    <string name="display_manager_overlay_display_name" msgid="5142365982271620716">"Overlay n. <xliff:g id="ID">%1$d</xliff:g>"</string>
+    <!-- no translation found for display_manager_overlay_display_title (652124517672257172) -->
     <skip />
-    <!-- no translation found for display_manager_overlay_display_title (8186674340178573982) -->
-    <skip />
-    <!-- no translation found for kg_emergency_call_label (684946192523830531) -->
-    <skip />
-    <!-- no translation found for kg_forgot_pattern_button_text (8852021467868220608) -->
-    <skip />
-    <!-- no translation found for kg_wrong_pattern (1850806070801358830) -->
-    <skip />
-    <!-- no translation found for kg_wrong_password (2333281762128113157) -->
-    <skip />
-    <!-- no translation found for kg_wrong_pin (1131306510833563801) -->
-    <skip />
-    <!-- no translation found for kg_too_many_failed_attempts_countdown (353963338189371686) -->
-    <skip />
-    <!-- no translation found for kg_pattern_instructions (398978611683075868) -->
-    <skip />
-    <!-- no translation found for kg_sim_pin_instructions (2319508550934557331) -->
-    <skip />
-    <!-- no translation found for kg_pin_instructions (2377242233495111557) -->
-    <skip />
-    <!-- no translation found for kg_password_instructions (5753646556186936819) -->
-    <skip />
-    <!-- no translation found for kg_puk_enter_puk_hint (5183097160254244459) -->
-    <skip />
-    <!-- no translation found for kg_puk_enter_pin_hint (597821135578014901) -->
-    <skip />
-    <!-- no translation found for kg_sim_unlock_progress_dialog_message (8950398016976865762) -->
-    <skip />
-    <!-- no translation found for kg_password_wrong_pin_code (1139324887413846912) -->
-    <skip />
-    <!-- no translation found for kg_invalid_sim_pin_hint (8795159358110620001) -->
-    <skip />
-    <!-- no translation found for kg_invalid_sim_puk_hint (5216603185442368307) -->
-    <skip />
-    <!-- no translation found for kg_sim_puk_recovery_hint (5577753137718442566) -->
-    <skip />
-    <!-- no translation found for kg_invalid_puk (5809955359950817326) -->
-    <skip />
-    <!-- no translation found for kg_login_too_many_attempts (6486842094005698475) -->
-    <skip />
-    <!-- no translation found for kg_login_instructions (1100551261265506448) -->
-    <skip />
-    <!-- no translation found for kg_login_username_hint (5718534272070920364) -->
-    <skip />
-    <!-- no translation found for kg_login_password_hint (9057289103827298549) -->
-    <skip />
-    <!-- no translation found for kg_login_submit_button (5355904582674054702) -->
-    <skip />
-    <!-- no translation found for kg_login_invalid_input (5754664119319872197) -->
-    <skip />
-    <!-- no translation found for kg_login_account_recovery_hint (5690709132841752974) -->
-    <skip />
-    <!-- no translation found for kg_login_checking_password (8849589033659332457) -->
-    <skip />
-    <!-- no translation found for kg_temp_back_string (5812983904056640466) -->
-    <skip />
+    <string name="kg_emergency_call_label" msgid="684946192523830531">"Chiamata di emergenza"</string>
+    <string name="kg_forgot_pattern_button_text" msgid="8852021467868220608">"Sequenza dimenticata"</string>
+    <string name="kg_wrong_pattern" msgid="1850806070801358830">"Sequenza sbagliata"</string>
+    <string name="kg_wrong_password" msgid="2333281762128113157">"Password sbagliata"</string>
+    <string name="kg_wrong_pin" msgid="1131306510833563801">"PIN errato"</string>
+    <string name="kg_too_many_failed_attempts_countdown" msgid="6358110221603297548">"Riprova fra <xliff:g id="NUMBER">%d</xliff:g> secondi."</string>
+    <string name="kg_pattern_instructions" msgid="398978611683075868">"Inserisci la sequenza"</string>
+    <string name="kg_sim_pin_instructions" msgid="2319508550934557331">"Inserisci il PIN della SIM"</string>
+    <string name="kg_pin_instructions" msgid="2377242233495111557">"Inserisci PIN"</string>
+    <string name="kg_password_instructions" msgid="5753646556186936819">"Inserisci la password"</string>
+    <string name="kg_puk_enter_puk_hint" msgid="5183097160254244459">"Codice PUK"</string>
+    <string name="kg_puk_enter_pin_hint" msgid="597821135578014901">"Nuovo codice PIN"</string>
+    <string name="kg_sim_unlock_progress_dialog_message" msgid="8950398016976865762">"Sblocco scheda SIM..."</string>
+    <string name="kg_password_wrong_pin_code" msgid="1139324887413846912">"Codice PIN errato."</string>
+    <string name="kg_invalid_sim_pin_hint" msgid="8795159358110620001">"Il PIN deve essere di 4-8 numeri."</string>
+    <string name="kg_invalid_sim_puk_hint" msgid="5216603185442368307">"Digita un PUK formato da almeno 8 numeri."</string>
+    <string name="kg_sim_puk_recovery_hint" msgid="5577753137718442566">"Inserisci il PUK e il nuovo codice PIN"</string>
+    <string name="kg_invalid_puk" msgid="5809955359950817326">"Il PUK digitato è errato."</string>
+    <string name="kg_login_too_many_attempts" msgid="6486842094005698475">"Troppi tentativi di inserimento della sequenza"</string>
+    <string name="kg_login_instructions" msgid="1100551261265506448">"Per sbloccare, accedi con il tuo account Google."</string>
+    <string name="kg_login_username_hint" msgid="5718534272070920364">"Nome utente (email)"</string>
+    <string name="kg_login_password_hint" msgid="9057289103827298549">"Password"</string>
+    <string name="kg_login_submit_button" msgid="5355904582674054702">"Accedi"</string>
+    <string name="kg_login_invalid_input" msgid="5754664119319872197">"Nome utente o password non validi."</string>
+    <string name="kg_login_account_recovery_hint" msgid="5690709132841752974">"Hai dimenticato il nome utente o la password?"\n"Visita "<b>"google.com/accounts/recovery"</b>"."</string>
+    <string name="kg_login_checking_password" msgid="8849589033659332457">"Verifica…"</string>
+    <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="8276745642049502550">"Hai digitato il tuo PIN <xliff:g id="NUMBER_0">%d</xliff:g> volte in modo errato. "\n\n"Riprova tra <xliff:g id="NUMBER_1">%d</xliff:g> secondi."</string>
+    <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="7813713389422226531">"Hai digitato la tua password <xliff:g id="NUMBER_0">%d</xliff:g> volte in modo errato. "\n\n"Riprova tra <xliff:g id="NUMBER_1">%d</xliff:g> secondi."</string>
+    <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="74089475965050805">"<xliff:g id="NUMBER_0">%d</xliff:g> tentativi errati di inserimento della sequenza di sblocco. "\n\n"Riprova tra <xliff:g id="NUMBER_1">%d</xliff:g> secondi."</string>
+    <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="1575557200627128949">"<xliff:g id="NUMBER_0">%d</xliff:g> tentativi errati di sblocco del tablet. Dopo altri <xliff:g id="NUMBER_1">%d</xliff:g> tentativi falliti, il tablet verrà sottoposto a un ripristino dei dati di fabbrica e tutti i dati utente andranno persi."</string>
+    <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="4051015943038199910">"<xliff:g id="NUMBER_0">%d</xliff:g> tentativi errati di sblocco del telefono. Dopo altri <xliff:g id="NUMBER_1">%d</xliff:g> tentativi falliti, il telefono verrà sottoposto a un ripristino dei dati di fabbrica e tutti i dati utente andranno persi."</string>
+    <string name="kg_failed_attempts_now_wiping" product="tablet" msgid="2072996269148483637">"<xliff:g id="NUMBER">%d</xliff:g> tentativi errati di sblocco del tablet. Il tablet verrà sottoposto a un ripristino dei dati di fabbrica."</string>
+    <string name="kg_failed_attempts_now_wiping" product="default" msgid="4817627474419471518">"<xliff:g id="NUMBER">%d</xliff:g> tentativi errati di sblocco del telefono. Il telefono verrà sottoposto a un ripristino dei dati di fabbrica."</string>
+    <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"<xliff:g id="NUMBER_0">%d</xliff:g> tentativi errati di inserimento della sequenza di sblocco. Dopo altri <xliff:g id="NUMBER_1">%d</xliff:g> tentativi falliti, ti verrà chiesto di sbloccare il tablet con un account email."\n\n" Riprova tra <xliff:g id="NUMBER_2">%d</xliff:g> secondi."</string>
+    <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"<xliff:g id="NUMBER_0">%d</xliff:g> tentativi errati di inserimento della sequenza di sblocco. Dopo altri <xliff:g id="NUMBER_1">%d</xliff:g> tentativi falliti, ti verrà chiesto di sbloccare il telefono con un account email."\n\n" Riprova tra <xliff:g id="NUMBER_2">%d</xliff:g> secondi."</string>
+    <string name="kg_temp_back_string" msgid="5812983904056640466">"&lt;"</string>
 </resources>
diff --git a/core/res/res/values-iw/strings.xml b/core/res/res/values-iw/strings.xml
index d7ce2e1..97c3a99 100644
--- a/core/res/res/values-iw/strings.xml
+++ b/core/res/res/values-iw/strings.xml
@@ -547,10 +547,8 @@
     <string name="permdesc_sdcardWrite" product="default" msgid="4337417790936632090">"מאפשר ליישום לכתוב לכרטיס ה-SD."</string>
     <string name="permlab_mediaStorageWrite" product="default" msgid="6859839199706879015">"שנה/מחק תוכן של אחסון מדיה פנימי"</string>
     <string name="permdesc_mediaStorageWrite" product="default" msgid="8189160597698529185">"מאפשר ליישום לשנות את התוכן של אמצעי האחסון הפנימי למדיה."</string>
-    <!-- no translation found for permlab_sdcardAccessAll (8150613823900460576) -->
-    <skip />
-    <!-- no translation found for permdesc_sdcardAccessAll (3215208357415891320) -->
-    <skip />
+    <string name="permlab_sdcardAccessAll" msgid="8150613823900460576">"גישה לאחסון חיצוני של כל המשתמשים"</string>
+    <string name="permdesc_sdcardAccessAll" msgid="3215208357415891320">"מאפשר ליישום לגשת לאחסון חיצוני עבור כל המשתמשים."</string>
     <string name="permlab_cache_filesystem" msgid="5656487264819669824">"גישה למערכת הקבצים בקובץ השמור"</string>
     <string name="permdesc_cache_filesystem" msgid="5578967642265550955">"מאפשר ליישום לקרוא ולכתוב במערכת הקבצים של הקבצים השמורים."</string>
     <string name="permlab_use_sip" msgid="5986952362795870502">"בצע/קבל שיחות אינטרנט"</string>
@@ -581,6 +579,10 @@
     <string name="policydesc_encryptedStorage" msgid="2637732115325316992">"דרוש שנתוני יישומים מאוחסנים יהיו מוצפנים."</string>
     <string name="policylab_disableCamera" msgid="6395301023152297826">"השבת מצלמות"</string>
     <string name="policydesc_disableCamera" msgid="2306349042834754597">"מנע שימוש בכל המצלמות שבמכשיר."</string>
+    <!-- no translation found for policylab_disableKeyguardWidgets (1794894613389073926) -->
+    <skip />
+    <!-- no translation found for policydesc_disableKeyguardWidgets (7254624892984033592) -->
+    <skip />
   <string-array name="phoneTypes">
     <item msgid="8901098336658710359">"בית"</item>
     <item msgid="869923650527136615">"נייד"</item>
@@ -1171,9 +1173,9 @@
     <string name="vpn_title_long" msgid="6400714798049252294">"VPN מופעל על ידי <xliff:g id="APP">%s</xliff:g>"</string>
     <string name="vpn_text" msgid="3011306607126450322">"גע כדי לנהל את הרשת."</string>
     <string name="vpn_text_long" msgid="6407351006249174473">"מחובר אל <xliff:g id="SESSION">%s</xliff:g>. גע כדי לנהל את הרשת."</string>
-    <string name="vpn_lockdown_connecting" msgid="6443438964440960745">"VPN מופעל תמיד מתחבר..."</string>
-    <string name="vpn_lockdown_connected" msgid="8202679674819213931">"VPN פועל תמיד מחובר"</string>
-    <string name="vpn_lockdown_error" msgid="6009249814034708175">"שגיאת VPN מופעל תמיד"</string>
+    <string name="vpn_lockdown_connecting" msgid="6443438964440960745">"ה-VPN שמופעל תמיד, מתחבר..."</string>
+    <string name="vpn_lockdown_connected" msgid="8202679674819213931">"ה-VPN שפועל תמיד, מחובר"</string>
+    <string name="vpn_lockdown_error" msgid="6009249814034708175">"שגיאת VPN שמופעל תמיד"</string>
     <string name="vpn_lockdown_reset" msgid="5365010427963548932">"גע כדי לאפס את החיבור"</string>
     <string name="upload_file" msgid="2897957172366730416">"בחר קובץ"</string>
     <string name="no_file_chosen" msgid="6363648562170759465">"לא נבחר קובץ"</string>
@@ -1319,64 +1321,46 @@
     <string name="bluetooth_a2dp_audio_route_name" msgid="8575624030406771015">"אודיו Bluetooth"</string>
     <string name="media_route_chooser_grouping_done" msgid="7966438307723317169">"סיום"</string>
     <string name="media_route_button_content_description" msgid="5758553567065145276">"פלט מדיה"</string>
-    <!-- no translation found for display_manager_built_in_display_name (2583134294292563941) -->
+    <string name="display_manager_built_in_display_name" msgid="2583134294292563941">"מסך מובנה"</string>
+    <!-- no translation found for display_manager_hdmi_display_name (1555264559227470109) -->
     <skip />
-    <!-- no translation found for display_manager_overlay_display_name (5142365982271620716) -->
+    <string name="display_manager_overlay_display_name" msgid="5142365982271620716">"שכבת על #<xliff:g id="ID">%1$d</xliff:g>"</string>
+    <!-- no translation found for display_manager_overlay_display_title (652124517672257172) -->
     <skip />
-    <!-- no translation found for display_manager_overlay_display_title (8186674340178573982) -->
-    <skip />
-    <!-- no translation found for kg_emergency_call_label (684946192523830531) -->
-    <skip />
-    <!-- no translation found for kg_forgot_pattern_button_text (8852021467868220608) -->
-    <skip />
-    <!-- no translation found for kg_wrong_pattern (1850806070801358830) -->
-    <skip />
-    <!-- no translation found for kg_wrong_password (2333281762128113157) -->
-    <skip />
-    <!-- no translation found for kg_wrong_pin (1131306510833563801) -->
-    <skip />
-    <!-- no translation found for kg_too_many_failed_attempts_countdown (353963338189371686) -->
-    <skip />
-    <!-- no translation found for kg_pattern_instructions (398978611683075868) -->
-    <skip />
-    <!-- no translation found for kg_sim_pin_instructions (2319508550934557331) -->
-    <skip />
-    <!-- no translation found for kg_pin_instructions (2377242233495111557) -->
-    <skip />
-    <!-- no translation found for kg_password_instructions (5753646556186936819) -->
-    <skip />
-    <!-- no translation found for kg_puk_enter_puk_hint (5183097160254244459) -->
-    <skip />
-    <!-- no translation found for kg_puk_enter_pin_hint (597821135578014901) -->
-    <skip />
-    <!-- no translation found for kg_sim_unlock_progress_dialog_message (8950398016976865762) -->
-    <skip />
-    <!-- no translation found for kg_password_wrong_pin_code (1139324887413846912) -->
-    <skip />
-    <!-- no translation found for kg_invalid_sim_pin_hint (8795159358110620001) -->
-    <skip />
-    <!-- no translation found for kg_invalid_sim_puk_hint (5216603185442368307) -->
-    <skip />
-    <!-- no translation found for kg_sim_puk_recovery_hint (5577753137718442566) -->
-    <skip />
-    <!-- no translation found for kg_invalid_puk (5809955359950817326) -->
-    <skip />
-    <!-- no translation found for kg_login_too_many_attempts (6486842094005698475) -->
-    <skip />
-    <!-- no translation found for kg_login_instructions (1100551261265506448) -->
-    <skip />
-    <!-- no translation found for kg_login_username_hint (5718534272070920364) -->
-    <skip />
-    <!-- no translation found for kg_login_password_hint (9057289103827298549) -->
-    <skip />
-    <!-- no translation found for kg_login_submit_button (5355904582674054702) -->
-    <skip />
-    <!-- no translation found for kg_login_invalid_input (5754664119319872197) -->
-    <skip />
-    <!-- no translation found for kg_login_account_recovery_hint (5690709132841752974) -->
-    <skip />
-    <!-- no translation found for kg_login_checking_password (8849589033659332457) -->
-    <skip />
-    <!-- no translation found for kg_temp_back_string (5812983904056640466) -->
-    <skip />
+    <string name="kg_emergency_call_label" msgid="684946192523830531">"שיחת חירום"</string>
+    <string name="kg_forgot_pattern_button_text" msgid="8852021467868220608">"שכחת את הקו"</string>
+    <string name="kg_wrong_pattern" msgid="1850806070801358830">"קו ביטול נעילה שגוי"</string>
+    <string name="kg_wrong_password" msgid="2333281762128113157">"סיסמה שגויה"</string>
+    <string name="kg_wrong_pin" msgid="1131306510833563801">"מספר PIN שגוי"</string>
+    <string name="kg_too_many_failed_attempts_countdown" msgid="6358110221603297548">"נסה שוב בעוד <xliff:g id="NUMBER">%d</xliff:g> שניות."</string>
+    <string name="kg_pattern_instructions" msgid="398978611683075868">"שרטט את קו ביטול הנעילה"</string>
+    <string name="kg_sim_pin_instructions" msgid="2319508550934557331">"הזן מספר PIN ל-SIM"</string>
+    <string name="kg_pin_instructions" msgid="2377242233495111557">"הזן מספר PIN"</string>
+    <string name="kg_password_instructions" msgid="5753646556186936819">"הזן את הסיסמה"</string>
+    <string name="kg_puk_enter_puk_hint" msgid="5183097160254244459">"קוד PUK"</string>
+    <string name="kg_puk_enter_pin_hint" msgid="597821135578014901">"קוד PIN חדש"</string>
+    <string name="kg_sim_unlock_progress_dialog_message" msgid="8950398016976865762">"מבטל נעילה של כרטיס SIM…"</string>
+    <string name="kg_password_wrong_pin_code" msgid="1139324887413846912">"קוד PIN שגוי."</string>
+    <string name="kg_invalid_sim_pin_hint" msgid="8795159358110620001">"הקלד מספר PIN שאורכו 4 עד 8 ספרות."</string>
+    <string name="kg_invalid_sim_puk_hint" msgid="5216603185442368307">"הקלד PUK באורך 8 ספרות או יותר."</string>
+    <string name="kg_sim_puk_recovery_hint" msgid="5577753137718442566">"הקלד את קוד ה-PUK וקוד ה-PIN החדש"</string>
+    <string name="kg_invalid_puk" msgid="5809955359950817326">"ה-PUK שהקלדת שגוי."</string>
+    <string name="kg_login_too_many_attempts" msgid="6486842094005698475">"ניסיונות רבים מדי לשרטוט קו ביטול נעילה."</string>
+    <string name="kg_login_instructions" msgid="1100551261265506448">"כדי לבטל את הנעילה, היכנס באמצעות חשבון Google שלך."</string>
+    <string name="kg_login_username_hint" msgid="5718534272070920364">"שם משתמש (דוא\"ל)"</string>
+    <string name="kg_login_password_hint" msgid="9057289103827298549">"סיסמה"</string>
+    <string name="kg_login_submit_button" msgid="5355904582674054702">"היכנס"</string>
+    <string name="kg_login_invalid_input" msgid="5754664119319872197">"שם משתמש או סיסמה לא חוקיים."</string>
+    <string name="kg_login_account_recovery_hint" msgid="5690709132841752974">"שכחת את שם המשתמש או הסיסמה?"\n"בקר בכתובת "<b>"google.com/accounts/recovery"</b></string>
+    <string name="kg_login_checking_password" msgid="8849589033659332457">"בודק…"</string>
+    <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="8276745642049502550">"הקלדת מספר PIN שגוי <xliff:g id="NUMBER_0">%d</xliff:g> פעמים. "\n\n"נסה שוב בעוד <xliff:g id="NUMBER_1">%d</xliff:g> שניות."</string>
+    <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="7813713389422226531">"הקלדת סיסמה שגויה <xliff:g id="NUMBER_0">%d</xliff:g> פעמים."\n\n"נסה שוב בעוד <xliff:g id="NUMBER_1">%d</xliff:g> שניות."</string>
+    <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="74089475965050805">"שרטטת את קו ביטול הנעילה באופן שגוי <xliff:g id="NUMBER_0">%d</xliff:g> פעמים. "\n\n"נסה שוב בעוד <xliff:g id="NUMBER_1">%d</xliff:g> שניות."</string>
+    <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="1575557200627128949">"ביצעת <xliff:g id="NUMBER_0">%d</xliff:g> ניסיונות שגויים לביטול נעילת הטלפון. לאחר <xliff:g id="NUMBER_1">%d</xliff:g> ניסיונות כושלים נוספים, הטאבלט יעבור איפוס לברירת המחדל של היצרן וכל נתוני המשתמש יאבדו."</string>
+    <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="4051015943038199910">"ביצעת <xliff:g id="NUMBER_0">%d</xliff:g> ניסיונות שגויים לביטול נעילת הטלפון. לאחר <xliff:g id="NUMBER_1">%d</xliff:g> ניסיונות כושלים נוספים, הטלפון יעבור איפוס לברירת המחדל של היצרן וכל נתוני המשתמש יאבדו."</string>
+    <string name="kg_failed_attempts_now_wiping" product="tablet" msgid="2072996269148483637">"ביצעת <xliff:g id="NUMBER">%d</xliff:g> ניסיונות שגויים לביטול נעילת הטאבלט. הטלפון יעבור כעת איפוס לברירת המחדל של היצרן."</string>
+    <string name="kg_failed_attempts_now_wiping" product="default" msgid="4817627474419471518">"ביצעת <xliff:g id="NUMBER">%d</xliff:g> ניסיונות שגויים לביטול נעילת הטלפון. הטלפון יעבור כעת איפוס לברירת המחדל של היצרן."</string>
+    <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"שרטטת את קו ביטול הנעילה באופן שגוי <xliff:g id="NUMBER_0">%d</xliff:g> פעמים. לאחר <xliff:g id="NUMBER_1">%d</xliff:g> ניסיונות כושלים נוספים, תתבקש לבטל את נעילת הטאבלט באמצעות חשבון דוא\"ל‏."\n\n"נסה שוב בעוד <xliff:g id="NUMBER_2">%d</xliff:g> שניות."</string>
+    <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"שרטטת את קו ביטול הנעילה באופן שגוי <xliff:g id="NUMBER_0">%d</xliff:g> פעמים. לאחר <xliff:g id="NUMBER_1">%d</xliff:g> ניסיונות כושלים נוספים, תתבקש לבטל את נעילת הטלפון באמצעות חשבון דוא\"ל‏."\n\n"נסה שוב בעוד <xliff:g id="NUMBER_2">%d</xliff:g> שניות."</string>
+    <string name="kg_temp_back_string" msgid="5812983904056640466">"&lt;"</string>
 </resources>
diff --git a/core/res/res/values-ja/strings.xml b/core/res/res/values-ja/strings.xml
index 0e1b9eb..504b57c 100644
--- a/core/res/res/values-ja/strings.xml
+++ b/core/res/res/values-ja/strings.xml
@@ -581,6 +581,10 @@
     <string name="policydesc_encryptedStorage" msgid="2637732115325316992">"保存したアプリデータが暗号化されるようにします。"</string>
     <string name="policylab_disableCamera" msgid="6395301023152297826">"カメラを無効にする"</string>
     <string name="policydesc_disableCamera" msgid="2306349042834754597">"すべての端末カメラを使用できないようにします。"</string>
+    <!-- no translation found for policylab_disableKeyguardWidgets (1794894613389073926) -->
+    <skip />
+    <!-- no translation found for policydesc_disableKeyguardWidgets (7254624892984033592) -->
+    <skip />
   <string-array name="phoneTypes">
     <item msgid="8901098336658710359">"自宅"</item>
     <item msgid="869923650527136615">"携帯"</item>
@@ -1171,14 +1175,10 @@
     <string name="vpn_title_long" msgid="6400714798049252294">"VPNが<xliff:g id="APP">%s</xliff:g>により有効化されました"</string>
     <string name="vpn_text" msgid="3011306607126450322">"タップしてネットワークを管理します。"</string>
     <string name="vpn_text_long" msgid="6407351006249174473">"<xliff:g id="SESSION">%s</xliff:g>に接続しました。ネットワークを管理するにはタップしてください。"</string>
-    <!-- no translation found for vpn_lockdown_connecting (6443438964440960745) -->
-    <skip />
-    <!-- no translation found for vpn_lockdown_connected (8202679674819213931) -->
-    <skip />
-    <!-- no translation found for vpn_lockdown_error (6009249814034708175) -->
-    <skip />
-    <!-- no translation found for vpn_lockdown_reset (5365010427963548932) -->
-    <skip />
+    <string name="vpn_lockdown_connecting" msgid="6443438964440960745">"VPNに常時接続しています…"</string>
+    <string name="vpn_lockdown_connected" msgid="8202679674819213931">"VPNに常時接続しました"</string>
+    <string name="vpn_lockdown_error" msgid="6009249814034708175">"常時接続VPNのエラー"</string>
+    <string name="vpn_lockdown_reset" msgid="5365010427963548932">"接続をリセットするにはタップします"</string>
     <string name="upload_file" msgid="2897957172366730416">"ファイルを選択"</string>
     <string name="no_file_chosen" msgid="6363648562170759465">"ファイルが選択されていません"</string>
     <string name="reset" msgid="2448168080964209908">"リセット"</string>
@@ -1325,9 +1325,11 @@
     <string name="media_route_button_content_description" msgid="5758553567065145276">"メディア出力"</string>
     <!-- no translation found for display_manager_built_in_display_name (2583134294292563941) -->
     <skip />
+    <!-- no translation found for display_manager_hdmi_display_name (1555264559227470109) -->
+    <skip />
     <!-- no translation found for display_manager_overlay_display_name (5142365982271620716) -->
     <skip />
-    <!-- no translation found for display_manager_overlay_display_title (8186674340178573982) -->
+    <!-- no translation found for display_manager_overlay_display_title (652124517672257172) -->
     <skip />
     <!-- no translation found for kg_emergency_call_label (684946192523830531) -->
     <skip />
@@ -1339,7 +1341,7 @@
     <skip />
     <!-- no translation found for kg_wrong_pin (1131306510833563801) -->
     <skip />
-    <!-- no translation found for kg_too_many_failed_attempts_countdown (353963338189371686) -->
+    <!-- no translation found for kg_too_many_failed_attempts_countdown (6358110221603297548) -->
     <skip />
     <!-- no translation found for kg_pattern_instructions (398978611683075868) -->
     <skip />
@@ -1381,6 +1383,24 @@
     <skip />
     <!-- no translation found for kg_login_checking_password (8849589033659332457) -->
     <skip />
+    <!-- no translation found for kg_too_many_failed_pin_attempts_dialog_message (8276745642049502550) -->
+    <skip />
+    <!-- no translation found for kg_too_many_failed_password_attempts_dialog_message (7813713389422226531) -->
+    <skip />
+    <!-- no translation found for kg_too_many_failed_pattern_attempts_dialog_message (74089475965050805) -->
+    <skip />
+    <!-- no translation found for kg_failed_attempts_almost_at_wipe (1575557200627128949) -->
+    <skip />
+    <!-- no translation found for kg_failed_attempts_almost_at_wipe (4051015943038199910) -->
+    <skip />
+    <!-- no translation found for kg_failed_attempts_now_wiping (2072996269148483637) -->
+    <skip />
+    <!-- no translation found for kg_failed_attempts_now_wiping (4817627474419471518) -->
+    <skip />
+    <!-- no translation found for kg_failed_attempts_almost_at_login (3253575572118914370) -->
+    <skip />
+    <!-- no translation found for kg_failed_attempts_almost_at_login (1437638152015574839) -->
+    <skip />
     <!-- no translation found for kg_temp_back_string (5812983904056640466) -->
     <skip />
 </resources>
diff --git a/core/res/res/values-ko/strings.xml b/core/res/res/values-ko/strings.xml
index ae9b0c0..dfceee6 100644
--- a/core/res/res/values-ko/strings.xml
+++ b/core/res/res/values-ko/strings.xml
@@ -547,10 +547,8 @@
     <string name="permdesc_sdcardWrite" product="default" msgid="4337417790936632090">"앱이 SD 카드에 쓸 수 있도록 허용합니다."</string>
     <string name="permlab_mediaStorageWrite" product="default" msgid="6859839199706879015">"내부 미디어 저장소 콘텐츠 수정/삭제"</string>
     <string name="permdesc_mediaStorageWrite" product="default" msgid="8189160597698529185">"앱이 내부 미디어 저장소의 콘텐츠를 수정할 수 있도록 허용합니다."</string>
-    <!-- no translation found for permlab_sdcardAccessAll (8150613823900460576) -->
-    <skip />
-    <!-- no translation found for permdesc_sdcardAccessAll (3215208357415891320) -->
-    <skip />
+    <string name="permlab_sdcardAccessAll" msgid="8150613823900460576">"모든 사용자의 외부 저장소에 액세스"</string>
+    <string name="permdesc_sdcardAccessAll" msgid="3215208357415891320">"앱이 모든 사용자의 외부 저장소에 액세스하도록 허용합니다."</string>
     <string name="permlab_cache_filesystem" msgid="5656487264819669824">"캐시 파일시스템 액세스"</string>
     <string name="permdesc_cache_filesystem" msgid="5578967642265550955">"앱이 캐시 파일 시스템을 읽고 쓸 수 있도록 허용합니다."</string>
     <string name="permlab_use_sip" msgid="5986952362795870502">"인터넷 전화 걸기/받기"</string>
@@ -581,6 +579,10 @@
     <string name="policydesc_encryptedStorage" msgid="2637732115325316992">"저장한 애플리케이션 데이터를 암호화해야 합니다."</string>
     <string name="policylab_disableCamera" msgid="6395301023152297826">"카메라 사용 안함"</string>
     <string name="policydesc_disableCamera" msgid="2306349042834754597">"모든 기기 카메라의 사용 차단"</string>
+    <!-- no translation found for policylab_disableKeyguardWidgets (1794894613389073926) -->
+    <skip />
+    <!-- no translation found for policydesc_disableKeyguardWidgets (7254624892984033592) -->
+    <skip />
   <string-array name="phoneTypes">
     <item msgid="8901098336658710359">"집"</item>
     <item msgid="869923650527136615">"모바일"</item>
@@ -1319,64 +1321,46 @@
     <string name="bluetooth_a2dp_audio_route_name" msgid="8575624030406771015">"블루투스 오디오"</string>
     <string name="media_route_chooser_grouping_done" msgid="7966438307723317169">"완료"</string>
     <string name="media_route_button_content_description" msgid="5758553567065145276">"미디어 출력"</string>
-    <!-- no translation found for display_manager_built_in_display_name (2583134294292563941) -->
+    <string name="display_manager_built_in_display_name" msgid="2583134294292563941">"기본으로 제공되는 화면"</string>
+    <!-- no translation found for display_manager_hdmi_display_name (1555264559227470109) -->
     <skip />
-    <!-- no translation found for display_manager_overlay_display_name (5142365982271620716) -->
+    <string name="display_manager_overlay_display_name" msgid="5142365982271620716">"<xliff:g id="ID">%1$d</xliff:g>번째 오버레이"</string>
+    <!-- no translation found for display_manager_overlay_display_title (652124517672257172) -->
     <skip />
-    <!-- no translation found for display_manager_overlay_display_title (8186674340178573982) -->
-    <skip />
-    <!-- no translation found for kg_emergency_call_label (684946192523830531) -->
-    <skip />
-    <!-- no translation found for kg_forgot_pattern_button_text (8852021467868220608) -->
-    <skip />
-    <!-- no translation found for kg_wrong_pattern (1850806070801358830) -->
-    <skip />
-    <!-- no translation found for kg_wrong_password (2333281762128113157) -->
-    <skip />
-    <!-- no translation found for kg_wrong_pin (1131306510833563801) -->
-    <skip />
-    <!-- no translation found for kg_too_many_failed_attempts_countdown (353963338189371686) -->
-    <skip />
-    <!-- no translation found for kg_pattern_instructions (398978611683075868) -->
-    <skip />
-    <!-- no translation found for kg_sim_pin_instructions (2319508550934557331) -->
-    <skip />
-    <!-- no translation found for kg_pin_instructions (2377242233495111557) -->
-    <skip />
-    <!-- no translation found for kg_password_instructions (5753646556186936819) -->
-    <skip />
-    <!-- no translation found for kg_puk_enter_puk_hint (5183097160254244459) -->
-    <skip />
-    <!-- no translation found for kg_puk_enter_pin_hint (597821135578014901) -->
-    <skip />
-    <!-- no translation found for kg_sim_unlock_progress_dialog_message (8950398016976865762) -->
-    <skip />
-    <!-- no translation found for kg_password_wrong_pin_code (1139324887413846912) -->
-    <skip />
-    <!-- no translation found for kg_invalid_sim_pin_hint (8795159358110620001) -->
-    <skip />
-    <!-- no translation found for kg_invalid_sim_puk_hint (5216603185442368307) -->
-    <skip />
-    <!-- no translation found for kg_sim_puk_recovery_hint (5577753137718442566) -->
-    <skip />
-    <!-- no translation found for kg_invalid_puk (5809955359950817326) -->
-    <skip />
-    <!-- no translation found for kg_login_too_many_attempts (6486842094005698475) -->
-    <skip />
-    <!-- no translation found for kg_login_instructions (1100551261265506448) -->
-    <skip />
-    <!-- no translation found for kg_login_username_hint (5718534272070920364) -->
-    <skip />
-    <!-- no translation found for kg_login_password_hint (9057289103827298549) -->
-    <skip />
-    <!-- no translation found for kg_login_submit_button (5355904582674054702) -->
-    <skip />
-    <!-- no translation found for kg_login_invalid_input (5754664119319872197) -->
-    <skip />
-    <!-- no translation found for kg_login_account_recovery_hint (5690709132841752974) -->
-    <skip />
-    <!-- no translation found for kg_login_checking_password (8849589033659332457) -->
-    <skip />
-    <!-- no translation found for kg_temp_back_string (5812983904056640466) -->
-    <skip />
+    <string name="kg_emergency_call_label" msgid="684946192523830531">"긴급 통화"</string>
+    <string name="kg_forgot_pattern_button_text" msgid="8852021467868220608">"패턴을 잊음"</string>
+    <string name="kg_wrong_pattern" msgid="1850806070801358830">"잘못된 패턴"</string>
+    <string name="kg_wrong_password" msgid="2333281762128113157">"잘못된 비밀번호"</string>
+    <string name="kg_wrong_pin" msgid="1131306510833563801">"잘못된 PIN"</string>
+    <string name="kg_too_many_failed_attempts_countdown" msgid="6358110221603297548">"<xliff:g id="NUMBER">%d</xliff:g>초 후에 다시 시도해 주세요."</string>
+    <string name="kg_pattern_instructions" msgid="398978611683075868">"패턴 그리기"</string>
+    <string name="kg_sim_pin_instructions" msgid="2319508550934557331">"SIM PIN 입력"</string>
+    <string name="kg_pin_instructions" msgid="2377242233495111557">"PIN 입력"</string>
+    <string name="kg_password_instructions" msgid="5753646556186936819">"비밀번호 입력"</string>
+    <string name="kg_puk_enter_puk_hint" msgid="5183097160254244459">"PUK 코드"</string>
+    <string name="kg_puk_enter_pin_hint" msgid="597821135578014901">"새 PIN 코드"</string>
+    <string name="kg_sim_unlock_progress_dialog_message" msgid="8950398016976865762">"SIM 카드 잠금해제 중..."</string>
+    <string name="kg_password_wrong_pin_code" msgid="1139324887413846912">"PIN 코드가 잘못되었습니다."</string>
+    <string name="kg_invalid_sim_pin_hint" msgid="8795159358110620001">"4~8자리 숫자로 된 PIN을 입력하세요."</string>
+    <string name="kg_invalid_sim_puk_hint" msgid="5216603185442368307">"8자리 이상의 숫자 PUK를 입력합니다."</string>
+    <string name="kg_sim_puk_recovery_hint" msgid="5577753137718442566">"PUK 및 새 PIN 코드 입력"</string>
+    <string name="kg_invalid_puk" msgid="5809955359950817326">"입력한 PUK가 올바르지 않습니다."</string>
+    <string name="kg_login_too_many_attempts" msgid="6486842094005698475">"패턴 시도 횟수가 너무 많음"</string>
+    <string name="kg_login_instructions" msgid="1100551261265506448">"잠금해제하려면 Google 계정으로 로그인하세요."</string>
+    <string name="kg_login_username_hint" msgid="5718534272070920364">"사용자 이름(이메일)"</string>
+    <string name="kg_login_password_hint" msgid="9057289103827298549">"비밀번호"</string>
+    <string name="kg_login_submit_button" msgid="5355904582674054702">"로그인"</string>
+    <string name="kg_login_invalid_input" msgid="5754664119319872197">"사용자 이름 또는 비밀번호가 잘못되었습니다."</string>
+    <string name="kg_login_account_recovery_hint" msgid="5690709132841752974">"사용자 이름이나 비밀번호를 잊어버렸습니까?"\n<b>"google.com/accounts/recovery"</b>" 페이지를 방문하세요."</string>
+    <string name="kg_login_checking_password" msgid="8849589033659332457">"확인 중…"</string>
+    <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="8276745642049502550">"PIN을 <xliff:g id="NUMBER_0">%d</xliff:g>회 잘못 입력했습니다. "\n\n"<xliff:g id="NUMBER_1">%d</xliff:g>초 후에 다시 시도해 주세요."</string>
+    <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="7813713389422226531">"비밀번호를 <xliff:g id="NUMBER_0">%d</xliff:g>회 잘못 입력했습니다. "\n\n"<xliff:g id="NUMBER_1">%d</xliff:g>초 후에 다시 시도해 주세요."</string>
+    <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="74089475965050805">"잠금해제 패턴을 <xliff:g id="NUMBER_0">%d</xliff:g>회 잘못 그렸습니다. "\n\n"<xliff:g id="NUMBER_1">%d</xliff:g>초 후에 다시 시도해 주세요."</string>
+    <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="1575557200627128949">"태블릿을 잠금해제하려는 시도가 <xliff:g id="NUMBER_0">%d</xliff:g>회 잘못되었습니다. <xliff:g id="NUMBER_1">%d</xliff:g>회 더 실패하면 태블릿이 초기화되고 사용자 데이터가 모두 사라집니다."</string>
+    <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="4051015943038199910">"휴대전화를 잠금해제하려는 시도가 <xliff:g id="NUMBER_0">%d</xliff:g>회 잘못되었습니다. <xliff:g id="NUMBER_1">%d</xliff:g>회 더 실패하면 휴대전화가 초기화되고 사용자 데이터가 모두 사라집니다."</string>
+    <string name="kg_failed_attempts_now_wiping" product="tablet" msgid="2072996269148483637">"태블릿을 잠금해제하려는 시도가 <xliff:g id="NUMBER">%d</xliff:g>회 잘못되었습니다. 태블릿이 초기화됩니다."</string>
+    <string name="kg_failed_attempts_now_wiping" product="default" msgid="4817627474419471518">"휴대전화를 잠금해제하려는 시도가 <xliff:g id="NUMBER">%d</xliff:g>회 잘못되었습니다. 휴대전화가 초기화됩니다."</string>
+    <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"잠금해제 패턴을 <xliff:g id="NUMBER_0">%d</xliff:g>회 잘못 그렸습니다. <xliff:g id="NUMBER_1">%d</xliff:g>회 더 실패하면 이메일 계정을 사용하여 태블릿을 잠금해제해야 합니다."\n\n" <xliff:g id="NUMBER_2">%d</xliff:g>초 후에 다시 시도해 주세요."</string>
+    <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"잠금해제 패턴을 <xliff:g id="NUMBER_0">%d</xliff:g>회 잘못 그렸습니다. <xliff:g id="NUMBER_1">%d</xliff:g>회 더 실패하면 이메일 계정을 사용하여 휴대전화를 잠금해제해야 합니다."\n\n" <xliff:g id="NUMBER_2">%d</xliff:g>초 후에 다시 시도해 주세요."</string>
+    <string name="kg_temp_back_string" msgid="5812983904056640466">"&lt;"</string>
 </resources>
diff --git a/core/res/res/values-lt/strings.xml b/core/res/res/values-lt/strings.xml
index 94c5825..2c5cab5 100644
--- a/core/res/res/values-lt/strings.xml
+++ b/core/res/res/values-lt/strings.xml
@@ -547,10 +547,8 @@
     <string name="permdesc_sdcardWrite" product="default" msgid="4337417790936632090">"Leidžiama programai rašyti į SD kortelę."</string>
     <string name="permlab_mediaStorageWrite" product="default" msgid="6859839199706879015">"keisti / ištr. vid. med. atm. tur."</string>
     <string name="permdesc_mediaStorageWrite" product="default" msgid="8189160597698529185">"Leidžiama programai keisti vidinės medijos saugyklos turinį."</string>
-    <!-- no translation found for permlab_sdcardAccessAll (8150613823900460576) -->
-    <skip />
-    <!-- no translation found for permdesc_sdcardAccessAll (3215208357415891320) -->
-    <skip />
+    <string name="permlab_sdcardAccessAll" msgid="8150613823900460576">"pasiekti visų naud. išor. atm."</string>
+    <string name="permdesc_sdcardAccessAll" msgid="3215208357415891320">"Leidžiama programai pasiekti visų naudotojų išorinę atmintinę."</string>
     <string name="permlab_cache_filesystem" msgid="5656487264819669824">"pasiekti talpyklos failų sistemą"</string>
     <string name="permdesc_cache_filesystem" msgid="5578967642265550955">"Leidžiama programai skaityti talpyklos failų sistemą ir į ją rašyti."</string>
     <string name="permlab_use_sip" msgid="5986952362795870502">"skambinti / priimti skambučius internetu"</string>
@@ -581,6 +579,10 @@
     <string name="policydesc_encryptedStorage" msgid="2637732115325316992">"Reikalauti, kad saugomos programos duomenys būtų šifruoti."</string>
     <string name="policylab_disableCamera" msgid="6395301023152297826">"Neleisti fotoaparatų"</string>
     <string name="policydesc_disableCamera" msgid="2306349042834754597">"Neleisti naudoti visų įrenginio fotoaparatų."</string>
+    <!-- no translation found for policylab_disableKeyguardWidgets (1794894613389073926) -->
+    <skip />
+    <!-- no translation found for policydesc_disableKeyguardWidgets (7254624892984033592) -->
+    <skip />
   <string-array name="phoneTypes">
     <item msgid="8901098336658710359">"Pagrindinis"</item>
     <item msgid="869923650527136615">"Mobilusis"</item>
@@ -1319,64 +1321,46 @@
     <string name="bluetooth_a2dp_audio_route_name" msgid="8575624030406771015">"„Bluetooth“ garsas"</string>
     <string name="media_route_chooser_grouping_done" msgid="7966438307723317169">"Atlikta"</string>
     <string name="media_route_button_content_description" msgid="5758553567065145276">"Medijos išvestis"</string>
-    <!-- no translation found for display_manager_built_in_display_name (2583134294292563941) -->
+    <string name="display_manager_built_in_display_name" msgid="2583134294292563941">"Integruotas ekranas"</string>
+    <!-- no translation found for display_manager_hdmi_display_name (1555264559227470109) -->
     <skip />
-    <!-- no translation found for display_manager_overlay_display_name (5142365982271620716) -->
+    <string name="display_manager_overlay_display_name" msgid="5142365982271620716">"Perdanga nr. <xliff:g id="ID">%1$d</xliff:g>"</string>
+    <!-- no translation found for display_manager_overlay_display_title (652124517672257172) -->
     <skip />
-    <!-- no translation found for display_manager_overlay_display_title (8186674340178573982) -->
-    <skip />
-    <!-- no translation found for kg_emergency_call_label (684946192523830531) -->
-    <skip />
-    <!-- no translation found for kg_forgot_pattern_button_text (8852021467868220608) -->
-    <skip />
-    <!-- no translation found for kg_wrong_pattern (1850806070801358830) -->
-    <skip />
-    <!-- no translation found for kg_wrong_password (2333281762128113157) -->
-    <skip />
-    <!-- no translation found for kg_wrong_pin (1131306510833563801) -->
-    <skip />
-    <!-- no translation found for kg_too_many_failed_attempts_countdown (353963338189371686) -->
-    <skip />
-    <!-- no translation found for kg_pattern_instructions (398978611683075868) -->
-    <skip />
-    <!-- no translation found for kg_sim_pin_instructions (2319508550934557331) -->
-    <skip />
-    <!-- no translation found for kg_pin_instructions (2377242233495111557) -->
-    <skip />
-    <!-- no translation found for kg_password_instructions (5753646556186936819) -->
-    <skip />
-    <!-- no translation found for kg_puk_enter_puk_hint (5183097160254244459) -->
-    <skip />
-    <!-- no translation found for kg_puk_enter_pin_hint (597821135578014901) -->
-    <skip />
-    <!-- no translation found for kg_sim_unlock_progress_dialog_message (8950398016976865762) -->
-    <skip />
-    <!-- no translation found for kg_password_wrong_pin_code (1139324887413846912) -->
-    <skip />
-    <!-- no translation found for kg_invalid_sim_pin_hint (8795159358110620001) -->
-    <skip />
-    <!-- no translation found for kg_invalid_sim_puk_hint (5216603185442368307) -->
-    <skip />
-    <!-- no translation found for kg_sim_puk_recovery_hint (5577753137718442566) -->
-    <skip />
-    <!-- no translation found for kg_invalid_puk (5809955359950817326) -->
-    <skip />
-    <!-- no translation found for kg_login_too_many_attempts (6486842094005698475) -->
-    <skip />
-    <!-- no translation found for kg_login_instructions (1100551261265506448) -->
-    <skip />
-    <!-- no translation found for kg_login_username_hint (5718534272070920364) -->
-    <skip />
-    <!-- no translation found for kg_login_password_hint (9057289103827298549) -->
-    <skip />
-    <!-- no translation found for kg_login_submit_button (5355904582674054702) -->
-    <skip />
-    <!-- no translation found for kg_login_invalid_input (5754664119319872197) -->
-    <skip />
-    <!-- no translation found for kg_login_account_recovery_hint (5690709132841752974) -->
-    <skip />
-    <!-- no translation found for kg_login_checking_password (8849589033659332457) -->
-    <skip />
-    <!-- no translation found for kg_temp_back_string (5812983904056640466) -->
-    <skip />
+    <string name="kg_emergency_call_label" msgid="684946192523830531">"Skambutis pagalbos numeriu"</string>
+    <string name="kg_forgot_pattern_button_text" msgid="8852021467868220608">"Pamiršau atrakinimo piešinį"</string>
+    <string name="kg_wrong_pattern" msgid="1850806070801358830">"Netinkamas atrakinimo piešinys"</string>
+    <string name="kg_wrong_password" msgid="2333281762128113157">"Netinkamas slaptažodis"</string>
+    <string name="kg_wrong_pin" msgid="1131306510833563801">"Netinkamas PIN kodas"</string>
+    <string name="kg_too_many_failed_attempts_countdown" msgid="6358110221603297548">"Bandyti dar kartą po <xliff:g id="NUMBER">%d</xliff:g> sek."</string>
+    <string name="kg_pattern_instructions" msgid="398978611683075868">"Nupieškite atrakinimo piešinį"</string>
+    <string name="kg_sim_pin_instructions" msgid="2319508550934557331">"Įveskite SIM PIN kodą"</string>
+    <string name="kg_pin_instructions" msgid="2377242233495111557">"Įveskite PIN kodą"</string>
+    <string name="kg_password_instructions" msgid="5753646556186936819">"Įveskite slaptažodį"</string>
+    <string name="kg_puk_enter_puk_hint" msgid="5183097160254244459">"PUK kodas"</string>
+    <string name="kg_puk_enter_pin_hint" msgid="597821135578014901">"Naujas PIN kodas"</string>
+    <string name="kg_sim_unlock_progress_dialog_message" msgid="8950398016976865762">"Atrakinama SIM kortelė…"</string>
+    <string name="kg_password_wrong_pin_code" msgid="1139324887413846912">"Netinkamas PIN kodas."</string>
+    <string name="kg_invalid_sim_pin_hint" msgid="8795159358110620001">"Įveskite PIN kodą, sudarytą iš 4–8 skaičių."</string>
+    <string name="kg_invalid_sim_puk_hint" msgid="5216603185442368307">"Įveskite 8 skaitmenų ar ilgesnį PUK kodą."</string>
+    <string name="kg_sim_puk_recovery_hint" msgid="5577753137718442566">"Įveskite PUK ir naują PIN kodus"</string>
+    <string name="kg_invalid_puk" msgid="5809955359950817326">"Įvestas PUK kodas netinkamas."</string>
+    <string name="kg_login_too_many_attempts" msgid="6486842094005698475">"Per daug atrakinimo piešinių bandymų"</string>
+    <string name="kg_login_instructions" msgid="1100551261265506448">"Jei norite atrakinti, prisijunkite naudodami „Google“ paskyrą."</string>
+    <string name="kg_login_username_hint" msgid="5718534272070920364">"Naudotojo vardas (el. paštas)"</string>
+    <string name="kg_login_password_hint" msgid="9057289103827298549">"Slaptažodis"</string>
+    <string name="kg_login_submit_button" msgid="5355904582674054702">"Prisijungti"</string>
+    <string name="kg_login_invalid_input" msgid="5754664119319872197">"Netinkamas naudotojo vardas ar slaptažodis."</string>
+    <string name="kg_login_account_recovery_hint" msgid="5690709132841752974">"Pamiršote naudotojo vardą ar slaptažodį?"\n"Apsilankykite šiuo adresu: "<b>"google.com/accounts/recovery"</b></string>
+    <string name="kg_login_checking_password" msgid="8849589033659332457">"Tikrinama…"</string>
+    <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="8276745642049502550">"PIN kodą netinkamai įvedėte <xliff:g id="NUMBER_0">%d</xliff:g> k. "\n\n"Bandykite dar kartą po <xliff:g id="NUMBER_1">%d</xliff:g> sek."</string>
+    <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="7813713389422226531">"Neteisingai įvedėte slaptažodį <xliff:g id="NUMBER_0">%d</xliff:g> k. "\n\n"Bandykite dar kartą po <xliff:g id="NUMBER_1">%d</xliff:g> sek."</string>
+    <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="74089475965050805">"Netinkamai nupiešėte atrakinimo piešinį <xliff:g id="NUMBER_0">%d</xliff:g> k. "\n\n"Bandykite dar kartą po <xliff:g id="NUMBER_1">%d</xliff:g> sek."</string>
+    <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="1575557200627128949">"<xliff:g id="NUMBER_0">%d</xliff:g> k. bandėte netinkamai atrakinti planšetinį kompiuterį. Po dar <xliff:g id="NUMBER_1">%d</xliff:g> nesėkm. band. planšetiniame kompiuteryje bus iš naujo nustatyti numatytieji gamyklos nustatymai ir bus prarasti visi naudotojo duomenys."</string>
+    <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="4051015943038199910">"<xliff:g id="NUMBER_0">%d</xliff:g> k. bandėte netinkamai atrakinti telefoną. Po dar <xliff:g id="NUMBER_1">%d</xliff:g> nesėkm. band. telefone bus iš naujo nustatyti numatytieji gamyklos nustatymai ir bus prarasti visi naudotojo duomenys."</string>
+    <string name="kg_failed_attempts_now_wiping" product="tablet" msgid="2072996269148483637">"<xliff:g id="NUMBER">%d</xliff:g> k. bandėte netinkamai atrakinti planšetinį kompiuterį. Planšetiniame kompiuteryje bus iš naujo nustatyti numatytieji gamyklos nustatymai."</string>
+    <string name="kg_failed_attempts_now_wiping" product="default" msgid="4817627474419471518">"<xliff:g id="NUMBER">%d</xliff:g> k. bandėte netinkamai atrakinti telefoną. Telefone bus iš naujo nustatyti numatytieji gamyklos nustatymai."</string>
+    <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"Netinkamai nupiešėte atrakinimo piešinį <xliff:g id="NUMBER_0">%d</xliff:g> k. Po dar <xliff:g id="NUMBER_1">%d</xliff:g> nesėkm. band. būsite paprašyti atrakinti planšetinį kompiuterį naudodami „Google“ prisijungimo duomenis."\n\n" Bandykite dar kartą po <xliff:g id="NUMBER_2">%d</xliff:g> sek."</string>
+    <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"Netinkamai nupiešėte atrakinimo piešinį <xliff:g id="NUMBER_0">%d</xliff:g> k. Po dar <xliff:g id="NUMBER_1">%d</xliff:g> nesėkm. band. būsite paprašyti atrakinti telefoną naudodami „Google“ prisijungimo duomenis."\n\n" Bandykite dar kartą po <xliff:g id="NUMBER_2">%d</xliff:g> sek."</string>
+    <string name="kg_temp_back_string" msgid="5812983904056640466">"&lt;"</string>
 </resources>
diff --git a/core/res/res/values-lv/strings.xml b/core/res/res/values-lv/strings.xml
index 91b414b..5be4d0c 100644
--- a/core/res/res/values-lv/strings.xml
+++ b/core/res/res/values-lv/strings.xml
@@ -547,10 +547,8 @@
     <string name="permdesc_sdcardWrite" product="default" msgid="4337417790936632090">"Ļauj lietotnei rakstīt SD kartē."</string>
     <string name="permlab_mediaStorageWrite" product="default" msgid="6859839199706879015">"pārv./dz.datu n.iekš.atm.sat."</string>
     <string name="permdesc_mediaStorageWrite" product="default" msgid="8189160597698529185">"Ļauj lietotnei modificēt datu nesēja iekšējās atmiņas saturu."</string>
-    <!-- no translation found for permlab_sdcardAccessAll (8150613823900460576) -->
-    <skip />
-    <!-- no translation found for permdesc_sdcardAccessAll (3215208357415891320) -->
-    <skip />
+    <string name="permlab_sdcardAccessAll" msgid="8150613823900460576">"piekļ. visu liet. ārējai krāt."</string>
+    <string name="permdesc_sdcardAccessAll" msgid="3215208357415891320">"Ļauj lietotnei piekļūt visu lietotāju ārējai krātuvei."</string>
     <string name="permlab_cache_filesystem" msgid="5656487264819669824">"piekļūt kešatmiņas failu sistēmai"</string>
     <string name="permdesc_cache_filesystem" msgid="5578967642265550955">"Ļauj lietotnei lasīt un rakstīt kešatmiņas failu sistēmā."</string>
     <string name="permlab_use_sip" msgid="5986952362795870502">"veikt/saņemt interneta zvanus"</string>
@@ -581,6 +579,10 @@
     <string name="policydesc_encryptedStorage" msgid="2637732115325316992">"Pieprasa, lai saglabātie lietotnes dati tiktu šifrēti."</string>
     <string name="policylab_disableCamera" msgid="6395301023152297826">"Atspējot kameras"</string>
     <string name="policydesc_disableCamera" msgid="2306349042834754597">"Neļauj izmantot nevienu ierīces kameru."</string>
+    <!-- no translation found for policylab_disableKeyguardWidgets (1794894613389073926) -->
+    <skip />
+    <!-- no translation found for policydesc_disableKeyguardWidgets (7254624892984033592) -->
+    <skip />
   <string-array name="phoneTypes">
     <item msgid="8901098336658710359">"Mājas"</item>
     <item msgid="869923650527136615">"Mobilais"</item>
@@ -1319,64 +1321,46 @@
     <string name="bluetooth_a2dp_audio_route_name" msgid="8575624030406771015">"Bluetooth audio"</string>
     <string name="media_route_chooser_grouping_done" msgid="7966438307723317169">"Gatavs"</string>
     <string name="media_route_button_content_description" msgid="5758553567065145276">"Multivides izeja"</string>
-    <!-- no translation found for display_manager_built_in_display_name (2583134294292563941) -->
+    <string name="display_manager_built_in_display_name" msgid="2583134294292563941">"Iebūvēts ekrāns"</string>
+    <!-- no translation found for display_manager_hdmi_display_name (1555264559227470109) -->
     <skip />
-    <!-- no translation found for display_manager_overlay_display_name (5142365982271620716) -->
+    <string name="display_manager_overlay_display_name" msgid="5142365982271620716">"Pārklājums Nr. <xliff:g id="ID">%1$d</xliff:g>"</string>
+    <!-- no translation found for display_manager_overlay_display_title (652124517672257172) -->
     <skip />
-    <!-- no translation found for display_manager_overlay_display_title (8186674340178573982) -->
-    <skip />
-    <!-- no translation found for kg_emergency_call_label (684946192523830531) -->
-    <skip />
-    <!-- no translation found for kg_forgot_pattern_button_text (8852021467868220608) -->
-    <skip />
-    <!-- no translation found for kg_wrong_pattern (1850806070801358830) -->
-    <skip />
-    <!-- no translation found for kg_wrong_password (2333281762128113157) -->
-    <skip />
-    <!-- no translation found for kg_wrong_pin (1131306510833563801) -->
-    <skip />
-    <!-- no translation found for kg_too_many_failed_attempts_countdown (353963338189371686) -->
-    <skip />
-    <!-- no translation found for kg_pattern_instructions (398978611683075868) -->
-    <skip />
-    <!-- no translation found for kg_sim_pin_instructions (2319508550934557331) -->
-    <skip />
-    <!-- no translation found for kg_pin_instructions (2377242233495111557) -->
-    <skip />
-    <!-- no translation found for kg_password_instructions (5753646556186936819) -->
-    <skip />
-    <!-- no translation found for kg_puk_enter_puk_hint (5183097160254244459) -->
-    <skip />
-    <!-- no translation found for kg_puk_enter_pin_hint (597821135578014901) -->
-    <skip />
-    <!-- no translation found for kg_sim_unlock_progress_dialog_message (8950398016976865762) -->
-    <skip />
-    <!-- no translation found for kg_password_wrong_pin_code (1139324887413846912) -->
-    <skip />
-    <!-- no translation found for kg_invalid_sim_pin_hint (8795159358110620001) -->
-    <skip />
-    <!-- no translation found for kg_invalid_sim_puk_hint (5216603185442368307) -->
-    <skip />
-    <!-- no translation found for kg_sim_puk_recovery_hint (5577753137718442566) -->
-    <skip />
-    <!-- no translation found for kg_invalid_puk (5809955359950817326) -->
-    <skip />
-    <!-- no translation found for kg_login_too_many_attempts (6486842094005698475) -->
-    <skip />
-    <!-- no translation found for kg_login_instructions (1100551261265506448) -->
-    <skip />
-    <!-- no translation found for kg_login_username_hint (5718534272070920364) -->
-    <skip />
-    <!-- no translation found for kg_login_password_hint (9057289103827298549) -->
-    <skip />
-    <!-- no translation found for kg_login_submit_button (5355904582674054702) -->
-    <skip />
-    <!-- no translation found for kg_login_invalid_input (5754664119319872197) -->
-    <skip />
-    <!-- no translation found for kg_login_account_recovery_hint (5690709132841752974) -->
-    <skip />
-    <!-- no translation found for kg_login_checking_password (8849589033659332457) -->
-    <skip />
-    <!-- no translation found for kg_temp_back_string (5812983904056640466) -->
-    <skip />
+    <string name="kg_emergency_call_label" msgid="684946192523830531">"Ārkārtas izsaukums"</string>
+    <string name="kg_forgot_pattern_button_text" msgid="8852021467868220608">"Aizmirsu kombināciju"</string>
+    <string name="kg_wrong_pattern" msgid="1850806070801358830">"Nepareiza kombinācija"</string>
+    <string name="kg_wrong_password" msgid="2333281762128113157">"Nepareiza parole"</string>
+    <string name="kg_wrong_pin" msgid="1131306510833563801">"Nepareizs PIN"</string>
+    <string name="kg_too_many_failed_attempts_countdown" msgid="6358110221603297548">"Mēģiniet vēlreiz pēc <xliff:g id="NUMBER">%d</xliff:g> sekundēm."</string>
+    <string name="kg_pattern_instructions" msgid="398978611683075868">"Norādiet savu kombināciju"</string>
+    <string name="kg_sim_pin_instructions" msgid="2319508550934557331">"Ievadiet SIM kartes PIN"</string>
+    <string name="kg_pin_instructions" msgid="2377242233495111557">"Ievadiet PIN"</string>
+    <string name="kg_password_instructions" msgid="5753646556186936819">"Ievadiet paroli"</string>
+    <string name="kg_puk_enter_puk_hint" msgid="5183097160254244459">"PUK kods"</string>
+    <string name="kg_puk_enter_pin_hint" msgid="597821135578014901">"Jauns PIN kods"</string>
+    <string name="kg_sim_unlock_progress_dialog_message" msgid="8950398016976865762">"Notiek SIM kartes atbloķēšana..."</string>
+    <string name="kg_password_wrong_pin_code" msgid="1139324887413846912">"PIN kods nav pareizs."</string>
+    <string name="kg_invalid_sim_pin_hint" msgid="8795159358110620001">"Ievadiet PIN, kas sastāv no 4 līdz 8 cipariem."</string>
+    <string name="kg_invalid_sim_puk_hint" msgid="5216603185442368307">"Ievadiet PUK, kas sastāv no vismaz 8 cipariem."</string>
+    <string name="kg_sim_puk_recovery_hint" msgid="5577753137718442566">"Ievadiet PUK kodu un jaunu PIN kodu"</string>
+    <string name="kg_invalid_puk" msgid="5809955359950817326">"Ievadītais PUK nav pareizs."</string>
+    <string name="kg_login_too_many_attempts" msgid="6486842094005698475">"Pārāk daudz kombinācijas mēģinājumu"</string>
+    <string name="kg_login_instructions" msgid="1100551261265506448">"Lai atbloķētu, pierakstieties, izmantojot savu Google kontu."</string>
+    <string name="kg_login_username_hint" msgid="5718534272070920364">"Lietotājvārds (e-pasts)"</string>
+    <string name="kg_login_password_hint" msgid="9057289103827298549">"Parole"</string>
+    <string name="kg_login_submit_button" msgid="5355904582674054702">"Pierakstīties"</string>
+    <string name="kg_login_invalid_input" msgid="5754664119319872197">"Nederīgs lietotājvārds vai parole."</string>
+    <string name="kg_login_account_recovery_hint" msgid="5690709132841752974">"Vai aizmirsāt lietotājvārdu vai paroli?"\n"Apmeklējiet vietni "<b>"google.com/accounts/recovery"</b>"."</string>
+    <string name="kg_login_checking_password" msgid="8849589033659332457">"Notiek pārbaude..."</string>
+    <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="8276745642049502550">"Jūs nepareizi ievadījāt PIN <xliff:g id="NUMBER_0">%d</xliff:g> reizes."\n\n"Mēģiniet vēlreiz pēc <xliff:g id="NUMBER_1">%d</xliff:g> sekundēm."</string>
+    <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="7813713389422226531">"Jūs nepareizi ievadījāt paroli <xliff:g id="NUMBER_0">%d</xliff:g> reizes."\n\n"Mēģiniet vēlreiz pēc <xliff:g id="NUMBER_1">%d</xliff:g> sekundēm."</string>
+    <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="74089475965050805">"Jūs nepareizi norādījāt atbloķēšanas kombināciju <xliff:g id="NUMBER_0">%d</xliff:g> reizes."\n\n"Mēģiniet vēlreiz pēc <xliff:g id="NUMBER_1">%d</xliff:g> sekundēm."</string>
+    <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="1575557200627128949">"Jūs nepareizi veicāt planšetdatora atbloķēšanu <xliff:g id="NUMBER_0">%d</xliff:g> reizes. Pēc vēl <xliff:g id="NUMBER_1">%d</xliff:g> neveiksmīgiem mēģinājumiem planšetdatorā tiks atiestatīti rūpnīcas noklusējuma iestatījumi un lietotāja dati tiks zaudēti."</string>
+    <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="4051015943038199910">"Jūs nepareizi veicāt tālruņa atbloķēšanu <xliff:g id="NUMBER_0">%d</xliff:g> reizes. Pēc vēl <xliff:g id="NUMBER_1">%d</xliff:g> neveiksmīgiem mēģinājumiem tālrunī tiks atiestatīti rūpnīcas noklusējuma iestatījumi un lietotāja dati tiks zaudēti."</string>
+    <string name="kg_failed_attempts_now_wiping" product="tablet" msgid="2072996269148483637">"Jūs nepareizi veicāt planšetdatora atbloķēšanu <xliff:g id="NUMBER">%d</xliff:g> reizes. Planšetdatorā tiks atiestatīti rūpnīcas noklusējuma iestatījumi."</string>
+    <string name="kg_failed_attempts_now_wiping" product="default" msgid="4817627474419471518">"Jūs nepareizi veicāt tālruņa atbloķēšanu <xliff:g id="NUMBER">%d</xliff:g> reizes. Tālrunī tiks atiestatīti rūpnīcas noklusējuma iestatījumi."</string>
+    <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"Jūs nepareizi norādījāt atbloķēšanas kombināciju <xliff:g id="NUMBER_0">%d</xliff:g> reizes. Pēc vēl <xliff:g id="NUMBER_1">%d</xliff:g> neveiksmīgiem mēģinājumiem planšetdators būs jāatbloķē, izmantojot e-pasta kontu."\n\n"Mēģiniet vēlreiz pēc <xliff:g id="NUMBER_2">%d</xliff:g> sekundēm."</string>
+    <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"Jūs nepareizi norādījāt atbloķēšanas kombināciju <xliff:g id="NUMBER_0">%d</xliff:g> reizes. Pēc vēl <xliff:g id="NUMBER_1">%d</xliff:g> neveiksmīgiem mēģinājumiem tālrunis būs jāatbloķē, izmantojot e-pasta kontu."\n\n"Mēģiniet vēlreiz pēc <xliff:g id="NUMBER_2">%d</xliff:g> sekundēm."</string>
+    <string name="kg_temp_back_string" msgid="5812983904056640466">"&lt;"</string>
 </resources>
diff --git a/core/res/res/values-ms/strings.xml b/core/res/res/values-ms/strings.xml
index b9fca83..5f00397 100644
--- a/core/res/res/values-ms/strings.xml
+++ b/core/res/res/values-ms/strings.xml
@@ -547,10 +547,8 @@
     <string name="permdesc_sdcardWrite" product="default" msgid="4337417790936632090">"Membenarkan apl menulis ke kad SD."</string>
     <string name="permlab_mediaStorageWrite" product="default" msgid="6859839199706879015">"ubh suai/pdm kdg strn mdia dlm"</string>
     <string name="permdesc_mediaStorageWrite" product="default" msgid="8189160597698529185">"Membenarkan apl mengubah suai kandungan storan media dalaman."</string>
-    <!-- no translation found for permlab_sdcardAccessAll (8150613823900460576) -->
-    <skip />
-    <!-- no translation found for permdesc_sdcardAccessAll (3215208357415891320) -->
-    <skip />
+    <string name="permlab_sdcardAccessAll" msgid="8150613823900460576">"mengakses storan luaran untuk semua pengguna"</string>
+    <string name="permdesc_sdcardAccessAll" msgid="3215208357415891320">"Membenarkan apl untuk mengakses storan luaran untuk semua pengguna."</string>
     <string name="permlab_cache_filesystem" msgid="5656487264819669824">"akses sistem fail cache"</string>
     <string name="permdesc_cache_filesystem" msgid="5578967642265550955">"Membenarkan apl membaca dan menulis cache sistem fail."</string>
     <string name="permlab_use_sip" msgid="5986952362795870502">"membuat/menerima panggilan Internet"</string>
@@ -581,6 +579,10 @@
     <string name="policydesc_encryptedStorage" msgid="2637732115325316992">"Memerlukan data apl yang disimpan itu disulitkan."</string>
     <string name="policylab_disableCamera" msgid="6395301023152297826">"Lumpuhkan kamera"</string>
     <string name="policydesc_disableCamera" msgid="2306349042834754597">"Menghalang penggunaan semua kamera peranti."</string>
+    <!-- no translation found for policylab_disableKeyguardWidgets (1794894613389073926) -->
+    <skip />
+    <!-- no translation found for policydesc_disableKeyguardWidgets (7254624892984033592) -->
+    <skip />
   <string-array name="phoneTypes">
     <item msgid="8901098336658710359">"Laman Utama"</item>
     <item msgid="869923650527136615">"Mudah alih"</item>
@@ -1319,64 +1321,46 @@
     <string name="bluetooth_a2dp_audio_route_name" msgid="8575624030406771015">"Audio Bluetooth"</string>
     <string name="media_route_chooser_grouping_done" msgid="7966438307723317169">"Selesai"</string>
     <string name="media_route_button_content_description" msgid="5758553567065145276">"Output media"</string>
-    <!-- no translation found for display_manager_built_in_display_name (2583134294292563941) -->
+    <string name="display_manager_built_in_display_name" msgid="2583134294292563941">"Skrin Terbina Dalam"</string>
+    <!-- no translation found for display_manager_hdmi_display_name (1555264559227470109) -->
     <skip />
-    <!-- no translation found for display_manager_overlay_display_name (5142365982271620716) -->
+    <string name="display_manager_overlay_display_name" msgid="5142365982271620716">"Tindih #<xliff:g id="ID">%1$d</xliff:g>"</string>
+    <!-- no translation found for display_manager_overlay_display_title (652124517672257172) -->
     <skip />
-    <!-- no translation found for display_manager_overlay_display_title (8186674340178573982) -->
-    <skip />
-    <!-- no translation found for kg_emergency_call_label (684946192523830531) -->
-    <skip />
-    <!-- no translation found for kg_forgot_pattern_button_text (8852021467868220608) -->
-    <skip />
-    <!-- no translation found for kg_wrong_pattern (1850806070801358830) -->
-    <skip />
-    <!-- no translation found for kg_wrong_password (2333281762128113157) -->
-    <skip />
-    <!-- no translation found for kg_wrong_pin (1131306510833563801) -->
-    <skip />
-    <!-- no translation found for kg_too_many_failed_attempts_countdown (353963338189371686) -->
-    <skip />
-    <!-- no translation found for kg_pattern_instructions (398978611683075868) -->
-    <skip />
-    <!-- no translation found for kg_sim_pin_instructions (2319508550934557331) -->
-    <skip />
-    <!-- no translation found for kg_pin_instructions (2377242233495111557) -->
-    <skip />
-    <!-- no translation found for kg_password_instructions (5753646556186936819) -->
-    <skip />
-    <!-- no translation found for kg_puk_enter_puk_hint (5183097160254244459) -->
-    <skip />
-    <!-- no translation found for kg_puk_enter_pin_hint (597821135578014901) -->
-    <skip />
-    <!-- no translation found for kg_sim_unlock_progress_dialog_message (8950398016976865762) -->
-    <skip />
-    <!-- no translation found for kg_password_wrong_pin_code (1139324887413846912) -->
-    <skip />
-    <!-- no translation found for kg_invalid_sim_pin_hint (8795159358110620001) -->
-    <skip />
-    <!-- no translation found for kg_invalid_sim_puk_hint (5216603185442368307) -->
-    <skip />
-    <!-- no translation found for kg_sim_puk_recovery_hint (5577753137718442566) -->
-    <skip />
-    <!-- no translation found for kg_invalid_puk (5809955359950817326) -->
-    <skip />
-    <!-- no translation found for kg_login_too_many_attempts (6486842094005698475) -->
-    <skip />
-    <!-- no translation found for kg_login_instructions (1100551261265506448) -->
-    <skip />
-    <!-- no translation found for kg_login_username_hint (5718534272070920364) -->
-    <skip />
-    <!-- no translation found for kg_login_password_hint (9057289103827298549) -->
-    <skip />
-    <!-- no translation found for kg_login_submit_button (5355904582674054702) -->
-    <skip />
-    <!-- no translation found for kg_login_invalid_input (5754664119319872197) -->
-    <skip />
-    <!-- no translation found for kg_login_account_recovery_hint (5690709132841752974) -->
-    <skip />
-    <!-- no translation found for kg_login_checking_password (8849589033659332457) -->
-    <skip />
-    <!-- no translation found for kg_temp_back_string (5812983904056640466) -->
-    <skip />
+    <string name="kg_emergency_call_label" msgid="684946192523830531">"Panggilan kecemasan"</string>
+    <string name="kg_forgot_pattern_button_text" msgid="8852021467868220608">"Lupa Corak"</string>
+    <string name="kg_wrong_pattern" msgid="1850806070801358830">"Corak Salah"</string>
+    <string name="kg_wrong_password" msgid="2333281762128113157">"Kata Laluan Salah"</string>
+    <string name="kg_wrong_pin" msgid="1131306510833563801">"PIN salah"</string>
+    <string name="kg_too_many_failed_attempts_countdown" msgid="6358110221603297548">"Cuba lagi dalam <xliff:g id="NUMBER">%d</xliff:g> saat."</string>
+    <string name="kg_pattern_instructions" msgid="398978611683075868">"Lukiskan corak anda"</string>
+    <string name="kg_sim_pin_instructions" msgid="2319508550934557331">"Masukkan PIN SIM"</string>
+    <string name="kg_pin_instructions" msgid="2377242233495111557">"Masukkan PIN"</string>
+    <string name="kg_password_instructions" msgid="5753646556186936819">"Masukkan Kata Laluan"</string>
+    <string name="kg_puk_enter_puk_hint" msgid="5183097160254244459">"Kod PUK"</string>
+    <string name="kg_puk_enter_pin_hint" msgid="597821135578014901">"Kod PIN Baharu"</string>
+    <string name="kg_sim_unlock_progress_dialog_message" msgid="8950398016976865762">"Membuka kunci kad SIM..."</string>
+    <string name="kg_password_wrong_pin_code" msgid="1139324887413846912">"Kod PIN salah."</string>
+    <string name="kg_invalid_sim_pin_hint" msgid="8795159358110620001">"Taipkan PIN yang mengandungi 4 hingga 8 nombor."</string>
+    <string name="kg_invalid_sim_puk_hint" msgid="5216603185442368307">"Taipkan PUK yang mempunyai 8 nombor atau lebih panjang."</string>
+    <string name="kg_sim_puk_recovery_hint" msgid="5577753137718442566">"Taip PUK dan kod PIN baharu"</string>
+    <string name="kg_invalid_puk" msgid="5809955359950817326">"Kod PUK yang anda taipkan tidak betul."</string>
+    <string name="kg_login_too_many_attempts" msgid="6486842094005698475">"Terlalu banyak percubaan melukis corak"</string>
+    <string name="kg_login_instructions" msgid="1100551261265506448">"Untuk membuka kunci, log masuk dengan akaun Google anda."</string>
+    <string name="kg_login_username_hint" msgid="5718534272070920364">"Nama Pengguna (E-mel)"</string>
+    <string name="kg_login_password_hint" msgid="9057289103827298549">"Kata laluan"</string>
+    <string name="kg_login_submit_button" msgid="5355904582674054702">"Log masuk"</string>
+    <string name="kg_login_invalid_input" msgid="5754664119319872197">"Nama pengguna atau kata laluan tidak sah."</string>
+    <string name="kg_login_account_recovery_hint" msgid="5690709132841752974">"Lupa nama pengguna atau kata laluan anda?"\n"Lawati"<b>"google.com/accounts/recovery"</b>"."</string>
+    <string name="kg_login_checking_password" msgid="8849589033659332457">"Menyemak…"</string>
+    <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="8276745642049502550">"Anda telah menaip PIN anda secara salah sebanyak <xliff:g id="NUMBER_0">%d</xliff:g> kali. "\n\n"Cuba lagi dalam <xliff:g id="NUMBER_1">%d</xliff:g> saat."</string>
+    <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="7813713389422226531">"Anda telah menaip kata laluan anda secara salah sebanyak <xliff:g id="NUMBER_0">%d</xliff:g> kali. "\n\n"Cuba lagi dalam <xliff:g id="NUMBER_1">%d</xliff:g> saat."</string>
+    <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="74089475965050805">"Anda telah tersilap melukis corak buka kunci anda sebanyak <xliff:g id="NUMBER_0">%d</xliff:g> kali. "\n\n"Cuba lagi dalam <xliff:g id="NUMBER_1">%d</xliff:g> saat."</string>
+    <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="1575557200627128949">"Anda telah mencuba untuk membuka kunci tablet dengan salah sebanyak <xliff:g id="NUMBER_0">%d</xliff:g> kali. Selepas <xliff:g id="NUMBER_1">%d</xliff:g> lagi percubaan yang tidak berjaya, tablet akan ditetapkan semula kepada tetapan lalai kilang dan semua data pengguna akan hilang."</string>
+    <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="4051015943038199910">"Anda telah mencuba untuk membuka kunci telefon dengan salah sebanyak <xliff:g id="NUMBER_0">%d</xliff:g> kali. Selepas <xliff:g id="NUMBER_1">%d</xliff:g> lagi percubaan yang tidak berjaya, telefon akan ditetapkan semula kepada tetapan lalai kilang dan semua data pengguna akan hilang."</string>
+    <string name="kg_failed_attempts_now_wiping" product="tablet" msgid="2072996269148483637">"Anda telah mencuba untuk membuka kunci tablet secara salah sebanyak <xliff:g id="NUMBER">%d</xliff:g> kali. Tablet kini akan ditetapkan semula ke tetapan lalai kilang."</string>
+    <string name="kg_failed_attempts_now_wiping" product="default" msgid="4817627474419471518">"Anda telah mencuba untuk membuka kunci telefon secara salah sebanyak <xliff:g id="NUMBER">%d</xliff:g> kali. Telefon kini akan ditetapkan semula ke tetapan lalai kilang."</string>
+    <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"Anda telah tersilap melukis corak buka kunci sebanyak <xliff:g id="NUMBER_0">%d</xliff:g> kali. Selepas <xliff:g id="NUMBER_1">%d</xliff:g> lagi percubaan yang tidak berjaya, anda akan diminta membuka kunci tablet anda menggunakan log masuk Google anda."\n\n" Cuba lagi dalam <xliff:g id="NUMBER_2">%d</xliff:g> saat."</string>
+    <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"Anda telah tersilap lukis corak buka kunci sebanyak <xliff:g id="NUMBER_0">%d</xliff:g> kali. Selepas <xliff:g id="NUMBER_1">%d</xliff:g> lagi percubaan yang tidak berjaya, anda akan diminta membuka kunci telefon anda menggunakan log masuk Google anda."\n\n" Cuba lagi dalam <xliff:g id="NUMBER_2">%d</xliff:g> saat."</string>
+    <string name="kg_temp_back_string" msgid="5812983904056640466">"&lt;"</string>
 </resources>
diff --git a/core/res/res/values-nb/strings.xml b/core/res/res/values-nb/strings.xml
index ef6a305..8ac299f 100644
--- a/core/res/res/values-nb/strings.xml
+++ b/core/res/res/values-nb/strings.xml
@@ -547,10 +547,8 @@
     <string name="permdesc_sdcardWrite" product="default" msgid="4337417790936632090">"Lar appen skrive til SD-kortet."</string>
     <string name="permlab_mediaStorageWrite" product="default" msgid="6859839199706879015">"endre eller slette innhold på interne medier"</string>
     <string name="permdesc_mediaStorageWrite" product="default" msgid="8189160597698529185">"Lar appen endre innholdet i det interne lagringsmediet."</string>
-    <!-- no translation found for permlab_sdcardAccessAll (8150613823900460576) -->
-    <skip />
-    <!-- no translation found for permdesc_sdcardAccessAll (3215208357415891320) -->
-    <skip />
+    <string name="permlab_sdcardAccessAll" msgid="8150613823900460576">"åpne eksternlagring for alle brukere"</string>
+    <string name="permdesc_sdcardAccessAll" msgid="3215208357415891320">"Tillater appen å åpne eksternlagring for alle brukere."</string>
     <string name="permlab_cache_filesystem" msgid="5656487264819669824">"tilgang til bufrede filer"</string>
     <string name="permdesc_cache_filesystem" msgid="5578967642265550955">"Lar appen lese og skrive til det bufrede filsystemet."</string>
     <string name="permlab_use_sip" msgid="5986952362795870502">"foreta/motta Internett-anrop"</string>
@@ -581,6 +579,10 @@
     <string name="policydesc_encryptedStorage" msgid="2637732115325316992">"Krev at lagrede appdata krypteres."</string>
     <string name="policylab_disableCamera" msgid="6395301023152297826">"Deaktiver kameraer"</string>
     <string name="policydesc_disableCamera" msgid="2306349042834754597">"Hindre bruk av alle kameraer på enheten."</string>
+    <!-- no translation found for policylab_disableKeyguardWidgets (1794894613389073926) -->
+    <skip />
+    <!-- no translation found for policydesc_disableKeyguardWidgets (7254624892984033592) -->
+    <skip />
   <string-array name="phoneTypes">
     <item msgid="8901098336658710359">"Hjemmenummer"</item>
     <item msgid="869923650527136615">"Mobil"</item>
@@ -1319,64 +1321,46 @@
     <string name="bluetooth_a2dp_audio_route_name" msgid="8575624030406771015">"Bluetooth-lyd"</string>
     <string name="media_route_chooser_grouping_done" msgid="7966438307723317169">"Fullført"</string>
     <string name="media_route_button_content_description" msgid="5758553567065145276">"Medieutgang"</string>
-    <!-- no translation found for display_manager_built_in_display_name (2583134294292563941) -->
+    <string name="display_manager_built_in_display_name" msgid="2583134294292563941">"Innebygd skjerm"</string>
+    <!-- no translation found for display_manager_hdmi_display_name (1555264559227470109) -->
     <skip />
-    <!-- no translation found for display_manager_overlay_display_name (5142365982271620716) -->
+    <string name="display_manager_overlay_display_name" msgid="5142365982271620716">"Overlegg #<xliff:g id="ID">%1$d</xliff:g>"</string>
+    <!-- no translation found for display_manager_overlay_display_title (652124517672257172) -->
     <skip />
-    <!-- no translation found for display_manager_overlay_display_title (8186674340178573982) -->
-    <skip />
-    <!-- no translation found for kg_emergency_call_label (684946192523830531) -->
-    <skip />
-    <!-- no translation found for kg_forgot_pattern_button_text (8852021467868220608) -->
-    <skip />
-    <!-- no translation found for kg_wrong_pattern (1850806070801358830) -->
-    <skip />
-    <!-- no translation found for kg_wrong_password (2333281762128113157) -->
-    <skip />
-    <!-- no translation found for kg_wrong_pin (1131306510833563801) -->
-    <skip />
-    <!-- no translation found for kg_too_many_failed_attempts_countdown (353963338189371686) -->
-    <skip />
-    <!-- no translation found for kg_pattern_instructions (398978611683075868) -->
-    <skip />
-    <!-- no translation found for kg_sim_pin_instructions (2319508550934557331) -->
-    <skip />
-    <!-- no translation found for kg_pin_instructions (2377242233495111557) -->
-    <skip />
-    <!-- no translation found for kg_password_instructions (5753646556186936819) -->
-    <skip />
-    <!-- no translation found for kg_puk_enter_puk_hint (5183097160254244459) -->
-    <skip />
-    <!-- no translation found for kg_puk_enter_pin_hint (597821135578014901) -->
-    <skip />
-    <!-- no translation found for kg_sim_unlock_progress_dialog_message (8950398016976865762) -->
-    <skip />
-    <!-- no translation found for kg_password_wrong_pin_code (1139324887413846912) -->
-    <skip />
-    <!-- no translation found for kg_invalid_sim_pin_hint (8795159358110620001) -->
-    <skip />
-    <!-- no translation found for kg_invalid_sim_puk_hint (5216603185442368307) -->
-    <skip />
-    <!-- no translation found for kg_sim_puk_recovery_hint (5577753137718442566) -->
-    <skip />
-    <!-- no translation found for kg_invalid_puk (5809955359950817326) -->
-    <skip />
-    <!-- no translation found for kg_login_too_many_attempts (6486842094005698475) -->
-    <skip />
-    <!-- no translation found for kg_login_instructions (1100551261265506448) -->
-    <skip />
-    <!-- no translation found for kg_login_username_hint (5718534272070920364) -->
-    <skip />
-    <!-- no translation found for kg_login_password_hint (9057289103827298549) -->
-    <skip />
-    <!-- no translation found for kg_login_submit_button (5355904582674054702) -->
-    <skip />
-    <!-- no translation found for kg_login_invalid_input (5754664119319872197) -->
-    <skip />
-    <!-- no translation found for kg_login_account_recovery_hint (5690709132841752974) -->
-    <skip />
-    <!-- no translation found for kg_login_checking_password (8849589033659332457) -->
-    <skip />
-    <!-- no translation found for kg_temp_back_string (5812983904056640466) -->
-    <skip />
+    <string name="kg_emergency_call_label" msgid="684946192523830531">"Nødnummer"</string>
+    <string name="kg_forgot_pattern_button_text" msgid="8852021467868220608">"Har du glemt mønsteret?"</string>
+    <string name="kg_wrong_pattern" msgid="1850806070801358830">"Feil mønster"</string>
+    <string name="kg_wrong_password" msgid="2333281762128113157">"Feil passord"</string>
+    <string name="kg_wrong_pin" msgid="1131306510833563801">"Feil PIN-kode"</string>
+    <string name="kg_too_many_failed_attempts_countdown" msgid="6358110221603297548">"Prøv på nytt om <xliff:g id="NUMBER">%d</xliff:g> sekunder."</string>
+    <string name="kg_pattern_instructions" msgid="398978611683075868">"Tegn mønsteret ditt"</string>
+    <string name="kg_sim_pin_instructions" msgid="2319508550934557331">"Skriv inn PIN-koden for SIM-kortet"</string>
+    <string name="kg_pin_instructions" msgid="2377242233495111557">"Skriv inn PIN-koden"</string>
+    <string name="kg_password_instructions" msgid="5753646556186936819">"Skriv inn passordet"</string>
+    <string name="kg_puk_enter_puk_hint" msgid="5183097160254244459">"PUK-kode"</string>
+    <string name="kg_puk_enter_pin_hint" msgid="597821135578014901">"Ny PIN-kode"</string>
+    <string name="kg_sim_unlock_progress_dialog_message" msgid="8950398016976865762">"Låser opp SIM-kortet ..."</string>
+    <string name="kg_password_wrong_pin_code" msgid="1139324887413846912">"Feil PIN-kode."</string>
+    <string name="kg_invalid_sim_pin_hint" msgid="8795159358110620001">"Skriv inn en PIN-kode på fire til åtte sifre."</string>
+    <string name="kg_invalid_sim_puk_hint" msgid="5216603185442368307">"Skriv inn en PUK-kode på åtte sifre eller mer."</string>
+    <string name="kg_sim_puk_recovery_hint" msgid="5577753137718442566">"Skriv inn PUK-koden og en ny PIN-kode"</string>
+    <string name="kg_invalid_puk" msgid="5809955359950817326">"PUK-koden du har skrevet inn er ikke riktig."</string>
+    <string name="kg_login_too_many_attempts" msgid="6486842094005698475">"For mange forsøk på tegning av mønster"</string>
+    <string name="kg_login_instructions" msgid="1100551261265506448">"Logg deg på med Google-kontoen din for å låse opp."</string>
+    <string name="kg_login_username_hint" msgid="5718534272070920364">"Brukernavn (e-postadresse)"</string>
+    <string name="kg_login_password_hint" msgid="9057289103827298549">"Passord"</string>
+    <string name="kg_login_submit_button" msgid="5355904582674054702">"Logg på"</string>
+    <string name="kg_login_invalid_input" msgid="5754664119319872197">"Ugyldig brukernavn eller passord."</string>
+    <string name="kg_login_account_recovery_hint" msgid="5690709132841752974">"Har du glemt brukernavnet eller passordet?"\n"Gå til "<b>"google.com/accounts/recovery"</b>"."</string>
+    <string name="kg_login_checking_password" msgid="8849589033659332457">"Kontrollerer …"</string>
+    <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="8276745642049502550">"Du har oppgitt feil PIN-kode <xliff:g id="NUMBER_0">%d</xliff:g> ganger. "\n\n"Prøv på nytt om <xliff:g id="NUMBER_1">%d</xliff:g> sekunder."</string>
+    <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="7813713389422226531">"Du har tastet inn passordet ditt feil <xliff:g id="NUMBER_0">%d</xliff:g> ganger. "\n\n"Prøv på nytt om <xliff:g id="NUMBER_1">%d</xliff:g> sekunder."</string>
+    <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="74089475965050805">"Du har tegnet opplåsningsmønsteret ditt feil <xliff:g id="NUMBER_0">%d</xliff:g> ganger. "\n\n"Prøv på nytt om <xliff:g id="NUMBER_1">%d</xliff:g> sekunder."</string>
+    <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="1575557200627128949">"Du har oppgitt feil opplåsningspassord for nettbrettet <xliff:g id="NUMBER_0">%d</xliff:g> ganger. Etter ytterligere <xliff:g id="NUMBER_1">%d</xliff:g> gale forsøk, tilbakestilles nettbrettet til fabrikkstandard og all data går tapt."</string>
+    <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="4051015943038199910">"Du har oppgitt feil opplåsningspassord for telefonen <xliff:g id="NUMBER_0">%d</xliff:g> ganger. Etter ytterligere <xliff:g id="NUMBER_1">%d</xliff:g> gale forsøk, tilbakestilles telefonen til fabrikkstandard og all data går tapt."</string>
+    <string name="kg_failed_attempts_now_wiping" product="tablet" msgid="2072996269148483637">"Du har oppgitt feil opplåsningspassord for nettbrettet <xliff:g id="NUMBER">%d</xliff:g> ganger. Telefonen tilbakestilles nå til fabrikkstandard."</string>
+    <string name="kg_failed_attempts_now_wiping" product="default" msgid="4817627474419471518">"Du har oppgitt feil opplåsningspassord for telefonen <xliff:g id="NUMBER">%d</xliff:g> ganger. Telefonen tilbakestilles nå til fabrikkstandard."</string>
+    <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"Du har tegnet opplåsningsmønsteret feil <xliff:g id="NUMBER_0">%d</xliff:g> ganger. Etter ytterligere <xliff:g id="NUMBER_1">%d</xliff:g> gale forsøk, blir du bedt om å låse opp nettbrettet via en e-postkonto."\n\n" Prøv på nytt om <xliff:g id="NUMBER_2">%d</xliff:g> sekunder."</string>
+    <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"Du har tegnet opplåsningsmønsteret feil <xliff:g id="NUMBER_0">%d</xliff:g> ganger. Etter ytterligere <xliff:g id="NUMBER_1">%d</xliff:g> gale forsøk, blir du bedt om å låse opp telefonen via en e-postkonto."\n\n" Prøv på nytt om <xliff:g id="NUMBER_2">%d</xliff:g> sekunder."</string>
+    <string name="kg_temp_back_string" msgid="5812983904056640466">"&lt;"</string>
 </resources>
diff --git a/core/res/res/values-nl/strings.xml b/core/res/res/values-nl/strings.xml
index 2ac476d..a2b2ada 100644
--- a/core/res/res/values-nl/strings.xml
+++ b/core/res/res/values-nl/strings.xml
@@ -547,10 +547,8 @@
     <string name="permdesc_sdcardWrite" product="default" msgid="4337417790936632090">"Hiermee kan de app schrijven naar de SD-kaart."</string>
     <string name="permlab_mediaStorageWrite" product="default" msgid="6859839199706879015">"inh. mediaopsl. wijz./verw."</string>
     <string name="permdesc_mediaStorageWrite" product="default" msgid="8189160597698529185">"Hiermee kan de app de inhoud van de interne mediaopslag aanpassen."</string>
-    <!-- no translation found for permlab_sdcardAccessAll (8150613823900460576) -->
-    <skip />
-    <!-- no translation found for permdesc_sdcardAccessAll (3215208357415891320) -->
-    <skip />
+    <string name="permlab_sdcardAccessAll" msgid="8150613823900460576">"toegang tot externe opslag van alle gebruikers"</string>
+    <string name="permdesc_sdcardAccessAll" msgid="3215208357415891320">"Hiermee krijgt de app toegang tot externe opslag van alle gebruikers."</string>
     <string name="permlab_cache_filesystem" msgid="5656487264819669824">"het cachebestandssysteem openen"</string>
     <string name="permdesc_cache_filesystem" msgid="5578967642265550955">"Hiermee kan de app het cachebestandssysteem lezen en schrijven."</string>
     <string name="permlab_use_sip" msgid="5986952362795870502">"internetoproepen starten/ontvangen"</string>
@@ -581,6 +579,10 @@
     <string name="policydesc_encryptedStorage" msgid="2637732115325316992">"Vereisen dat opgeslagen appgegevens kunnen worden gecodeerd."</string>
     <string name="policylab_disableCamera" msgid="6395301023152297826">"Camera\'s uitschakelen"</string>
     <string name="policydesc_disableCamera" msgid="2306349042834754597">"Het gebruik van alle apparaatcamera\'s voorkomen."</string>
+    <!-- no translation found for policylab_disableKeyguardWidgets (1794894613389073926) -->
+    <skip />
+    <!-- no translation found for policydesc_disableKeyguardWidgets (7254624892984033592) -->
+    <skip />
   <string-array name="phoneTypes">
     <item msgid="8901098336658710359">"Thuis"</item>
     <item msgid="869923650527136615">"Mobiel"</item>
@@ -1319,64 +1321,46 @@
     <string name="bluetooth_a2dp_audio_route_name" msgid="8575624030406771015">"Bluetooth-audio"</string>
     <string name="media_route_chooser_grouping_done" msgid="7966438307723317169">"Gereed"</string>
     <string name="media_route_button_content_description" msgid="5758553567065145276">"Media-uitvoer"</string>
-    <!-- no translation found for display_manager_built_in_display_name (2583134294292563941) -->
+    <string name="display_manager_built_in_display_name" msgid="2583134294292563941">"Ingebouwd scherm"</string>
+    <!-- no translation found for display_manager_hdmi_display_name (1555264559227470109) -->
     <skip />
-    <!-- no translation found for display_manager_overlay_display_name (5142365982271620716) -->
+    <string name="display_manager_overlay_display_name" msgid="5142365982271620716">"Overlay <xliff:g id="ID">%1$d</xliff:g>"</string>
+    <!-- no translation found for display_manager_overlay_display_title (652124517672257172) -->
     <skip />
-    <!-- no translation found for display_manager_overlay_display_title (8186674340178573982) -->
-    <skip />
-    <!-- no translation found for kg_emergency_call_label (684946192523830531) -->
-    <skip />
-    <!-- no translation found for kg_forgot_pattern_button_text (8852021467868220608) -->
-    <skip />
-    <!-- no translation found for kg_wrong_pattern (1850806070801358830) -->
-    <skip />
-    <!-- no translation found for kg_wrong_password (2333281762128113157) -->
-    <skip />
-    <!-- no translation found for kg_wrong_pin (1131306510833563801) -->
-    <skip />
-    <!-- no translation found for kg_too_many_failed_attempts_countdown (353963338189371686) -->
-    <skip />
-    <!-- no translation found for kg_pattern_instructions (398978611683075868) -->
-    <skip />
-    <!-- no translation found for kg_sim_pin_instructions (2319508550934557331) -->
-    <skip />
-    <!-- no translation found for kg_pin_instructions (2377242233495111557) -->
-    <skip />
-    <!-- no translation found for kg_password_instructions (5753646556186936819) -->
-    <skip />
-    <!-- no translation found for kg_puk_enter_puk_hint (5183097160254244459) -->
-    <skip />
-    <!-- no translation found for kg_puk_enter_pin_hint (597821135578014901) -->
-    <skip />
-    <!-- no translation found for kg_sim_unlock_progress_dialog_message (8950398016976865762) -->
-    <skip />
-    <!-- no translation found for kg_password_wrong_pin_code (1139324887413846912) -->
-    <skip />
-    <!-- no translation found for kg_invalid_sim_pin_hint (8795159358110620001) -->
-    <skip />
-    <!-- no translation found for kg_invalid_sim_puk_hint (5216603185442368307) -->
-    <skip />
-    <!-- no translation found for kg_sim_puk_recovery_hint (5577753137718442566) -->
-    <skip />
-    <!-- no translation found for kg_invalid_puk (5809955359950817326) -->
-    <skip />
-    <!-- no translation found for kg_login_too_many_attempts (6486842094005698475) -->
-    <skip />
-    <!-- no translation found for kg_login_instructions (1100551261265506448) -->
-    <skip />
-    <!-- no translation found for kg_login_username_hint (5718534272070920364) -->
-    <skip />
-    <!-- no translation found for kg_login_password_hint (9057289103827298549) -->
-    <skip />
-    <!-- no translation found for kg_login_submit_button (5355904582674054702) -->
-    <skip />
-    <!-- no translation found for kg_login_invalid_input (5754664119319872197) -->
-    <skip />
-    <!-- no translation found for kg_login_account_recovery_hint (5690709132841752974) -->
-    <skip />
-    <!-- no translation found for kg_login_checking_password (8849589033659332457) -->
-    <skip />
-    <!-- no translation found for kg_temp_back_string (5812983904056640466) -->
-    <skip />
+    <string name="kg_emergency_call_label" msgid="684946192523830531">"Noodoproep"</string>
+    <string name="kg_forgot_pattern_button_text" msgid="8852021467868220608">"Patroon vergeten"</string>
+    <string name="kg_wrong_pattern" msgid="1850806070801358830">"Onjuist patroon"</string>
+    <string name="kg_wrong_password" msgid="2333281762128113157">"Onjuist wachtwoord"</string>
+    <string name="kg_wrong_pin" msgid="1131306510833563801">"Onjuiste pincode"</string>
+    <string name="kg_too_many_failed_attempts_countdown" msgid="6358110221603297548">"Probeer het over <xliff:g id="NUMBER">%d</xliff:g> seconden opnieuw."</string>
+    <string name="kg_pattern_instructions" msgid="398978611683075868">"Teken uw patroon"</string>
+    <string name="kg_sim_pin_instructions" msgid="2319508550934557331">"Geef de pincode van de simkaart op"</string>
+    <string name="kg_pin_instructions" msgid="2377242233495111557">"Pincode opgeven"</string>
+    <string name="kg_password_instructions" msgid="5753646556186936819">"Wachtwoord invoeren"</string>
+    <string name="kg_puk_enter_puk_hint" msgid="5183097160254244459">"PUK-code"</string>
+    <string name="kg_puk_enter_pin_hint" msgid="597821135578014901">"Nieuwe pincode"</string>
+    <string name="kg_sim_unlock_progress_dialog_message" msgid="8950398016976865762">"Simkaart ontgrendelen..."</string>
+    <string name="kg_password_wrong_pin_code" msgid="1139324887413846912">"Onjuiste pincode."</string>
+    <string name="kg_invalid_sim_pin_hint" msgid="8795159358110620001">"Voer een pincode van 4 tot 8 cijfers in."</string>
+    <string name="kg_invalid_sim_puk_hint" msgid="5216603185442368307">"Typ een PUK-code die 8 cijfers of langer is."</string>
+    <string name="kg_sim_puk_recovery_hint" msgid="5577753137718442566">"Geef de PUK-code en de nieuwe pincode op"</string>
+    <string name="kg_invalid_puk" msgid="5809955359950817326">"De PUK-code die u heeft ingevoerd, is onjuist."</string>
+    <string name="kg_login_too_many_attempts" msgid="6486842094005698475">"Te veel patroonpogingen"</string>
+    <string name="kg_login_instructions" msgid="1100551261265506448">"Als u wilt ontgrendelen, moet u zich aanmelden bij uw Google-account."</string>
+    <string name="kg_login_username_hint" msgid="5718534272070920364">"Gebruikersnaam (e-mail)"</string>
+    <string name="kg_login_password_hint" msgid="9057289103827298549">"Wachtwoord"</string>
+    <string name="kg_login_submit_button" msgid="5355904582674054702">"Aanmelden"</string>
+    <string name="kg_login_invalid_input" msgid="5754664119319872197">"Ongeldige gebruikersnaam of wachtwoord."</string>
+    <string name="kg_login_account_recovery_hint" msgid="5690709132841752974">"Bent u uw gebruikersnaam of wachtwoord vergeten?"\n"Ga naar "<b>"google.com/accounts/recovery"</b>"."</string>
+    <string name="kg_login_checking_password" msgid="8849589033659332457">"Controleren…"</string>
+    <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="8276745642049502550">"U heeft uw pincode <xliff:g id="NUMBER_0">%d</xliff:g> keer onjuist getypt. "\n\n"Probeer het over <xliff:g id="NUMBER_1">%d</xliff:g> seconden opnieuw."</string>
+    <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="7813713389422226531">"U heeft uw wachtwoord <xliff:g id="NUMBER_0">%d</xliff:g> keer onjuist getypt. "\n\n"Probeer het over <xliff:g id="NUMBER_1">%d</xliff:g> seconden opnieuw."</string>
+    <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="74089475965050805">"U heeft uw ontgrendelingspatroon <xliff:g id="NUMBER_0">%d</xliff:g> keer onjuist getekend. "\n\n"Probeer het over <xliff:g id="NUMBER_1">%d</xliff:g> seconden opnieuw."</string>
+    <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="1575557200627128949">"U heeft <xliff:g id="NUMBER_0">%d</xliff:g> keer geprobeerd de tablet op een onjuiste manier te ontgrendelen. Na nog eens <xliff:g id="NUMBER_1">%d</xliff:g> mislukte pogingen worden de fabrieksinstellingen hersteld op de tablet en gaan alle gebruikersgegevens verloren."</string>
+    <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="4051015943038199910">"U heeft nu <xliff:g id="NUMBER_0">%d</xliff:g> keer geprobeerd de telefoon op een onjuiste manier te ontgrendelen. Na nog eens <xliff:g id="NUMBER_1">%d</xliff:g> mislukte pogingen worden de fabrieksinstellingen hersteld op de telefoon en gaan alle gebruikersgegevens verloren."</string>
+    <string name="kg_failed_attempts_now_wiping" product="tablet" msgid="2072996269148483637">"U heeft <xliff:g id="NUMBER">%d</xliff:g> keer geprobeerd de tablet op een onjuiste manier te ontgrendelen. De fabrieksinstellingen worden nu hersteld op de tablet."</string>
+    <string name="kg_failed_attempts_now_wiping" product="default" msgid="4817627474419471518">"U heeft <xliff:g id="NUMBER">%d</xliff:g> keer geprobeerd de telefoon op een onjuiste manier te ontgrendelen. De fabrieksinstellingen worden nu hersteld op de telefoon."</string>
+    <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"U heeft uw ontgrendelingspatroon <xliff:g id="NUMBER_0">%d</xliff:g> keer onjuist getekend. Na nog eens <xliff:g id="NUMBER_1">%d</xliff:g> mislukte pogingen wordt u gevraagd uw tablet te ontgrendelen via een e-mailaccount."\n\n" Probeer het over <xliff:g id="NUMBER_2">%d</xliff:g> seconden opnieuw."</string>
+    <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"U heeft uw ontgrendelingspatroon <xliff:g id="NUMBER_0">%d</xliff:g> keer onjuist getekend. Na nog eens <xliff:g id="NUMBER_1">%d</xliff:g> mislukte pogingen wordt u gevraagd uw telefoon te ontgrendelen via een e-mailaccount."\n\n" Probeer het over <xliff:g id="NUMBER_2">%d</xliff:g> seconden opnieuw."</string>
+    <string name="kg_temp_back_string" msgid="5812983904056640466">"&lt;"</string>
 </resources>
diff --git a/core/res/res/values-pl/strings.xml b/core/res/res/values-pl/strings.xml
index bdea11f..66995e9 100644
--- a/core/res/res/values-pl/strings.xml
+++ b/core/res/res/values-pl/strings.xml
@@ -547,10 +547,8 @@
     <string name="permdesc_sdcardWrite" product="default" msgid="4337417790936632090">"Pozwala aplikacji na zapis na karcie SD."</string>
     <string name="permlab_mediaStorageWrite" product="default" msgid="6859839199706879015">"modyfikowanie/usuwanie zawartości pamięci wew."</string>
     <string name="permdesc_mediaStorageWrite" product="default" msgid="8189160597698529185">"Pozwala aplikacji na modyfikowanie zawartości pamięci wewnętrznej."</string>
-    <!-- no translation found for permlab_sdcardAccessAll (8150613823900460576) -->
-    <skip />
-    <!-- no translation found for permdesc_sdcardAccessAll (3215208357415891320) -->
-    <skip />
+    <string name="permlab_sdcardAccessAll" msgid="8150613823900460576">"dostęp do zewnętrznej pamięci wszystkich użytkowników"</string>
+    <string name="permdesc_sdcardAccessAll" msgid="3215208357415891320">"Pozwala aplikacji na dostęp do zewnętrznej pamięci masowej dla wszystkich użytkowników."</string>
     <string name="permlab_cache_filesystem" msgid="5656487264819669824">"dostęp do systemu plików pamięci podręcznej"</string>
     <string name="permdesc_cache_filesystem" msgid="5578967642265550955">"Pozwala aplikacji na odczyt i zapis w systemie plików pamięci podręcznej."</string>
     <string name="permlab_use_sip" msgid="5986952362795870502">"nawiązywanie/odbieranie połączeń przez internet"</string>
@@ -581,6 +579,10 @@
     <string name="policydesc_encryptedStorage" msgid="2637732115325316992">"Wymaganie szyfrowania przechowywanych danych aplikacji"</string>
     <string name="policylab_disableCamera" msgid="6395301023152297826">"Wyłącz aparaty"</string>
     <string name="policydesc_disableCamera" msgid="2306349042834754597">"Zapobieganie używaniu wszystkich aparatów w urządzeniu"</string>
+    <!-- no translation found for policylab_disableKeyguardWidgets (1794894613389073926) -->
+    <skip />
+    <!-- no translation found for policydesc_disableKeyguardWidgets (7254624892984033592) -->
+    <skip />
   <string-array name="phoneTypes">
     <item msgid="8901098336658710359">"Dom"</item>
     <item msgid="869923650527136615">"Komórka"</item>
@@ -1319,64 +1321,46 @@
     <string name="bluetooth_a2dp_audio_route_name" msgid="8575624030406771015">"Dźwięk Bluetooth"</string>
     <string name="media_route_chooser_grouping_done" msgid="7966438307723317169">"Gotowe"</string>
     <string name="media_route_button_content_description" msgid="5758553567065145276">"Wyjście multimediów"</string>
-    <!-- no translation found for display_manager_built_in_display_name (2583134294292563941) -->
+    <string name="display_manager_built_in_display_name" msgid="2583134294292563941">"Wbudowany ekran"</string>
+    <!-- no translation found for display_manager_hdmi_display_name (1555264559227470109) -->
     <skip />
-    <!-- no translation found for display_manager_overlay_display_name (5142365982271620716) -->
+    <string name="display_manager_overlay_display_name" msgid="5142365982271620716">"Nakładka nr <xliff:g id="ID">%1$d</xliff:g>"</string>
+    <!-- no translation found for display_manager_overlay_display_title (652124517672257172) -->
     <skip />
-    <!-- no translation found for display_manager_overlay_display_title (8186674340178573982) -->
-    <skip />
-    <!-- no translation found for kg_emergency_call_label (684946192523830531) -->
-    <skip />
-    <!-- no translation found for kg_forgot_pattern_button_text (8852021467868220608) -->
-    <skip />
-    <!-- no translation found for kg_wrong_pattern (1850806070801358830) -->
-    <skip />
-    <!-- no translation found for kg_wrong_password (2333281762128113157) -->
-    <skip />
-    <!-- no translation found for kg_wrong_pin (1131306510833563801) -->
-    <skip />
-    <!-- no translation found for kg_too_many_failed_attempts_countdown (353963338189371686) -->
-    <skip />
-    <!-- no translation found for kg_pattern_instructions (398978611683075868) -->
-    <skip />
-    <!-- no translation found for kg_sim_pin_instructions (2319508550934557331) -->
-    <skip />
-    <!-- no translation found for kg_pin_instructions (2377242233495111557) -->
-    <skip />
-    <!-- no translation found for kg_password_instructions (5753646556186936819) -->
-    <skip />
-    <!-- no translation found for kg_puk_enter_puk_hint (5183097160254244459) -->
-    <skip />
-    <!-- no translation found for kg_puk_enter_pin_hint (597821135578014901) -->
-    <skip />
-    <!-- no translation found for kg_sim_unlock_progress_dialog_message (8950398016976865762) -->
-    <skip />
-    <!-- no translation found for kg_password_wrong_pin_code (1139324887413846912) -->
-    <skip />
-    <!-- no translation found for kg_invalid_sim_pin_hint (8795159358110620001) -->
-    <skip />
-    <!-- no translation found for kg_invalid_sim_puk_hint (5216603185442368307) -->
-    <skip />
-    <!-- no translation found for kg_sim_puk_recovery_hint (5577753137718442566) -->
-    <skip />
-    <!-- no translation found for kg_invalid_puk (5809955359950817326) -->
-    <skip />
-    <!-- no translation found for kg_login_too_many_attempts (6486842094005698475) -->
-    <skip />
-    <!-- no translation found for kg_login_instructions (1100551261265506448) -->
-    <skip />
-    <!-- no translation found for kg_login_username_hint (5718534272070920364) -->
-    <skip />
-    <!-- no translation found for kg_login_password_hint (9057289103827298549) -->
-    <skip />
-    <!-- no translation found for kg_login_submit_button (5355904582674054702) -->
-    <skip />
-    <!-- no translation found for kg_login_invalid_input (5754664119319872197) -->
-    <skip />
-    <!-- no translation found for kg_login_account_recovery_hint (5690709132841752974) -->
-    <skip />
-    <!-- no translation found for kg_login_checking_password (8849589033659332457) -->
-    <skip />
-    <!-- no translation found for kg_temp_back_string (5812983904056640466) -->
-    <skip />
+    <string name="kg_emergency_call_label" msgid="684946192523830531">"Połączenie alarmowe"</string>
+    <string name="kg_forgot_pattern_button_text" msgid="8852021467868220608">"Nie pamiętam wzoru"</string>
+    <string name="kg_wrong_pattern" msgid="1850806070801358830">"Nieprawidłowy wzór"</string>
+    <string name="kg_wrong_password" msgid="2333281762128113157">"Nieprawidłowe hasło"</string>
+    <string name="kg_wrong_pin" msgid="1131306510833563801">"Nieprawidłowy PIN"</string>
+    <string name="kg_too_many_failed_attempts_countdown" msgid="6358110221603297548">"Spróbuj ponownie za <xliff:g id="NUMBER">%d</xliff:g> s."</string>
+    <string name="kg_pattern_instructions" msgid="398978611683075868">"Narysuj swój wzór"</string>
+    <string name="kg_sim_pin_instructions" msgid="2319508550934557331">"Podaj PIN karty SIM"</string>
+    <string name="kg_pin_instructions" msgid="2377242233495111557">"Podaj PIN"</string>
+    <string name="kg_password_instructions" msgid="5753646556186936819">"Wpisz hasło"</string>
+    <string name="kg_puk_enter_puk_hint" msgid="5183097160254244459">"PUK"</string>
+    <string name="kg_puk_enter_pin_hint" msgid="597821135578014901">"Nowy PIN"</string>
+    <string name="kg_sim_unlock_progress_dialog_message" msgid="8950398016976865762">"Odblokowuję kartę SIM…"</string>
+    <string name="kg_password_wrong_pin_code" msgid="1139324887413846912">"Nieprawidłowy PIN."</string>
+    <string name="kg_invalid_sim_pin_hint" msgid="8795159358110620001">"Wpisz PIN o długości od 4 do 8 cyfr."</string>
+    <string name="kg_invalid_sim_puk_hint" msgid="5216603185442368307">"Wpisz PUK składający się z co najmniej 8 cyfr."</string>
+    <string name="kg_sim_puk_recovery_hint" msgid="5577753137718442566">"Wpisz PUK i nowy PIN"</string>
+    <string name="kg_invalid_puk" msgid="5809955359950817326">"Podany PUK jest nieprawidłowy."</string>
+    <string name="kg_login_too_many_attempts" msgid="6486842094005698475">"Zbyt wiele prób narysowania wzoru"</string>
+    <string name="kg_login_instructions" msgid="1100551261265506448">"Aby odblokować, zaloguj się na konto Google."</string>
+    <string name="kg_login_username_hint" msgid="5718534272070920364">"Nazwa użytkownika (e-mail)"</string>
+    <string name="kg_login_password_hint" msgid="9057289103827298549">"Hasło"</string>
+    <string name="kg_login_submit_button" msgid="5355904582674054702">"Zaloguj się"</string>
+    <string name="kg_login_invalid_input" msgid="5754664119319872197">"Nieprawidłowa nazwa użytkownika lub hasło."</string>
+    <string name="kg_login_account_recovery_hint" msgid="5690709132841752974">"Nie pamiętasz nazwy użytkownika lub hasła?"\n"Wejdź na stronę "<b>"google.com/accounts/recovery"</b>"."</string>
+    <string name="kg_login_checking_password" msgid="8849589033659332457">"Sprawdzam…"</string>
+    <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="8276745642049502550">"Po raz <xliff:g id="NUMBER_0">%d</xliff:g> wpisałeś nieprawidłowy PIN. "\n\n"Spróbuj ponownie za <xliff:g id="NUMBER_1">%d</xliff:g> s."</string>
+    <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="7813713389422226531">"Po raz <xliff:g id="NUMBER_0">%d</xliff:g> wpisałeś nieprawidłowe hasło. "\n\n"Spróbuj ponownie za <xliff:g id="NUMBER_1">%d</xliff:g> s."</string>
+    <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="74089475965050805">"Po raz <xliff:g id="NUMBER_0">%d</xliff:g> narysowałeś nieprawidłowy wzór odblokowania. "\n\n"Spróbuj ponownie za <xliff:g id="NUMBER_1">%d</xliff:g> s."</string>
+    <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="1575557200627128949">"Po raz <xliff:g id="NUMBER_0">%d</xliff:g> próbowałeś nieprawidłowo odblokować tablet. Po kolejnych <xliff:g id="NUMBER_1">%d</xliff:g> nieudanych próbach tablet zostanie zresetowany do ustawień fabrycznych, a wszystkie dane użytkownika zostaną utracone."</string>
+    <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="4051015943038199910">"Po raz <xliff:g id="NUMBER_0">%d</xliff:g> próbowałeś nieprawidłowo odblokować telefon. Po kolejnych <xliff:g id="NUMBER_1">%d</xliff:g> nieudanych próbach telefon zostanie zresetowany do ustawień fabrycznych, a wszystkie dane użytkownika zostaną utracone."</string>
+    <string name="kg_failed_attempts_now_wiping" product="tablet" msgid="2072996269148483637">"Po raz <xliff:g id="NUMBER">%d</xliff:g> próbowałeś nieprawidłowo odblokować tablet. Tablet zostanie teraz zresetowany do ustawień fabrycznych."</string>
+    <string name="kg_failed_attempts_now_wiping" product="default" msgid="4817627474419471518">"Po raz <xliff:g id="NUMBER">%d</xliff:g> próbowałeś nieprawidłowo odblokować telefon. Telefon zostanie teraz zresetowany do ustawień fabrycznych."</string>
+    <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"Po raz <xliff:g id="NUMBER_0">%d</xliff:g> nieprawidłowo narysowałeś wzór odblokowania. Po kolejnych <xliff:g id="NUMBER_1">%d</xliff:g> nieudanych próbach konieczne będzie odblokowanie tabletu przy użyciu danych logowania na konto Google."\n\n" Spróbuj ponownie za <xliff:g id="NUMBER_2">%d</xliff:g> s."</string>
+    <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"Po raz <xliff:g id="NUMBER_0">%d</xliff:g> nieprawidłowo narysowałeś wzór odblokowania. Po kolejnych <xliff:g id="NUMBER_1">%d</xliff:g> nieudanych próbach konieczne będzie odblokowanie telefonu przy użyciu danych logowania na konto Google."\n\n" Spróbuj ponownie za <xliff:g id="NUMBER_2">%d</xliff:g> s."</string>
+    <string name="kg_temp_back_string" msgid="5812983904056640466">"&lt;"</string>
 </resources>
diff --git a/core/res/res/values-pt-rPT/strings.xml b/core/res/res/values-pt-rPT/strings.xml
index 390faaa..892c88e 100644
--- a/core/res/res/values-pt-rPT/strings.xml
+++ b/core/res/res/values-pt-rPT/strings.xml
@@ -547,10 +547,8 @@
     <string name="permdesc_sdcardWrite" product="default" msgid="4337417790936632090">"Permite que a aplicação escreva no cartão SD."</string>
     <string name="permlab_mediaStorageWrite" product="default" msgid="6859839199706879015">"modif./elim. armaz. interno"</string>
     <string name="permdesc_mediaStorageWrite" product="default" msgid="8189160597698529185">"Permite que a aplicação modifique o conteúdo de armazenamento de suportes internos."</string>
-    <!-- no translation found for permlab_sdcardAccessAll (8150613823900460576) -->
-    <skip />
-    <!-- no translation found for permdesc_sdcardAccessAll (3215208357415891320) -->
-    <skip />
+    <string name="permlab_sdcardAccessAll" msgid="8150613823900460576">"aceder ao armazenamento externo de todos os utilizadores"</string>
+    <string name="permdesc_sdcardAccessAll" msgid="3215208357415891320">"Permite que a aplicação aceda ao armazenamento externo para todos os utilizadores."</string>
     <string name="permlab_cache_filesystem" msgid="5656487264819669824">"aceder ao sistema de ficheiros da cache"</string>
     <string name="permdesc_cache_filesystem" msgid="5578967642265550955">"Permite à aplicação ler e escrever no sistema de ficheiros da cache."</string>
     <string name="permlab_use_sip" msgid="5986952362795870502">"fazer/receber chamadas pela internet"</string>
@@ -581,6 +579,10 @@
     <string name="policydesc_encryptedStorage" msgid="2637732115325316992">"Solicitar encriptação dos dados da aplicação armazenados."</string>
     <string name="policylab_disableCamera" msgid="6395301023152297826">"Desativar câmaras"</string>
     <string name="policydesc_disableCamera" msgid="2306349042834754597">"Evitar a utilização de todas as câmaras do aparelho."</string>
+    <!-- no translation found for policylab_disableKeyguardWidgets (1794894613389073926) -->
+    <skip />
+    <!-- no translation found for policydesc_disableKeyguardWidgets (7254624892984033592) -->
+    <skip />
   <string-array name="phoneTypes">
     <item msgid="8901098336658710359">"Residência"</item>
     <item msgid="869923650527136615">"Móvel"</item>
@@ -1319,64 +1321,46 @@
     <string name="bluetooth_a2dp_audio_route_name" msgid="8575624030406771015">"Áudio Bluetooth"</string>
     <string name="media_route_chooser_grouping_done" msgid="7966438307723317169">"Concluído"</string>
     <string name="media_route_button_content_description" msgid="5758553567065145276">"Saída de som multimédia"</string>
-    <!-- no translation found for display_manager_built_in_display_name (2583134294292563941) -->
+    <string name="display_manager_built_in_display_name" msgid="2583134294292563941">"Ecrã Integrado"</string>
+    <!-- no translation found for display_manager_hdmi_display_name (1555264559227470109) -->
     <skip />
-    <!-- no translation found for display_manager_overlay_display_name (5142365982271620716) -->
+    <string name="display_manager_overlay_display_name" msgid="5142365982271620716">"Sobreposição #<xliff:g id="ID">%1$d</xliff:g>"</string>
+    <!-- no translation found for display_manager_overlay_display_title (652124517672257172) -->
     <skip />
-    <!-- no translation found for display_manager_overlay_display_title (8186674340178573982) -->
-    <skip />
-    <!-- no translation found for kg_emergency_call_label (684946192523830531) -->
-    <skip />
-    <!-- no translation found for kg_forgot_pattern_button_text (8852021467868220608) -->
-    <skip />
-    <!-- no translation found for kg_wrong_pattern (1850806070801358830) -->
-    <skip />
-    <!-- no translation found for kg_wrong_password (2333281762128113157) -->
-    <skip />
-    <!-- no translation found for kg_wrong_pin (1131306510833563801) -->
-    <skip />
-    <!-- no translation found for kg_too_many_failed_attempts_countdown (353963338189371686) -->
-    <skip />
-    <!-- no translation found for kg_pattern_instructions (398978611683075868) -->
-    <skip />
-    <!-- no translation found for kg_sim_pin_instructions (2319508550934557331) -->
-    <skip />
-    <!-- no translation found for kg_pin_instructions (2377242233495111557) -->
-    <skip />
-    <!-- no translation found for kg_password_instructions (5753646556186936819) -->
-    <skip />
-    <!-- no translation found for kg_puk_enter_puk_hint (5183097160254244459) -->
-    <skip />
-    <!-- no translation found for kg_puk_enter_pin_hint (597821135578014901) -->
-    <skip />
-    <!-- no translation found for kg_sim_unlock_progress_dialog_message (8950398016976865762) -->
-    <skip />
-    <!-- no translation found for kg_password_wrong_pin_code (1139324887413846912) -->
-    <skip />
-    <!-- no translation found for kg_invalid_sim_pin_hint (8795159358110620001) -->
-    <skip />
-    <!-- no translation found for kg_invalid_sim_puk_hint (5216603185442368307) -->
-    <skip />
-    <!-- no translation found for kg_sim_puk_recovery_hint (5577753137718442566) -->
-    <skip />
-    <!-- no translation found for kg_invalid_puk (5809955359950817326) -->
-    <skip />
-    <!-- no translation found for kg_login_too_many_attempts (6486842094005698475) -->
-    <skip />
-    <!-- no translation found for kg_login_instructions (1100551261265506448) -->
-    <skip />
-    <!-- no translation found for kg_login_username_hint (5718534272070920364) -->
-    <skip />
-    <!-- no translation found for kg_login_password_hint (9057289103827298549) -->
-    <skip />
-    <!-- no translation found for kg_login_submit_button (5355904582674054702) -->
-    <skip />
-    <!-- no translation found for kg_login_invalid_input (5754664119319872197) -->
-    <skip />
-    <!-- no translation found for kg_login_account_recovery_hint (5690709132841752974) -->
-    <skip />
-    <!-- no translation found for kg_login_checking_password (8849589033659332457) -->
-    <skip />
-    <!-- no translation found for kg_temp_back_string (5812983904056640466) -->
-    <skip />
+    <string name="kg_emergency_call_label" msgid="684946192523830531">"Chamada de emergência"</string>
+    <string name="kg_forgot_pattern_button_text" msgid="8852021467868220608">"Esqueceu-se da Sequência"</string>
+    <string name="kg_wrong_pattern" msgid="1850806070801358830">"Sequência Incorreta"</string>
+    <string name="kg_wrong_password" msgid="2333281762128113157">"Palavra-passe Incorreta"</string>
+    <string name="kg_wrong_pin" msgid="1131306510833563801">"PIN Incorreto"</string>
+    <string name="kg_too_many_failed_attempts_countdown" msgid="6358110221603297548">"Tente novamente dentro de <xliff:g id="NUMBER">%d</xliff:g> segundos."</string>
+    <string name="kg_pattern_instructions" msgid="398978611683075868">"Desenhe a sua sequência"</string>
+    <string name="kg_sim_pin_instructions" msgid="2319508550934557331">"Introduzir PIN do cartão SIM"</string>
+    <string name="kg_pin_instructions" msgid="2377242233495111557">"Introduzir PIN"</string>
+    <string name="kg_password_instructions" msgid="5753646556186936819">"Introduzir Palavra-passe"</string>
+    <string name="kg_puk_enter_puk_hint" msgid="5183097160254244459">"Código PUK"</string>
+    <string name="kg_puk_enter_pin_hint" msgid="597821135578014901">"Novo código PIN"</string>
+    <string name="kg_sim_unlock_progress_dialog_message" msgid="8950398016976865762">"A desbloquear cartão SIM..."</string>
+    <string name="kg_password_wrong_pin_code" msgid="1139324887413846912">"Código PIN incorreto."</string>
+    <string name="kg_invalid_sim_pin_hint" msgid="8795159358110620001">"Introduza um PIN entre 4 e 8 números."</string>
+    <string name="kg_invalid_sim_puk_hint" msgid="5216603185442368307">"Introduza um PUK que tenha 8 ou mais algarismos."</string>
+    <string name="kg_sim_puk_recovery_hint" msgid="5577753137718442566">"Introduzir PUK e o novo código PIN"</string>
+    <string name="kg_invalid_puk" msgid="5809955359950817326">"O PUK que introduziu não está correto."</string>
+    <string name="kg_login_too_many_attempts" msgid="6486842094005698475">"Demasiadas tentativas para desenhar sequência"</string>
+    <string name="kg_login_instructions" msgid="1100551261265506448">"Para desbloquear, inicie sessão com a sua Conta do Google."</string>
+    <string name="kg_login_username_hint" msgid="5718534272070920364">"Nome de utilizador (mail)"</string>
+    <string name="kg_login_password_hint" msgid="9057289103827298549">"Palavra-passe"</string>
+    <string name="kg_login_submit_button" msgid="5355904582674054702">"Iniciar sessão"</string>
+    <string name="kg_login_invalid_input" msgid="5754664119319872197">"Nome de utilizador ou palavra-passe inválidos."</string>
+    <string name="kg_login_account_recovery_hint" msgid="5690709132841752974">"Esqueceu-se do nome de utilizador ou da palavra-passe?"\n"Aceda a "<b>"google.com/accounts/recovery"</b>"."</string>
+    <string name="kg_login_checking_password" msgid="8849589033659332457">"A verificar…"</string>
+    <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="8276745642049502550">"Escreveu o PIN incorretamente <xliff:g id="NUMBER_0">%d</xliff:g> vezes. "\n\n"Tente novamente dentro de <xliff:g id="NUMBER_1">%d</xliff:g> segundos."</string>
+    <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="7813713389422226531">"Escreveu a palavra-passe incorretamente <xliff:g id="NUMBER_0">%d</xliff:g> vezes. "\n\n"Tente novamente dentro de <xliff:g id="NUMBER_1">%d</xliff:g> segundos."</string>
+    <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="74089475965050805">"Desenhou a sua sequência de desbloqueio incorretamente <xliff:g id="NUMBER_0">%d</xliff:g> vezes. "\n\n"Tente novamente dentro de <xliff:g id="NUMBER_1">%d</xliff:g> segundos."</string>
+    <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="1575557200627128949">"Tentou desbloquear o tablet <xliff:g id="NUMBER_0">%d</xliff:g> vezes de forma incorreta. Depois de mais <xliff:g id="NUMBER_1">%d</xliff:g> tentativas sem êxito, as definições de origem do telemóvel serão repostas e todos os dados do utilizador serão perdidos."</string>
+    <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="4051015943038199910">"Tentou desbloquear o telemóvel <xliff:g id="NUMBER_0">%d</xliff:g> vezes de forma incorreta. Depois de mais <xliff:g id="NUMBER_1">%d</xliff:g> tentativas sem êxito, as definições de origem do telemóvel serão repostas e todos os dados do utilizador serão perdidos."</string>
+    <string name="kg_failed_attempts_now_wiping" product="tablet" msgid="2072996269148483637">"Tentou desbloquear o tablet <xliff:g id="NUMBER">%d</xliff:g> vezes de forma incorreta, pelo que será reposta a predefinição de fábrica."</string>
+    <string name="kg_failed_attempts_now_wiping" product="default" msgid="4817627474419471518">"Tentou desbloquear o telemóvel <xliff:g id="NUMBER">%d</xliff:g> vezes de forma incorreta, pelo que será reposta a predefinição de fábrica."</string>
+    <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"Desenhou a sequência de desbloqueio incorretamente <xliff:g id="NUMBER_0">%d</xliff:g> vezes. Depois de mais <xliff:g id="NUMBER_1">%d</xliff:g> tentativas sem sucesso, ser-lhe-á pedido para desbloquear o tablet através de uma conta de email."\n\n" Tente novamente dentro de <xliff:g id="NUMBER_2">%d</xliff:g> segundos."</string>
+    <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"Desenhou a sequência de desbloqueio incorretamente <xliff:g id="NUMBER_0">%d</xliff:g> vezes. Depois de mais <xliff:g id="NUMBER_1">%d</xliff:g> tentativas sem sucesso, ser-lhe-á pedido para desbloquear o telemóvel através de uma conta de email."\n\n" Tente novamente dentro de <xliff:g id="NUMBER_2">%d</xliff:g> segundos."</string>
+    <string name="kg_temp_back_string" msgid="5812983904056640466">"&lt;"</string>
 </resources>
diff --git a/core/res/res/values-pt/strings.xml b/core/res/res/values-pt/strings.xml
index 5ec23f9..812edff 100644
--- a/core/res/res/values-pt/strings.xml
+++ b/core/res/res/values-pt/strings.xml
@@ -547,10 +547,8 @@
     <string name="permdesc_sdcardWrite" product="default" msgid="4337417790936632090">"Permite que o aplicativo grave em seu cartão SD."</string>
     <string name="permlab_mediaStorageWrite" product="default" msgid="6859839199706879015">"modificar/excluir conteúdos de armazenamento de mídia internos"</string>
     <string name="permdesc_mediaStorageWrite" product="default" msgid="8189160597698529185">"Permite que o aplicativo modifique o conteúdo da mídia de armazenamento interno."</string>
-    <!-- no translation found for permlab_sdcardAccessAll (8150613823900460576) -->
-    <skip />
-    <!-- no translation found for permdesc_sdcardAccessAll (3215208357415891320) -->
-    <skip />
+    <string name="permlab_sdcardAccessAll" msgid="8150613823900460576">"acessar arm. ext. dos usuários"</string>
+    <string name="permdesc_sdcardAccessAll" msgid="3215208357415891320">"Permite que o aplicativo acesse o armazenamento externo para todos os usuários."</string>
     <string name="permlab_cache_filesystem" msgid="5656487264819669824">"acessar o sistema de arquivos de cache"</string>
     <string name="permdesc_cache_filesystem" msgid="5578967642265550955">"Permite que o aplicativo leia e grave o sistema de arquivos cache."</string>
     <string name="permlab_use_sip" msgid="5986952362795870502">"fazer/receber chamadas pela internet"</string>
@@ -581,6 +579,10 @@
     <string name="policydesc_encryptedStorage" msgid="2637732115325316992">"Exija que os dados armazenados do aplicativo sejam criptografados."</string>
     <string name="policylab_disableCamera" msgid="6395301023152297826">"Desativar câmeras"</string>
     <string name="policydesc_disableCamera" msgid="2306349042834754597">"Impeça o uso de todas as câmeras do dispositivo."</string>
+    <!-- no translation found for policylab_disableKeyguardWidgets (1794894613389073926) -->
+    <skip />
+    <!-- no translation found for policydesc_disableKeyguardWidgets (7254624892984033592) -->
+    <skip />
   <string-array name="phoneTypes">
     <item msgid="8901098336658710359">"Residencial"</item>
     <item msgid="869923650527136615">"Celular"</item>
@@ -712,8 +714,8 @@
     <string name="lockscreen_emergency_call" msgid="5347633784401285225">"Chamada de emergência"</string>
     <string name="lockscreen_return_to_call" msgid="5244259785500040021">"Retornar à chamada"</string>
     <string name="lockscreen_pattern_correct" msgid="9039008650362261237">"Correto!"</string>
-    <string name="lockscreen_pattern_wrong" msgid="4317955014948108794">"Tentar novamente"</string>
-    <string name="lockscreen_password_wrong" msgid="5737815393253165301">"Tentar novamente"</string>
+    <string name="lockscreen_pattern_wrong" msgid="4317955014948108794">"Tente novamente"</string>
+    <string name="lockscreen_password_wrong" msgid="5737815393253165301">"Tente novamente"</string>
     <string name="faceunlock_multiple_failures" msgid="754137583022792429">"O número máximo de tentativas de Desbloqueio por reconhecimento facial foi excedido"</string>
     <string name="lockscreen_plugged_in" msgid="8057762828355572315">"Carregando, <xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENT">%%</xliff:g>"</string>
     <string name="lockscreen_charged" msgid="4938930459620989972">"Carregado."</string>
@@ -1171,14 +1173,10 @@
     <string name="vpn_title_long" msgid="6400714798049252294">"A VPN está ativada por <xliff:g id="APP">%s</xliff:g>"</string>
     <string name="vpn_text" msgid="3011306607126450322">"Toque para gerenciar a rede."</string>
     <string name="vpn_text_long" msgid="6407351006249174473">"Conectado a <xliff:g id="SESSION">%s</xliff:g>. Toque para gerenciar a rede."</string>
-    <!-- no translation found for vpn_lockdown_connecting (6443438964440960745) -->
-    <skip />
-    <!-- no translation found for vpn_lockdown_connected (8202679674819213931) -->
-    <skip />
-    <!-- no translation found for vpn_lockdown_error (6009249814034708175) -->
-    <skip />
-    <!-- no translation found for vpn_lockdown_reset (5365010427963548932) -->
-    <skip />
+    <string name="vpn_lockdown_connecting" msgid="6443438964440960745">"VPN sempre ativa conectando..."</string>
+    <string name="vpn_lockdown_connected" msgid="8202679674819213931">"VPN sempre ativa conectada"</string>
+    <string name="vpn_lockdown_error" msgid="6009249814034708175">"Erro na VPN sempre ativa"</string>
+    <string name="vpn_lockdown_reset" msgid="5365010427963548932">"Toque para redefinir a conexão"</string>
     <string name="upload_file" msgid="2897957172366730416">"Escolher arquivo"</string>
     <string name="no_file_chosen" msgid="6363648562170759465">"Nenhum arquivo escolhido"</string>
     <string name="reset" msgid="2448168080964209908">"Redefinir"</string>
@@ -1323,64 +1321,46 @@
     <string name="bluetooth_a2dp_audio_route_name" msgid="8575624030406771015">"Áudio Bluetooth"</string>
     <string name="media_route_chooser_grouping_done" msgid="7966438307723317169">"Concluído"</string>
     <string name="media_route_button_content_description" msgid="5758553567065145276">"Saída de mídia"</string>
-    <!-- no translation found for display_manager_built_in_display_name (2583134294292563941) -->
+    <string name="display_manager_built_in_display_name" msgid="2583134294292563941">"Tela integrada"</string>
+    <!-- no translation found for display_manager_hdmi_display_name (1555264559227470109) -->
     <skip />
-    <!-- no translation found for display_manager_overlay_display_name (5142365982271620716) -->
+    <string name="display_manager_overlay_display_name" msgid="5142365982271620716">"Sobreposição nº <xliff:g id="ID">%1$d</xliff:g>"</string>
+    <!-- no translation found for display_manager_overlay_display_title (652124517672257172) -->
     <skip />
-    <!-- no translation found for display_manager_overlay_display_title (8186674340178573982) -->
-    <skip />
-    <!-- no translation found for kg_emergency_call_label (684946192523830531) -->
-    <skip />
-    <!-- no translation found for kg_forgot_pattern_button_text (8852021467868220608) -->
-    <skip />
-    <!-- no translation found for kg_wrong_pattern (1850806070801358830) -->
-    <skip />
-    <!-- no translation found for kg_wrong_password (2333281762128113157) -->
-    <skip />
-    <!-- no translation found for kg_wrong_pin (1131306510833563801) -->
-    <skip />
-    <!-- no translation found for kg_too_many_failed_attempts_countdown (353963338189371686) -->
-    <skip />
-    <!-- no translation found for kg_pattern_instructions (398978611683075868) -->
-    <skip />
-    <!-- no translation found for kg_sim_pin_instructions (2319508550934557331) -->
-    <skip />
-    <!-- no translation found for kg_pin_instructions (2377242233495111557) -->
-    <skip />
-    <!-- no translation found for kg_password_instructions (5753646556186936819) -->
-    <skip />
-    <!-- no translation found for kg_puk_enter_puk_hint (5183097160254244459) -->
-    <skip />
-    <!-- no translation found for kg_puk_enter_pin_hint (597821135578014901) -->
-    <skip />
-    <!-- no translation found for kg_sim_unlock_progress_dialog_message (8950398016976865762) -->
-    <skip />
-    <!-- no translation found for kg_password_wrong_pin_code (1139324887413846912) -->
-    <skip />
-    <!-- no translation found for kg_invalid_sim_pin_hint (8795159358110620001) -->
-    <skip />
-    <!-- no translation found for kg_invalid_sim_puk_hint (5216603185442368307) -->
-    <skip />
-    <!-- no translation found for kg_sim_puk_recovery_hint (5577753137718442566) -->
-    <skip />
-    <!-- no translation found for kg_invalid_puk (5809955359950817326) -->
-    <skip />
-    <!-- no translation found for kg_login_too_many_attempts (6486842094005698475) -->
-    <skip />
-    <!-- no translation found for kg_login_instructions (1100551261265506448) -->
-    <skip />
-    <!-- no translation found for kg_login_username_hint (5718534272070920364) -->
-    <skip />
-    <!-- no translation found for kg_login_password_hint (9057289103827298549) -->
-    <skip />
-    <!-- no translation found for kg_login_submit_button (5355904582674054702) -->
-    <skip />
-    <!-- no translation found for kg_login_invalid_input (5754664119319872197) -->
-    <skip />
-    <!-- no translation found for kg_login_account_recovery_hint (5690709132841752974) -->
-    <skip />
-    <!-- no translation found for kg_login_checking_password (8849589033659332457) -->
-    <skip />
-    <!-- no translation found for kg_temp_back_string (5812983904056640466) -->
-    <skip />
+    <string name="kg_emergency_call_label" msgid="684946192523830531">"Chamada de emergência"</string>
+    <string name="kg_forgot_pattern_button_text" msgid="8852021467868220608">"Esqueci o padrão"</string>
+    <string name="kg_wrong_pattern" msgid="1850806070801358830">"Padrão incorreto"</string>
+    <string name="kg_wrong_password" msgid="2333281762128113157">"Senha incorreta"</string>
+    <string name="kg_wrong_pin" msgid="1131306510833563801">"PIN incorreto"</string>
+    <string name="kg_too_many_failed_attempts_countdown" msgid="6358110221603297548">"Tente novamente em <xliff:g id="NUMBER">%d</xliff:g> segundos."</string>
+    <string name="kg_pattern_instructions" msgid="398978611683075868">"Desenhe seu padrão"</string>
+    <string name="kg_sim_pin_instructions" msgid="2319508550934557331">"Digite o PIN do cartão SIM"</string>
+    <string name="kg_pin_instructions" msgid="2377242233495111557">"Digite o PIN"</string>
+    <string name="kg_password_instructions" msgid="5753646556186936819">"Digite a senha"</string>
+    <string name="kg_puk_enter_puk_hint" msgid="5183097160254244459">"Código PUK"</string>
+    <string name="kg_puk_enter_pin_hint" msgid="597821135578014901">"Novo código PIN"</string>
+    <string name="kg_sim_unlock_progress_dialog_message" msgid="8950398016976865762">"Desbloqueando o cartão SIM…"</string>
+    <string name="kg_password_wrong_pin_code" msgid="1139324887413846912">"Código PIN incorreto."</string>
+    <string name="kg_invalid_sim_pin_hint" msgid="8795159358110620001">"Digite um PIN com quatro a oito números."</string>
+    <string name="kg_invalid_sim_puk_hint" msgid="5216603185442368307">"Digite um PUK com oito números ou mais."</string>
+    <string name="kg_sim_puk_recovery_hint" msgid="5577753137718442566">"Insira o PUK e o novo código PIN"</string>
+    <string name="kg_invalid_puk" msgid="5809955359950817326">"O PUK digitado está incorreto."</string>
+    <string name="kg_login_too_many_attempts" msgid="6486842094005698475">"Muitas tentativas de padrão"</string>
+    <string name="kg_login_instructions" msgid="1100551261265506448">"Para desbloquear, faça login usando sua Conta do Google."</string>
+    <string name="kg_login_username_hint" msgid="5718534272070920364">"Nome de usuário (e-mail)"</string>
+    <string name="kg_login_password_hint" msgid="9057289103827298549">"Senha"</string>
+    <string name="kg_login_submit_button" msgid="5355904582674054702">"Fazer login"</string>
+    <string name="kg_login_invalid_input" msgid="5754664119319872197">"Nome de usuário ou senha inválidos."</string>
+    <string name="kg_login_account_recovery_hint" msgid="5690709132841752974">"Esqueceu seu nome de usuário ou senha?"\n"Acesse "<b>"google.com.br/accounts/recovery"</b>"."</string>
+    <string name="kg_login_checking_password" msgid="8849589033659332457">"Verificando..."</string>
+    <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="8276745642049502550">"Você digitou seu PIN incorretamente <xliff:g id="NUMBER_0">%d</xliff:g> vezes. "\n\n"Tente novamente em <xliff:g id="NUMBER_1">%d</xliff:g> segundos."</string>
+    <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="7813713389422226531">"Você digitou sua senha incorretamente <xliff:g id="NUMBER_0">%d</xliff:g> vezes. "\n\n"Tente novamente em <xliff:g id="NUMBER_1">%d</xliff:g> segundos."</string>
+    <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="74089475965050805">"Você desenhou sua sequência de desbloqueio incorretamente <xliff:g id="NUMBER_0">%d</xliff:g> vezes. "\n\n"Tente novamente em <xliff:g id="NUMBER_1">%d</xliff:g> segundos."</string>
+    <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="1575557200627128949">"Você tentou desbloquear incorretamente o tablet <xliff:g id="NUMBER_0">%d</xliff:g> vezes. Após mais <xliff:g id="NUMBER_1">%d</xliff:g> tentativas malsucedidas, o tablet será redefinido para o padrão de fábrica e todos os dados do usuário serão perdidos."</string>
+    <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="4051015943038199910">"Você tentou desbloquear incorretamente o telefone <xliff:g id="NUMBER_0">%d</xliff:g> vezes. Após mais <xliff:g id="NUMBER_1">%d</xliff:g> tentativas malsucedidas, o telefone será redefinido para o padrão de fábrica e todos os dados do usuário serão perdidos."</string>
+    <string name="kg_failed_attempts_now_wiping" product="tablet" msgid="2072996269148483637">"Você tentou desbloquear incorretamente o tablet <xliff:g id="NUMBER">%d</xliff:g> vezes. O tablet será redefinido para o padrão de fábrica."</string>
+    <string name="kg_failed_attempts_now_wiping" product="default" msgid="4817627474419471518">"Você tentou desbloquear incorretamente o telefone <xliff:g id="NUMBER">%d</xliff:g> vezes. O telefone será redefinido para o padrão de fábrica."</string>
+    <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"Você desenhou sua sequência de desbloqueio incorretamente <xliff:g id="NUMBER_0">%d</xliff:g> vezes. Se fizer mais <xliff:g id="NUMBER_1">%d</xliff:g> tentativas incorretas, será solicitado que você use o login do Google para desbloquear seu tablet."\n\n" Tente novamente em <xliff:g id="NUMBER_2">%d</xliff:g> segundos."</string>
+    <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"Você desenhou sua sequência de desbloqueio incorretamente <xliff:g id="NUMBER_0">%d</xliff:g> vezes. Se fizer mais <xliff:g id="NUMBER_1">%d</xliff:g> tentativas incorretas, será solicitado que você use o login do Google para desbloquear."\n\n" Tente novamente em <xliff:g id="NUMBER_2">%d</xliff:g> segundos."</string>
+    <string name="kg_temp_back_string" msgid="5812983904056640466">"&lt;"</string>
 </resources>
diff --git a/core/res/res/values-rm/strings.xml b/core/res/res/values-rm/strings.xml
index 40fad47..bf555e8 100644
--- a/core/res/res/values-rm/strings.xml
+++ b/core/res/res/values-rm/strings.xml
@@ -951,6 +951,10 @@
     <skip />
     <!-- no translation found for policydesc_disableCamera (2306349042834754597) -->
     <skip />
+    <!-- no translation found for policylab_disableKeyguardWidgets (1794894613389073926) -->
+    <skip />
+    <!-- no translation found for policydesc_disableKeyguardWidgets (7254624892984033592) -->
+    <skip />
   <string-array name="phoneTypes">
     <item msgid="8901098336658710359">"Privat"</item>
     <item msgid="869923650527136615">"Telefonin"</item>
@@ -2084,9 +2088,11 @@
     <skip />
     <!-- no translation found for display_manager_built_in_display_name (2583134294292563941) -->
     <skip />
+    <!-- no translation found for display_manager_hdmi_display_name (1555264559227470109) -->
+    <skip />
     <!-- no translation found for display_manager_overlay_display_name (5142365982271620716) -->
     <skip />
-    <!-- no translation found for display_manager_overlay_display_title (8186674340178573982) -->
+    <!-- no translation found for display_manager_overlay_display_title (652124517672257172) -->
     <skip />
     <!-- no translation found for kg_emergency_call_label (684946192523830531) -->
     <skip />
@@ -2098,7 +2104,7 @@
     <skip />
     <!-- no translation found for kg_wrong_pin (1131306510833563801) -->
     <skip />
-    <!-- no translation found for kg_too_many_failed_attempts_countdown (353963338189371686) -->
+    <!-- no translation found for kg_too_many_failed_attempts_countdown (6358110221603297548) -->
     <skip />
     <!-- no translation found for kg_pattern_instructions (398978611683075868) -->
     <skip />
@@ -2140,6 +2146,24 @@
     <skip />
     <!-- no translation found for kg_login_checking_password (8849589033659332457) -->
     <skip />
+    <!-- no translation found for kg_too_many_failed_pin_attempts_dialog_message (8276745642049502550) -->
+    <skip />
+    <!-- no translation found for kg_too_many_failed_password_attempts_dialog_message (7813713389422226531) -->
+    <skip />
+    <!-- no translation found for kg_too_many_failed_pattern_attempts_dialog_message (74089475965050805) -->
+    <skip />
+    <!-- no translation found for kg_failed_attempts_almost_at_wipe (1575557200627128949) -->
+    <skip />
+    <!-- no translation found for kg_failed_attempts_almost_at_wipe (4051015943038199910) -->
+    <skip />
+    <!-- no translation found for kg_failed_attempts_now_wiping (2072996269148483637) -->
+    <skip />
+    <!-- no translation found for kg_failed_attempts_now_wiping (4817627474419471518) -->
+    <skip />
+    <!-- no translation found for kg_failed_attempts_almost_at_login (3253575572118914370) -->
+    <skip />
+    <!-- no translation found for kg_failed_attempts_almost_at_login (1437638152015574839) -->
+    <skip />
     <!-- no translation found for kg_temp_back_string (5812983904056640466) -->
     <skip />
 </resources>
diff --git a/core/res/res/values-ro/strings.xml b/core/res/res/values-ro/strings.xml
index 52c0c42..08dca1a 100644
--- a/core/res/res/values-ro/strings.xml
+++ b/core/res/res/values-ro/strings.xml
@@ -547,10 +547,8 @@
     <string name="permdesc_sdcardWrite" product="default" msgid="4337417790936632090">"Permite aplicaţiei să scrie pe cardul SD."</string>
     <string name="permlab_mediaStorageWrite" product="default" msgid="6859839199706879015">"modif./şterg. conţinutul media stocat intern"</string>
     <string name="permdesc_mediaStorageWrite" product="default" msgid="8189160597698529185">"Permite aplicaţiei să modifice conţinutul stocării media interne."</string>
-    <!-- no translation found for permlab_sdcardAccessAll (8150613823900460576) -->
-    <skip />
-    <!-- no translation found for permdesc_sdcardAccessAll (3215208357415891320) -->
-    <skip />
+    <string name="permlab_sdcardAccessAll" msgid="8150613823900460576">"acces. stoc. ext. pt. toţi utilizat."</string>
+    <string name="permdesc_sdcardAccessAll" msgid="3215208357415891320">"Permite aplicaţiei să acceseze stocarea externă pentru toţi utilizatorii."</string>
     <string name="permlab_cache_filesystem" msgid="5656487264819669824">"accesare sistem de fişiere cache"</string>
     <string name="permdesc_cache_filesystem" msgid="5578967642265550955">"Permite aplicaţiei să scrie şi să citească sistemul de fişiere cache."</string>
     <string name="permlab_use_sip" msgid="5986952362795870502">"efectuare/primire apeluri prin internet"</string>
@@ -581,6 +579,10 @@
     <string name="policydesc_encryptedStorage" msgid="2637732115325316992">"Necesită ca datele aplicaţiei stocate să fie criptate."</string>
     <string name="policylab_disableCamera" msgid="6395301023152297826">"Dezactivaţi camerele foto"</string>
     <string name="policydesc_disableCamera" msgid="2306349042834754597">"Împiedicaţi utilizarea camerelor foto de pe dispozitiv."</string>
+    <!-- no translation found for policylab_disableKeyguardWidgets (1794894613389073926) -->
+    <skip />
+    <!-- no translation found for policydesc_disableKeyguardWidgets (7254624892984033592) -->
+    <skip />
   <string-array name="phoneTypes">
     <item msgid="8901098336658710359">"Domiciliu"</item>
     <item msgid="869923650527136615">"Mobil"</item>
@@ -1319,64 +1321,46 @@
     <string name="bluetooth_a2dp_audio_route_name" msgid="8575624030406771015">"Audio Bluetooth"</string>
     <string name="media_route_chooser_grouping_done" msgid="7966438307723317169">"Terminat"</string>
     <string name="media_route_button_content_description" msgid="5758553567065145276">"Rezultate media"</string>
-    <!-- no translation found for display_manager_built_in_display_name (2583134294292563941) -->
+    <string name="display_manager_built_in_display_name" msgid="2583134294292563941">"Ecran încorporat"</string>
+    <!-- no translation found for display_manager_hdmi_display_name (1555264559227470109) -->
     <skip />
-    <!-- no translation found for display_manager_overlay_display_name (5142365982271620716) -->
+    <string name="display_manager_overlay_display_name" msgid="5142365982271620716">"Suprapunerea <xliff:g id="ID">%1$d</xliff:g>"</string>
+    <!-- no translation found for display_manager_overlay_display_title (652124517672257172) -->
     <skip />
-    <!-- no translation found for display_manager_overlay_display_title (8186674340178573982) -->
-    <skip />
-    <!-- no translation found for kg_emergency_call_label (684946192523830531) -->
-    <skip />
-    <!-- no translation found for kg_forgot_pattern_button_text (8852021467868220608) -->
-    <skip />
-    <!-- no translation found for kg_wrong_pattern (1850806070801358830) -->
-    <skip />
-    <!-- no translation found for kg_wrong_password (2333281762128113157) -->
-    <skip />
-    <!-- no translation found for kg_wrong_pin (1131306510833563801) -->
-    <skip />
-    <!-- no translation found for kg_too_many_failed_attempts_countdown (353963338189371686) -->
-    <skip />
-    <!-- no translation found for kg_pattern_instructions (398978611683075868) -->
-    <skip />
-    <!-- no translation found for kg_sim_pin_instructions (2319508550934557331) -->
-    <skip />
-    <!-- no translation found for kg_pin_instructions (2377242233495111557) -->
-    <skip />
-    <!-- no translation found for kg_password_instructions (5753646556186936819) -->
-    <skip />
-    <!-- no translation found for kg_puk_enter_puk_hint (5183097160254244459) -->
-    <skip />
-    <!-- no translation found for kg_puk_enter_pin_hint (597821135578014901) -->
-    <skip />
-    <!-- no translation found for kg_sim_unlock_progress_dialog_message (8950398016976865762) -->
-    <skip />
-    <!-- no translation found for kg_password_wrong_pin_code (1139324887413846912) -->
-    <skip />
-    <!-- no translation found for kg_invalid_sim_pin_hint (8795159358110620001) -->
-    <skip />
-    <!-- no translation found for kg_invalid_sim_puk_hint (5216603185442368307) -->
-    <skip />
-    <!-- no translation found for kg_sim_puk_recovery_hint (5577753137718442566) -->
-    <skip />
-    <!-- no translation found for kg_invalid_puk (5809955359950817326) -->
-    <skip />
-    <!-- no translation found for kg_login_too_many_attempts (6486842094005698475) -->
-    <skip />
-    <!-- no translation found for kg_login_instructions (1100551261265506448) -->
-    <skip />
-    <!-- no translation found for kg_login_username_hint (5718534272070920364) -->
-    <skip />
-    <!-- no translation found for kg_login_password_hint (9057289103827298549) -->
-    <skip />
-    <!-- no translation found for kg_login_submit_button (5355904582674054702) -->
-    <skip />
-    <!-- no translation found for kg_login_invalid_input (5754664119319872197) -->
-    <skip />
-    <!-- no translation found for kg_login_account_recovery_hint (5690709132841752974) -->
-    <skip />
-    <!-- no translation found for kg_login_checking_password (8849589033659332457) -->
-    <skip />
-    <!-- no translation found for kg_temp_back_string (5812983904056640466) -->
-    <skip />
+    <string name="kg_emergency_call_label" msgid="684946192523830531">"Apel de urgenţă"</string>
+    <string name="kg_forgot_pattern_button_text" msgid="8852021467868220608">"Model uitat"</string>
+    <string name="kg_wrong_pattern" msgid="1850806070801358830">"Model greşit"</string>
+    <string name="kg_wrong_password" msgid="2333281762128113157">"Parolă greşită"</string>
+    <string name="kg_wrong_pin" msgid="1131306510833563801">"Cod PIN greşit"</string>
+    <string name="kg_too_many_failed_attempts_countdown" msgid="6358110221603297548">"Încercaţi din nou peste <xliff:g id="NUMBER">%d</xliff:g> (de) secunde."</string>
+    <string name="kg_pattern_instructions" msgid="398978611683075868">"Desenaţi modelul"</string>
+    <string name="kg_sim_pin_instructions" msgid="2319508550934557331">"Introduceţi codul PIN al cardului SIM"</string>
+    <string name="kg_pin_instructions" msgid="2377242233495111557">"Introduceţi codul PIN"</string>
+    <string name="kg_password_instructions" msgid="5753646556186936819">"Introduceţi parola"</string>
+    <string name="kg_puk_enter_puk_hint" msgid="5183097160254244459">"Codul PUK"</string>
+    <string name="kg_puk_enter_pin_hint" msgid="597821135578014901">"Noul cod PIN"</string>
+    <string name="kg_sim_unlock_progress_dialog_message" msgid="8950398016976865762">"Se deblochează cardul SIM..."</string>
+    <string name="kg_password_wrong_pin_code" msgid="1139324887413846912">"Cod PIN incorect."</string>
+    <string name="kg_invalid_sim_pin_hint" msgid="8795159358110620001">"Introduceţi un cod PIN alcătuit din 4 până la 8 cifre."</string>
+    <string name="kg_invalid_sim_puk_hint" msgid="5216603185442368307">"Introduceţi un cod PUK care să aibă 8 cifre sau mai mult."</string>
+    <string name="kg_sim_puk_recovery_hint" msgid="5577753137718442566">"Introduceţi codul PUK şi noul cod PIN"</string>
+    <string name="kg_invalid_puk" msgid="5809955359950817326">"Codul PUK introdus nu este corect."</string>
+    <string name="kg_login_too_many_attempts" msgid="6486842094005698475">"Prea multe încercări de desenare a modelului"</string>
+    <string name="kg_login_instructions" msgid="1100551261265506448">"Pentru a debloca, conectaţi-vă cu Contul dvs. Google."</string>
+    <string name="kg_login_username_hint" msgid="5718534272070920364">"Nume de utilizator (e-mail)"</string>
+    <string name="kg_login_password_hint" msgid="9057289103827298549">"Parolă"</string>
+    <string name="kg_login_submit_button" msgid="5355904582674054702">"Conectaţi-vă"</string>
+    <string name="kg_login_invalid_input" msgid="5754664119319872197">"Nume de utilizator sau parolă nevalide."</string>
+    <string name="kg_login_account_recovery_hint" msgid="5690709132841752974">"Aţi uitat numele de utilizator sau parola?"\n"Accesaţi "<b>"google.com/accounts/recovery"</b>"."</string>
+    <string name="kg_login_checking_password" msgid="8849589033659332457">"Se verifică..."</string>
+    <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="8276745642049502550">"Aţi introdus incorect codul PIN de <xliff:g id="NUMBER_0">%d</xliff:g> ori."\n\n"Încercaţi din nou peste <xliff:g id="NUMBER_1">%d</xliff:g> (de) secunde."</string>
+    <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="7813713389422226531">"Aţi introdus incorect parola de <xliff:g id="NUMBER_0">%d</xliff:g> ori. "\n\n"Încercaţi din nou peste <xliff:g id="NUMBER_1">%d</xliff:g> (de) secunde."</string>
+    <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="74089475965050805">"Aţi desenat incorect modelul pentru deblocare de <xliff:g id="NUMBER_0">%d</xliff:g> ori. "\n\n"Încercaţi din nou peste <xliff:g id="NUMBER_1">%d</xliff:g> (de) secunde."</string>
+    <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="1575557200627128949">"Aţi efectuat <xliff:g id="NUMBER_0">%d</xliff:g> încercări incorecte de deblocare a tabletei. După încă <xliff:g id="NUMBER_1">%d</xliff:g> încercări nereuşite, aceasta va fi resetată la setările prestabilite din fabrică, iar toate datele de utilizator vor fi pierdute."</string>
+    <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="4051015943038199910">"Aţi efectuat <xliff:g id="NUMBER_0">%d</xliff:g> încercări incorecte de deblocare a telefonului. După încă <xliff:g id="NUMBER_1">%d</xliff:g> încercări nereuşite, acesta va fi resetat la setările prestabilite din fabrică, iar toate datele de utilizator vor fi pierdute."</string>
+    <string name="kg_failed_attempts_now_wiping" product="tablet" msgid="2072996269148483637">"Aţi efectuat <xliff:g id="NUMBER">%d</xliff:g> încercări incorecte de deblocare a tabletei. Tableta va fi acum resetată la setările prestabilite din fabrică."</string>
+    <string name="kg_failed_attempts_now_wiping" product="default" msgid="4817627474419471518">"Aţi efectuat <xliff:g id="NUMBER">%d</xliff:g> încercări incorecte de deblocare a telefonului. Telefonul va fi acum resetat la setările prestabilite din fabrică."</string>
+    <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"Aţi desenat incorect modelul pentru deblocare de <xliff:g id="NUMBER_0">%d</xliff:g> ori. După încă <xliff:g id="NUMBER_1">%d</xliff:g> încercări nereuşite, vi se va solicita să deblocaţi tableta cu ajutorul unui cont de e-mail."\n\n" Încercaţi din nou peste <xliff:g id="NUMBER_2">%d</xliff:g> (de) secunde."</string>
+    <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"Aţi desenat incorect modelul pentru deblocare de <xliff:g id="NUMBER_0">%d</xliff:g> ori. După încă <xliff:g id="NUMBER_1">%d</xliff:g> încercări nereuşite, vi se va solicita să deblocaţi telefonul cu ajutorul unui cont de e-mail."\n\n" Încercaţi din nou peste <xliff:g id="NUMBER_2">%d</xliff:g> (de) secunde."</string>
+    <string name="kg_temp_back_string" msgid="5812983904056640466">"&lt;"</string>
 </resources>
diff --git a/core/res/res/values-ru/strings.xml b/core/res/res/values-ru/strings.xml
index a9a0d0c..eae0ecb 100644
--- a/core/res/res/values-ru/strings.xml
+++ b/core/res/res/values-ru/strings.xml
@@ -547,10 +547,8 @@
     <string name="permdesc_sdcardWrite" product="default" msgid="4337417790936632090">"Приложение сможет записывать данные на SD-карту."</string>
     <string name="permlab_mediaStorageWrite" product="default" msgid="6859839199706879015">"изм./удал. данных мультимедиа"</string>
     <string name="permdesc_mediaStorageWrite" product="default" msgid="8189160597698529185">"Приложение сможет изменять контент внутреннего хранилища мультимедиа."</string>
-    <!-- no translation found for permlab_sdcardAccessAll (8150613823900460576) -->
-    <skip />
-    <!-- no translation found for permdesc_sdcardAccessAll (3215208357415891320) -->
-    <skip />
+    <string name="permlab_sdcardAccessAll" msgid="8150613823900460576">"разрешить доступ к внешним накопителям из всех аккаунтов"</string>
+    <string name="permdesc_sdcardAccessAll" msgid="3215208357415891320">"Приложение сможет обращаться к внешним накопителям из всех аккаунтов."</string>
     <string name="permlab_cache_filesystem" msgid="5656487264819669824">"получать доступ к кэшу файловой системы"</string>
     <string name="permdesc_cache_filesystem" msgid="5578967642265550955">"Приложение сможет выполнять чтение и запись в файловую систему кэша."</string>
     <string name="permlab_use_sip" msgid="5986952362795870502">"Осуществление/прием интернет-вызовов"</string>
@@ -581,6 +579,10 @@
     <string name="policydesc_encryptedStorage" msgid="2637732115325316992">"Шифровать данные приложений в хранилище."</string>
     <string name="policylab_disableCamera" msgid="6395301023152297826">"Отключить камеры"</string>
     <string name="policydesc_disableCamera" msgid="2306349042834754597">"Запретить использование камер на устройстве."</string>
+    <!-- no translation found for policylab_disableKeyguardWidgets (1794894613389073926) -->
+    <skip />
+    <!-- no translation found for policydesc_disableKeyguardWidgets (7254624892984033592) -->
+    <skip />
   <string-array name="phoneTypes">
     <item msgid="8901098336658710359">"Домашний"</item>
     <item msgid="869923650527136615">"Мобильный"</item>
@@ -1319,64 +1321,46 @@
     <string name="bluetooth_a2dp_audio_route_name" msgid="8575624030406771015">"Воспроизведение звука через Bluetooth"</string>
     <string name="media_route_chooser_grouping_done" msgid="7966438307723317169">"Готово"</string>
     <string name="media_route_button_content_description" msgid="5758553567065145276">"Перенаправлять поток мультимедиа"</string>
-    <!-- no translation found for display_manager_built_in_display_name (2583134294292563941) -->
+    <string name="display_manager_built_in_display_name" msgid="2583134294292563941">"Встроенный экран"</string>
+    <!-- no translation found for display_manager_hdmi_display_name (1555264559227470109) -->
     <skip />
-    <!-- no translation found for display_manager_overlay_display_name (5142365982271620716) -->
+    <string name="display_manager_overlay_display_name" msgid="5142365982271620716">"Наложение № <xliff:g id="ID">%1$d</xliff:g>"</string>
+    <!-- no translation found for display_manager_overlay_display_title (652124517672257172) -->
     <skip />
-    <!-- no translation found for display_manager_overlay_display_title (8186674340178573982) -->
-    <skip />
-    <!-- no translation found for kg_emergency_call_label (684946192523830531) -->
-    <skip />
-    <!-- no translation found for kg_forgot_pattern_button_text (8852021467868220608) -->
-    <skip />
-    <!-- no translation found for kg_wrong_pattern (1850806070801358830) -->
-    <skip />
-    <!-- no translation found for kg_wrong_password (2333281762128113157) -->
-    <skip />
-    <!-- no translation found for kg_wrong_pin (1131306510833563801) -->
-    <skip />
-    <!-- no translation found for kg_too_many_failed_attempts_countdown (353963338189371686) -->
-    <skip />
-    <!-- no translation found for kg_pattern_instructions (398978611683075868) -->
-    <skip />
-    <!-- no translation found for kg_sim_pin_instructions (2319508550934557331) -->
-    <skip />
-    <!-- no translation found for kg_pin_instructions (2377242233495111557) -->
-    <skip />
-    <!-- no translation found for kg_password_instructions (5753646556186936819) -->
-    <skip />
-    <!-- no translation found for kg_puk_enter_puk_hint (5183097160254244459) -->
-    <skip />
-    <!-- no translation found for kg_puk_enter_pin_hint (597821135578014901) -->
-    <skip />
-    <!-- no translation found for kg_sim_unlock_progress_dialog_message (8950398016976865762) -->
-    <skip />
-    <!-- no translation found for kg_password_wrong_pin_code (1139324887413846912) -->
-    <skip />
-    <!-- no translation found for kg_invalid_sim_pin_hint (8795159358110620001) -->
-    <skip />
-    <!-- no translation found for kg_invalid_sim_puk_hint (5216603185442368307) -->
-    <skip />
-    <!-- no translation found for kg_sim_puk_recovery_hint (5577753137718442566) -->
-    <skip />
-    <!-- no translation found for kg_invalid_puk (5809955359950817326) -->
-    <skip />
-    <!-- no translation found for kg_login_too_many_attempts (6486842094005698475) -->
-    <skip />
-    <!-- no translation found for kg_login_instructions (1100551261265506448) -->
-    <skip />
-    <!-- no translation found for kg_login_username_hint (5718534272070920364) -->
-    <skip />
-    <!-- no translation found for kg_login_password_hint (9057289103827298549) -->
-    <skip />
-    <!-- no translation found for kg_login_submit_button (5355904582674054702) -->
-    <skip />
-    <!-- no translation found for kg_login_invalid_input (5754664119319872197) -->
-    <skip />
-    <!-- no translation found for kg_login_account_recovery_hint (5690709132841752974) -->
-    <skip />
-    <!-- no translation found for kg_login_checking_password (8849589033659332457) -->
-    <skip />
-    <!-- no translation found for kg_temp_back_string (5812983904056640466) -->
-    <skip />
+    <string name="kg_emergency_call_label" msgid="684946192523830531">"Экстренный вызов"</string>
+    <string name="kg_forgot_pattern_button_text" msgid="8852021467868220608">"Забыли графический ключ?"</string>
+    <string name="kg_wrong_pattern" msgid="1850806070801358830">"Неправильный графический ключ"</string>
+    <string name="kg_wrong_password" msgid="2333281762128113157">"Неправильный пароль"</string>
+    <string name="kg_wrong_pin" msgid="1131306510833563801">"Неправильный PIN-код"</string>
+    <string name="kg_too_many_failed_attempts_countdown" msgid="6358110221603297548">"Повторите попытку через <xliff:g id="NUMBER">%d</xliff:g> сек."</string>
+    <string name="kg_pattern_instructions" msgid="398978611683075868">"Введите графический ключ"</string>
+    <string name="kg_sim_pin_instructions" msgid="2319508550934557331">"Введите PIN-код SIM-карты"</string>
+    <string name="kg_pin_instructions" msgid="2377242233495111557">"Введите PIN"</string>
+    <string name="kg_password_instructions" msgid="5753646556186936819">"Введите пароль"</string>
+    <string name="kg_puk_enter_puk_hint" msgid="5183097160254244459">"PUK-код"</string>
+    <string name="kg_puk_enter_pin_hint" msgid="597821135578014901">"Новый PIN-код"</string>
+    <string name="kg_sim_unlock_progress_dialog_message" msgid="8950398016976865762">"Разблокировка SIM-карты…"</string>
+    <string name="kg_password_wrong_pin_code" msgid="1139324887413846912">"Неверный PIN-код."</string>
+    <string name="kg_invalid_sim_pin_hint" msgid="8795159358110620001">"Введите PIN-код (от 4 до 8 цифр)."</string>
+    <string name="kg_invalid_sim_puk_hint" msgid="5216603185442368307">"Введите PUK-код из 8 или более цифр."</string>
+    <string name="kg_sim_puk_recovery_hint" msgid="5577753137718442566">"Введите PUK-код и новый PIN-код"</string>
+    <string name="kg_invalid_puk" msgid="5809955359950817326">"Введен неверный PUK-код."</string>
+    <string name="kg_login_too_many_attempts" msgid="6486842094005698475">"Слишком много попыток ввода графического ключа"</string>
+    <string name="kg_login_instructions" msgid="1100551261265506448">"Чтобы разблокировать устройство, войдите в свой аккаунт Google."</string>
+    <string name="kg_login_username_hint" msgid="5718534272070920364">"Имя пользователя (эл. почта)"</string>
+    <string name="kg_login_password_hint" msgid="9057289103827298549">"Пароль"</string>
+    <string name="kg_login_submit_button" msgid="5355904582674054702">"Войти"</string>
+    <string name="kg_login_invalid_input" msgid="5754664119319872197">"Неверное имя пользователя или пароль."</string>
+    <string name="kg_login_account_recovery_hint" msgid="5690709132841752974">"Забыли имя пользователя или пароль?"\n"Перейдите на страницу "<b>"google.com/accounts/recovery"</b>"."</string>
+    <string name="kg_login_checking_password" msgid="8849589033659332457">"Проверка…"</string>
+    <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="8276745642049502550">"Не удалось разблокировать устройство с помощью PIN-кода (число неудачных попыток: <xliff:g id="NUMBER_0">%d</xliff:g>). "\n\n"Повторите попытку через <xliff:g id="NUMBER_1">%d</xliff:g> сек."</string>
+    <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="7813713389422226531">"Не удалось разблокировать устройство с помощью пароля (число неудачных попыток: <xliff:g id="NUMBER_0">%d</xliff:g>)."\n\n"Повторите попытку через <xliff:g id="NUMBER_1">%d</xliff:g> сек."</string>
+    <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="74089475965050805">"Не удалось разблокировать устройство с помощью графического ключа (число неудачных попыток: <xliff:g id="NUMBER_0">%d</xliff:g>)."\n\n"Повторите попытку через <xliff:g id="NUMBER_1">%d</xliff:g> сек."</string>
+    <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="1575557200627128949">"Не удалось разблокировать планшетный ПК (число неудачных попыток: <xliff:g id="NUMBER_0">%d</xliff:g>). Осталось попыток: <xliff:g id="NUMBER_1">%d</xliff:g>. После этого будут установлены настройки по умолчанию, что приведет к удалению всех пользовательских данных."</string>
+    <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="4051015943038199910">"Не удалось разблокировать телефон (число неудачных попыток: <xliff:g id="NUMBER_0">%d</xliff:g>). Осталось попыток: <xliff:g id="NUMBER_1">%d</xliff:g>. После этого будут установлены настройки по умолчанию, что приведет к удалению всех пользовательских данных."</string>
+    <string name="kg_failed_attempts_now_wiping" product="tablet" msgid="2072996269148483637">"Не удалось разблокировать планшетный ПК (число неудачных попыток: <xliff:g id="NUMBER">%d</xliff:g>). Будут установлены настройки по умолчанию."</string>
+    <string name="kg_failed_attempts_now_wiping" product="default" msgid="4817627474419471518">"Не удалось разблокировать телефон (число неудачных попыток: <xliff:g id="NUMBER">%d</xliff:g>). Будут установлены настройки по умолчанию."</string>
+    <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"Не удалось разблокировать планшетный ПК с помощью графического ключа (число неудачных попыток: <xliff:g id="NUMBER_0">%d</xliff:g>). Осталось попыток: <xliff:g id="NUMBER_1">%d</xliff:g>. После этого вам будет предложено разблокировать устройство с помощью аккаунта электронной почты."\n\n"Повторите попытку через <xliff:g id="NUMBER_2">%d</xliff:g> сек."</string>
+    <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"Не удалось разблокировать телефон с помощью графического ключа (число неудачных попыток: <xliff:g id="NUMBER_0">%d</xliff:g>). Осталось попыток: <xliff:g id="NUMBER_1">%d</xliff:g>. После этого вам будет предложено разблокировать устройство с помощью аккаунта электронной почты."\n\n"Повторите попытку через <xliff:g id="NUMBER_2">%d</xliff:g> сек."</string>
+    <string name="kg_temp_back_string" msgid="5812983904056640466">"&lt;"</string>
 </resources>
diff --git a/core/res/res/values-sk/strings.xml b/core/res/res/values-sk/strings.xml
index 2bfa219..fdc9c44 100644
--- a/core/res/res/values-sk/strings.xml
+++ b/core/res/res/values-sk/strings.xml
@@ -547,10 +547,8 @@
     <string name="permdesc_sdcardWrite" product="default" msgid="4337417790936632090">"Umožňuje aplikácii zápis na kartu SD."</string>
     <string name="permlab_mediaStorageWrite" product="default" msgid="6859839199706879015">"úprava alebo odstránenie obsahu interného ukladacieho priestoru média"</string>
     <string name="permdesc_mediaStorageWrite" product="default" msgid="8189160597698529185">"Umožňuje aplikácii zmeniť obsah interného ukladacieho priestoru média."</string>
-    <!-- no translation found for permlab_sdcardAccessAll (8150613823900460576) -->
-    <skip />
-    <!-- no translation found for permdesc_sdcardAccessAll (3215208357415891320) -->
-    <skip />
+    <string name="permlab_sdcardAccessAll" msgid="8150613823900460576">"pristupovať k externému ukladaciemu priestoru pre všetkých používateľov"</string>
+    <string name="permdesc_sdcardAccessAll" msgid="3215208357415891320">"Umožňuje aplikácii pristupovať k externému ukladaciemu priestoru pre všetkých používateľov."</string>
     <string name="permlab_cache_filesystem" msgid="5656487264819669824">"pristupovať do súborového systému vyrovnávacej pamäte"</string>
     <string name="permdesc_cache_filesystem" msgid="5578967642265550955">"Umožňuje aplikácii čítať a zapisovať do súborového systému vyrovnávacej pamäte."</string>
     <string name="permlab_use_sip" msgid="5986952362795870502">"uskutočňovať a prijímať internetové hovory"</string>
@@ -581,6 +579,10 @@
     <string name="policydesc_encryptedStorage" msgid="2637732115325316992">"Vyžadovať šifrovanie uložených údajov aplikácií."</string>
     <string name="policylab_disableCamera" msgid="6395301023152297826">"Zakázať fotoaparáty"</string>
     <string name="policydesc_disableCamera" msgid="2306349042834754597">"Zakázať používanie všetkých fotoaparátov zariadenia."</string>
+    <!-- no translation found for policylab_disableKeyguardWidgets (1794894613389073926) -->
+    <skip />
+    <!-- no translation found for policydesc_disableKeyguardWidgets (7254624892984033592) -->
+    <skip />
   <string-array name="phoneTypes">
     <item msgid="8901098336658710359">"Domovská stránka"</item>
     <item msgid="869923650527136615">"Mobil"</item>
@@ -1319,64 +1321,46 @@
     <string name="bluetooth_a2dp_audio_route_name" msgid="8575624030406771015">"Bluetooth audio"</string>
     <string name="media_route_chooser_grouping_done" msgid="7966438307723317169">"Hotovo"</string>
     <string name="media_route_button_content_description" msgid="5758553567065145276">"Výstup médií"</string>
-    <!-- no translation found for display_manager_built_in_display_name (2583134294292563941) -->
+    <string name="display_manager_built_in_display_name" msgid="2583134294292563941">"Vstavaná obrazovka"</string>
+    <!-- no translation found for display_manager_hdmi_display_name (1555264559227470109) -->
     <skip />
-    <!-- no translation found for display_manager_overlay_display_name (5142365982271620716) -->
+    <string name="display_manager_overlay_display_name" msgid="5142365982271620716">"Prekrytie č. <xliff:g id="ID">%1$d</xliff:g>"</string>
+    <!-- no translation found for display_manager_overlay_display_title (652124517672257172) -->
     <skip />
-    <!-- no translation found for display_manager_overlay_display_title (8186674340178573982) -->
-    <skip />
-    <!-- no translation found for kg_emergency_call_label (684946192523830531) -->
-    <skip />
-    <!-- no translation found for kg_forgot_pattern_button_text (8852021467868220608) -->
-    <skip />
-    <!-- no translation found for kg_wrong_pattern (1850806070801358830) -->
-    <skip />
-    <!-- no translation found for kg_wrong_password (2333281762128113157) -->
-    <skip />
-    <!-- no translation found for kg_wrong_pin (1131306510833563801) -->
-    <skip />
-    <!-- no translation found for kg_too_many_failed_attempts_countdown (353963338189371686) -->
-    <skip />
-    <!-- no translation found for kg_pattern_instructions (398978611683075868) -->
-    <skip />
-    <!-- no translation found for kg_sim_pin_instructions (2319508550934557331) -->
-    <skip />
-    <!-- no translation found for kg_pin_instructions (2377242233495111557) -->
-    <skip />
-    <!-- no translation found for kg_password_instructions (5753646556186936819) -->
-    <skip />
-    <!-- no translation found for kg_puk_enter_puk_hint (5183097160254244459) -->
-    <skip />
-    <!-- no translation found for kg_puk_enter_pin_hint (597821135578014901) -->
-    <skip />
-    <!-- no translation found for kg_sim_unlock_progress_dialog_message (8950398016976865762) -->
-    <skip />
-    <!-- no translation found for kg_password_wrong_pin_code (1139324887413846912) -->
-    <skip />
-    <!-- no translation found for kg_invalid_sim_pin_hint (8795159358110620001) -->
-    <skip />
-    <!-- no translation found for kg_invalid_sim_puk_hint (5216603185442368307) -->
-    <skip />
-    <!-- no translation found for kg_sim_puk_recovery_hint (5577753137718442566) -->
-    <skip />
-    <!-- no translation found for kg_invalid_puk (5809955359950817326) -->
-    <skip />
-    <!-- no translation found for kg_login_too_many_attempts (6486842094005698475) -->
-    <skip />
-    <!-- no translation found for kg_login_instructions (1100551261265506448) -->
-    <skip />
-    <!-- no translation found for kg_login_username_hint (5718534272070920364) -->
-    <skip />
-    <!-- no translation found for kg_login_password_hint (9057289103827298549) -->
-    <skip />
-    <!-- no translation found for kg_login_submit_button (5355904582674054702) -->
-    <skip />
-    <!-- no translation found for kg_login_invalid_input (5754664119319872197) -->
-    <skip />
-    <!-- no translation found for kg_login_account_recovery_hint (5690709132841752974) -->
-    <skip />
-    <!-- no translation found for kg_login_checking_password (8849589033659332457) -->
-    <skip />
-    <!-- no translation found for kg_temp_back_string (5812983904056640466) -->
-    <skip />
+    <string name="kg_emergency_call_label" msgid="684946192523830531">"Tiesňové volanie"</string>
+    <string name="kg_forgot_pattern_button_text" msgid="8852021467868220608">"Nepamätám si vzor"</string>
+    <string name="kg_wrong_pattern" msgid="1850806070801358830">"Nesprávny vzor"</string>
+    <string name="kg_wrong_password" msgid="2333281762128113157">"Nesprávne heslo"</string>
+    <string name="kg_wrong_pin" msgid="1131306510833563801">"Nesprávny kód PIN"</string>
+    <string name="kg_too_many_failed_attempts_countdown" msgid="6358110221603297548">"Skúste to znova o <xliff:g id="NUMBER">%d</xliff:g> s."</string>
+    <string name="kg_pattern_instructions" msgid="398978611683075868">"Nakreslite svoj vzor"</string>
+    <string name="kg_sim_pin_instructions" msgid="2319508550934557331">"Zadajte kód PIN karty SIM"</string>
+    <string name="kg_pin_instructions" msgid="2377242233495111557">"Zadajte kód PIN"</string>
+    <string name="kg_password_instructions" msgid="5753646556186936819">"Zadajte heslo"</string>
+    <string name="kg_puk_enter_puk_hint" msgid="5183097160254244459">"Kód PUK"</string>
+    <string name="kg_puk_enter_pin_hint" msgid="597821135578014901">"Nový kód PIN"</string>
+    <string name="kg_sim_unlock_progress_dialog_message" msgid="8950398016976865762">"Prebieha odomykanie karty SIM..."</string>
+    <string name="kg_password_wrong_pin_code" msgid="1139324887413846912">"Nesprávny kód PIN."</string>
+    <string name="kg_invalid_sim_pin_hint" msgid="8795159358110620001">"Zadajte kód PIN s dĺžkou 4 až 8 číslic."</string>
+    <string name="kg_invalid_sim_puk_hint" msgid="5216603185442368307">"Zadajte kód PUK, ktorý má 8 alebo viac číslic."</string>
+    <string name="kg_sim_puk_recovery_hint" msgid="5577753137718442566">"Zadajte kód PUK a nový kód PIN"</string>
+    <string name="kg_invalid_puk" msgid="5809955359950817326">"Zadaný kód PUK nie je správny."</string>
+    <string name="kg_login_too_many_attempts" msgid="6486842094005698475">"Príliš veľa pokusov o nakreslenie vzoru"</string>
+    <string name="kg_login_instructions" msgid="1100551261265506448">"Ak chcete telefón odomknúť, prihláste sa pomocou svojho účtu Google."</string>
+    <string name="kg_login_username_hint" msgid="5718534272070920364">"Používateľské meno (e-mail)"</string>
+    <string name="kg_login_password_hint" msgid="9057289103827298549">"Heslo"</string>
+    <string name="kg_login_submit_button" msgid="5355904582674054702">"Prihlásiť sa"</string>
+    <string name="kg_login_invalid_input" msgid="5754664119319872197">"Neplatné používateľské meno alebo heslo."</string>
+    <string name="kg_login_account_recovery_hint" msgid="5690709132841752974">"Zabudli ste svoje používateľské meno alebo heslo?"\n" Navštívte stránky "<b>"google.com/accounts/recovery"</b>"."</string>
+    <string name="kg_login_checking_password" msgid="8849589033659332457">"Prebieha kontrola..."</string>
+    <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="8276745642049502550">"<xliff:g id="NUMBER_0">%d</xliff:g>-krát ste zadali nesprávny kód PIN. "\n\n"Skúste to znova o <xliff:g id="NUMBER_1">%d</xliff:g> s."</string>
+    <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="7813713389422226531">"<xliff:g id="NUMBER_0">%d</xliff:g>-krát ste zadali nesprávne heslo. "\n\n"Skúste to znova o <xliff:g id="NUMBER_1">%d</xliff:g>."</string>
+    <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="74089475965050805">"<xliff:g id="NUMBER_0">%d</xliff:g>-krát ste použili nesprávny bezpečnostný vzor. "\n\n"Skúste to znova o <xliff:g id="NUMBER_1">%d</xliff:g> s."</string>
+    <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="1575557200627128949">"Tablet ste sa pokúsili odomknúť nesprávnym spôsobom <xliff:g id="NUMBER_0">%d</xliff:g>-krát. Po <xliff:g id="NUMBER_1">%d</xliff:g> ďalších neúspešných pokusoch sa v tablete obnovia predvolené továrenské nastavenia a všetky používateľské údaje budú stratené."</string>
+    <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="4051015943038199910">"Telefón ste sa pokúsili odomknúť nesprávnym spôsobom <xliff:g id="NUMBER_0">%d</xliff:g>-krát. Po <xliff:g id="NUMBER_1">%d</xliff:g> ďalších neúspešných pokusoch sa v telefóne obnovia predvolené továrenské nastavenia a všetky používateľské údaje budú stratené."</string>
+    <string name="kg_failed_attempts_now_wiping" product="tablet" msgid="2072996269148483637">"Tablet ste sa pokúsili odomknúť nesprávnym spôsobom <xliff:g id="NUMBER">%d</xliff:g>-krát. V tablete sa teraz obnovia predvolené továrenské nastavenia."</string>
+    <string name="kg_failed_attempts_now_wiping" product="default" msgid="4817627474419471518">"Telefón ste sa pokúsili odomknúť nesprávnym spôsobom <xliff:g id="NUMBER">%d</xliff:g>-krát. V telefóne sa teraz obnovia predvolené továrenské nastavenia."</string>
+    <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"<xliff:g id="NUMBER_0">%d</xliff:g>-krát ste nesprávne nakreslili svoj bezpečnostný vzor. Po ďalších neúspešných pokusoch (<xliff:g id="NUMBER_1">%d</xliff:g>) budete vyzvaní odomknúť tablet pomocou e-mailového účtu."\n\n" Skúste to znova o <xliff:g id="NUMBER_2">%d</xliff:g> s."</string>
+    <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"<xliff:g id="NUMBER_0">%d</xliff:g>-krát ste nesprávne nakreslili svoj bezpečnostný vzor. Po <xliff:g id="NUMBER_1">%d</xliff:g> ďalších neúspešných pokusoch sa zobrazí výzva na odomknutie telefónu pomocou e-mailového účtu."\n\n" Skúste to znova o <xliff:g id="NUMBER_2">%d</xliff:g> s."</string>
+    <string name="kg_temp_back_string" msgid="5812983904056640466">"&lt;"</string>
 </resources>
diff --git a/core/res/res/values-sl/strings.xml b/core/res/res/values-sl/strings.xml
index 78c2806..e429d71 100644
--- a/core/res/res/values-sl/strings.xml
+++ b/core/res/res/values-sl/strings.xml
@@ -547,10 +547,8 @@
     <string name="permdesc_sdcardWrite" product="default" msgid="4337417790936632090">"Programu omogoča pisanje na kartico SD."</string>
     <string name="permlab_mediaStorageWrite" product="default" msgid="6859839199706879015">"spreminjanje/brisanje vsebine notranje shrambe nosilca podatkov"</string>
     <string name="permdesc_mediaStorageWrite" product="default" msgid="8189160597698529185">"Programu omogoča spreminjanje vsebine notranje shrambe nosilca podatkov."</string>
-    <!-- no translation found for permlab_sdcardAccessAll (8150613823900460576) -->
-    <skip />
-    <!-- no translation found for permdesc_sdcardAccessAll (3215208357415891320) -->
-    <skip />
+    <string name="permlab_sdcardAccessAll" msgid="8150613823900460576">"dostop do zunanje naprave za shranjevanje za vse uporabnike"</string>
+    <string name="permdesc_sdcardAccessAll" msgid="3215208357415891320">"Aplikaciji omogoča dostop do zunanje naprave za shranjevanje za vse uporabnike."</string>
     <string name="permlab_cache_filesystem" msgid="5656487264819669824">"dostop do datotečnega sistema predpomnilnika"</string>
     <string name="permdesc_cache_filesystem" msgid="5578967642265550955">"Programu omogoča branje in pisanje v datotečni sistem predpomnilnika."</string>
     <string name="permlab_use_sip" msgid="5986952362795870502">"opravljanje/sprejemanje internetnih klicev"</string>
@@ -581,6 +579,10 @@
     <string name="policydesc_encryptedStorage" msgid="2637732115325316992">"Shranjeni podatki programa morajo biti šifrirani."</string>
     <string name="policylab_disableCamera" msgid="6395301023152297826">"Onemogoči fotoaparate"</string>
     <string name="policydesc_disableCamera" msgid="2306349042834754597">"Prepreči uporabo vseh fotoaparatov v napravi."</string>
+    <!-- no translation found for policylab_disableKeyguardWidgets (1794894613389073926) -->
+    <skip />
+    <!-- no translation found for policydesc_disableKeyguardWidgets (7254624892984033592) -->
+    <skip />
   <string-array name="phoneTypes">
     <item msgid="8901098336658710359">"Začetna stran"</item>
     <item msgid="869923650527136615">"Mobilni"</item>
@@ -1172,7 +1174,7 @@
     <string name="vpn_text" msgid="3011306607126450322">"Dotaknite se, če želite upravljati omrežje."</string>
     <string name="vpn_text_long" msgid="6407351006249174473">"Vzpostavljena povezava s sejo <xliff:g id="SESSION">%s</xliff:g>. Dotaknite se, če želite upravljati omrežje."</string>
     <string name="vpn_lockdown_connecting" msgid="6443438964440960745">"Povezovanje v stalno vklopljeno navidezno zasebno omrežje ..."</string>
-    <string name="vpn_lockdown_connected" msgid="8202679674819213931">"Stalno vklopljeno navidezno zasebno omrežje povezano"</string>
+    <string name="vpn_lockdown_connected" msgid="8202679674819213931">"Vzpostavljena povezava v stalno vklopljeno navidezno zasebno omrežje"</string>
     <string name="vpn_lockdown_error" msgid="6009249814034708175">"Napaka stalno vklopljenega navideznega zasebnega omrežja"</string>
     <string name="vpn_lockdown_reset" msgid="5365010427963548932">"Dotaknite se, da ponastavite povezavo"</string>
     <string name="upload_file" msgid="2897957172366730416">"Izberi datoteko"</string>
@@ -1319,64 +1321,46 @@
     <string name="bluetooth_a2dp_audio_route_name" msgid="8575624030406771015">"Zvok prek Bluetootha"</string>
     <string name="media_route_chooser_grouping_done" msgid="7966438307723317169">"Končano"</string>
     <string name="media_route_button_content_description" msgid="5758553567065145276">"Izhod predstavnosti"</string>
-    <!-- no translation found for display_manager_built_in_display_name (2583134294292563941) -->
+    <string name="display_manager_built_in_display_name" msgid="2583134294292563941">"Vgrajen zaslon"</string>
+    <!-- no translation found for display_manager_hdmi_display_name (1555264559227470109) -->
     <skip />
-    <!-- no translation found for display_manager_overlay_display_name (5142365982271620716) -->
+    <string name="display_manager_overlay_display_name" msgid="5142365982271620716">"Prekrivanje #<xliff:g id="ID">%1$d</xliff:g>"</string>
+    <!-- no translation found for display_manager_overlay_display_title (652124517672257172) -->
     <skip />
-    <!-- no translation found for display_manager_overlay_display_title (8186674340178573982) -->
-    <skip />
-    <!-- no translation found for kg_emergency_call_label (684946192523830531) -->
-    <skip />
-    <!-- no translation found for kg_forgot_pattern_button_text (8852021467868220608) -->
-    <skip />
-    <!-- no translation found for kg_wrong_pattern (1850806070801358830) -->
-    <skip />
-    <!-- no translation found for kg_wrong_password (2333281762128113157) -->
-    <skip />
-    <!-- no translation found for kg_wrong_pin (1131306510833563801) -->
-    <skip />
-    <!-- no translation found for kg_too_many_failed_attempts_countdown (353963338189371686) -->
-    <skip />
-    <!-- no translation found for kg_pattern_instructions (398978611683075868) -->
-    <skip />
-    <!-- no translation found for kg_sim_pin_instructions (2319508550934557331) -->
-    <skip />
-    <!-- no translation found for kg_pin_instructions (2377242233495111557) -->
-    <skip />
-    <!-- no translation found for kg_password_instructions (5753646556186936819) -->
-    <skip />
-    <!-- no translation found for kg_puk_enter_puk_hint (5183097160254244459) -->
-    <skip />
-    <!-- no translation found for kg_puk_enter_pin_hint (597821135578014901) -->
-    <skip />
-    <!-- no translation found for kg_sim_unlock_progress_dialog_message (8950398016976865762) -->
-    <skip />
-    <!-- no translation found for kg_password_wrong_pin_code (1139324887413846912) -->
-    <skip />
-    <!-- no translation found for kg_invalid_sim_pin_hint (8795159358110620001) -->
-    <skip />
-    <!-- no translation found for kg_invalid_sim_puk_hint (5216603185442368307) -->
-    <skip />
-    <!-- no translation found for kg_sim_puk_recovery_hint (5577753137718442566) -->
-    <skip />
-    <!-- no translation found for kg_invalid_puk (5809955359950817326) -->
-    <skip />
-    <!-- no translation found for kg_login_too_many_attempts (6486842094005698475) -->
-    <skip />
-    <!-- no translation found for kg_login_instructions (1100551261265506448) -->
-    <skip />
-    <!-- no translation found for kg_login_username_hint (5718534272070920364) -->
-    <skip />
-    <!-- no translation found for kg_login_password_hint (9057289103827298549) -->
-    <skip />
-    <!-- no translation found for kg_login_submit_button (5355904582674054702) -->
-    <skip />
-    <!-- no translation found for kg_login_invalid_input (5754664119319872197) -->
-    <skip />
-    <!-- no translation found for kg_login_account_recovery_hint (5690709132841752974) -->
-    <skip />
-    <!-- no translation found for kg_login_checking_password (8849589033659332457) -->
-    <skip />
-    <!-- no translation found for kg_temp_back_string (5812983904056640466) -->
-    <skip />
+    <string name="kg_emergency_call_label" msgid="684946192523830531">"Klic v sili"</string>
+    <string name="kg_forgot_pattern_button_text" msgid="8852021467868220608">"Pozabljen vzorec"</string>
+    <string name="kg_wrong_pattern" msgid="1850806070801358830">"Napačen vzorec"</string>
+    <string name="kg_wrong_password" msgid="2333281762128113157">"Napačno geslo"</string>
+    <string name="kg_wrong_pin" msgid="1131306510833563801">"Napačen PIN"</string>
+    <string name="kg_too_many_failed_attempts_countdown" msgid="6358110221603297548">"Čez <xliff:g id="NUMBER">%d</xliff:g> sekund poskusite znova."</string>
+    <string name="kg_pattern_instructions" msgid="398978611683075868">"Narišite vzorec"</string>
+    <string name="kg_sim_pin_instructions" msgid="2319508550934557331">"Vnesite PIN za kartico SIM"</string>
+    <string name="kg_pin_instructions" msgid="2377242233495111557">"Vnesite PIN"</string>
+    <string name="kg_password_instructions" msgid="5753646556186936819">"Vnesite geslo"</string>
+    <string name="kg_puk_enter_puk_hint" msgid="5183097160254244459">"Koda PUK"</string>
+    <string name="kg_puk_enter_pin_hint" msgid="597821135578014901">"Nova koda PIN"</string>
+    <string name="kg_sim_unlock_progress_dialog_message" msgid="8950398016976865762">"Odklepanje kartice SIM ..."</string>
+    <string name="kg_password_wrong_pin_code" msgid="1139324887413846912">"Napačna koda PIN."</string>
+    <string name="kg_invalid_sim_pin_hint" msgid="8795159358110620001">"Vnesite PIN, ki vsebuje od štiri do osem številk."</string>
+    <string name="kg_invalid_sim_puk_hint" msgid="5216603185442368307">"Vnesite 8- ali več mestni PUK."</string>
+    <string name="kg_sim_puk_recovery_hint" msgid="5577753137718442566">"Vnesite kodo PUK in novo kodo PIN"</string>
+    <string name="kg_invalid_puk" msgid="5809955359950817326">"Vneseni PUK ni pravilen."</string>
+    <string name="kg_login_too_many_attempts" msgid="6486842094005698475">"Preveč poskusov vzorca"</string>
+    <string name="kg_login_instructions" msgid="1100551261265506448">"Če želite odkleniti napravo, se prijavite z Google Računom."</string>
+    <string name="kg_login_username_hint" msgid="5718534272070920364">"Uporabniško ime (e-pošta)"</string>
+    <string name="kg_login_password_hint" msgid="9057289103827298549">"Geslo"</string>
+    <string name="kg_login_submit_button" msgid="5355904582674054702">"Prijava"</string>
+    <string name="kg_login_invalid_input" msgid="5754664119319872197">"Neveljavno uporabniško ime ali geslo."</string>
+    <string name="kg_login_account_recovery_hint" msgid="5690709132841752974">"Ali ste pozabili uporabniško ime ali geslo?"\n"Obiščite "<b>"google.com/accounts/recovery"</b>"."</string>
+    <string name="kg_login_checking_password" msgid="8849589033659332457">"Preverjanje ..."</string>
+    <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="8276745642049502550">"PIN ste <xliff:g id="NUMBER_0">%d</xliff:g>-krat vnesli napačno. "\n\n"Znova poskusite čez <xliff:g id="NUMBER_1">%d</xliff:g> s."</string>
+    <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="7813713389422226531">"Geslo ste <xliff:g id="NUMBER_0">%d</xliff:g>-krat vnesli napačno. "\n\n"Znova poskusite čez <xliff:g id="NUMBER_1">%d</xliff:g> s."</string>
+    <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="74089475965050805">"Vzorec za odklepanje ste nepravilno narisali <xliff:g id="NUMBER_0">%d</xliff:g>-krat. "\n\n"Poskusite znova čez <xliff:g id="NUMBER_1">%d</xliff:g> s."</string>
+    <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="1575557200627128949">"Tablični računalnik ste poskusili <xliff:g id="NUMBER_0">%d</xliff:g>-krat napačno odkleniti. Če poskusite še <xliff:g id="NUMBER_1">%d</xliff:g>-krat in ne uspete, bo ponastavljen na privzete tovarniške nastavitve in vsi uporabniški podatki bodo izgubljeni."</string>
+    <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="4051015943038199910">"Telefon ste poskusili <xliff:g id="NUMBER_0">%d</xliff:g>-krat napačno odkleniti. Če poskusite še <xliff:g id="NUMBER_1">%d</xliff:g>-krat in ne uspete, bo ponastavljen na privzete tovarniške nastavitve in vsi uporabniški podatki bodo izgubljeni."</string>
+    <string name="kg_failed_attempts_now_wiping" product="tablet" msgid="2072996269148483637">"Tablični računalnik ste poskusili <xliff:g id="NUMBER">%d</xliff:g>-krat napačno odkleniti, zato bo ponastavljen na privzete tovarniške nastavitve."</string>
+    <string name="kg_failed_attempts_now_wiping" product="default" msgid="4817627474419471518">"Telefon ste poskusili <xliff:g id="NUMBER">%d</xliff:g>-krat napačno odkleniti, zato bo ponastavljen na privzete tovarniške nastavitve."</string>
+    <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"Vzorec za odklepanje ste <xliff:g id="NUMBER_0">%d</xliff:g>-krat napačno vnesli. Po nadaljnjih <xliff:g id="NUMBER_1">%d</xliff:g> neuspešnih poskusih boste pozvani, da tablični računalnik odklenete z e-poštnim računom."\n\n"Poskusite znova čez <xliff:g id="NUMBER_2">%d</xliff:g> s."</string>
+    <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"Vzorec za odklepanje ste <xliff:g id="NUMBER_0">%d</xliff:g>-krat napačno vnesli. Po nadaljnjih <xliff:g id="NUMBER_1">%d</xliff:g> neuspešnih poskusih boste pozvani, da odklenete telefon z Googlovimi podatki za prijavo."\n\n"Poskusite znova čez <xliff:g id="NUMBER_2">%d</xliff:g> s."</string>
+    <string name="kg_temp_back_string" msgid="5812983904056640466">"&lt;"</string>
 </resources>
diff --git a/core/res/res/values-sr/strings.xml b/core/res/res/values-sr/strings.xml
index e7c11b6..83eb61e 100644
--- a/core/res/res/values-sr/strings.xml
+++ b/core/res/res/values-sr/strings.xml
@@ -547,10 +547,8 @@
     <string name="permdesc_sdcardWrite" product="default" msgid="4337417790936632090">"Дозвољава апликацији да уписује податке на SD картицу."</string>
     <string name="permlab_mediaStorageWrite" product="default" msgid="6859839199706879015">"измена/брисање интерне меморије медија"</string>
     <string name="permdesc_mediaStorageWrite" product="default" msgid="8189160597698529185">"Дозвољава апликацији да мења садржај интерне меморије медијума."</string>
-    <!-- no translation found for permlab_sdcardAccessAll (8150613823900460576) -->
-    <skip />
-    <!-- no translation found for permdesc_sdcardAccessAll (3215208357415891320) -->
-    <skip />
+    <string name="permlab_sdcardAccessAll" msgid="8150613823900460576">"приступ спољној меморији свих корисника"</string>
+    <string name="permdesc_sdcardAccessAll" msgid="3215208357415891320">"Дозвољава апликацији да приступа спољној меморији за све кориснике."</string>
     <string name="permlab_cache_filesystem" msgid="5656487264819669824">"приступ систему датотека кеша"</string>
     <string name="permdesc_cache_filesystem" msgid="5578967642265550955">"Дозвољава апликацији да чита систем датотека кеша и уписује податке у њега."</string>
     <string name="permlab_use_sip" msgid="5986952362795870502">"упућивање/пријем Интернет позива"</string>
@@ -581,6 +579,10 @@
     <string name="policydesc_encryptedStorage" msgid="2637732115325316992">"Захтева да сачувани подаци апликације буду шифровани."</string>
     <string name="policylab_disableCamera" msgid="6395301023152297826">"Онемогућавање камера"</string>
     <string name="policydesc_disableCamera" msgid="2306349042834754597">"Спречите коришћење свих камера уређаја."</string>
+    <!-- no translation found for policylab_disableKeyguardWidgets (1794894613389073926) -->
+    <skip />
+    <!-- no translation found for policydesc_disableKeyguardWidgets (7254624892984033592) -->
+    <skip />
   <string-array name="phoneTypes">
     <item msgid="8901098336658710359">"Кућа"</item>
     <item msgid="869923650527136615">"Мобилни"</item>
@@ -1319,64 +1321,46 @@
     <string name="bluetooth_a2dp_audio_route_name" msgid="8575624030406771015">"Bluetooth аудио"</string>
     <string name="media_route_chooser_grouping_done" msgid="7966438307723317169">"Готово"</string>
     <string name="media_route_button_content_description" msgid="5758553567065145276">"Излаз медија"</string>
-    <!-- no translation found for display_manager_built_in_display_name (2583134294292563941) -->
+    <string name="display_manager_built_in_display_name" msgid="2583134294292563941">"Уграђени екран"</string>
+    <!-- no translation found for display_manager_hdmi_display_name (1555264559227470109) -->
     <skip />
-    <!-- no translation found for display_manager_overlay_display_name (5142365982271620716) -->
+    <string name="display_manager_overlay_display_name" msgid="5142365982271620716">"Постављени елемент бр. <xliff:g id="ID">%1$d</xliff:g>"</string>
+    <!-- no translation found for display_manager_overlay_display_title (652124517672257172) -->
     <skip />
-    <!-- no translation found for display_manager_overlay_display_title (8186674340178573982) -->
-    <skip />
-    <!-- no translation found for kg_emergency_call_label (684946192523830531) -->
-    <skip />
-    <!-- no translation found for kg_forgot_pattern_button_text (8852021467868220608) -->
-    <skip />
-    <!-- no translation found for kg_wrong_pattern (1850806070801358830) -->
-    <skip />
-    <!-- no translation found for kg_wrong_password (2333281762128113157) -->
-    <skip />
-    <!-- no translation found for kg_wrong_pin (1131306510833563801) -->
-    <skip />
-    <!-- no translation found for kg_too_many_failed_attempts_countdown (353963338189371686) -->
-    <skip />
-    <!-- no translation found for kg_pattern_instructions (398978611683075868) -->
-    <skip />
-    <!-- no translation found for kg_sim_pin_instructions (2319508550934557331) -->
-    <skip />
-    <!-- no translation found for kg_pin_instructions (2377242233495111557) -->
-    <skip />
-    <!-- no translation found for kg_password_instructions (5753646556186936819) -->
-    <skip />
-    <!-- no translation found for kg_puk_enter_puk_hint (5183097160254244459) -->
-    <skip />
-    <!-- no translation found for kg_puk_enter_pin_hint (597821135578014901) -->
-    <skip />
-    <!-- no translation found for kg_sim_unlock_progress_dialog_message (8950398016976865762) -->
-    <skip />
-    <!-- no translation found for kg_password_wrong_pin_code (1139324887413846912) -->
-    <skip />
-    <!-- no translation found for kg_invalid_sim_pin_hint (8795159358110620001) -->
-    <skip />
-    <!-- no translation found for kg_invalid_sim_puk_hint (5216603185442368307) -->
-    <skip />
-    <!-- no translation found for kg_sim_puk_recovery_hint (5577753137718442566) -->
-    <skip />
-    <!-- no translation found for kg_invalid_puk (5809955359950817326) -->
-    <skip />
-    <!-- no translation found for kg_login_too_many_attempts (6486842094005698475) -->
-    <skip />
-    <!-- no translation found for kg_login_instructions (1100551261265506448) -->
-    <skip />
-    <!-- no translation found for kg_login_username_hint (5718534272070920364) -->
-    <skip />
-    <!-- no translation found for kg_login_password_hint (9057289103827298549) -->
-    <skip />
-    <!-- no translation found for kg_login_submit_button (5355904582674054702) -->
-    <skip />
-    <!-- no translation found for kg_login_invalid_input (5754664119319872197) -->
-    <skip />
-    <!-- no translation found for kg_login_account_recovery_hint (5690709132841752974) -->
-    <skip />
-    <!-- no translation found for kg_login_checking_password (8849589033659332457) -->
-    <skip />
-    <!-- no translation found for kg_temp_back_string (5812983904056640466) -->
-    <skip />
+    <string name="kg_emergency_call_label" msgid="684946192523830531">"Хитни позив"</string>
+    <string name="kg_forgot_pattern_button_text" msgid="8852021467868220608">"Заборављени шаблон"</string>
+    <string name="kg_wrong_pattern" msgid="1850806070801358830">"Погрешан шаблон"</string>
+    <string name="kg_wrong_password" msgid="2333281762128113157">"Погрешна лозинка"</string>
+    <string name="kg_wrong_pin" msgid="1131306510833563801">"Погрешан PIN"</string>
+    <string name="kg_too_many_failed_attempts_countdown" msgid="6358110221603297548">"Покушајте поново за <xliff:g id="NUMBER">%d</xliff:g> секунде(и)."</string>
+    <string name="kg_pattern_instructions" msgid="398978611683075868">"Нацртајте шаблон"</string>
+    <string name="kg_sim_pin_instructions" msgid="2319508550934557331">"Унесите PIN SIM картице"</string>
+    <string name="kg_pin_instructions" msgid="2377242233495111557">"Унесите PIN"</string>
+    <string name="kg_password_instructions" msgid="5753646556186936819">"Унесите лозинку"</string>
+    <string name="kg_puk_enter_puk_hint" msgid="5183097160254244459">"PUK кôд"</string>
+    <string name="kg_puk_enter_pin_hint" msgid="597821135578014901">"Нови PIN кôд"</string>
+    <string name="kg_sim_unlock_progress_dialog_message" msgid="8950398016976865762">"Откључавање SIM картице…"</string>
+    <string name="kg_password_wrong_pin_code" msgid="1139324887413846912">"PIN кôд је нетачан."</string>
+    <string name="kg_invalid_sim_pin_hint" msgid="8795159358110620001">"Унесите PIN који има од 4 до 8 бројева."</string>
+    <string name="kg_invalid_sim_puk_hint" msgid="5216603185442368307">"Унесите PUK који се састоји од 8 бројева или више."</string>
+    <string name="kg_sim_puk_recovery_hint" msgid="5577753137718442566">"Унесите PUK и нови PIN кôд"</string>
+    <string name="kg_invalid_puk" msgid="5809955359950817326">"PUK који сте унели није тачан."</string>
+    <string name="kg_login_too_many_attempts" msgid="6486842094005698475">"Превише покушаја уноса шаблона"</string>
+    <string name="kg_login_instructions" msgid="1100551261265506448">"Да бисте откључали, пријавите се помоћу Google налога."</string>
+    <string name="kg_login_username_hint" msgid="5718534272070920364">"Корисничко име (адреса е-поште)"</string>
+    <string name="kg_login_password_hint" msgid="9057289103827298549">"Лозинка"</string>
+    <string name="kg_login_submit_button" msgid="5355904582674054702">"Пријави ме"</string>
+    <string name="kg_login_invalid_input" msgid="5754664119319872197">"Неважеће корисничко име или лозинка."</string>
+    <string name="kg_login_account_recovery_hint" msgid="5690709132841752974">"Заборавили сте корисничко име или лозинку?"\n"Посетите адресу "<b>"google.com/accounts/recovery"</b>"."</string>
+    <string name="kg_login_checking_password" msgid="8849589033659332457">"Проверавање..."</string>
+    <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="8276745642049502550">"Унели сте PIN неисправно <xliff:g id="NUMBER_0">%d</xliff:g> пута. "\n\n"Покушајте поново за <xliff:g id="NUMBER_1">%d</xliff:g> секунде(и)."</string>
+    <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="7813713389422226531">"Унели сте лозинку неисправно <xliff:g id="NUMBER_0">%d</xliff:g> пута. "\n\n"Покушајте поново за <xliff:g id="NUMBER_1">%d</xliff:g> секунде(и)."</string>
+    <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="74089475965050805">"Нацртали сте шаблон за откључавање неисправно <xliff:g id="NUMBER_0">%d</xliff:g> пута. "\n\n"Покушајте поново за <xliff:g id="NUMBER_1">%d</xliff:g> секунде(и)."</string>
+    <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="1575557200627128949">"Покушали сте да откључате таблет неисправно <xliff:g id="NUMBER_0">%d</xliff:g> пута. Након још <xliff:g id="NUMBER_1">%d</xliff:g> неуспешна(их) покушаја таблет ће бити враћен на подразумевана фабричка подешавања и сви кориснички подаци ће бити изгубљени."</string>
+    <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="4051015943038199910">"Покушали сте да откључате телефон неисправно <xliff:g id="NUMBER_0">%d</xliff:g> пута. Након још <xliff:g id="NUMBER_1">%d</xliff:g> неуспешна(их) покушаја телефон ће бити враћен на подразумевана фабричка подешавања и сви кориснички подаци ће бити изгубљени."</string>
+    <string name="kg_failed_attempts_now_wiping" product="tablet" msgid="2072996269148483637">"Покушали сте да откључате таблет неисправно <xliff:g id="NUMBER">%d</xliff:g> пута. Таблет ће сада бити враћен на подразумевана фабричка подешавања."</string>
+    <string name="kg_failed_attempts_now_wiping" product="default" msgid="4817627474419471518">"Покушали сте да откључате телефон неисправно <xliff:g id="NUMBER">%d</xliff:g> пута. Телефон ће сада бити враћен на подразумевана фабричка подешавања."</string>
+    <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"Нацртали сте шаблон за откључавање неисправно <xliff:g id="NUMBER_0">%d</xliff:g> пута. Након још <xliff:g id="NUMBER_1">%d</xliff:g> неуспешна(их) покушаја, од вас ће бити затражено да откључате таблет помоћу налога е-поште."\n\n"Покушајте поново за <xliff:g id="NUMBER_2">%d</xliff:g> секунде(и)."</string>
+    <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"Нацртали сте шаблон за откључавање неисправно <xliff:g id="NUMBER_0">%d</xliff:g> пута. Након још <xliff:g id="NUMBER_1">%d</xliff:g> неуспешна(их) покушаја, од вас ће бити затражено да откључате телефон помоћу налога е-поште."\n\n"Покушајте поново за <xliff:g id="NUMBER_2">%d</xliff:g> секунде(и)."</string>
+    <string name="kg_temp_back_string" msgid="5812983904056640466">"&lt;"</string>
 </resources>
diff --git a/core/res/res/values-sv/strings.xml b/core/res/res/values-sv/strings.xml
index b1009e2..747a05e 100644
--- a/core/res/res/values-sv/strings.xml
+++ b/core/res/res/values-sv/strings.xml
@@ -547,10 +547,8 @@
     <string name="permdesc_sdcardWrite" product="default" msgid="4337417790936632090">"Tillåter att appen skriver till SD-kortet."</string>
     <string name="permlab_mediaStorageWrite" product="default" msgid="6859839199706879015">"ändra/ta bort innehåll"</string>
     <string name="permdesc_mediaStorageWrite" product="default" msgid="8189160597698529185">"Tillåter att appen ändrar innehållet på den interna lagringsenheten."</string>
-    <!-- no translation found for permlab_sdcardAccessAll (8150613823900460576) -->
-    <skip />
-    <!-- no translation found for permdesc_sdcardAccessAll (3215208357415891320) -->
-    <skip />
+    <string name="permlab_sdcardAccessAll" msgid="8150613823900460576">"åtkomst till lagringsutrymme"</string>
+    <string name="permdesc_sdcardAccessAll" msgid="3215208357415891320">"Tillåter att appen får åtkomst till en extern lagringsenhet för alla användare."</string>
     <string name="permlab_cache_filesystem" msgid="5656487264819669824">"åtkomst till cachefilsystemet"</string>
     <string name="permdesc_cache_filesystem" msgid="5578967642265550955">"Tillåter att appen läser och skriver till cachefilsystemet."</string>
     <string name="permlab_use_sip" msgid="5986952362795870502">"ringa/ta emot Internetsamtal"</string>
@@ -581,6 +579,10 @@
     <string name="policydesc_encryptedStorage" msgid="2637732115325316992">"Kräv att sparade appdata krypteras."</string>
     <string name="policylab_disableCamera" msgid="6395301023152297826">"Inaktivera kameror"</string>
     <string name="policydesc_disableCamera" msgid="2306349042834754597">"Förhindra att enhetens kameror används."</string>
+    <!-- no translation found for policylab_disableKeyguardWidgets (1794894613389073926) -->
+    <skip />
+    <!-- no translation found for policydesc_disableKeyguardWidgets (7254624892984033592) -->
+    <skip />
   <string-array name="phoneTypes">
     <item msgid="8901098336658710359">"Hem"</item>
     <item msgid="869923650527136615">"Mobil"</item>
@@ -1319,64 +1321,46 @@
     <string name="bluetooth_a2dp_audio_route_name" msgid="8575624030406771015">"Bluetooth-ljud"</string>
     <string name="media_route_chooser_grouping_done" msgid="7966438307723317169">"Klar"</string>
     <string name="media_route_button_content_description" msgid="5758553567065145276">"Medieuppspelning"</string>
-    <!-- no translation found for display_manager_built_in_display_name (2583134294292563941) -->
+    <string name="display_manager_built_in_display_name" msgid="2583134294292563941">"Inbyggd skärm"</string>
+    <!-- no translation found for display_manager_hdmi_display_name (1555264559227470109) -->
     <skip />
-    <!-- no translation found for display_manager_overlay_display_name (5142365982271620716) -->
+    <string name="display_manager_overlay_display_name" msgid="5142365982271620716">"Överlagring #<xliff:g id="ID">%1$d</xliff:g>"</string>
+    <!-- no translation found for display_manager_overlay_display_title (652124517672257172) -->
     <skip />
-    <!-- no translation found for display_manager_overlay_display_title (8186674340178573982) -->
-    <skip />
-    <!-- no translation found for kg_emergency_call_label (684946192523830531) -->
-    <skip />
-    <!-- no translation found for kg_forgot_pattern_button_text (8852021467868220608) -->
-    <skip />
-    <!-- no translation found for kg_wrong_pattern (1850806070801358830) -->
-    <skip />
-    <!-- no translation found for kg_wrong_password (2333281762128113157) -->
-    <skip />
-    <!-- no translation found for kg_wrong_pin (1131306510833563801) -->
-    <skip />
-    <!-- no translation found for kg_too_many_failed_attempts_countdown (353963338189371686) -->
-    <skip />
-    <!-- no translation found for kg_pattern_instructions (398978611683075868) -->
-    <skip />
-    <!-- no translation found for kg_sim_pin_instructions (2319508550934557331) -->
-    <skip />
-    <!-- no translation found for kg_pin_instructions (2377242233495111557) -->
-    <skip />
-    <!-- no translation found for kg_password_instructions (5753646556186936819) -->
-    <skip />
-    <!-- no translation found for kg_puk_enter_puk_hint (5183097160254244459) -->
-    <skip />
-    <!-- no translation found for kg_puk_enter_pin_hint (597821135578014901) -->
-    <skip />
-    <!-- no translation found for kg_sim_unlock_progress_dialog_message (8950398016976865762) -->
-    <skip />
-    <!-- no translation found for kg_password_wrong_pin_code (1139324887413846912) -->
-    <skip />
-    <!-- no translation found for kg_invalid_sim_pin_hint (8795159358110620001) -->
-    <skip />
-    <!-- no translation found for kg_invalid_sim_puk_hint (5216603185442368307) -->
-    <skip />
-    <!-- no translation found for kg_sim_puk_recovery_hint (5577753137718442566) -->
-    <skip />
-    <!-- no translation found for kg_invalid_puk (5809955359950817326) -->
-    <skip />
-    <!-- no translation found for kg_login_too_many_attempts (6486842094005698475) -->
-    <skip />
-    <!-- no translation found for kg_login_instructions (1100551261265506448) -->
-    <skip />
-    <!-- no translation found for kg_login_username_hint (5718534272070920364) -->
-    <skip />
-    <!-- no translation found for kg_login_password_hint (9057289103827298549) -->
-    <skip />
-    <!-- no translation found for kg_login_submit_button (5355904582674054702) -->
-    <skip />
-    <!-- no translation found for kg_login_invalid_input (5754664119319872197) -->
-    <skip />
-    <!-- no translation found for kg_login_account_recovery_hint (5690709132841752974) -->
-    <skip />
-    <!-- no translation found for kg_login_checking_password (8849589033659332457) -->
-    <skip />
-    <!-- no translation found for kg_temp_back_string (5812983904056640466) -->
-    <skip />
+    <string name="kg_emergency_call_label" msgid="684946192523830531">"Nödsamtal"</string>
+    <string name="kg_forgot_pattern_button_text" msgid="8852021467868220608">"Har du glömt ditt grafiska lösenord?"</string>
+    <string name="kg_wrong_pattern" msgid="1850806070801358830">"Fel grafiskt lösenord"</string>
+    <string name="kg_wrong_password" msgid="2333281762128113157">"Fel lösenord"</string>
+    <string name="kg_wrong_pin" msgid="1131306510833563801">"Fel PIN-kod"</string>
+    <string name="kg_too_many_failed_attempts_countdown" msgid="6358110221603297548">"Försök igen om <xliff:g id="NUMBER">%d</xliff:g> sekunder."</string>
+    <string name="kg_pattern_instructions" msgid="398978611683075868">"Rita ditt grafiska lösenord"</string>
+    <string name="kg_sim_pin_instructions" msgid="2319508550934557331">"Ange PIN-kod för SIM-kortet"</string>
+    <string name="kg_pin_instructions" msgid="2377242233495111557">"Ange PIN-kod"</string>
+    <string name="kg_password_instructions" msgid="5753646556186936819">"Ange lösenord"</string>
+    <string name="kg_puk_enter_puk_hint" msgid="5183097160254244459">"PUK-kod"</string>
+    <string name="kg_puk_enter_pin_hint" msgid="597821135578014901">"Ny PIN-kod"</string>
+    <string name="kg_sim_unlock_progress_dialog_message" msgid="8950398016976865762">"Låser upp SIM-kort …"</string>
+    <string name="kg_password_wrong_pin_code" msgid="1139324887413846912">"Fel PIN-kod."</string>
+    <string name="kg_invalid_sim_pin_hint" msgid="8795159358110620001">"Ange en PIN-kod med 4 till 8 siffror."</string>
+    <string name="kg_invalid_sim_puk_hint" msgid="5216603185442368307">"Ange en PUK-kod med minst 8 siffror."</string>
+    <string name="kg_sim_puk_recovery_hint" msgid="5577753137718442566">"Ange PUK-koden och en ny PIN-kod"</string>
+    <string name="kg_invalid_puk" msgid="5809955359950817326">"PUK-koden som du angav är felaktig."</string>
+    <string name="kg_login_too_many_attempts" msgid="6486842094005698475">"För många försök med grafiskt lösenord"</string>
+    <string name="kg_login_instructions" msgid="1100551261265506448">"Logga in med ditt Google-konto om du vill låsa upp."</string>
+    <string name="kg_login_username_hint" msgid="5718534272070920364">"Användarnamn (e-post)"</string>
+    <string name="kg_login_password_hint" msgid="9057289103827298549">"Lösenord"</string>
+    <string name="kg_login_submit_button" msgid="5355904582674054702">"Logga in"</string>
+    <string name="kg_login_invalid_input" msgid="5754664119319872197">"Ogiltigt användarnamn eller lösenord."</string>
+    <string name="kg_login_account_recovery_hint" msgid="5690709132841752974">"Har du glömt ditt användarnamn eller lösenord?"\n"Besök "<b>"google.com/accounts/recovery"</b>"."</string>
+    <string name="kg_login_checking_password" msgid="8849589033659332457">"Kontrollerar …"</string>
+    <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="8276745642049502550">"Du har angett fel lösenord <xliff:g id="NUMBER_0">%d</xliff:g> gånger. "\n\n"Försök igen om <xliff:g id="NUMBER_1">%d</xliff:g> sekunder."</string>
+    <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="7813713389422226531">"Du har angett fel lösenord <xliff:g id="NUMBER_0">%d</xliff:g> gånger. "\n\n"Försök igen om <xliff:g id="NUMBER_1">%d</xliff:g> sekunder."</string>
+    <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="74089475965050805">"Du har ritat ditt grafiska lösenord fel <xliff:g id="NUMBER_0">%d</xliff:g> gånger. "\n\n"Försök igen om <xliff:g id="NUMBER_1">%d</xliff:g> sekunder."</string>
+    <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="1575557200627128949">"Du har försökt låsa upp mobilen på fel sätt <xliff:g id="NUMBER_0">%d</xliff:g> gånger. Efter ytterligare <xliff:g id="NUMBER_1">%d</xliff:g> misslyckade försök återställs surfplattan till fabriksinställningarna. Du förlorar då alla användardata."</string>
+    <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="4051015943038199910">"Du har försökt låsa upp mobilen på fel sätt <xliff:g id="NUMBER_0">%d</xliff:g> gånger. Efter ytterligare <xliff:g id="NUMBER_1">%d</xliff:g> misslyckade försök återställs mobilen till fabriksinställningarna. Du förlorar då alla användardata."</string>
+    <string name="kg_failed_attempts_now_wiping" product="tablet" msgid="2072996269148483637">"Du har försökt låsa upp surfplattan på fel sätt <xliff:g id="NUMBER">%d</xliff:g> gånger. Surfplattan återställs nu till fabriksinställningarna."</string>
+    <string name="kg_failed_attempts_now_wiping" product="default" msgid="4817627474419471518">"Du har försökt låsa upp mobilen på fel sätt <xliff:g id="NUMBER">%d</xliff:g> gånger. Mobilen återställs nu till fabriksinställningarna."</string>
+    <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"Du har ritat ditt grafiska lösenord fel <xliff:g id="NUMBER_0">%d</xliff:g> gånger. Efter ytterligare <xliff:g id="NUMBER_1">%d</xliff:g> försök ombeds du låsa upp surfplattan med ett e-postkonto."\n\n" Försök igen om <xliff:g id="NUMBER_2">%d</xliff:g> sekunder."</string>
+    <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"Du har ritat ditt grafiska lösenord fel <xliff:g id="NUMBER_0">%d</xliff:g> gånger. Efter ytterligare <xliff:g id="NUMBER_1">%d</xliff:g> försök ombeds du låsa upp mobilen med hjälp av ett e-postkonto."\n\n" Försök igen om <xliff:g id="NUMBER_2">%d</xliff:g> sekunder."</string>
+    <string name="kg_temp_back_string" msgid="5812983904056640466">"&lt;"</string>
 </resources>
diff --git a/core/res/res/values-sw/strings.xml b/core/res/res/values-sw/strings.xml
index cf489c2..0daf8b8 100644
--- a/core/res/res/values-sw/strings.xml
+++ b/core/res/res/values-sw/strings.xml
@@ -547,10 +547,8 @@
     <string name="permdesc_sdcardWrite" product="default" msgid="4337417790936632090">"Inaruhusu programu kuandikia kadi ya SD."</string>
     <string name="permlab_mediaStorageWrite" product="default" msgid="6859839199706879015">"badilisha/futa maudhui ya hifadhi ya media ya ndani."</string>
     <string name="permdesc_mediaStorageWrite" product="default" msgid="8189160597698529185">"Inaruhusu programu kurekebisha maudhui ya hifadhi ya ndani vyombo vya habari."</string>
-    <!-- no translation found for permlab_sdcardAccessAll (8150613823900460576) -->
-    <skip />
-    <!-- no translation found for permdesc_sdcardAccessAll (3215208357415891320) -->
-    <skip />
+    <string name="permlab_sdcardAccessAll" msgid="8150613823900460576">"Fikia hifadhi ya nje ya watumiaji wote"</string>
+    <string name="permdesc_sdcardAccessAll" msgid="3215208357415891320">"Inaruhusu programu kufikia hifadhi ya nje kwa watumiaji wote."</string>
     <string name="permlab_cache_filesystem" msgid="5656487264819669824">"fikia faili za mfumo za kache"</string>
     <string name="permdesc_cache_filesystem" msgid="5578967642265550955">"Inaruhusu programu kusoma na kuandika mfumo wa faili wa kache."</string>
     <string name="permlab_use_sip" msgid="5986952362795870502">"piga/pokea simu za mtandao"</string>
@@ -581,6 +579,10 @@
     <string name="policydesc_encryptedStorage" msgid="2637732115325316992">"Inahitaji kwamba data ya programu iliyohifadhiwa iwe na msimbo fiche."</string>
     <string name="policylab_disableCamera" msgid="6395301023152297826">"Lemaza kamera"</string>
     <string name="policydesc_disableCamera" msgid="2306349042834754597">"Zuia matumizi yote ya kamera za kifaa."</string>
+    <!-- no translation found for policylab_disableKeyguardWidgets (1794894613389073926) -->
+    <skip />
+    <!-- no translation found for policydesc_disableKeyguardWidgets (7254624892984033592) -->
+    <skip />
   <string-array name="phoneTypes">
     <item msgid="8901098336658710359">"Nyumbani"</item>
     <item msgid="869923650527136615">"Simu ya mkononi"</item>
@@ -1319,64 +1321,46 @@
     <string name="bluetooth_a2dp_audio_route_name" msgid="8575624030406771015">"Sauti ya Bluetooth"</string>
     <string name="media_route_chooser_grouping_done" msgid="7966438307723317169">"Kwisha"</string>
     <string name="media_route_button_content_description" msgid="5758553567065145276">"Towe la midia"</string>
-    <!-- no translation found for display_manager_built_in_display_name (2583134294292563941) -->
+    <string name="display_manager_built_in_display_name" msgid="2583134294292563941">"Skrini Iliyojengwa ndani"</string>
+    <!-- no translation found for display_manager_hdmi_display_name (1555264559227470109) -->
     <skip />
-    <!-- no translation found for display_manager_overlay_display_name (5142365982271620716) -->
+    <string name="display_manager_overlay_display_name" msgid="5142365982271620716">"Mpanganisho #<xliff:g id="ID">%1$d</xliff:g>"</string>
+    <!-- no translation found for display_manager_overlay_display_title (652124517672257172) -->
     <skip />
-    <!-- no translation found for display_manager_overlay_display_title (8186674340178573982) -->
-    <skip />
-    <!-- no translation found for kg_emergency_call_label (684946192523830531) -->
-    <skip />
-    <!-- no translation found for kg_forgot_pattern_button_text (8852021467868220608) -->
-    <skip />
-    <!-- no translation found for kg_wrong_pattern (1850806070801358830) -->
-    <skip />
-    <!-- no translation found for kg_wrong_password (2333281762128113157) -->
-    <skip />
-    <!-- no translation found for kg_wrong_pin (1131306510833563801) -->
-    <skip />
-    <!-- no translation found for kg_too_many_failed_attempts_countdown (353963338189371686) -->
-    <skip />
-    <!-- no translation found for kg_pattern_instructions (398978611683075868) -->
-    <skip />
-    <!-- no translation found for kg_sim_pin_instructions (2319508550934557331) -->
-    <skip />
-    <!-- no translation found for kg_pin_instructions (2377242233495111557) -->
-    <skip />
-    <!-- no translation found for kg_password_instructions (5753646556186936819) -->
-    <skip />
-    <!-- no translation found for kg_puk_enter_puk_hint (5183097160254244459) -->
-    <skip />
-    <!-- no translation found for kg_puk_enter_pin_hint (597821135578014901) -->
-    <skip />
-    <!-- no translation found for kg_sim_unlock_progress_dialog_message (8950398016976865762) -->
-    <skip />
-    <!-- no translation found for kg_password_wrong_pin_code (1139324887413846912) -->
-    <skip />
-    <!-- no translation found for kg_invalid_sim_pin_hint (8795159358110620001) -->
-    <skip />
-    <!-- no translation found for kg_invalid_sim_puk_hint (5216603185442368307) -->
-    <skip />
-    <!-- no translation found for kg_sim_puk_recovery_hint (5577753137718442566) -->
-    <skip />
-    <!-- no translation found for kg_invalid_puk (5809955359950817326) -->
-    <skip />
-    <!-- no translation found for kg_login_too_many_attempts (6486842094005698475) -->
-    <skip />
-    <!-- no translation found for kg_login_instructions (1100551261265506448) -->
-    <skip />
-    <!-- no translation found for kg_login_username_hint (5718534272070920364) -->
-    <skip />
-    <!-- no translation found for kg_login_password_hint (9057289103827298549) -->
-    <skip />
-    <!-- no translation found for kg_login_submit_button (5355904582674054702) -->
-    <skip />
-    <!-- no translation found for kg_login_invalid_input (5754664119319872197) -->
-    <skip />
-    <!-- no translation found for kg_login_account_recovery_hint (5690709132841752974) -->
-    <skip />
-    <!-- no translation found for kg_login_checking_password (8849589033659332457) -->
-    <skip />
-    <!-- no translation found for kg_temp_back_string (5812983904056640466) -->
-    <skip />
+    <string name="kg_emergency_call_label" msgid="684946192523830531">"Simu ya dharura"</string>
+    <string name="kg_forgot_pattern_button_text" msgid="8852021467868220608">"Umesahau Ruwaza"</string>
+    <string name="kg_wrong_pattern" msgid="1850806070801358830">"Ruwaza Isiyofaa"</string>
+    <string name="kg_wrong_password" msgid="2333281762128113157">"Nenosiri Lisilofaa"</string>
+    <string name="kg_wrong_pin" msgid="1131306510833563801">"PIN Isiyofaa"</string>
+    <string name="kg_too_many_failed_attempts_countdown" msgid="6358110221603297548">"Jaribu tena kwa sekunde <xliff:g id="NUMBER">%d</xliff:g>."</string>
+    <string name="kg_pattern_instructions" msgid="398978611683075868">"Chora ruwaza yako"</string>
+    <string name="kg_sim_pin_instructions" msgid="2319508550934557331">"Ingiza SIM PIN"</string>
+    <string name="kg_pin_instructions" msgid="2377242233495111557">"Ingiza PIN"</string>
+    <string name="kg_password_instructions" msgid="5753646556186936819">"Ingiza Nenosiri"</string>
+    <string name="kg_puk_enter_puk_hint" msgid="5183097160254244459">"Msimbo wa PUK"</string>
+    <string name="kg_puk_enter_pin_hint" msgid="597821135578014901">"Msimbo mpya wa PIN"</string>
+    <string name="kg_sim_unlock_progress_dialog_message" msgid="8950398016976865762">"Inafungua kadi ya SIM..."</string>
+    <string name="kg_password_wrong_pin_code" msgid="1139324887413846912">"Msimbo wa PIN usio sahihi."</string>
+    <string name="kg_invalid_sim_pin_hint" msgid="8795159358110620001">"Charaza PIN ambayo ni nambari 4 hadi 8."</string>
+    <string name="kg_invalid_sim_puk_hint" msgid="5216603185442368307">"Andika PUK ambayo ina urefu wa nambari 8 au zaidi."</string>
+    <string name="kg_sim_puk_recovery_hint" msgid="5577753137718442566">"Charaza PUK na msimbo mpya wa PIN"</string>
+    <string name="kg_invalid_puk" msgid="5809955359950817326">"PUK uliyoicharaza siyo sahihi."</string>
+    <string name="kg_login_too_many_attempts" msgid="6486842094005698475">"Majaribio mengi mno ya mchoro"</string>
+    <string name="kg_login_instructions" msgid="1100551261265506448">"Ili kufungua, ingia kwa Akaunti yako ya Google."</string>
+    <string name="kg_login_username_hint" msgid="5718534272070920364">"Jina la mtumiaji (barua pepe)"</string>
+    <string name="kg_login_password_hint" msgid="9057289103827298549">"Nenosiri"</string>
+    <string name="kg_login_submit_button" msgid="5355904582674054702">"Ingia"</string>
+    <string name="kg_login_invalid_input" msgid="5754664119319872197">"Jina la mtumiaji au nenosiri batili."</string>
+    <string name="kg_login_account_recovery_hint" msgid="5690709132841752974">"Je, umesahau jina lako la mtumiaji au nenosiri?"\n"Tembela "<b>"Bgoogle.com/accounts/recovery"</b>"."</string>
+    <string name="kg_login_checking_password" msgid="8849589033659332457">"Inakagua..."</string>
+    <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="8276745642049502550">"Umeingiza nenosiri lako kimakosa mara <xliff:g id="NUMBER_0">%d</xliff:g>. "\n\n" Jaribu tena katika sekunde <xliff:g id="NUMBER_1">%d</xliff:g>."</string>
+    <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="7813713389422226531">"Umeingiza nenosiri lako kimakosa mara <xliff:g id="NUMBER_0">%d</xliff:g>. "\n\n" Jaribu tena kwa sekunde <xliff:g id="NUMBER_1">%d</xliff:g>."</string>
+    <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="74089475965050805">"Umechora ruwaza yako ya kufunga kimakosa mara <xliff:g id="NUMBER_0">%d</xliff:g>. "\n\n" Jaribu tena kwa sekunde <xliff:g id="NUMBER_1">%d</xliff:g>."</string>
+    <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="1575557200627128949">"Umejaribu kufungua kompyuta ndogo kwa njia isiyo sahihi mara <xliff:g id="NUMBER_0">%d</xliff:g>. Baada ya majaribio <xliff:g id="NUMBER_1">%d</xliff:g> zaidi yasiyofaulu, kompyuta ndogo itawekwa upya kwenye kiwanda chaguo-msingi na data yote ya mtumiaji itapotea."</string>
+    <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="4051015943038199910">"Umejaribu kufungua simu kwa njia isiyo sahihi mara <xliff:g id="NUMBER_0">%d</xliff:g>. Baada ya majaribio <xliff:g id="NUMBER_1">%d</xliff:g> zaidi yasiyofaulu, simu itawekwa upya kwenye kiwanda chaguo-msingi na data yote ya mtumiaji itapotea."</string>
+    <string name="kg_failed_attempts_now_wiping" product="tablet" msgid="2072996269148483637">"Umejaribu kufungua kompyuta ndogo kwa njia isiyo sahihi mara <xliff:g id="NUMBER">%d</xliff:g>. Sasa kompyuta ndogo itawekwa upya kwenye kiwanda chaguo-msingi."</string>
+    <string name="kg_failed_attempts_now_wiping" product="default" msgid="4817627474419471518">"Umejaribu kufungua simu kwa njia isiyo sahihi mara <xliff:g id="NUMBER">%d</xliff:g>. Sasa simu itawekwa upya kwenye kiwanda chaguo-msingi."</string>
+    <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"Umekosea katika kuweka mchoro wako wa kufungua mara <xliff:g id="NUMBER_0">%d</xliff:g>. Baada ya majaribio <xliff:g id="NUMBER_1">%d</xliff:g> bila kufaulu, utaombwa kufungua kompyuta yako ndogo kwa kutumia akaunti yako ya barua pepe."\n\n" Jaribu tena kwa sekunde <xliff:g id="NUMBER_2">%d</xliff:g>."</string>
+    <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"Umekosea kuchora mchoro wako wa kufungua mara <xliff:g id="NUMBER_0">%d</xliff:g>. Baada ya majaribio <xliff:g id="NUMBER_1">%d</xliff:g> yasiyofaulu, utaombwa kufungua simu yako kwa kutumia akaunti ya barua pepe."\n\n" Jaribu tena kwa sekunde <xliff:g id="NUMBER_2">%d</xliff:g>."</string>
+    <string name="kg_temp_back_string" msgid="5812983904056640466">"&lt;"</string>
 </resources>
diff --git a/core/res/res/values-sw600dp/dimens.xml b/core/res/res/values-sw600dp/dimens.xml
index 8937c2a..4e202ac 100644
--- a/core/res/res/values-sw600dp/dimens.xml
+++ b/core/res/res/values-sw600dp/dimens.xml
@@ -45,6 +45,9 @@
     <!-- Size of lockscreen outerring on unsecure unlock LockScreen -->
     <dimen name="keyguard_lockscreen_outerring_diameter">364dp</dimen>
 
+    <!-- Height of FaceUnlock view in keyguard -->
+    <dimen name="face_unlock_height">430dip</dimen>
+
     <!-- target placement radius for GlowPadView. Should be 1/2 of outerring diameter. -->
     <dimen name="glowpadview_target_placement_radius">182dip</dimen>
 
diff --git a/core/res/res/values-th/strings.xml b/core/res/res/values-th/strings.xml
index 9358870..7ada8ec 100644
--- a/core/res/res/values-th/strings.xml
+++ b/core/res/res/values-th/strings.xml
@@ -547,10 +547,8 @@
     <string name="permdesc_sdcardWrite" product="default" msgid="4337417790936632090">"อนุญาตให้แอปพลิเคชันเขียนลงบนการ์ด SD"</string>
     <string name="permlab_mediaStorageWrite" product="default" msgid="6859839199706879015">"แก้/ลบเนื้อหาข้อมูลสื่อภายใน"</string>
     <string name="permdesc_mediaStorageWrite" product="default" msgid="8189160597698529185">"อนุญาตให้แอปพลิเคชันแก้ไขเนื้อหาของที่เก็บข้อมูลสื่อภายใน"</string>
-    <!-- no translation found for permlab_sdcardAccessAll (8150613823900460576) -->
-    <skip />
-    <!-- no translation found for permdesc_sdcardAccessAll (3215208357415891320) -->
-    <skip />
+    <string name="permlab_sdcardAccessAll" msgid="8150613823900460576">"เข้าถึงที่จัดเก็บภายนอกของผู้ใช้ทั้งหมด"</string>
+    <string name="permdesc_sdcardAccessAll" msgid="3215208357415891320">"อนุญาตให้แอปพลิเคชันเข้าถึงที่จัดเก็บข้อมูลภายนอกสำหรับผู้ใช้ทั้งหมด"</string>
     <string name="permlab_cache_filesystem" msgid="5656487264819669824">"เข้าถึงระบบไฟล์แคช"</string>
     <string name="permdesc_cache_filesystem" msgid="5578967642265550955">"อนุญาตให้แอปพลิเคชันอ่านและเขียนระบบไฟล์แคช"</string>
     <string name="permlab_use_sip" msgid="5986952362795870502">"โทรออก/รับสายอินเทอร์เน็ต"</string>
@@ -581,6 +579,10 @@
     <string name="policydesc_encryptedStorage" msgid="2637732115325316992">"ข้อมูลของแอปพลิเคชันที่จัดเก็บต้องมีการเข้ารหัส"</string>
     <string name="policylab_disableCamera" msgid="6395301023152297826">"ปิดใช้งานกล้องถ่ายรูป"</string>
     <string name="policydesc_disableCamera" msgid="2306349042834754597">"ป้องกันการใช้กล้องถ่ายรูปของอุปกรณ์ทั้งหมด"</string>
+    <!-- no translation found for policylab_disableKeyguardWidgets (1794894613389073926) -->
+    <skip />
+    <!-- no translation found for policydesc_disableKeyguardWidgets (7254624892984033592) -->
+    <skip />
   <string-array name="phoneTypes">
     <item msgid="8901098336658710359">"บ้าน"</item>
     <item msgid="869923650527136615">"มือถือ"</item>
@@ -1319,64 +1321,46 @@
     <string name="bluetooth_a2dp_audio_route_name" msgid="8575624030406771015">"เสียงบลูทูธ"</string>
     <string name="media_route_chooser_grouping_done" msgid="7966438307723317169">"เสร็จสิ้น"</string>
     <string name="media_route_button_content_description" msgid="5758553567065145276">"เอาต์พุตสื่อ"</string>
-    <!-- no translation found for display_manager_built_in_display_name (2583134294292563941) -->
+    <string name="display_manager_built_in_display_name" msgid="2583134294292563941">"หน้าจอในตัว"</string>
+    <!-- no translation found for display_manager_hdmi_display_name (1555264559227470109) -->
     <skip />
-    <!-- no translation found for display_manager_overlay_display_name (5142365982271620716) -->
+    <string name="display_manager_overlay_display_name" msgid="5142365982271620716">"การวางซ้อน #<xliff:g id="ID">%1$d</xliff:g>"</string>
+    <!-- no translation found for display_manager_overlay_display_title (652124517672257172) -->
     <skip />
-    <!-- no translation found for display_manager_overlay_display_title (8186674340178573982) -->
-    <skip />
-    <!-- no translation found for kg_emergency_call_label (684946192523830531) -->
-    <skip />
-    <!-- no translation found for kg_forgot_pattern_button_text (8852021467868220608) -->
-    <skip />
-    <!-- no translation found for kg_wrong_pattern (1850806070801358830) -->
-    <skip />
-    <!-- no translation found for kg_wrong_password (2333281762128113157) -->
-    <skip />
-    <!-- no translation found for kg_wrong_pin (1131306510833563801) -->
-    <skip />
-    <!-- no translation found for kg_too_many_failed_attempts_countdown (353963338189371686) -->
-    <skip />
-    <!-- no translation found for kg_pattern_instructions (398978611683075868) -->
-    <skip />
-    <!-- no translation found for kg_sim_pin_instructions (2319508550934557331) -->
-    <skip />
-    <!-- no translation found for kg_pin_instructions (2377242233495111557) -->
-    <skip />
-    <!-- no translation found for kg_password_instructions (5753646556186936819) -->
-    <skip />
-    <!-- no translation found for kg_puk_enter_puk_hint (5183097160254244459) -->
-    <skip />
-    <!-- no translation found for kg_puk_enter_pin_hint (597821135578014901) -->
-    <skip />
-    <!-- no translation found for kg_sim_unlock_progress_dialog_message (8950398016976865762) -->
-    <skip />
-    <!-- no translation found for kg_password_wrong_pin_code (1139324887413846912) -->
-    <skip />
-    <!-- no translation found for kg_invalid_sim_pin_hint (8795159358110620001) -->
-    <skip />
-    <!-- no translation found for kg_invalid_sim_puk_hint (5216603185442368307) -->
-    <skip />
-    <!-- no translation found for kg_sim_puk_recovery_hint (5577753137718442566) -->
-    <skip />
-    <!-- no translation found for kg_invalid_puk (5809955359950817326) -->
-    <skip />
-    <!-- no translation found for kg_login_too_many_attempts (6486842094005698475) -->
-    <skip />
-    <!-- no translation found for kg_login_instructions (1100551261265506448) -->
-    <skip />
-    <!-- no translation found for kg_login_username_hint (5718534272070920364) -->
-    <skip />
-    <!-- no translation found for kg_login_password_hint (9057289103827298549) -->
-    <skip />
-    <!-- no translation found for kg_login_submit_button (5355904582674054702) -->
-    <skip />
-    <!-- no translation found for kg_login_invalid_input (5754664119319872197) -->
-    <skip />
-    <!-- no translation found for kg_login_account_recovery_hint (5690709132841752974) -->
-    <skip />
-    <!-- no translation found for kg_login_checking_password (8849589033659332457) -->
-    <skip />
-    <!-- no translation found for kg_temp_back_string (5812983904056640466) -->
-    <skip />
+    <string name="kg_emergency_call_label" msgid="684946192523830531">"หมายเลขฉุกเฉิน"</string>
+    <string name="kg_forgot_pattern_button_text" msgid="8852021467868220608">"ลืมรูปแบบใช่หรือไม่"</string>
+    <string name="kg_wrong_pattern" msgid="1850806070801358830">"รูปแบบไม่ถูกต้อง"</string>
+    <string name="kg_wrong_password" msgid="2333281762128113157">"รหัสผ่านไม่ถูกต้อง"</string>
+    <string name="kg_wrong_pin" msgid="1131306510833563801">"PIN ไม่ถูกต้อง"</string>
+    <string name="kg_too_many_failed_attempts_countdown" msgid="6358110221603297548">"ลองอีกครั้งในอีก <xliff:g id="NUMBER">%d</xliff:g> วินาที"</string>
+    <string name="kg_pattern_instructions" msgid="398978611683075868">"วาดรูปแบบของคุณ"</string>
+    <string name="kg_sim_pin_instructions" msgid="2319508550934557331">"ป้อน PIN ของซิม"</string>
+    <string name="kg_pin_instructions" msgid="2377242233495111557">"ป้อน PIN"</string>
+    <string name="kg_password_instructions" msgid="5753646556186936819">"ป้อนรหัสผ่าน"</string>
+    <string name="kg_puk_enter_puk_hint" msgid="5183097160254244459">"รหัส PUK"</string>
+    <string name="kg_puk_enter_pin_hint" msgid="597821135578014901">"รหัส PIN ใหม่"</string>
+    <string name="kg_sim_unlock_progress_dialog_message" msgid="8950398016976865762">"กำลังปลดล็อกซิมการ์ด…"</string>
+    <string name="kg_password_wrong_pin_code" msgid="1139324887413846912">"รหัส PIN ไม่ถูกต้อง"</string>
+    <string name="kg_invalid_sim_pin_hint" msgid="8795159358110620001">"พิมพ์ PIN ซึ่งเป็นเลข 4 ถึง 8 หลัก"</string>
+    <string name="kg_invalid_sim_puk_hint" msgid="5216603185442368307">"พิมพ์ PUK ซึ่งต้องเป็นตัวเลขอย่างน้อย 8 หลัก"</string>
+    <string name="kg_sim_puk_recovery_hint" msgid="5577753137718442566">"พิมพ์ PUK และรหัส PIN ใหม่"</string>
+    <string name="kg_invalid_puk" msgid="5809955359950817326">"PUK ที่คุณพิมพ์ไม่ถูกต้อง"</string>
+    <string name="kg_login_too_many_attempts" msgid="6486842094005698475">"ลองหลายรูปแบบมากเกินไป"</string>
+    <string name="kg_login_instructions" msgid="1100551261265506448">"หากต้องการปลดล็อก ให้ลงชื่อเข้าใช้ด้วยบัญชี Google ของคุณ"</string>
+    <string name="kg_login_username_hint" msgid="5718534272070920364">"ชื่อผู้ใช้ (อีเมล)"</string>
+    <string name="kg_login_password_hint" msgid="9057289103827298549">"รหัสผ่าน"</string>
+    <string name="kg_login_submit_button" msgid="5355904582674054702">"ลงชื่อเข้าใช้"</string>
+    <string name="kg_login_invalid_input" msgid="5754664119319872197">"ชื่อผู้ใช้หรือรหัสผ่านไม่ถูกต้อง"</string>
+    <string name="kg_login_account_recovery_hint" msgid="5690709132841752974">"หากลืมชื่อผู้ใช้หรือรหัสผ่าน"\n"โปรดไปที่ "<b>"google.com/accounts/recovery"</b></string>
+    <string name="kg_login_checking_password" msgid="8849589033659332457">"กำลังตรวจสอบ…"</string>
+    <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="8276745642049502550">"คุณพิมพ์ PIN ไม่ถูกต้องไป <xliff:g id="NUMBER_0">%d</xliff:g> ครั้งแล้ว "\n\n"โปรดลองอีกครั้งใน <xliff:g id="NUMBER_1">%d</xliff:g> วินาีที"</string>
+    <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="7813713389422226531">"คุณพิมพ์รหัสผ่านไม่ถูกต้องไป <xliff:g id="NUMBER_0">%d</xliff:g> ครั้งแล้ว "\n\n"โปรดลองอีกครั้งใน <xliff:g id="NUMBER_1">%d</xliff:g> วินาที"</string>
+    <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="74089475965050805">"คุณวาดรูปแบบการปลดล็อกไม่ถูกต้องไป <xliff:g id="NUMBER_0">%d</xliff:g> ครั้งแล้ว "\n\n"โปรดลองอีกครั้งใน <xliff:g id="NUMBER_1">%d</xliff:g> วินาที"</string>
+    <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="1575557200627128949">"คุณพยายามปลดล็อกแท็บเล็ตอย่างไม่ถูกต้อง <xliff:g id="NUMBER_0">%d</xliff:g> ครั้งแล้ว หากพยายามแล้วไม่สำเร็จอีก <xliff:g id="NUMBER_1">%d</xliff:g> ครั้ง แท็บเล็ตจะถูกรีเซ็ตเป็นค่าเริ่มต้นจากโรงงานและข้อมูลผู้ใช้ทั้งหมดจะหายไป"</string>
+    <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="4051015943038199910">"คุณพยายามปลดล็อกโทรศัพท์อย่างไม่ถูกต้อง <xliff:g id="NUMBER_0">%d</xliff:g> ครั้งแล้ว หากพยายามแล้วไม่สำเร็จอีก <xliff:g id="NUMBER_1">%d</xliff:g> ครั้ง โทรศัพท์จะถูกรีเซ็ตเป็นค่าเริ่มต้นจากโรงงานและข้อมูลผู้ใช้ทั้งหมดจะหายไป"</string>
+    <string name="kg_failed_attempts_now_wiping" product="tablet" msgid="2072996269148483637">"คุณพยายามปลดล็อกแท็บเล็ตอย่างไม่ถูกต้อง <xliff:g id="NUMBER">%d</xliff:g> ครั้งแล้ว ขณะนี้แท็บเล็ตจะถูกรีเซ็ตเป็นค่าเริ่มต้นจากโรงงาน"</string>
+    <string name="kg_failed_attempts_now_wiping" product="default" msgid="4817627474419471518">"คุณพยายามปลดล็อกโทรศัพท์อย่างไม่ถูกต้อง <xliff:g id="NUMBER">%d</xliff:g> ครั้งแล้ว ขณะนี้โทรศัพท์จะถูกรีเซ็ตเป็นค่าเริ่มต้นจากโรงงาน"</string>
+    <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"คุณวาดรูปแบบการปลดล็อกไม่ถูกต้อง <xliff:g id="NUMBER_0">%d</xliff:g> ครั้งแล้ว หากทำไม่สำเร็จอีก <xliff:g id="NUMBER_1">%d</xliff:g> ครั้ง ระบบจะขอให้คุณปลดล็อกแท็บเล็ตโดยใช้บัญชีอีเมล"\n\n" โปรดลองอีกครั้งใน <xliff:g id="NUMBER_2">%d</xliff:g> วินาที"</string>
+    <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"คุณวาดรูปแบบการปลดล็อกไม่ถูกต้อง <xliff:g id="NUMBER_0">%d</xliff:g> ครั้งแล้ว หากทำไม่สำเร็จอีก <xliff:g id="NUMBER_1">%d</xliff:g> ครั้ง ระบบจะขอให้คุณปลดล็อกโทรศัพท์โดยใช้ับัญชีอีเมล"\n\n" โปรดลองอีกครั้งในอีก <xliff:g id="NUMBER_2">%d</xliff:g> วินาที"</string>
+    <string name="kg_temp_back_string" msgid="5812983904056640466">"&lt;"</string>
 </resources>
diff --git a/core/res/res/values-tl/strings.xml b/core/res/res/values-tl/strings.xml
index 1147059..91d7d10 100644
--- a/core/res/res/values-tl/strings.xml
+++ b/core/res/res/values-tl/strings.xml
@@ -547,10 +547,8 @@
     <string name="permdesc_sdcardWrite" product="default" msgid="4337417790936632090">"Pinapayagan ang app na magsulat sa SD card."</string>
     <string name="permlab_mediaStorageWrite" product="default" msgid="6859839199706879015">"baguhin/tanggalin ang mga nilalaman ng panloob na imbakan ng media"</string>
     <string name="permdesc_mediaStorageWrite" product="default" msgid="8189160597698529185">"Pinapayagan ang app na baguhin ang mga nilalaman ng panloob na media storage."</string>
-    <!-- no translation found for permlab_sdcardAccessAll (8150613823900460576) -->
-    <skip />
-    <!-- no translation found for permdesc_sdcardAccessAll (3215208357415891320) -->
-    <skip />
+    <string name="permlab_sdcardAccessAll" msgid="8150613823900460576">"i-access panlabas na storage ng user"</string>
+    <string name="permdesc_sdcardAccessAll" msgid="3215208357415891320">"Pinapayagan ang app na mag-access ng panlabas na storage para sa lahat ng user."</string>
     <string name="permlab_cache_filesystem" msgid="5656487264819669824">"i-access ang cache filesystem"</string>
     <string name="permdesc_cache_filesystem" msgid="5578967642265550955">"Pinapayagan ang app na basahin at isulat ang cache filesystem."</string>
     <string name="permlab_use_sip" msgid="5986952362795870502">"gumawa/tumanggap ng mga tawag sa Internet"</string>
@@ -581,6 +579,10 @@
     <string name="policydesc_encryptedStorage" msgid="2637732115325316992">"Hilinging naka-encrypt ang nakaimbak na data ng app."</string>
     <string name="policylab_disableCamera" msgid="6395301023152297826">"Huwag paganahin mga camera"</string>
     <string name="policydesc_disableCamera" msgid="2306349042834754597">"Pigilan ang paggamit sa lahat ng camera ng device."</string>
+    <!-- no translation found for policylab_disableKeyguardWidgets (1794894613389073926) -->
+    <skip />
+    <!-- no translation found for policydesc_disableKeyguardWidgets (7254624892984033592) -->
+    <skip />
   <string-array name="phoneTypes">
     <item msgid="8901098336658710359">"Home"</item>
     <item msgid="869923650527136615">"Mobile"</item>
@@ -1319,64 +1321,46 @@
     <string name="bluetooth_a2dp_audio_route_name" msgid="8575624030406771015">"Audio sa Bluetooth"</string>
     <string name="media_route_chooser_grouping_done" msgid="7966438307723317169">"Tapos na"</string>
     <string name="media_route_button_content_description" msgid="5758553567065145276">"Output ng media"</string>
-    <!-- no translation found for display_manager_built_in_display_name (2583134294292563941) -->
+    <string name="display_manager_built_in_display_name" msgid="2583134294292563941">"Built-in na Screen"</string>
+    <!-- no translation found for display_manager_hdmi_display_name (1555264559227470109) -->
     <skip />
-    <!-- no translation found for display_manager_overlay_display_name (5142365982271620716) -->
+    <string name="display_manager_overlay_display_name" msgid="5142365982271620716">"Overlay #<xliff:g id="ID">%1$d</xliff:g>"</string>
+    <!-- no translation found for display_manager_overlay_display_title (652124517672257172) -->
     <skip />
-    <!-- no translation found for display_manager_overlay_display_title (8186674340178573982) -->
-    <skip />
-    <!-- no translation found for kg_emergency_call_label (684946192523830531) -->
-    <skip />
-    <!-- no translation found for kg_forgot_pattern_button_text (8852021467868220608) -->
-    <skip />
-    <!-- no translation found for kg_wrong_pattern (1850806070801358830) -->
-    <skip />
-    <!-- no translation found for kg_wrong_password (2333281762128113157) -->
-    <skip />
-    <!-- no translation found for kg_wrong_pin (1131306510833563801) -->
-    <skip />
-    <!-- no translation found for kg_too_many_failed_attempts_countdown (353963338189371686) -->
-    <skip />
-    <!-- no translation found for kg_pattern_instructions (398978611683075868) -->
-    <skip />
-    <!-- no translation found for kg_sim_pin_instructions (2319508550934557331) -->
-    <skip />
-    <!-- no translation found for kg_pin_instructions (2377242233495111557) -->
-    <skip />
-    <!-- no translation found for kg_password_instructions (5753646556186936819) -->
-    <skip />
-    <!-- no translation found for kg_puk_enter_puk_hint (5183097160254244459) -->
-    <skip />
-    <!-- no translation found for kg_puk_enter_pin_hint (597821135578014901) -->
-    <skip />
-    <!-- no translation found for kg_sim_unlock_progress_dialog_message (8950398016976865762) -->
-    <skip />
-    <!-- no translation found for kg_password_wrong_pin_code (1139324887413846912) -->
-    <skip />
-    <!-- no translation found for kg_invalid_sim_pin_hint (8795159358110620001) -->
-    <skip />
-    <!-- no translation found for kg_invalid_sim_puk_hint (5216603185442368307) -->
-    <skip />
-    <!-- no translation found for kg_sim_puk_recovery_hint (5577753137718442566) -->
-    <skip />
-    <!-- no translation found for kg_invalid_puk (5809955359950817326) -->
-    <skip />
-    <!-- no translation found for kg_login_too_many_attempts (6486842094005698475) -->
-    <skip />
-    <!-- no translation found for kg_login_instructions (1100551261265506448) -->
-    <skip />
-    <!-- no translation found for kg_login_username_hint (5718534272070920364) -->
-    <skip />
-    <!-- no translation found for kg_login_password_hint (9057289103827298549) -->
-    <skip />
-    <!-- no translation found for kg_login_submit_button (5355904582674054702) -->
-    <skip />
-    <!-- no translation found for kg_login_invalid_input (5754664119319872197) -->
-    <skip />
-    <!-- no translation found for kg_login_account_recovery_hint (5690709132841752974) -->
-    <skip />
-    <!-- no translation found for kg_login_checking_password (8849589033659332457) -->
-    <skip />
-    <!-- no translation found for kg_temp_back_string (5812983904056640466) -->
-    <skip />
+    <string name="kg_emergency_call_label" msgid="684946192523830531">"Emergency na tawag"</string>
+    <string name="kg_forgot_pattern_button_text" msgid="8852021467868220608">"Nakalimutan ang Pattern"</string>
+    <string name="kg_wrong_pattern" msgid="1850806070801358830">"Maling Pattern"</string>
+    <string name="kg_wrong_password" msgid="2333281762128113157">"Maling Password"</string>
+    <string name="kg_wrong_pin" msgid="1131306510833563801">"Maling PIN"</string>
+    <string name="kg_too_many_failed_attempts_countdown" msgid="6358110221603297548">"Subukang muli sa loob ng <xliff:g id="NUMBER">%d</xliff:g> (na) segundo."</string>
+    <string name="kg_pattern_instructions" msgid="398978611683075868">"Iguhit ang iyong pattern"</string>
+    <string name="kg_sim_pin_instructions" msgid="2319508550934557331">"Ilagay ang SIM PIN"</string>
+    <string name="kg_pin_instructions" msgid="2377242233495111557">"Ilagay ang PIN"</string>
+    <string name="kg_password_instructions" msgid="5753646556186936819">"Ilagay ang Password"</string>
+    <string name="kg_puk_enter_puk_hint" msgid="5183097160254244459">"PUK code"</string>
+    <string name="kg_puk_enter_pin_hint" msgid="597821135578014901">"Bagong PIN code"</string>
+    <string name="kg_sim_unlock_progress_dialog_message" msgid="8950398016976865762">"Ina-unlock ang SIM card…"</string>
+    <string name="kg_password_wrong_pin_code" msgid="1139324887413846912">"Hindi tamang PIN code."</string>
+    <string name="kg_invalid_sim_pin_hint" msgid="8795159358110620001">"Mag-type ng PIN na 4 hanggang 8 numero."</string>
+    <string name="kg_invalid_sim_puk_hint" msgid="5216603185442368307">"Mag-type ng PUK na may 8 numbero o mas mahaba."</string>
+    <string name="kg_sim_puk_recovery_hint" msgid="5577753137718442566">"I-type ang PUK at bagong PIN code"</string>
+    <string name="kg_invalid_puk" msgid="5809955359950817326">"Hindi tama ang na-type mong PUK."</string>
+    <string name="kg_login_too_many_attempts" msgid="6486842094005698475">"Masyadong maraming pagtatangka sa pattern"</string>
+    <string name="kg_login_instructions" msgid="1100551261265506448">"Upang i-unlock, mag-sign in gamit ang iyong Google account."</string>
+    <string name="kg_login_username_hint" msgid="5718534272070920364">"Username (email)"</string>
+    <string name="kg_login_password_hint" msgid="9057289103827298549">"Password"</string>
+    <string name="kg_login_submit_button" msgid="5355904582674054702">"Mag-sign in"</string>
+    <string name="kg_login_invalid_input" msgid="5754664119319872197">"Di-wastong username o password."</string>
+    <string name="kg_login_account_recovery_hint" msgid="5690709132841752974">"Nakalimutan ang iyong username o password?"\n"Bisitahin ang "<b>"google.com/accounts/recovery"</b>"."</string>
+    <string name="kg_login_checking_password" msgid="8849589033659332457">"Sinusuri…"</string>
+    <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="8276745642049502550">"Na-type mo nang hindi tama ang iyong PIN nang <xliff:g id="NUMBER_0">%d</xliff:g> (na) beses. "\n\n"Subukang muli sa loob ng <xliff:g id="NUMBER_1">%d</xliff:g> (na) segundo."</string>
+    <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="7813713389422226531">"Na-type mo nang hindi tama ang iyong password nang <xliff:g id="NUMBER_0">%d</xliff:g> (na) beses. "\n\n"Subukang muli sa loob ng <xliff:g id="NUMBER_1">%d</xliff:g> (na) segundo."</string>
+    <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="74089475965050805">"Naguhit mo nang hindi tama ang iyong pattern sa pag-unlock nang <xliff:g id="NUMBER_0">%d</xliff:g> (na) beses. "\n\n"Subukang muli sa loob ng <xliff:g id="NUMBER_1">%d</xliff:g> (na) segundo."</string>
+    <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="1575557200627128949">"Tinangka mo sa hindi tamang paraan na i-unlock ang tabelt nang <xliff:g id="NUMBER_0">%d</xliff:g> (na) beses. Pagkatapos ng <xliff:g id="NUMBER_1">%d</xliff:g> pang hindi matagumpay na pagtatangka, ire-reset ang tablet sa factory default at mawawala ang lahat ng data ng user."</string>
+    <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="4051015943038199910">"Tinangka mo sa hindi tamang paraan na i-unlock ang telepono nang <xliff:g id="NUMBER_0">%d</xliff:g> (na) beses. Pagkatapos ng <xliff:g id="NUMBER_1">%d</xliff:g> pang hindi matagumpay na pagtatangka, ire-reset ang telepono sa factory default at mawawala ang lahat ng data ng user."</string>
+    <string name="kg_failed_attempts_now_wiping" product="tablet" msgid="2072996269148483637">"Tinangka mo sa hindi tamang paraan na i-unlock ang tablet nang <xliff:g id="NUMBER">%d</xliff:g> (na) beses. Ire-reset na ngayon ang tablet sa factory default."</string>
+    <string name="kg_failed_attempts_now_wiping" product="default" msgid="4817627474419471518">"Tinangka mo sa hindi tamang paraan na i-unlock ang telepono nang <xliff:g id="NUMBER">%d</xliff:g> (na) beses. Ire-reset na ngayon ang telepono sa factory default."</string>
+    <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"Naguhit mo nang hindi tama ang iyong pattern sa pag-unlock nang <xliff:g id="NUMBER_0">%d</xliff:g> (na) beses. Pagkatapos ng <xliff:g id="NUMBER_1">%d</xliff:g> pang hindi matagumpay na pagtatangka, hihilingin sa iyong i-unlock ang tablet mo gamit ang isang email account."\n\n" Subukang muli sa loob ng <xliff:g id="NUMBER_2">%d</xliff:g> (na) segundo."</string>
+    <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"Naguhit mo nang hindi tama ang iyong pattern sa pag-unlock nang <xliff:g id="NUMBER_0">%d</xliff:g> (na) beses. Pagkatapos ng <xliff:g id="NUMBER_1">%d</xliff:g> pang hindi matagumpay na pagtatangka, hihilingin sa iyong i-unlock ang telepono mo gamit ang isang email account."\n\n" Subukang muli sa loob ng <xliff:g id="NUMBER_2">%d</xliff:g> (na) segundo."</string>
+    <string name="kg_temp_back_string" msgid="5812983904056640466">"&lt;"</string>
 </resources>
diff --git a/core/res/res/values-tr/strings.xml b/core/res/res/values-tr/strings.xml
index a4e7d4d..64e665b 100644
--- a/core/res/res/values-tr/strings.xml
+++ b/core/res/res/values-tr/strings.xml
@@ -547,10 +547,8 @@
     <string name="permdesc_sdcardWrite" product="default" msgid="4337417790936632090">"Uygulamaya, SD karta yazma izni verir."</string>
     <string name="permlab_mediaStorageWrite" product="default" msgid="6859839199706879015">"dahili medya depolama birimi içeriğini değiştir/sil"</string>
     <string name="permdesc_mediaStorageWrite" product="default" msgid="8189160597698529185">"Uygulamaya, dahili medya depolama içeriğini değiştirme izni verir."</string>
-    <!-- no translation found for permlab_sdcardAccessAll (8150613823900460576) -->
-    <skip />
-    <!-- no translation found for permdesc_sdcardAccessAll (3215208357415891320) -->
-    <skip />
+    <string name="permlab_sdcardAccessAll" msgid="8150613823900460576">"tüm kullanıcılar için harici depolama eriş"</string>
+    <string name="permdesc_sdcardAccessAll" msgid="3215208357415891320">"Uygulamaya tüm kullanıcılar için harici depolamaya erişim izni verir."</string>
     <string name="permlab_cache_filesystem" msgid="5656487264819669824">"önbellek dosya sistemine eriş"</string>
     <string name="permdesc_cache_filesystem" msgid="5578967642265550955">"Uygulamaya, önbellek dosya sisteminde okuma ve yazma yapma izni verir."</string>
     <string name="permlab_use_sip" msgid="5986952362795870502">"İnternet çağrılar yap/alma"</string>
@@ -581,6 +579,10 @@
     <string name="policydesc_encryptedStorage" msgid="2637732115325316992">"Depolanan uygulama verilerinin şifrelenmiş olmasını zorunlu kılma."</string>
     <string name="policylab_disableCamera" msgid="6395301023152297826">"Kameraları devre dışı bırak"</string>
     <string name="policydesc_disableCamera" msgid="2306349042834754597">"Tüm cihaz kameralarının kullanımını engelleme."</string>
+    <!-- no translation found for policylab_disableKeyguardWidgets (1794894613389073926) -->
+    <skip />
+    <!-- no translation found for policydesc_disableKeyguardWidgets (7254624892984033592) -->
+    <skip />
   <string-array name="phoneTypes">
     <item msgid="8901098336658710359">"Ev"</item>
     <item msgid="869923650527136615">"Mobil"</item>
@@ -1319,64 +1321,46 @@
     <string name="bluetooth_a2dp_audio_route_name" msgid="8575624030406771015">"Bluetooth ses"</string>
     <string name="media_route_chooser_grouping_done" msgid="7966438307723317169">"Tamamlandı"</string>
     <string name="media_route_button_content_description" msgid="5758553567065145276">"Medya çıkışı"</string>
-    <!-- no translation found for display_manager_built_in_display_name (2583134294292563941) -->
+    <string name="display_manager_built_in_display_name" msgid="2583134294292563941">"Yerleşik Ekran"</string>
+    <!-- no translation found for display_manager_hdmi_display_name (1555264559227470109) -->
     <skip />
-    <!-- no translation found for display_manager_overlay_display_name (5142365982271620716) -->
+    <string name="display_manager_overlay_display_name" msgid="5142365982271620716">"Yer Paylaşımı No. <xliff:g id="ID">%1$d</xliff:g>"</string>
+    <!-- no translation found for display_manager_overlay_display_title (652124517672257172) -->
     <skip />
-    <!-- no translation found for display_manager_overlay_display_title (8186674340178573982) -->
-    <skip />
-    <!-- no translation found for kg_emergency_call_label (684946192523830531) -->
-    <skip />
-    <!-- no translation found for kg_forgot_pattern_button_text (8852021467868220608) -->
-    <skip />
-    <!-- no translation found for kg_wrong_pattern (1850806070801358830) -->
-    <skip />
-    <!-- no translation found for kg_wrong_password (2333281762128113157) -->
-    <skip />
-    <!-- no translation found for kg_wrong_pin (1131306510833563801) -->
-    <skip />
-    <!-- no translation found for kg_too_many_failed_attempts_countdown (353963338189371686) -->
-    <skip />
-    <!-- no translation found for kg_pattern_instructions (398978611683075868) -->
-    <skip />
-    <!-- no translation found for kg_sim_pin_instructions (2319508550934557331) -->
-    <skip />
-    <!-- no translation found for kg_pin_instructions (2377242233495111557) -->
-    <skip />
-    <!-- no translation found for kg_password_instructions (5753646556186936819) -->
-    <skip />
-    <!-- no translation found for kg_puk_enter_puk_hint (5183097160254244459) -->
-    <skip />
-    <!-- no translation found for kg_puk_enter_pin_hint (597821135578014901) -->
-    <skip />
-    <!-- no translation found for kg_sim_unlock_progress_dialog_message (8950398016976865762) -->
-    <skip />
-    <!-- no translation found for kg_password_wrong_pin_code (1139324887413846912) -->
-    <skip />
-    <!-- no translation found for kg_invalid_sim_pin_hint (8795159358110620001) -->
-    <skip />
-    <!-- no translation found for kg_invalid_sim_puk_hint (5216603185442368307) -->
-    <skip />
-    <!-- no translation found for kg_sim_puk_recovery_hint (5577753137718442566) -->
-    <skip />
-    <!-- no translation found for kg_invalid_puk (5809955359950817326) -->
-    <skip />
-    <!-- no translation found for kg_login_too_many_attempts (6486842094005698475) -->
-    <skip />
-    <!-- no translation found for kg_login_instructions (1100551261265506448) -->
-    <skip />
-    <!-- no translation found for kg_login_username_hint (5718534272070920364) -->
-    <skip />
-    <!-- no translation found for kg_login_password_hint (9057289103827298549) -->
-    <skip />
-    <!-- no translation found for kg_login_submit_button (5355904582674054702) -->
-    <skip />
-    <!-- no translation found for kg_login_invalid_input (5754664119319872197) -->
-    <skip />
-    <!-- no translation found for kg_login_account_recovery_hint (5690709132841752974) -->
-    <skip />
-    <!-- no translation found for kg_login_checking_password (8849589033659332457) -->
-    <skip />
-    <!-- no translation found for kg_temp_back_string (5812983904056640466) -->
-    <skip />
+    <string name="kg_emergency_call_label" msgid="684946192523830531">"Acil durum çağrısı"</string>
+    <string name="kg_forgot_pattern_button_text" msgid="8852021467868220608">"Deseni Unuttunuz mu?"</string>
+    <string name="kg_wrong_pattern" msgid="1850806070801358830">"Yanlış Desen"</string>
+    <string name="kg_wrong_password" msgid="2333281762128113157">"Yanlış Şifre"</string>
+    <string name="kg_wrong_pin" msgid="1131306510833563801">"Yanlış PIN"</string>
+    <string name="kg_too_many_failed_attempts_countdown" msgid="6358110221603297548">"<xliff:g id="NUMBER">%d</xliff:g> saniye içinde yeniden deneyin."</string>
+    <string name="kg_pattern_instructions" msgid="398978611683075868">"Deseninizi çizin"</string>
+    <string name="kg_sim_pin_instructions" msgid="2319508550934557331">"SIM PIN kodunu girin"</string>
+    <string name="kg_pin_instructions" msgid="2377242233495111557">"PIN\'i girin"</string>
+    <string name="kg_password_instructions" msgid="5753646556186936819">"Şifreyi Girin"</string>
+    <string name="kg_puk_enter_puk_hint" msgid="5183097160254244459">"PUK kodu"</string>
+    <string name="kg_puk_enter_pin_hint" msgid="597821135578014901">"Yeni PIN kodu"</string>
+    <string name="kg_sim_unlock_progress_dialog_message" msgid="8950398016976865762">"SIM kart kilidi açılıyor…"</string>
+    <string name="kg_password_wrong_pin_code" msgid="1139324887413846912">"Yanlış PIN kodu."</string>
+    <string name="kg_invalid_sim_pin_hint" msgid="8795159358110620001">"4-8 rakamdan oluşan bir PIN girin."</string>
+    <string name="kg_invalid_sim_puk_hint" msgid="5216603185442368307">"8 veya daha uzun basamaklı bir PUK kodu yazın."</string>
+    <string name="kg_sim_puk_recovery_hint" msgid="5577753137718442566">"PUK ve yeni PIN kodunu yazın"</string>
+    <string name="kg_invalid_puk" msgid="5809955359950817326">"Yazdığınız PUK doğru değil."</string>
+    <string name="kg_login_too_many_attempts" msgid="6486842094005698475">"Çok fazla sayıda desen denemesi yapıldı"</string>
+    <string name="kg_login_instructions" msgid="1100551261265506448">"Kilidi açmak için Google hesabınızla oturum açın."</string>
+    <string name="kg_login_username_hint" msgid="5718534272070920364">"Kullanıcı adı (e-posta)"</string>
+    <string name="kg_login_password_hint" msgid="9057289103827298549">"Şifre"</string>
+    <string name="kg_login_submit_button" msgid="5355904582674054702">"Oturum aç"</string>
+    <string name="kg_login_invalid_input" msgid="5754664119319872197">"Geçersiz kullanıcı adı veya şifre."</string>
+    <string name="kg_login_account_recovery_hint" msgid="5690709132841752974">"Kullanıcı adınızı veya şifrenizi mi unuttunuz?"\n<b>"google.com/accounts/recovery"</b>" adresini ziyaret edin."</string>
+    <string name="kg_login_checking_password" msgid="8849589033659332457">"Kontrol ediliyor…"</string>
+    <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="8276745642049502550">"PIN kodunuzu <xliff:g id="NUMBER_0">%d</xliff:g> kez yanlış girdiniz. "\n\n"<xliff:g id="NUMBER_1">%d</xliff:g> saniye içinde tekrar deneyin."</string>
+    <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="7813713389422226531">"Şifrenizi <xliff:g id="NUMBER_0">%d</xliff:g> kez yanlış yazdınız. "\n\n"<xliff:g id="NUMBER_1">%d</xliff:g> saniye içinde tekrar deneyin."</string>
+    <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="74089475965050805">"Kilit açma deseninizi <xliff:g id="NUMBER_0">%d</xliff:g> kez yanlış çizdiniz. "\n\n"<xliff:g id="NUMBER_1">%d</xliff:g> saniye içinde tekrar deneyin."</string>
+    <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="1575557200627128949">"Tablet kilidini <xliff:g id="NUMBER_0">%d</xliff:g> defa yanlış bir şekilde açmaya çalıştınız. <xliff:g id="NUMBER_1">%d</xliff:g> defa daha başarısız deneme yapılırsa, tablet fabrika varsayılan değerine sıfırlanır ve tüm kullanıcı verileri kaybedilir."</string>
+    <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="4051015943038199910">"Telefonun kilidini <xliff:g id="NUMBER_0">%d</xliff:g> defa yanlış bir şekilde açmaya çalıştınız. <xliff:g id="NUMBER_1">%d</xliff:g> defa daha başarısız deneme yapılırsa, telefon fabrika varsayılan değerine sıfırlanır ve tüm kullanıcı verileri kaybedilir."</string>
+    <string name="kg_failed_attempts_now_wiping" product="tablet" msgid="2072996269148483637">"Tablet kilidini <xliff:g id="NUMBER">%d</xliff:g> defa yanlış bir şekilde açmaya çalıştınız. Tablet şimdi fabrika varsayılanına sıfırlanacak."</string>
+    <string name="kg_failed_attempts_now_wiping" product="default" msgid="4817627474419471518">"Telefon kilidini <xliff:g id="NUMBER">%d</xliff:g> defa yanlış bir şekilde açmaya çalıştınız. Telefon şimdi fabrika varsayılanına sıfırlanacak."</string>
+    <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"Kilit açma deseninizi <xliff:g id="NUMBER_0">%d</xliff:g> kez yanlış çizdiniz. <xliff:g id="NUMBER_1">%d</xliff:g> başarısız denemeden sonra, tabletinizi bir e-posta hesabı kullanarak açmanız istenir."\n\n" <xliff:g id="NUMBER_2">%d</xliff:g> saniye içinde tekrar deneyin."</string>
+    <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"Kilit açma deseninizi <xliff:g id="NUMBER_0">%d</xliff:g> kez yanlış çizdiniz. <xliff:g id="NUMBER_1">%d</xliff:g> başarısız denemeden sonra telefonunuzu bir e-posta hesabı kullanarak açmanız istenir."\n\n" <xliff:g id="NUMBER_2">%d</xliff:g> saniye içinde tekrar deneyin."</string>
+    <string name="kg_temp_back_string" msgid="5812983904056640466">"&lt;"</string>
 </resources>
diff --git a/core/res/res/values-uk/strings.xml b/core/res/res/values-uk/strings.xml
index 5c4a1b1..8a2cf15 100644
--- a/core/res/res/values-uk/strings.xml
+++ b/core/res/res/values-uk/strings.xml
@@ -547,10 +547,8 @@
     <string name="permdesc_sdcardWrite" product="default" msgid="4337417790936632090">"Дозволяє програмі записувати на карту SD."</string>
     <string name="permlab_mediaStorageWrite" product="default" msgid="6859839199706879015">"змінювати/видаляти вміст внутр. сховища даних"</string>
     <string name="permdesc_mediaStorageWrite" product="default" msgid="8189160597698529185">"Дозволяє програмі змінювати вміст внутрішнього сховища даних."</string>
-    <!-- no translation found for permlab_sdcardAccessAll (8150613823900460576) -->
-    <skip />
-    <!-- no translation found for permdesc_sdcardAccessAll (3215208357415891320) -->
-    <skip />
+    <string name="permlab_sdcardAccessAll" msgid="8150613823900460576">"доступ до зовн. пам’яті всіх корист."</string>
+    <string name="permdesc_sdcardAccessAll" msgid="3215208357415891320">"Дозволяє програмі отримувати доступ до зовнішньої пам’яті всіх користувачів."</string>
     <string name="permlab_cache_filesystem" msgid="5656487264819669824">"отр. дост. до файл. сист. кешу"</string>
     <string name="permdesc_cache_filesystem" msgid="5578967642265550955">"Дозволяє програмі читати з файлової системи кеш-пам’яті та писати в неї."</string>
     <string name="permlab_use_sip" msgid="5986952362795870502">"здійсн./отрим. Інтернет-дзвін."</string>
@@ -581,6 +579,10 @@
     <string name="policydesc_encryptedStorage" msgid="2637732115325316992">"Вимагати шифрування даних збереженої програми."</string>
     <string name="policylab_disableCamera" msgid="6395301023152297826">"Вимкнути камери"</string>
     <string name="policydesc_disableCamera" msgid="2306349042834754597">"Запобігати використанню всіх камер пристрою."</string>
+    <!-- no translation found for policylab_disableKeyguardWidgets (1794894613389073926) -->
+    <skip />
+    <!-- no translation found for policydesc_disableKeyguardWidgets (7254624892984033592) -->
+    <skip />
   <string-array name="phoneTypes">
     <item msgid="8901098336658710359">"Дом."</item>
     <item msgid="869923650527136615">"Мобільний"</item>
@@ -1319,64 +1321,46 @@
     <string name="bluetooth_a2dp_audio_route_name" msgid="8575624030406771015">"Аудіо Bluetooth"</string>
     <string name="media_route_chooser_grouping_done" msgid="7966438307723317169">"Готово"</string>
     <string name="media_route_button_content_description" msgid="5758553567065145276">"Вивід медіа-даних"</string>
-    <!-- no translation found for display_manager_built_in_display_name (2583134294292563941) -->
+    <string name="display_manager_built_in_display_name" msgid="2583134294292563941">"Вбудований екран"</string>
+    <!-- no translation found for display_manager_hdmi_display_name (1555264559227470109) -->
     <skip />
-    <!-- no translation found for display_manager_overlay_display_name (5142365982271620716) -->
+    <string name="display_manager_overlay_display_name" msgid="5142365982271620716">"Накладання №<xliff:g id="ID">%1$d</xliff:g>"</string>
+    <!-- no translation found for display_manager_overlay_display_title (652124517672257172) -->
     <skip />
-    <!-- no translation found for display_manager_overlay_display_title (8186674340178573982) -->
-    <skip />
-    <!-- no translation found for kg_emergency_call_label (684946192523830531) -->
-    <skip />
-    <!-- no translation found for kg_forgot_pattern_button_text (8852021467868220608) -->
-    <skip />
-    <!-- no translation found for kg_wrong_pattern (1850806070801358830) -->
-    <skip />
-    <!-- no translation found for kg_wrong_password (2333281762128113157) -->
-    <skip />
-    <!-- no translation found for kg_wrong_pin (1131306510833563801) -->
-    <skip />
-    <!-- no translation found for kg_too_many_failed_attempts_countdown (353963338189371686) -->
-    <skip />
-    <!-- no translation found for kg_pattern_instructions (398978611683075868) -->
-    <skip />
-    <!-- no translation found for kg_sim_pin_instructions (2319508550934557331) -->
-    <skip />
-    <!-- no translation found for kg_pin_instructions (2377242233495111557) -->
-    <skip />
-    <!-- no translation found for kg_password_instructions (5753646556186936819) -->
-    <skip />
-    <!-- no translation found for kg_puk_enter_puk_hint (5183097160254244459) -->
-    <skip />
-    <!-- no translation found for kg_puk_enter_pin_hint (597821135578014901) -->
-    <skip />
-    <!-- no translation found for kg_sim_unlock_progress_dialog_message (8950398016976865762) -->
-    <skip />
-    <!-- no translation found for kg_password_wrong_pin_code (1139324887413846912) -->
-    <skip />
-    <!-- no translation found for kg_invalid_sim_pin_hint (8795159358110620001) -->
-    <skip />
-    <!-- no translation found for kg_invalid_sim_puk_hint (5216603185442368307) -->
-    <skip />
-    <!-- no translation found for kg_sim_puk_recovery_hint (5577753137718442566) -->
-    <skip />
-    <!-- no translation found for kg_invalid_puk (5809955359950817326) -->
-    <skip />
-    <!-- no translation found for kg_login_too_many_attempts (6486842094005698475) -->
-    <skip />
-    <!-- no translation found for kg_login_instructions (1100551261265506448) -->
-    <skip />
-    <!-- no translation found for kg_login_username_hint (5718534272070920364) -->
-    <skip />
-    <!-- no translation found for kg_login_password_hint (9057289103827298549) -->
-    <skip />
-    <!-- no translation found for kg_login_submit_button (5355904582674054702) -->
-    <skip />
-    <!-- no translation found for kg_login_invalid_input (5754664119319872197) -->
-    <skip />
-    <!-- no translation found for kg_login_account_recovery_hint (5690709132841752974) -->
-    <skip />
-    <!-- no translation found for kg_login_checking_password (8849589033659332457) -->
-    <skip />
-    <!-- no translation found for kg_temp_back_string (5812983904056640466) -->
-    <skip />
+    <string name="kg_emergency_call_label" msgid="684946192523830531">"Екстрений виклик"</string>
+    <string name="kg_forgot_pattern_button_text" msgid="8852021467868220608">"Не пам’ятаю ключ"</string>
+    <string name="kg_wrong_pattern" msgid="1850806070801358830">"Неправильний ключ"</string>
+    <string name="kg_wrong_password" msgid="2333281762128113157">"Неправильний пароль"</string>
+    <string name="kg_wrong_pin" msgid="1131306510833563801">"Неправильний PIN-код"</string>
+    <string name="kg_too_many_failed_attempts_countdown" msgid="6358110221603297548">"Повторіть спробу через <xliff:g id="NUMBER">%d</xliff:g> сек."</string>
+    <string name="kg_pattern_instructions" msgid="398978611683075868">"Намалюйте ключ"</string>
+    <string name="kg_sim_pin_instructions" msgid="2319508550934557331">"Введіть PIN-код SIM-карти"</string>
+    <string name="kg_pin_instructions" msgid="2377242233495111557">"Введіть PIN-код"</string>
+    <string name="kg_password_instructions" msgid="5753646556186936819">"Введіть пароль"</string>
+    <string name="kg_puk_enter_puk_hint" msgid="5183097160254244459">"PUK-код"</string>
+    <string name="kg_puk_enter_pin_hint" msgid="597821135578014901">"Новий PIN-код"</string>
+    <string name="kg_sim_unlock_progress_dialog_message" msgid="8950398016976865762">"Розблокування SIM-карти…"</string>
+    <string name="kg_password_wrong_pin_code" msgid="1139324887413846912">"Неправильний PIN-код."</string>
+    <string name="kg_invalid_sim_pin_hint" msgid="8795159358110620001">"Введіть PIN-код із 4–8 цифр."</string>
+    <string name="kg_invalid_sim_puk_hint" msgid="5216603185442368307">"Введіть PUK-код із 8 або більше цифр."</string>
+    <string name="kg_sim_puk_recovery_hint" msgid="5577753137718442566">"Введіть PUK-код і новий PIN-код"</string>
+    <string name="kg_invalid_puk" msgid="5809955359950817326">"Введений PUK-код не правильний."</string>
+    <string name="kg_login_too_many_attempts" msgid="6486842094005698475">"Забагато спроб намалювати ключ"</string>
+    <string name="kg_login_instructions" msgid="1100551261265506448">"Щоб розблокувати, увійдіть, використовуючи дані облікового запису Google."</string>
+    <string name="kg_login_username_hint" msgid="5718534272070920364">"Ім’я користувача (електронна адреса)"</string>
+    <string name="kg_login_password_hint" msgid="9057289103827298549">"Пароль"</string>
+    <string name="kg_login_submit_button" msgid="5355904582674054702">"Увійти"</string>
+    <string name="kg_login_invalid_input" msgid="5754664119319872197">"Недійсне ім’я користувача чи пароль."</string>
+    <string name="kg_login_account_recovery_hint" msgid="5690709132841752974">"Не пам’ятаєте ім’я користувача чи пароль?"\n"Відвідайте сторінку "<b>"google.com/accounts/recovery"</b>"."</string>
+    <string name="kg_login_checking_password" msgid="8849589033659332457">"Перевірка…"</string>
+    <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="8276745642049502550">"PIN-код неправильно введено стільки разів: <xliff:g id="NUMBER_0">%d</xliff:g>. "\n\n"Повторіть спробу через <xliff:g id="NUMBER_1">%d</xliff:g> сек."</string>
+    <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="7813713389422226531">"Пароль неправильно введено стільки разів: <xliff:g id="NUMBER_0">%d</xliff:g>. "\n\n"Повторіть спробу через <xliff:g id="NUMBER_1">%d</xliff:g> сек."</string>
+    <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="74089475965050805">"Ключ розблокування неправильно намальовано стільки разів: <xliff:g id="NUMBER_0">%d</xliff:g>. "\n\n"Повторіть спробу через <xliff:g id="NUMBER_1">%d</xliff:g> сек."</string>
+    <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="1575557200627128949">"Кількість невдалих спроб розблокувати планшетний ПК: <xliff:g id="NUMBER_0">%d</xliff:g>. У вас є ще стільки спроб: <xliff:g id="NUMBER_1">%d</xliff:g>. У разі невдачі налаштування планшетного ПК буде змінено на заводські за умовчанням, а всі дані користувача – втрачено."</string>
+    <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="4051015943038199910">"Кількість невдалих спроб розблокувати телефон: <xliff:g id="NUMBER_0">%d</xliff:g>. У вас є ще стільки спроб: <xliff:g id="NUMBER_1">%d</xliff:g>. У разі невдачі налаштування телефону буде змінено на заводські за умовчанням, а всі дані користувача – втрачено."</string>
+    <string name="kg_failed_attempts_now_wiping" product="tablet" msgid="2072996269148483637">"Кількість невдалих спроб розблокувати планшетний ПК: <xliff:g id="NUMBER">%d</xliff:g>. Налаштування планшетного ПК буде змінено на заводські за умовчанням."</string>
+    <string name="kg_failed_attempts_now_wiping" product="default" msgid="4817627474419471518">"Кількість невдалих спроб розблокувати телефон: <xliff:g id="NUMBER">%d</xliff:g>. Налаштування телефону буде змінено на заводські за умовчанням."</string>
+    <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"Ключ розблокування неправильно намальовано стільки разів: <xliff:g id="NUMBER_0">%d</xliff:g>. У вас є ще стільки спроб: <xliff:g id="NUMBER_1">%d</xliff:g>. У разі невдачі з’явиться запит розблокувати планшетний ПК за допомогою облікового запису електронної пошти."\n\n" Повторіть спробу через <xliff:g id="NUMBER_2">%d</xliff:g> сек."</string>
+    <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"Ключ розблокування неправильно намальовано стільки разів: <xliff:g id="NUMBER_0">%d</xliff:g>. У вас є ще стільки спроб: <xliff:g id="NUMBER_1">%d</xliff:g>. У разі невдачі з’явиться запит розблокувати телефон за допомогою облікового запису електронної пошти."\n\n" Повторіть спробу через <xliff:g id="NUMBER_2">%d</xliff:g> сек."</string>
+    <string name="kg_temp_back_string" msgid="5812983904056640466">"&lt;"</string>
 </resources>
diff --git a/core/res/res/values-vi/strings.xml b/core/res/res/values-vi/strings.xml
index 66d0f31..2c9289d 100644
--- a/core/res/res/values-vi/strings.xml
+++ b/core/res/res/values-vi/strings.xml
@@ -547,10 +547,8 @@
     <string name="permdesc_sdcardWrite" product="default" msgid="4337417790936632090">"Cho phép ứng dụng ghi vào thẻ SD."</string>
     <string name="permlab_mediaStorageWrite" product="default" msgid="6859839199706879015">"sửa đổi/xóa nội dung trên bộ nhớ phương tiện cục bộ"</string>
     <string name="permdesc_mediaStorageWrite" product="default" msgid="8189160597698529185">"Cho phép ứng dụng sửa đổi nội dung của bộ lưu trữ phương tiện nội bộ."</string>
-    <!-- no translation found for permlab_sdcardAccessAll (8150613823900460576) -->
-    <skip />
-    <!-- no translation found for permdesc_sdcardAccessAll (3215208357415891320) -->
-    <skip />
+    <string name="permlab_sdcardAccessAll" msgid="8150613823900460576">"truy cập bộ nhớ ngoài của tất cả người dùng"</string>
+    <string name="permdesc_sdcardAccessAll" msgid="3215208357415891320">"Cho phép ứng dụng truy cập bộ nhớ ngoài của tất cả người dùng."</string>
     <string name="permlab_cache_filesystem" msgid="5656487264819669824">"truy cập hệ thống tệp bộ nhớ cache"</string>
     <string name="permdesc_cache_filesystem" msgid="5578967642265550955">"Cho phép ứng dụng đọc và ghi hệ thống tệp bộ nhớ cache."</string>
     <string name="permlab_use_sip" msgid="5986952362795870502">"thực hiện/nhận cuộc gọi qua Internet"</string>
@@ -581,6 +579,10 @@
     <string name="policydesc_encryptedStorage" msgid="2637732115325316992">"Yêu cầu dữ liệu ứng dụng được lưu trữ phải được mã hóa."</string>
     <string name="policylab_disableCamera" msgid="6395301023152297826">"Vô hiệu hóa máy ảnh"</string>
     <string name="policydesc_disableCamera" msgid="2306349042834754597">"Ngăn sử dụng tất cả máy ảnh của thiết bị."</string>
+    <!-- no translation found for policylab_disableKeyguardWidgets (1794894613389073926) -->
+    <skip />
+    <!-- no translation found for policydesc_disableKeyguardWidgets (7254624892984033592) -->
+    <skip />
   <string-array name="phoneTypes">
     <item msgid="8901098336658710359">"Nhà riêng"</item>
     <item msgid="869923650527136615">"ĐT di động"</item>
@@ -1319,64 +1321,46 @@
     <string name="bluetooth_a2dp_audio_route_name" msgid="8575624030406771015">"Âm thanh Bluetooth"</string>
     <string name="media_route_chooser_grouping_done" msgid="7966438307723317169">"Xong"</string>
     <string name="media_route_button_content_description" msgid="5758553567065145276">"Đầu ra phương tiện"</string>
-    <!-- no translation found for display_manager_built_in_display_name (2583134294292563941) -->
+    <string name="display_manager_built_in_display_name" msgid="2583134294292563941">"Màn hình tích hợp"</string>
+    <!-- no translation found for display_manager_hdmi_display_name (1555264559227470109) -->
     <skip />
-    <!-- no translation found for display_manager_overlay_display_name (5142365982271620716) -->
+    <string name="display_manager_overlay_display_name" msgid="5142365982271620716">"Lớp phủ #<xliff:g id="ID">%1$d</xliff:g>"</string>
+    <!-- no translation found for display_manager_overlay_display_title (652124517672257172) -->
     <skip />
-    <!-- no translation found for display_manager_overlay_display_title (8186674340178573982) -->
-    <skip />
-    <!-- no translation found for kg_emergency_call_label (684946192523830531) -->
-    <skip />
-    <!-- no translation found for kg_forgot_pattern_button_text (8852021467868220608) -->
-    <skip />
-    <!-- no translation found for kg_wrong_pattern (1850806070801358830) -->
-    <skip />
-    <!-- no translation found for kg_wrong_password (2333281762128113157) -->
-    <skip />
-    <!-- no translation found for kg_wrong_pin (1131306510833563801) -->
-    <skip />
-    <!-- no translation found for kg_too_many_failed_attempts_countdown (353963338189371686) -->
-    <skip />
-    <!-- no translation found for kg_pattern_instructions (398978611683075868) -->
-    <skip />
-    <!-- no translation found for kg_sim_pin_instructions (2319508550934557331) -->
-    <skip />
-    <!-- no translation found for kg_pin_instructions (2377242233495111557) -->
-    <skip />
-    <!-- no translation found for kg_password_instructions (5753646556186936819) -->
-    <skip />
-    <!-- no translation found for kg_puk_enter_puk_hint (5183097160254244459) -->
-    <skip />
-    <!-- no translation found for kg_puk_enter_pin_hint (597821135578014901) -->
-    <skip />
-    <!-- no translation found for kg_sim_unlock_progress_dialog_message (8950398016976865762) -->
-    <skip />
-    <!-- no translation found for kg_password_wrong_pin_code (1139324887413846912) -->
-    <skip />
-    <!-- no translation found for kg_invalid_sim_pin_hint (8795159358110620001) -->
-    <skip />
-    <!-- no translation found for kg_invalid_sim_puk_hint (5216603185442368307) -->
-    <skip />
-    <!-- no translation found for kg_sim_puk_recovery_hint (5577753137718442566) -->
-    <skip />
-    <!-- no translation found for kg_invalid_puk (5809955359950817326) -->
-    <skip />
-    <!-- no translation found for kg_login_too_many_attempts (6486842094005698475) -->
-    <skip />
-    <!-- no translation found for kg_login_instructions (1100551261265506448) -->
-    <skip />
-    <!-- no translation found for kg_login_username_hint (5718534272070920364) -->
-    <skip />
-    <!-- no translation found for kg_login_password_hint (9057289103827298549) -->
-    <skip />
-    <!-- no translation found for kg_login_submit_button (5355904582674054702) -->
-    <skip />
-    <!-- no translation found for kg_login_invalid_input (5754664119319872197) -->
-    <skip />
-    <!-- no translation found for kg_login_account_recovery_hint (5690709132841752974) -->
-    <skip />
-    <!-- no translation found for kg_login_checking_password (8849589033659332457) -->
-    <skip />
-    <!-- no translation found for kg_temp_back_string (5812983904056640466) -->
-    <skip />
+    <string name="kg_emergency_call_label" msgid="684946192523830531">"Cuộc gọi khẩn cấp"</string>
+    <string name="kg_forgot_pattern_button_text" msgid="8852021467868220608">"Đã quên hình"</string>
+    <string name="kg_wrong_pattern" msgid="1850806070801358830">"Hình sai"</string>
+    <string name="kg_wrong_password" msgid="2333281762128113157">"Mật khẩu sai"</string>
+    <string name="kg_wrong_pin" msgid="1131306510833563801">"PIN sai"</string>
+    <string name="kg_too_many_failed_attempts_countdown" msgid="6358110221603297548">"Hãy thử lại sau <xliff:g id="NUMBER">%d</xliff:g> giây."</string>
+    <string name="kg_pattern_instructions" msgid="398978611683075868">"Vẽ hình của bạn"</string>
+    <string name="kg_sim_pin_instructions" msgid="2319508550934557331">"Nhập PIN của SIM"</string>
+    <string name="kg_pin_instructions" msgid="2377242233495111557">"Nhập PIN"</string>
+    <string name="kg_password_instructions" msgid="5753646556186936819">"Nhập mật khẩu"</string>
+    <string name="kg_puk_enter_puk_hint" msgid="5183097160254244459">"Mã PUK"</string>
+    <string name="kg_puk_enter_pin_hint" msgid="597821135578014901">"Mã PIN mới"</string>
+    <string name="kg_sim_unlock_progress_dialog_message" msgid="8950398016976865762">"Đang mở khóa thẻ SIM…"</string>
+    <string name="kg_password_wrong_pin_code" msgid="1139324887413846912">"Mã PIN không chính xác."</string>
+    <string name="kg_invalid_sim_pin_hint" msgid="8795159358110620001">"Nhập mã PIN có từ 4 đến 8 số."</string>
+    <string name="kg_invalid_sim_puk_hint" msgid="5216603185442368307">"Nhập PUK có từ 8 số trở lên."</string>
+    <string name="kg_sim_puk_recovery_hint" msgid="5577753137718442566">"Nhập PUK và mã PIN mới"</string>
+    <string name="kg_invalid_puk" msgid="5809955359950817326">"PUK bạn đã nhập không đúng."</string>
+    <string name="kg_login_too_many_attempts" msgid="6486842094005698475">"Quá nhiều lần nhập hình"</string>
+    <string name="kg_login_instructions" msgid="1100551261265506448">"Để mở khóa, hãy đăng nhập bằng tài khoản Google của bạn."</string>
+    <string name="kg_login_username_hint" msgid="5718534272070920364">"Tên người dùng (email)"</string>
+    <string name="kg_login_password_hint" msgid="9057289103827298549">"Mật khẩu"</string>
+    <string name="kg_login_submit_button" msgid="5355904582674054702">"Đăng nhập"</string>
+    <string name="kg_login_invalid_input" msgid="5754664119319872197">"Tên người dùng hoặc mật khẩu không hợp lệ."</string>
+    <string name="kg_login_account_recovery_hint" msgid="5690709132841752974">"Bạn quên tên người dùng hoặc mật khẩu?"\n"Hãy truy cập "<b>"google.com/accounts/recovery"</b>"."</string>
+    <string name="kg_login_checking_password" msgid="8849589033659332457">"Đang kiểm tra…"</string>
+    <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="8276745642049502550">"Bạn đã <xliff:g id="NUMBER_0">%d</xliff:g> lần nhập sai mã PIN của mình. Hãy "\n\n"thử lại sau <xliff:g id="NUMBER_1">%d</xliff:g> giây."</string>
+    <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="7813713389422226531">"Bạn đã <xliff:g id="NUMBER_0">%d</xliff:g> lần nhập sai mật khẩu của mình. Hãy "\n\n"thử lại sau <xliff:g id="NUMBER_1">%d</xliff:g> giây."</string>
+    <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="74089475965050805">"Bạn đã <xliff:g id="NUMBER_0">%d</xliff:g> lần vẽ không chính xác hình mở khóa của mình. Hãy "\n\n"thử lại sau <xliff:g id="NUMBER_1">%d</xliff:g> giây."</string>
+    <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="1575557200627128949">"Bạn đã <xliff:g id="NUMBER_0">%d</xliff:g> lần mở khóa máy tính bảng không đúng cách. Sau <xliff:g id="NUMBER_1">%d</xliff:g> lần mở khóa không thành công nữa, máy tính bảng sẽ được đặt lại về mặc định ban đầu và tất cả dữ liệu người dùng sẽ bị mất."</string>
+    <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="4051015943038199910">"Bạn đã <xliff:g id="NUMBER_0">%d</xliff:g> lần mở khóa điện thoại không đúng cách. Sau <xliff:g id="NUMBER_1">%d</xliff:g> lần mở khóa không thành công nữa, điện thoại sẽ được đặt lại về mặc định ban đầu và tất cả dữ liệu người dùng sẽ bị mất."</string>
+    <string name="kg_failed_attempts_now_wiping" product="tablet" msgid="2072996269148483637">"Bạn đã <xliff:g id="NUMBER">%d</xliff:g> lần mở khóa máy tính bảng không đúng cách. Bây giờ, máy tính bảng sẽ được đặt lại về mặc định ban đầu."</string>
+    <string name="kg_failed_attempts_now_wiping" product="default" msgid="4817627474419471518">"Bạn đã <xliff:g id="NUMBER">%d</xliff:g> lần mở khóa điện thoại không đúng cách. Bây giờ, điện thoại sẽ được đặt lại về mặc định ban đầu."</string>
+    <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"Bạn đã <xliff:g id="NUMBER_0">%d</xliff:g> lần vẽ không chính xác hình mở khóa của mình. Sau <xliff:g id="NUMBER_1">%d</xliff:g> lần thử không thành công nữa, bạn sẽ được yêu cầu mở khóa máy tính bảng bằng tài khoản email."\n\n" Vui lòng thử lại sau <xliff:g id="NUMBER_2">%d</xliff:g> giây."</string>
+    <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"Bạn đã <xliff:g id="NUMBER_0">%d</xliff:g> lần vẽ không chính xác hình mở khóa của mình. Sau <xliff:g id="NUMBER_1">%d</xliff:g> lần thử không thành công nữa, bạn sẽ được yêu cầu mở khóa điện thoại bằng tài khoản email."\n\n" Vui lòng thử lại sau <xliff:g id="NUMBER_2">%d</xliff:g> giây."</string>
+    <string name="kg_temp_back_string" msgid="5812983904056640466">"&lt;"</string>
 </resources>
diff --git a/core/res/res/values-zh-rCN/strings.xml b/core/res/res/values-zh-rCN/strings.xml
index 4c42e4a..5a86940 100644
--- a/core/res/res/values-zh-rCN/strings.xml
+++ b/core/res/res/values-zh-rCN/strings.xml
@@ -547,10 +547,8 @@
     <string name="permdesc_sdcardWrite" product="default" msgid="4337417790936632090">"允许应用写入 SD 卡。"</string>
     <string name="permlab_mediaStorageWrite" product="default" msgid="6859839199706879015">"修改/删除内部媒体存储设备的内容"</string>
     <string name="permdesc_mediaStorageWrite" product="default" msgid="8189160597698529185">"允许应用修改内部媒体存储设备的内容。"</string>
-    <!-- no translation found for permlab_sdcardAccessAll (8150613823900460576) -->
-    <skip />
-    <!-- no translation found for permdesc_sdcardAccessAll (3215208357415891320) -->
-    <skip />
+    <string name="permlab_sdcardAccessAll" msgid="8150613823900460576">"访问所有用户的外部存储设备"</string>
+    <string name="permdesc_sdcardAccessAll" msgid="3215208357415891320">"允许应用访问所有用户的外部存储设备。"</string>
     <string name="permlab_cache_filesystem" msgid="5656487264819669824">"访问缓存文件系统"</string>
     <string name="permdesc_cache_filesystem" msgid="5578967642265550955">"允许应用读取和写入缓存文件系统。"</string>
     <string name="permlab_use_sip" msgid="5986952362795870502">"拨打/接听互联网通话"</string>
@@ -581,6 +579,10 @@
     <string name="policydesc_encryptedStorage" msgid="2637732115325316992">"要求对存储的应用数据进行加密。"</string>
     <string name="policylab_disableCamera" msgid="6395301023152297826">"停用相机"</string>
     <string name="policydesc_disableCamera" msgid="2306349042834754597">"禁止使用所有设备摄像头。"</string>
+    <!-- no translation found for policylab_disableKeyguardWidgets (1794894613389073926) -->
+    <skip />
+    <!-- no translation found for policydesc_disableKeyguardWidgets (7254624892984033592) -->
+    <skip />
   <string-array name="phoneTypes">
     <item msgid="8901098336658710359">"住宅"</item>
     <item msgid="869923650527136615">"手机"</item>
@@ -1171,14 +1173,10 @@
     <string name="vpn_title_long" msgid="6400714798049252294">"“<xliff:g id="APP">%s</xliff:g>”已激活 VPN"</string>
     <string name="vpn_text" msgid="3011306607126450322">"触摸可管理网络。"</string>
     <string name="vpn_text_long" msgid="6407351006249174473">"已连接到“<xliff:g id="SESSION">%s</xliff:g>”。触摸可管理网络。"</string>
-    <!-- no translation found for vpn_lockdown_connecting (6443438964440960745) -->
-    <skip />
-    <!-- no translation found for vpn_lockdown_connected (8202679674819213931) -->
-    <skip />
-    <!-- no translation found for vpn_lockdown_error (6009249814034708175) -->
-    <skip />
-    <!-- no translation found for vpn_lockdown_reset (5365010427963548932) -->
-    <skip />
+    <string name="vpn_lockdown_connecting" msgid="6443438964440960745">"正在连接到始终处于打开状态的 VPN…"</string>
+    <string name="vpn_lockdown_connected" msgid="8202679674819213931">"已连接到始终处于打开状态的 VPN"</string>
+    <string name="vpn_lockdown_error" msgid="6009249814034708175">"始终处于打开状态的 VPN 出现错误"</string>
+    <string name="vpn_lockdown_reset" msgid="5365010427963548932">"触摸即可重置连接"</string>
     <string name="upload_file" msgid="2897957172366730416">"选择文件"</string>
     <string name="no_file_chosen" msgid="6363648562170759465">"未选定任何文件"</string>
     <string name="reset" msgid="2448168080964209908">"重置"</string>
@@ -1323,64 +1321,46 @@
     <string name="bluetooth_a2dp_audio_route_name" msgid="8575624030406771015">"蓝牙音频"</string>
     <string name="media_route_chooser_grouping_done" msgid="7966438307723317169">"完成"</string>
     <string name="media_route_button_content_description" msgid="5758553567065145276">"媒体输出线路"</string>
-    <!-- no translation found for display_manager_built_in_display_name (2583134294292563941) -->
+    <string name="display_manager_built_in_display_name" msgid="2583134294292563941">"内置屏幕"</string>
+    <!-- no translation found for display_manager_hdmi_display_name (1555264559227470109) -->
     <skip />
-    <!-- no translation found for display_manager_overlay_display_name (5142365982271620716) -->
+    <string name="display_manager_overlay_display_name" msgid="5142365982271620716">"重叠视图 #<xliff:g id="ID">%1$d</xliff:g>"</string>
+    <!-- no translation found for display_manager_overlay_display_title (652124517672257172) -->
     <skip />
-    <!-- no translation found for display_manager_overlay_display_title (8186674340178573982) -->
-    <skip />
-    <!-- no translation found for kg_emergency_call_label (684946192523830531) -->
-    <skip />
-    <!-- no translation found for kg_forgot_pattern_button_text (8852021467868220608) -->
-    <skip />
-    <!-- no translation found for kg_wrong_pattern (1850806070801358830) -->
-    <skip />
-    <!-- no translation found for kg_wrong_password (2333281762128113157) -->
-    <skip />
-    <!-- no translation found for kg_wrong_pin (1131306510833563801) -->
-    <skip />
-    <!-- no translation found for kg_too_many_failed_attempts_countdown (353963338189371686) -->
-    <skip />
-    <!-- no translation found for kg_pattern_instructions (398978611683075868) -->
-    <skip />
-    <!-- no translation found for kg_sim_pin_instructions (2319508550934557331) -->
-    <skip />
-    <!-- no translation found for kg_pin_instructions (2377242233495111557) -->
-    <skip />
-    <!-- no translation found for kg_password_instructions (5753646556186936819) -->
-    <skip />
-    <!-- no translation found for kg_puk_enter_puk_hint (5183097160254244459) -->
-    <skip />
-    <!-- no translation found for kg_puk_enter_pin_hint (597821135578014901) -->
-    <skip />
-    <!-- no translation found for kg_sim_unlock_progress_dialog_message (8950398016976865762) -->
-    <skip />
-    <!-- no translation found for kg_password_wrong_pin_code (1139324887413846912) -->
-    <skip />
-    <!-- no translation found for kg_invalid_sim_pin_hint (8795159358110620001) -->
-    <skip />
-    <!-- no translation found for kg_invalid_sim_puk_hint (5216603185442368307) -->
-    <skip />
-    <!-- no translation found for kg_sim_puk_recovery_hint (5577753137718442566) -->
-    <skip />
-    <!-- no translation found for kg_invalid_puk (5809955359950817326) -->
-    <skip />
-    <!-- no translation found for kg_login_too_many_attempts (6486842094005698475) -->
-    <skip />
-    <!-- no translation found for kg_login_instructions (1100551261265506448) -->
-    <skip />
-    <!-- no translation found for kg_login_username_hint (5718534272070920364) -->
-    <skip />
-    <!-- no translation found for kg_login_password_hint (9057289103827298549) -->
-    <skip />
-    <!-- no translation found for kg_login_submit_button (5355904582674054702) -->
-    <skip />
-    <!-- no translation found for kg_login_invalid_input (5754664119319872197) -->
-    <skip />
-    <!-- no translation found for kg_login_account_recovery_hint (5690709132841752974) -->
-    <skip />
-    <!-- no translation found for kg_login_checking_password (8849589033659332457) -->
-    <skip />
-    <!-- no translation found for kg_temp_back_string (5812983904056640466) -->
-    <skip />
+    <string name="kg_emergency_call_label" msgid="684946192523830531">"紧急呼救"</string>
+    <string name="kg_forgot_pattern_button_text" msgid="8852021467868220608">"忘记了图案?"</string>
+    <string name="kg_wrong_pattern" msgid="1850806070801358830">"图案错误"</string>
+    <string name="kg_wrong_password" msgid="2333281762128113157">"密码错误"</string>
+    <string name="kg_wrong_pin" msgid="1131306510833563801">"PIN 有误"</string>
+    <string name="kg_too_many_failed_attempts_countdown" msgid="6358110221603297548">"请在 <xliff:g id="NUMBER">%d</xliff:g> 秒后重试。"</string>
+    <string name="kg_pattern_instructions" msgid="398978611683075868">"绘制您的图案"</string>
+    <string name="kg_sim_pin_instructions" msgid="2319508550934557331">"输入 SIM PIN"</string>
+    <string name="kg_pin_instructions" msgid="2377242233495111557">"输入 PIN"</string>
+    <string name="kg_password_instructions" msgid="5753646556186936819">"输入密码"</string>
+    <string name="kg_puk_enter_puk_hint" msgid="5183097160254244459">"PUK 码"</string>
+    <string name="kg_puk_enter_pin_hint" msgid="597821135578014901">"新的 PIN 码"</string>
+    <string name="kg_sim_unlock_progress_dialog_message" msgid="8950398016976865762">"正在解锁 SIM 卡..."</string>
+    <string name="kg_password_wrong_pin_code" msgid="1139324887413846912">"PIN 码有误。"</string>
+    <string name="kg_invalid_sim_pin_hint" msgid="8795159358110620001">"请输入 4 至 8 位数的 PIN。"</string>
+    <string name="kg_invalid_sim_puk_hint" msgid="5216603185442368307">"请输入至少 8 位数的 PUK。"</string>
+    <string name="kg_sim_puk_recovery_hint" msgid="5577753137718442566">"请输入 PUK 和新的 PIN 码"</string>
+    <string name="kg_invalid_puk" msgid="5809955359950817326">"您输入的 PUK 不正确。"</string>
+    <string name="kg_login_too_many_attempts" msgid="6486842094005698475">"图案尝试次数过多"</string>
+    <string name="kg_login_instructions" msgid="1100551261265506448">"要解锁,请登录您的 Google 帐户。"</string>
+    <string name="kg_login_username_hint" msgid="5718534272070920364">"用户名(电子邮件地址)"</string>
+    <string name="kg_login_password_hint" msgid="9057289103827298549">"密码"</string>
+    <string name="kg_login_submit_button" msgid="5355904582674054702">"登录"</string>
+    <string name="kg_login_invalid_input" msgid="5754664119319872197">"用户名或密码无效。"</string>
+    <string name="kg_login_account_recovery_hint" msgid="5690709132841752974">"忘记了用户名或密码?"\n"请访问 "<b>"google.com/accounts/recovery"</b>"。"</string>
+    <string name="kg_login_checking_password" msgid="8849589033659332457">"正在检查..."</string>
+    <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="8276745642049502550">"您已经 <xliff:g id="NUMBER_0">%d</xliff:g> 次错误地输入了 PIN。"\n\n"请在 <xliff:g id="NUMBER_1">%d</xliff:g> 秒后重试。"</string>
+    <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="7813713389422226531">"您已经 <xliff:g id="NUMBER_0">%d</xliff:g> 次错误地输入了密码。"\n\n"请在 <xliff:g id="NUMBER_1">%d</xliff:g> 秒后重试。"</string>
+    <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="74089475965050805">"您已经 <xliff:g id="NUMBER_0">%d</xliff:g> 次错误地绘制了解锁图案。"\n\n"请在 <xliff:g id="NUMBER_1">%d</xliff:g> 秒后重试。"</string>
+    <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="1575557200627128949">"您已经 <xliff:g id="NUMBER_0">%d</xliff:g> 次错误地尝试解锁平板电脑。如果再尝试 <xliff:g id="NUMBER_1">%d</xliff:g> 次后仍不成功,平板电脑就会重置为出厂默认设置,而且所有用户数据都会丢失。"</string>
+    <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="4051015943038199910">"您已经 <xliff:g id="NUMBER_0">%d</xliff:g> 次错误地尝试解锁手机。如果再尝试 <xliff:g id="NUMBER_1">%d</xliff:g> 次后仍不成功,手机就会重置为出厂默认设置,而且所有用户数据都会丢失。"</string>
+    <string name="kg_failed_attempts_now_wiping" product="tablet" msgid="2072996269148483637">"您已经 <xliff:g id="NUMBER">%d</xliff:g> 次错误地尝试解锁平板电脑。平板电脑现在将重置为出厂默认设置。"</string>
+    <string name="kg_failed_attempts_now_wiping" product="default" msgid="4817627474419471518">"您已经 <xliff:g id="NUMBER">%d</xliff:g> 次错误地尝试解锁手机。手机现在将重置为出厂默认设置。"</string>
+    <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"您已经 <xliff:g id="NUMBER_0">%d</xliff:g> 次错误地绘制了解锁图案。如果再尝试 <xliff:g id="NUMBER_1">%d</xliff:g> 次后仍不成功,系统就会要求您使用自己的电子邮件帐户解锁平板电脑。"\n\n"请在 <xliff:g id="NUMBER_2">%d</xliff:g> 秒后重试。"</string>
+    <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"您已经 <xliff:g id="NUMBER_0">%d</xliff:g> 次错误地绘制了解锁图案。如果再尝试 <xliff:g id="NUMBER_1">%d</xliff:g> 次后仍不成功,系统就会要求您使用自己的电子邮件帐户解锁手机。"\n\n"请在 <xliff:g id="NUMBER_2">%d</xliff:g> 秒后重试。"</string>
+    <string name="kg_temp_back_string" msgid="5812983904056640466">"&lt;"</string>
 </resources>
diff --git a/core/res/res/values-zh-rTW/strings.xml b/core/res/res/values-zh-rTW/strings.xml
index 53f3d39..1086764 100644
--- a/core/res/res/values-zh-rTW/strings.xml
+++ b/core/res/res/values-zh-rTW/strings.xml
@@ -547,10 +547,8 @@
     <string name="permdesc_sdcardWrite" product="default" msgid="4337417790936632090">"允許應用程式寫入 SD 卡。"</string>
     <string name="permlab_mediaStorageWrite" product="default" msgid="6859839199706879015">"修改/刪除內部媒體儲存裝置內容"</string>
     <string name="permdesc_mediaStorageWrite" product="default" msgid="8189160597698529185">"允許應用程式修改內部媒體儲存空間的內容。"</string>
-    <!-- no translation found for permlab_sdcardAccessAll (8150613823900460576) -->
-    <skip />
-    <!-- no translation found for permdesc_sdcardAccessAll (3215208357415891320) -->
-    <skip />
+    <string name="permlab_sdcardAccessAll" msgid="8150613823900460576">"存取外部儲存空間 (所有使用者)"</string>
+    <string name="permdesc_sdcardAccessAll" msgid="3215208357415891320">"允許應用程式存取外部儲存空間 (所有使用者)。"</string>
     <string name="permlab_cache_filesystem" msgid="5656487264819669824">"存取快取檔案系統"</string>
     <string name="permdesc_cache_filesystem" msgid="5578967642265550955">"允許應用程式讀取及寫入快取檔案系統。"</string>
     <string name="permlab_use_sip" msgid="5986952362795870502">"撥打/接聽網路電話"</string>
@@ -581,6 +579,10 @@
     <string name="policydesc_encryptedStorage" msgid="2637732115325316992">"必須為儲存的應用程式資料加密。"</string>
     <string name="policylab_disableCamera" msgid="6395301023152297826">"停用相機"</string>
     <string name="policydesc_disableCamera" msgid="2306349042834754597">"禁止使用所有裝置相機。"</string>
+    <!-- no translation found for policylab_disableKeyguardWidgets (1794894613389073926) -->
+    <skip />
+    <!-- no translation found for policydesc_disableKeyguardWidgets (7254624892984033592) -->
+    <skip />
   <string-array name="phoneTypes">
     <item msgid="8901098336658710359">"住家電話"</item>
     <item msgid="869923650527136615">"行動電話"</item>
@@ -1319,64 +1321,46 @@
     <string name="bluetooth_a2dp_audio_route_name" msgid="8575624030406771015">"藍牙音訊"</string>
     <string name="media_route_chooser_grouping_done" msgid="7966438307723317169">"完成"</string>
     <string name="media_route_button_content_description" msgid="5758553567065145276">"媒體輸出"</string>
-    <!-- no translation found for display_manager_built_in_display_name (2583134294292563941) -->
+    <string name="display_manager_built_in_display_name" msgid="2583134294292563941">"內建畫面"</string>
+    <!-- no translation found for display_manager_hdmi_display_name (1555264559227470109) -->
     <skip />
-    <!-- no translation found for display_manager_overlay_display_name (5142365982271620716) -->
+    <string name="display_manager_overlay_display_name" msgid="5142365982271620716">"第 <xliff:g id="ID">%1$d</xliff:g> 個重疊效果"</string>
+    <!-- no translation found for display_manager_overlay_display_title (652124517672257172) -->
     <skip />
-    <!-- no translation found for display_manager_overlay_display_title (8186674340178573982) -->
-    <skip />
-    <!-- no translation found for kg_emergency_call_label (684946192523830531) -->
-    <skip />
-    <!-- no translation found for kg_forgot_pattern_button_text (8852021467868220608) -->
-    <skip />
-    <!-- no translation found for kg_wrong_pattern (1850806070801358830) -->
-    <skip />
-    <!-- no translation found for kg_wrong_password (2333281762128113157) -->
-    <skip />
-    <!-- no translation found for kg_wrong_pin (1131306510833563801) -->
-    <skip />
-    <!-- no translation found for kg_too_many_failed_attempts_countdown (353963338189371686) -->
-    <skip />
-    <!-- no translation found for kg_pattern_instructions (398978611683075868) -->
-    <skip />
-    <!-- no translation found for kg_sim_pin_instructions (2319508550934557331) -->
-    <skip />
-    <!-- no translation found for kg_pin_instructions (2377242233495111557) -->
-    <skip />
-    <!-- no translation found for kg_password_instructions (5753646556186936819) -->
-    <skip />
-    <!-- no translation found for kg_puk_enter_puk_hint (5183097160254244459) -->
-    <skip />
-    <!-- no translation found for kg_puk_enter_pin_hint (597821135578014901) -->
-    <skip />
-    <!-- no translation found for kg_sim_unlock_progress_dialog_message (8950398016976865762) -->
-    <skip />
-    <!-- no translation found for kg_password_wrong_pin_code (1139324887413846912) -->
-    <skip />
-    <!-- no translation found for kg_invalid_sim_pin_hint (8795159358110620001) -->
-    <skip />
-    <!-- no translation found for kg_invalid_sim_puk_hint (5216603185442368307) -->
-    <skip />
-    <!-- no translation found for kg_sim_puk_recovery_hint (5577753137718442566) -->
-    <skip />
-    <!-- no translation found for kg_invalid_puk (5809955359950817326) -->
-    <skip />
-    <!-- no translation found for kg_login_too_many_attempts (6486842094005698475) -->
-    <skip />
-    <!-- no translation found for kg_login_instructions (1100551261265506448) -->
-    <skip />
-    <!-- no translation found for kg_login_username_hint (5718534272070920364) -->
-    <skip />
-    <!-- no translation found for kg_login_password_hint (9057289103827298549) -->
-    <skip />
-    <!-- no translation found for kg_login_submit_button (5355904582674054702) -->
-    <skip />
-    <!-- no translation found for kg_login_invalid_input (5754664119319872197) -->
-    <skip />
-    <!-- no translation found for kg_login_account_recovery_hint (5690709132841752974) -->
-    <skip />
-    <!-- no translation found for kg_login_checking_password (8849589033659332457) -->
-    <skip />
-    <!-- no translation found for kg_temp_back_string (5812983904056640466) -->
-    <skip />
+    <string name="kg_emergency_call_label" msgid="684946192523830531">"緊急電話"</string>
+    <string name="kg_forgot_pattern_button_text" msgid="8852021467868220608">"忘記圖形"</string>
+    <string name="kg_wrong_pattern" msgid="1850806070801358830">"圖形錯誤"</string>
+    <string name="kg_wrong_password" msgid="2333281762128113157">"密碼錯誤"</string>
+    <string name="kg_wrong_pin" msgid="1131306510833563801">"PIN 錯誤"</string>
+    <string name="kg_too_many_failed_attempts_countdown" msgid="6358110221603297548">"請在 <xliff:g id="NUMBER">%d</xliff:g> 秒後再試一次。"</string>
+    <string name="kg_pattern_instructions" msgid="398978611683075868">"畫出圖形"</string>
+    <string name="kg_sim_pin_instructions" msgid="2319508550934557331">"輸入 SIM PIN"</string>
+    <string name="kg_pin_instructions" msgid="2377242233495111557">"輸入 PIN"</string>
+    <string name="kg_password_instructions" msgid="5753646556186936819">"輸入密碼"</string>
+    <string name="kg_puk_enter_puk_hint" msgid="5183097160254244459">"PUK 碼"</string>
+    <string name="kg_puk_enter_pin_hint" msgid="597821135578014901">"新 PIN 碼"</string>
+    <string name="kg_sim_unlock_progress_dialog_message" msgid="8950398016976865762">"正在解除 SIM 卡鎖定..."</string>
+    <string name="kg_password_wrong_pin_code" msgid="1139324887413846912">"PIN 碼不正確。"</string>
+    <string name="kg_invalid_sim_pin_hint" msgid="8795159358110620001">"請輸入 4 到 8 碼的 PIN。"</string>
+    <string name="kg_invalid_sim_puk_hint" msgid="5216603185442368307">"請輸入 8 碼以上的 PUK。"</string>
+    <string name="kg_sim_puk_recovery_hint" msgid="5577753137718442566">"輸入 PUK 碼和新 PIN 碼"</string>
+    <string name="kg_invalid_puk" msgid="5809955359950817326">"您輸入的 PUK 不正確。"</string>
+    <string name="kg_login_too_many_attempts" msgid="6486842094005698475">"圖形嘗試次數過多"</string>
+    <string name="kg_login_instructions" msgid="1100551261265506448">"如要解除鎖定,請使用 Google 帳戶登入。"</string>
+    <string name="kg_login_username_hint" msgid="5718534272070920364">"使用者名稱 (電子郵件)"</string>
+    <string name="kg_login_password_hint" msgid="9057289103827298549">"密碼"</string>
+    <string name="kg_login_submit_button" msgid="5355904582674054702">"登入"</string>
+    <string name="kg_login_invalid_input" msgid="5754664119319872197">"使用者名稱或密碼無效。"</string>
+    <string name="kg_login_account_recovery_hint" msgid="5690709132841752974">"忘了使用者名稱或密碼?"\n"請前往 "<b>"google.com/accounts/recovery"</b>"。"</string>
+    <string name="kg_login_checking_password" msgid="8849589033659332457">"檢查中…"</string>
+    <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="8276745642049502550">"您的 PIN 已輸錯 <xliff:g id="NUMBER_0">%d</xliff:g> 次。"\n\n"請在 <xliff:g id="NUMBER_1">%d</xliff:g> 秒後再試一次。"</string>
+    <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="7813713389422226531">"您的密碼已輸錯 <xliff:g id="NUMBER_0">%d</xliff:g> 次。"\n\n"請在 <xliff:g id="NUMBER_1">%d</xliff:g> 秒後再試一次。"</string>
+    <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="74089475965050805">"您的解鎖圖形已畫錯 <xliff:g id="NUMBER_0">%d</xliff:g> 次。"\n\n"請在 <xliff:g id="NUMBER_1">%d</xliff:g> 秒後再試一次。"</string>
+    <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="1575557200627128949">"您嘗試解除這個平板電腦的鎖定已失敗 <xliff:g id="NUMBER_0">%d</xliff:g> 次,目前還剩 <xliff:g id="NUMBER_1">%d</xliff:g> 次機會。如果失敗次數超過限制,平板電腦將恢復原廠設定,所有使用者資料都會遺失。"</string>
+    <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="4051015943038199910">"您嘗試解除這支手機的鎖定已失敗 <xliff:g id="NUMBER_0">%d</xliff:g> 次,目前還剩 <xliff:g id="NUMBER_1">%d</xliff:g> 次機會。如果失敗次數超過限制,手機將恢復原廠設定,所有使用者資料都會遺失。"</string>
+    <string name="kg_failed_attempts_now_wiping" product="tablet" msgid="2072996269148483637">"您嘗試解除這個平板電腦的鎖定已失敗 <xliff:g id="NUMBER">%d</xliff:g> 次,平板電腦現在將恢復原廠設定。"</string>
+    <string name="kg_failed_attempts_now_wiping" product="default" msgid="4817627474419471518">"您嘗試解除這支手機的鎖定已失敗 <xliff:g id="NUMBER">%d</xliff:g> 次,手機現在將恢復原廠設定。"</string>
+    <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"您的解鎖圖形已畫錯 <xliff:g id="NUMBER_0">%d</xliff:g> 次,如果再嘗試 <xliff:g id="NUMBER_1">%d</xliff:g> 次仍未成功,系統就會要求您透過電子郵件帳戶解除平板電腦的鎖定狀態。"\n\n"請在 <xliff:g id="NUMBER_2">%d</xliff:g> 秒後再試一次。"</string>
+    <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"您的解鎖圖形已畫錯 <xliff:g id="NUMBER_0">%d</xliff:g> 次,如果再嘗試 <xliff:g id="NUMBER_1">%d</xliff:g> 次仍未成功,系統就會要求您透過電子郵件帳戶解除手機的鎖定狀態。"\n\n"請在 <xliff:g id="NUMBER_2">%d</xliff:g> 秒後再試一次。"</string>
+    <string name="kg_temp_back_string" msgid="5812983904056640466">"&lt;"</string>
 </resources>
diff --git a/core/res/res/values-zu/strings.xml b/core/res/res/values-zu/strings.xml
index 232c933..4921b3c 100644
--- a/core/res/res/values-zu/strings.xml
+++ b/core/res/res/values-zu/strings.xml
@@ -547,10 +547,8 @@
     <string name="permdesc_sdcardWrite" product="default" msgid="4337417790936632090">"Ivumela insiza ukuthi ibhalele ekhadini le-SD."</string>
     <string name="permlab_mediaStorageWrite" product="default" msgid="6859839199706879015">"guqula/susa okuqukethwe kwisitoreji semidiya yangaphakathi"</string>
     <string name="permdesc_mediaStorageWrite" product="default" msgid="8189160597698529185">"Ivumela insiza ukuthi iguqule okuqukethwe kokulondoloza imidiya yangaphakathi."</string>
-    <!-- no translation found for permlab_sdcardAccessAll (8150613823900460576) -->
-    <skip />
-    <!-- no translation found for permdesc_sdcardAccessAll (3215208357415891320) -->
-    <skip />
+    <string name="permlab_sdcardAccessAll" msgid="8150613823900460576">"ukufinyelela isilondolozi sangaphandle sabo bonke abasebenzisi"</string>
+    <string name="permdesc_sdcardAccessAll" msgid="3215208357415891320">"Vumela uhlelo lokusebenza ukufinyelela isilondolozi sangaphandle kubo bonke abasebenzisi."</string>
     <string name="permlab_cache_filesystem" msgid="5656487264819669824">"finyelela kunqolobane yesistimu yefayela"</string>
     <string name="permdesc_cache_filesystem" msgid="5578967642265550955">"Ivumela insiza ukuthi ifunde futhi ibhale isistimu yokufayila amafayela esikhashana."</string>
     <string name="permlab_use_sip" msgid="5986952362795870502">"yena/thola amakholi e-Inthanethi"</string>
@@ -581,6 +579,10 @@
     <string name="policydesc_encryptedStorage" msgid="2637732115325316992">"Idinga ukuthi idatha yohlelo lokusebenza olugciniwe ibethelwe"</string>
     <string name="policylab_disableCamera" msgid="6395301023152297826">"Khubaza amakhamera"</string>
     <string name="policydesc_disableCamera" msgid="2306349042834754597">"Vimbela ukusetshenziswa kwamadivaysi wonke wamakhamera"</string>
+    <!-- no translation found for policylab_disableKeyguardWidgets (1794894613389073926) -->
+    <skip />
+    <!-- no translation found for policydesc_disableKeyguardWidgets (7254624892984033592) -->
+    <skip />
   <string-array name="phoneTypes">
     <item msgid="8901098336658710359">"Ekhaya"</item>
     <item msgid="869923650527136615">"Iselula"</item>
@@ -1319,64 +1321,46 @@
     <string name="bluetooth_a2dp_audio_route_name" msgid="8575624030406771015">"Umsindo we-Bluetooth"</string>
     <string name="media_route_chooser_grouping_done" msgid="7966438307723317169">"Qedile"</string>
     <string name="media_route_button_content_description" msgid="5758553567065145276">"Okukhiphayo kwemidiya"</string>
-    <!-- no translation found for display_manager_built_in_display_name (2583134294292563941) -->
+    <string name="display_manager_built_in_display_name" msgid="2583134294292563941">"Okwakhelwe ngaphakathi kwesikrini"</string>
+    <!-- no translation found for display_manager_hdmi_display_name (1555264559227470109) -->
     <skip />
-    <!-- no translation found for display_manager_overlay_display_name (5142365982271620716) -->
+    <string name="display_manager_overlay_display_name" msgid="5142365982271620716">"Isendlalelo #<xliff:g id="ID">%1$d</xliff:g>"</string>
+    <!-- no translation found for display_manager_overlay_display_title (652124517672257172) -->
     <skip />
-    <!-- no translation found for display_manager_overlay_display_title (8186674340178573982) -->
-    <skip />
-    <!-- no translation found for kg_emergency_call_label (684946192523830531) -->
-    <skip />
-    <!-- no translation found for kg_forgot_pattern_button_text (8852021467868220608) -->
-    <skip />
-    <!-- no translation found for kg_wrong_pattern (1850806070801358830) -->
-    <skip />
-    <!-- no translation found for kg_wrong_password (2333281762128113157) -->
-    <skip />
-    <!-- no translation found for kg_wrong_pin (1131306510833563801) -->
-    <skip />
-    <!-- no translation found for kg_too_many_failed_attempts_countdown (353963338189371686) -->
-    <skip />
-    <!-- no translation found for kg_pattern_instructions (398978611683075868) -->
-    <skip />
-    <!-- no translation found for kg_sim_pin_instructions (2319508550934557331) -->
-    <skip />
-    <!-- no translation found for kg_pin_instructions (2377242233495111557) -->
-    <skip />
-    <!-- no translation found for kg_password_instructions (5753646556186936819) -->
-    <skip />
-    <!-- no translation found for kg_puk_enter_puk_hint (5183097160254244459) -->
-    <skip />
-    <!-- no translation found for kg_puk_enter_pin_hint (597821135578014901) -->
-    <skip />
-    <!-- no translation found for kg_sim_unlock_progress_dialog_message (8950398016976865762) -->
-    <skip />
-    <!-- no translation found for kg_password_wrong_pin_code (1139324887413846912) -->
-    <skip />
-    <!-- no translation found for kg_invalid_sim_pin_hint (8795159358110620001) -->
-    <skip />
-    <!-- no translation found for kg_invalid_sim_puk_hint (5216603185442368307) -->
-    <skip />
-    <!-- no translation found for kg_sim_puk_recovery_hint (5577753137718442566) -->
-    <skip />
-    <!-- no translation found for kg_invalid_puk (5809955359950817326) -->
-    <skip />
-    <!-- no translation found for kg_login_too_many_attempts (6486842094005698475) -->
-    <skip />
-    <!-- no translation found for kg_login_instructions (1100551261265506448) -->
-    <skip />
-    <!-- no translation found for kg_login_username_hint (5718534272070920364) -->
-    <skip />
-    <!-- no translation found for kg_login_password_hint (9057289103827298549) -->
-    <skip />
-    <!-- no translation found for kg_login_submit_button (5355904582674054702) -->
-    <skip />
-    <!-- no translation found for kg_login_invalid_input (5754664119319872197) -->
-    <skip />
-    <!-- no translation found for kg_login_account_recovery_hint (5690709132841752974) -->
-    <skip />
-    <!-- no translation found for kg_login_checking_password (8849589033659332457) -->
-    <skip />
-    <!-- no translation found for kg_temp_back_string (5812983904056640466) -->
-    <skip />
+    <string name="kg_emergency_call_label" msgid="684946192523830531">"Ucingo lwezimo eziphuthumayo"</string>
+    <string name="kg_forgot_pattern_button_text" msgid="8852021467868220608">"Ukhohlwe iphethini?"</string>
+    <string name="kg_wrong_pattern" msgid="1850806070801358830">"Iphatheni engalungile"</string>
+    <string name="kg_wrong_password" msgid="2333281762128113157">"Iphasiwedi engalungile"</string>
+    <string name="kg_wrong_pin" msgid="1131306510833563801">"Iphinikhodi engalungile"</string>
+    <string name="kg_too_many_failed_attempts_countdown" msgid="6358110221603297548">"Zama futhi emasekhondini angu-<xliff:g id="NUMBER">%d</xliff:g>."</string>
+    <string name="kg_pattern_instructions" msgid="398978611683075868">"Dweba iphethini"</string>
+    <string name="kg_sim_pin_instructions" msgid="2319508550934557331">"Faka iphinikhodi ye-SIM"</string>
+    <string name="kg_pin_instructions" msgid="2377242233495111557">"Faka iphinikhodi"</string>
+    <string name="kg_password_instructions" msgid="5753646556186936819">"Faka iphasiwedi"</string>
+    <string name="kg_puk_enter_puk_hint" msgid="5183097160254244459">"Ikhodi le-PUK"</string>
+    <string name="kg_puk_enter_pin_hint" msgid="597821135578014901">"Iphinikhodi entsha"</string>
+    <string name="kg_sim_unlock_progress_dialog_message" msgid="8950398016976865762">"Ivula ikhadi le-SIM..."</string>
+    <string name="kg_password_wrong_pin_code" msgid="1139324887413846912">"Iphinikhodi engalungile!"</string>
+    <string name="kg_invalid_sim_pin_hint" msgid="8795159358110620001">"Thayipha iphinikhodi enezinombolo ezingu-4 kuya kwezingu-8."</string>
+    <string name="kg_invalid_sim_puk_hint" msgid="5216603185442368307">"Thayipha i-PUK enezinombolo ezingu-8 noma ngaphezu."</string>
+    <string name="kg_sim_puk_recovery_hint" msgid="5577753137718442566">"Faka i-PUK nephinikhodi entsha"</string>
+    <string name="kg_invalid_puk" msgid="5809955359950817326">"I-PUK oyithayiphile ayilungile."</string>
+    <string name="kg_login_too_many_attempts" msgid="6486842094005698475">"Kunemizamo eminingi kakhulu yephathini!"</string>
+    <string name="kg_login_instructions" msgid="1100551261265506448">"Ukuvula, ngena ngemvumekwi-akhawunti ye-Google"</string>
+    <string name="kg_login_username_hint" msgid="5718534272070920364">"Igama lomsebenzisi (i-imeyli)"</string>
+    <string name="kg_login_password_hint" msgid="9057289103827298549">"Iphasiwedi"</string>
+    <string name="kg_login_submit_button" msgid="5355904582674054702">"Ngena ngemvume"</string>
+    <string name="kg_login_invalid_input" msgid="5754664119319872197">"Igama lomsebezisi elingalungile noma iphasiwedi."</string>
+    <string name="kg_login_account_recovery_hint" msgid="5690709132841752974">"Ukhohlwe igama lomsebenzisi noma iphasiwedi?"\n"Vakashela"<b>"google.com/accounts/recovery"</b></string>
+    <string name="kg_login_checking_password" msgid="8849589033659332457">"Iyahlola..."</string>
+    <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="8276745642049502550">"Ubhale iphinikhodi ykho ngendlela engafanele izikhathi ezingu-<xliff:g id="NUMBER_0">%d</xliff:g>. "\n\n"Zama futhi emasekhondini angu-<xliff:g id="NUMBER_1">%d</xliff:g>."</string>
+    <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="7813713389422226531">"Ubhale iphasiwedi yakho ngendlela engafanele <xliff:g id="NUMBER_0">%d</xliff:g> izikhathi. "\n\n"Zama futhi emasekhondini angu-<xliff:g id="NUMBER_1">%d</xliff:g>."</string>
+    <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="74089475965050805">"Udwebe iphathini yakho yokuvula ngendlela engafanele-<xliff:g id="NUMBER_0">%d</xliff:g>. "\n\n" Zama futhi emasekhondini angu-<xliff:g id="NUMBER_1">%d</xliff:g>"</string>
+    <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="1575557200627128949">"Uzame ngokusebenzisa indlela engafanele ukuvula ithebhulethi izikhathi ezingu-<xliff:g id="NUMBER_0">%d</xliff:g>. Ngemuva kokuzama ngaphandle kwempumelelo okungu-<xliff:g id="NUMBER_1">%d</xliff:g>, ithebhulethi izobuyiselwa kwizimiso zasembonini futhi yonke imininingwane yomsebenzisi izolahleka."</string>
+    <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="4051015943038199910">"Uzame ngokusebenzisa indlela engafanele ukuvula ifoni izikhathi ezingu-<xliff:g id="NUMBER_0">%d</xliff:g>. Ngemuva kokuzama ngaphandle kwempumelelo okungu-<xliff:g id="NUMBER_1">%d</xliff:g>, ifoni izobuyiselwa kwizimiso zasembonini futhi yonke imininingwane yomsebenzisi izolahleka."</string>
+    <string name="kg_failed_attempts_now_wiping" product="tablet" msgid="2072996269148483637">"Uzame ukuvula ngendlela engafanele ifoni izikhathi ezingu-<xliff:g id="NUMBER">%d</xliff:g>. Ithebhulethi manje isizosethwa kabusha ibe yizimiso ezizenzakalelayo."</string>
+    <string name="kg_failed_attempts_now_wiping" product="default" msgid="4817627474419471518">"Uzame ukuvula ngendlela engafanele ifoni izikhathi ezingu-<xliff:g id="NUMBER">%d</xliff:g>. Ifoni manje isizosethwa kabusha ibe yizimiso ezizenzakalelayo."</string>
+    <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"Udwebe ngokungalungile iphathini yakho yokuvula izikhathi ezingu-<xliff:g id="NUMBER_0">%d</xliff:g>. Emva <xliff:g id="NUMBER_1">%d</xliff:g> kweminye imizamo engaphumelelanga, uzocelwa ukuvula ithebhulethi yakho usebenzisa ukungena ngemvume kwi-Google."\n\n" Sicela uzame futhi kwengu-<xliff:g id="NUMBER_2">%d</xliff:g> imizuzwana."</string>
+    <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"Ukulayisha ungenisa iphathini yakho yokuvula ngendlela engalungile izikhathi ezi-<xliff:g id="NUMBER_0">%d</xliff:g> Emva kweminye imizamo engu-<xliff:g id="NUMBER_1">%d</xliff:g>, uzocelwa ukuvula ifoni yakho usebenzisa ukungena ngemvume ku-Google"\n\n" Zame futhi emumva kwengu- <xliff:g id="NUMBER_2">%d</xliff:g> imizuzwana."</string>
+    <string name="kg_temp_back_string" msgid="5812983904056640466">"&lt;"</string>
 </resources>
diff --git a/core/res/res/values/attrs.xml b/core/res/res/values/attrs.xml
index 9601ad4..e6fd538 100755
--- a/core/res/res/values/attrs.xml
+++ b/core/res/res/values/attrs.xml
@@ -4079,6 +4079,10 @@
                  The clip will be based on the horizontal gravity: a left gravity will clip the right
                  edge, a right gravity will clip the left edge, and neither will clip both edges. -->
             <flag name="clip_horizontal" value="0x08" />
+            <!-- Push object to the beginning of its container, not changing its size. -->
+            <flag name="start" value="0x00800003" />
+            <!-- Push object to the end of its container, not changing its size. -->
+            <flag name="end" value="0x00800005" />
         </attr>
         <!-- Reference to a drawable resource to draw with the specified scale. -->
         <attr name="drawable" />
diff --git a/core/res/res/values/dimens.xml b/core/res/res/values/dimens.xml
index 48c52cc..3be3b0b 100644
--- a/core/res/res/values/dimens.xml
+++ b/core/res/res/values/dimens.xml
@@ -193,7 +193,7 @@
     <!-- Padding on left margin of PIN text entry field to center it when del button is showing -->
     <dimen name="keyguard_lockscreen_pin_margin_left">40dip</dimen>
 
-    <!-- Height of FaceUnlock widget in keyguard -->
+    <!-- Height of FaceUnlock view in keyguard -->
     <dimen name="face_unlock_height">330dip</dimen>
 
     <!-- Minimum popup width for selecting an activity in ActivityChooserDialog/ActivityChooserView. -->
diff --git a/core/res/res/values/public.xml b/core/res/res/values/public.xml
index 307fc81..139715c 100644
--- a/core/res/res/values/public.xml
+++ b/core/res/res/values/public.xml
@@ -1139,6 +1139,8 @@
   <java-symbol type="layout" name="notification_template_part_time" />
   <java-symbol type="layout" name="notification_template_part_chronometer" />
   <java-symbol type="layout" name="notification_template_inbox" />
+  <java-symbol type="layout" name="keyguard_multi_user_avatar" />
+  <java-symbol type="layout" name="keyguard_multi_user_selector_widget" />
 
   <java-symbol type="anim" name="slide_in_child_bottom" />
   <java-symbol type="anim" name="slide_in_right" />
@@ -1259,6 +1261,7 @@
   <java-symbol type="drawable" name="jog_tab_right_sound_on" />
   <java-symbol type="drawable" name="jog_tab_target_green" />
   <java-symbol type="drawable" name="jog_tab_target_yellow" />
+  <java-symbol type="drawable" name="magnified_region_frame" />
   <java-symbol type="drawable" name="menu_background" />
   <java-symbol type="drawable" name="stat_sys_secure" />
   <java-symbol type="drawable" name="kg_widget_overscroll_layer_left" />
@@ -1338,6 +1341,10 @@
   <java-symbol type="id" name="sim_pin_entry" />
   <java-symbol type="id" name="puk_delete_button" />
   <java-symbol type="id" name="pin_delete_button" />
+  <java-symbol type="id" name="keyguard_user_avatar" />
+  <java-symbol type="id" name="keyguard_user_name" />
+  <java-symbol type="id" name="keyguard_active_user" />
+  <java-symbol type="id" name="keyguard_inactive_users" />
   <java-symbol type="integer" name="config_carDockRotation" />
   <java-symbol type="integer" name="config_defaultUiModeType" />
   <java-symbol type="integer" name="config_deskDockRotation" />
@@ -1359,6 +1366,13 @@
   <java-symbol type="layout" name="keyguard_screen_tab_unlock_land" />
   <java-symbol type="layout" name="keyguard_screen_unlock_landscape" />
   <java-symbol type="layout" name="keyguard_screen_unlock_portrait" />
+  <java-symbol type="layout" name="keyguard_selector_view" />
+  <java-symbol type="layout" name="keyguard_pattern_view" />
+  <java-symbol type="layout" name="keyguard_password_view" />
+  <java-symbol type="layout" name="keyguard_face_unlock_view" />
+  <java-symbol type="layout" name="keyguard_sim_pin_view" />
+  <java-symbol type="layout" name="keyguard_sim_puk_view" />
+  <java-symbol type="layout" name="keyguard_account_view" />
   <java-symbol type="layout" name="recent_apps_dialog" />
   <java-symbol type="layout" name="screen_action_bar" />
   <java-symbol type="layout" name="screen_action_bar_overlay" />
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index d2951bf..f989e4e 100755
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -669,8 +669,15 @@
     <string name="permlab_filter_events">filter events</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_filter_events">Allows an application to register an input filter
-        which filters the stream of all user events before they are dispatched. Malicious app
-        may control the system UI whtout user intervention.</string>
+            which filters the stream of all user events before they are dispatched. Malicious app
+            may control the system UI whtout user intervention.</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_magnify_display">magnify display</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_magnify_display">Allows an application to magnify the content of a
+        display. Malicious apps may transform the display content in a way that renders the
+        device unusable.</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_shutdown">partial shutdown</string>
@@ -1184,6 +1191,16 @@
     <string name="permdesc_readFrameBuffer">Allows the app to read the content of the frame buffer.</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_configureWifiDisplay">configure Wifi displays</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_configureWifiDisplay">Allows the app to configure and connect to Wifi displays.</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_controlWifiDisplay">control Wifi displays</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_controlWifiDisplay">Allows the app to control low-level features of Wifi displays.</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_modifyAudioSettings">change your audio settings</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_modifyAudioSettings">Allows the app to modify global audio settings such as volume and which speaker is used for output.</string>
diff --git a/core/tests/coretests/apks/FrameworkCoreTests_apk.mk b/core/tests/coretests/apks/FrameworkCoreTests_apk.mk
index ac545ca..1e03270 100644
--- a/core/tests/coretests/apks/FrameworkCoreTests_apk.mk
+++ b/core/tests/coretests/apks/FrameworkCoreTests_apk.mk
@@ -7,6 +7,9 @@
 # Make sure every package name gets the FrameworkCoreTests_ prefix.
 LOCAL_PACKAGE_NAME := FrameworkCoreTests_$(LOCAL_PACKAGE_NAME)
 
+# Every package should have a native library
+LOCAL_JNI_SHARED_LIBRARIES := libframeworks_coretests_jni
+
 FrameworkCoreTests_all_apks += $(LOCAL_PACKAGE_NAME)
 
 include $(BUILD_PACKAGE)
diff --git a/core/tests/coretests/apks/install_jni_lib/Android.mk b/core/tests/coretests/apks/install_jni_lib/Android.mk
new file mode 100644
index 0000000..de2993a
--- /dev/null
+++ b/core/tests/coretests/apks/install_jni_lib/Android.mk
@@ -0,0 +1,28 @@
+# Copyright (C) 2012 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.
+
+LOCAL_PATH := $(call my-dir)
+
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES := \
+    com_android_frameworks_coretests_JNITest.cpp
+
+LOCAL_SHARED_LIBRARIES := \
+    libnativehelper
+
+LOCAL_MODULE := libframeworks_coretests_jni
+LOCAL_MODULE_TAGS := optional
+
+include $(BUILD_SHARED_LIBRARY)
diff --git a/core/tests/coretests/apks/install_jni_lib/com_android_frameworks_coretests_JNITest.cpp b/core/tests/coretests/apks/install_jni_lib/com_android_frameworks_coretests_JNITest.cpp
new file mode 100644
index 0000000..957fc4a
--- /dev/null
+++ b/core/tests/coretests/apks/install_jni_lib/com_android_frameworks_coretests_JNITest.cpp
@@ -0,0 +1,54 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "nativehelper/JNIHelp.h"
+
+namespace android {
+
+static jint checkFunction(JNIEnv*, jclass) {
+    return 1;
+}
+
+static JNINativeMethod sMethods[] = {
+    /* name, signature, funcPtr */
+    { "checkFunction", "()I", (void*) checkFunction },
+};
+
+int register_com_android_framework_coretests_JNITests(JNIEnv* env) {
+    return jniRegisterNativeMethods(env, "com/android/framework/coretests/JNITests", sMethods,
+            NELEM(sMethods));
+}
+
+}
+
+/*
+ * JNI Initialization
+ */
+jint JNI_OnLoad(JavaVM *jvm, void *reserved) {
+    JNIEnv *e;
+    int status;
+
+    // Check JNI version
+    if (jvm->GetEnv((void **) &e, JNI_VERSION_1_6)) {
+        return JNI_ERR;
+    }
+
+    if ((status = android::register_com_android_framework_coretests_JNITests(e)) < 0) {
+        return JNI_ERR;
+    }
+
+    return JNI_VERSION_1_6;
+}
diff --git a/core/tests/coretests/src/android/content/pm/PackageManagerTests.java b/core/tests/coretests/src/android/content/pm/PackageManagerTests.java
index a1fd14e..1868d1c 100755
--- a/core/tests/coretests/src/android/content/pm/PackageManagerTests.java
+++ b/core/tests/coretests/src/android/content/pm/PackageManagerTests.java
@@ -16,6 +16,8 @@
 
 package android.content.pm;
 
+import static libcore.io.OsConstants.*;
+
 import com.android.frameworks.coretests.R;
 import com.android.internal.content.PackageHelper;
 
@@ -32,9 +34,11 @@
 import android.os.Environment;
 import android.os.FileUtils;
 import android.os.IBinder;
+import android.os.Process;
 import android.os.RemoteException;
 import android.os.ServiceManager;
 import android.os.StatFs;
+import android.os.SystemClock;
 import android.os.storage.IMountService;
 import android.os.storage.StorageListener;
 import android.os.storage.StorageManager;
@@ -52,22 +56,37 @@
 import java.io.InputStream;
 
 import java.util.List;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+
+import libcore.io.ErrnoException;
+import libcore.io.Libcore;
+import libcore.io.StructStat;
 
 public class PackageManagerTests extends AndroidTestCase {
     private static final boolean localLOGV = true;
-    public static final String TAG="PackageManagerTests";
-    public final long MAX_WAIT_TIME = 25*1000;
-    public final long WAIT_TIME_INCR = 5*1000;
-    private static final String SECURE_CONTAINERS_PREFIX = "/mnt/asec";
+
+    public static final String TAG = "PackageManagerTests";
+
+    public final long MAX_WAIT_TIME = 25 * 1000;
+
+    public final long WAIT_TIME_INCR = 5 * 1000;
+
+    private static final String SECURE_CONTAINERS_PREFIX = "/mnt/asec/";
+
     private static final int APP_INSTALL_AUTO = PackageHelper.APP_INSTALL_AUTO;
+
     private static final int APP_INSTALL_DEVICE = PackageHelper.APP_INSTALL_INTERNAL;
+
     private static final int APP_INSTALL_SDCARD = PackageHelper.APP_INSTALL_EXTERNAL;
+
     private boolean mOrigState;
 
     void failStr(String errMsg) {
-        Log.w(TAG, "errMsg="+errMsg);
+        Log.w(TAG, "errMsg=" + errMsg);
         fail(errMsg);
     }
+
     void failStr(Exception e) {
         failStr(e.getMessage());
     }
@@ -97,10 +116,11 @@
 
     private class PackageInstallObserver extends IPackageInstallObserver.Stub {
         public int returnCode;
+
         private boolean doneFlag = false;
 
         public void packageInstalled(String packageName, int returnCode) {
-            synchronized(this) {
+            synchronized (this) {
                 this.returnCode = returnCode;
                 doneFlag = true;
                 notifyAll();
@@ -114,10 +134,15 @@
 
     abstract class GenericReceiver extends BroadcastReceiver {
         private boolean doneFlag = false;
+
         boolean received = false;
+
         Intent intent;
+
         IntentFilter filter;
+
         abstract boolean notifyNow(Intent intent);
+
         @Override
         public void onReceive(Context context, Intent intent) {
             if (notifyNow(intent)) {
@@ -179,11 +204,11 @@
         mContext.registerReceiver(receiver, receiver.filter);
         try {
             // Wait on observer
-            synchronized(observer) {
+            synchronized (observer) {
                 synchronized (receiver) {
                     getPm().installPackage(packageURI, observer, flags, null);
                     long waitTime = 0;
-                    while((!observer.isDone()) && (waitTime < MAX_WAIT_TIME) ) {
+                    while ((!observer.isDone()) && (waitTime < MAX_WAIT_TIME)) {
                         try {
                             observer.wait(WAIT_TIME_INCR);
                             waitTime += WAIT_TIME_INCR;
@@ -191,7 +216,7 @@
                             Log.i(TAG, "Interrupted during sleep", e);
                         }
                     }
-                    if(!observer.isDone()) {
+                    if (!observer.isDone()) {
                         fail("Timed out waiting for packageInstalled callback");
                     }
 
@@ -214,7 +239,7 @@
 
                     // Verify we received the broadcast
                     waitTime = 0;
-                    while((!receiver.isDone()) && (waitTime < MAX_WAIT_TIME) ) {
+                    while ((!receiver.isDone()) && (waitTime < MAX_WAIT_TIME)) {
                         try {
                             receiver.wait(WAIT_TIME_INCR);
                             waitTime += WAIT_TIME_INCR;
@@ -222,7 +247,7 @@
                             Log.i(TAG, "Interrupted during sleep", e);
                         }
                     }
-                    if(!receiver.isDone()) {
+                    if (!receiver.isDone()) {
                         fail("Timed out waiting for PACKAGE_ADDED notification");
                     }
                 }
@@ -236,10 +261,10 @@
         PackageInstallObserver observer = new PackageInstallObserver();
         try {
             // Wait on observer
-            synchronized(observer) {
+            synchronized (observer) {
                 getPm().installPackage(packageURI, observer, flags, null);
                 long waitTime = 0;
-                while((!observer.isDone()) && (waitTime < MAX_WAIT_TIME) ) {
+                while ((!observer.isDone()) && (waitTime < MAX_WAIT_TIME)) {
                     try {
                         observer.wait(WAIT_TIME_INCR);
                         waitTime += WAIT_TIME_INCR;
@@ -247,7 +272,7 @@
                         Log.i(TAG, "Interrupted during sleep", e);
                     }
                 }
-                if(!observer.isDone()) {
+                if (!observer.isDone()) {
                     fail("Timed out waiting for packageInstalled callback");
                 }
                 assertEquals(expectedResult, observer.returnCode);
@@ -280,39 +305,42 @@
         File sourceFile = new File(archiveFilePath);
         DisplayMetrics metrics = new DisplayMetrics();
         metrics.setToDefaults();
-        PackageParser.Package pkg = packageParser.parsePackage(sourceFile, archiveFilePath, metrics, 0);
+        PackageParser.Package pkg = packageParser.parsePackage(sourceFile, archiveFilePath,
+                metrics, 0);
         packageParser = null;
         return pkg;
     }
+
     private boolean checkSd(long pkgLen) {
         String status = Environment.getExternalStorageState();
         if (!status.equals(Environment.MEDIA_MOUNTED)) {
             return false;
         }
         long sdSize = -1;
-        StatFs sdStats = new StatFs(
-                Environment.getExternalStorageDirectory().getPath());
-        sdSize = (long)sdStats.getAvailableBlocks() *
-                (long)sdStats.getBlockSize();
+        StatFs sdStats = new StatFs(Environment.getExternalStorageDirectory().getPath());
+        sdSize = (long) sdStats.getAvailableBlocks() * (long) sdStats.getBlockSize();
         // TODO check for thresholds here
         return pkgLen <= sdSize;
 
     }
+
     private boolean checkInt(long pkgLen) {
         StatFs intStats = new StatFs(Environment.getDataDirectory().getPath());
-        long intSize = (long)intStats.getBlockCount() *
-                (long)intStats.getBlockSize();
-        long iSize = (long)intStats.getAvailableBlocks() *
-                (long)intStats.getBlockSize();
+        long intSize = (long) intStats.getBlockCount() * (long) intStats.getBlockSize();
+        long iSize = (long) intStats.getAvailableBlocks() * (long) intStats.getBlockSize();
         // TODO check for thresholds here?
         return pkgLen <= iSize;
     }
+
     private static final int INSTALL_LOC_INT = 1;
+
     private static final int INSTALL_LOC_SD = 2;
+
     private static final int INSTALL_LOC_ERR = -1;
+
     private int getInstallLoc(int flags, int expInstallLocation, long pkgLen) {
         // Flags explicitly over ride everything else.
-        if ((flags & PackageManager.INSTALL_EXTERNAL) != 0 ) {
+        if ((flags & PackageManager.INSTALL_EXTERNAL) != 0) {
             return INSTALL_LOC_SD;
         } else if ((flags & PackageManager.INSTALL_INTERNAL) != 0) {
             return INSTALL_LOC_INT;
@@ -320,7 +348,7 @@
         // Manifest option takes precedence next
         if (expInstallLocation == PackageInfo.INSTALL_LOCATION_PREFER_EXTERNAL) {
             if (checkSd(pkgLen)) {
-               return INSTALL_LOC_SD;
+                return INSTALL_LOC_SD;
             }
             if (checkInt(pkgLen)) {
                 return INSTALL_LOC_INT;
@@ -386,20 +414,32 @@
                 if ((flags & PackageManager.INSTALL_FORWARD_LOCK) != 0) {
                     assertTrue("The application should be installed forward locked",
                             (info.flags & ApplicationInfo.FLAG_FORWARD_LOCK) != 0);
-                    assertTrue("The APK path (" + srcPath + ") should start with "
-                            + SECURE_CONTAINERS_PREFIX,
-                            srcPath.startsWith(SECURE_CONTAINERS_PREFIX));
-                    assertTrue("The public APK path (" + publicSrcPath + ") should start with "
-                            + SECURE_CONTAINERS_PREFIX,
-                            publicSrcPath.startsWith(SECURE_CONTAINERS_PREFIX));
-                    assertTrue("The native library path (" + info.nativeLibraryDir
-                            + ") should start with " + SECURE_CONTAINERS_PREFIX,
-                            info.nativeLibraryDir.startsWith(SECURE_CONTAINERS_PREFIX));
+                    assertStartsWith("The APK path should point to the ASEC",
+                            SECURE_CONTAINERS_PREFIX, srcPath);
+                    assertStartsWith("The public APK path should point to the ASEC",
+                            SECURE_CONTAINERS_PREFIX, publicSrcPath);
+                    assertStartsWith("The native library path should point to the ASEC",
+                            SECURE_CONTAINERS_PREFIX, info.nativeLibraryDir);
+                    try {
+                        String compatLib = new File(info.dataDir + "/lib").getCanonicalPath();
+                        assertEquals("The compatibility lib directory should be a symbolic link to "
+                                + info.nativeLibraryDir,
+                                info.nativeLibraryDir, compatLib);
+                    } catch (IOException e) {
+                        fail("compat check: Can't read " + info.dataDir + "/lib");
+                    }
                 } else {
                     assertFalse((info.flags & ApplicationInfo.FLAG_FORWARD_LOCK) != 0);
                     assertEquals(srcPath, appInstallPath);
                     assertEquals(publicSrcPath, appInstallPath);
-                    assertTrue(info.nativeLibraryDir.startsWith(dataDir.getPath()));
+                    assertStartsWith("Native library should point to shared lib directory",
+                            dataDir.getPath(),
+                            info.nativeLibraryDir);
+                    assertDirOwnerGroupPerms(
+                            "Native library directory should be owned by system:system and 0755",
+                            Process.SYSTEM_UID, Process.SYSTEM_UID,
+                            S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH,
+                            info.nativeLibraryDir);
                 }
                 assertFalse((info.flags & ApplicationInfo.FLAG_EXTERNAL_STORAGE) != 0);
 
@@ -409,12 +449,11 @@
                         nativeLibDir.exists());
                 try {
                     assertEquals("Native library dir should not be a symlink",
-                            info.nativeLibraryDir,
-                            nativeLibDir.getCanonicalPath());
+                            info.nativeLibraryDir, nativeLibDir.getCanonicalPath());
                 } catch (IOException e) {
                     fail("Can't read " + nativeLibDir.getPath());
                 }
-            } else if (rLoc == INSTALL_LOC_SD){
+            } else if (rLoc == INSTALL_LOC_SD) {
                 if ((flags & PackageManager.INSTALL_FORWARD_LOCK) != 0) {
                     assertTrue("The application should be installed forward locked",
                             (info.flags & ApplicationInfo.FLAG_FORWARD_LOCK) != 0);
@@ -427,14 +466,12 @@
                         (info.flags & ApplicationInfo.FLAG_EXTERNAL_STORAGE) != 0);
                 // Might need to check:
                 // ((info.flags & ApplicationInfo.FLAG_FORWARD_LOCK) != 0)
-                assertTrue("The APK path (" + srcPath + ") should start with "
-                        + SECURE_CONTAINERS_PREFIX, srcPath.startsWith(SECURE_CONTAINERS_PREFIX));
-                assertTrue("The public APK path (" + publicSrcPath + ") should start with "
-                        + SECURE_CONTAINERS_PREFIX,
-                        publicSrcPath.startsWith(SECURE_CONTAINERS_PREFIX));
-                assertTrue("The native library path (" + info.nativeLibraryDir
-                        + ") should start with " + SECURE_CONTAINERS_PREFIX,
-                        info.nativeLibraryDir.startsWith(SECURE_CONTAINERS_PREFIX));
+                assertStartsWith("The APK path should point to the ASEC",
+                        SECURE_CONTAINERS_PREFIX, srcPath);
+                assertStartsWith("The public APK path should point to the ASEC",
+                        SECURE_CONTAINERS_PREFIX, publicSrcPath);
+                assertStartsWith("The native library path should point to the ASEC",
+                        SECURE_CONTAINERS_PREFIX, info.nativeLibraryDir);
 
                 // Make sure the native library in /data/data/<app>/lib is a
                 // symlink to the ASEC
@@ -443,8 +480,8 @@
                         nativeLibSymLink.exists());
                 try {
                     assertEquals(nativeLibSymLink.getPath() + " should be a symlink to "
-                            + info.nativeLibraryDir, info.nativeLibraryDir, nativeLibSymLink
-                            .getCanonicalPath());
+                            + info.nativeLibraryDir, info.nativeLibraryDir,
+                            nativeLibSymLink.getCanonicalPath());
                 } catch (IOException e) {
                     fail("Can't read " + nativeLibSymLink.getPath());
                 }
@@ -457,6 +494,66 @@
         }
     }
 
+    private void assertDirOwnerGroupPerms(String reason, int uid, int gid, int perms, String path) {
+        final StructStat stat;
+
+        try {
+            stat = Libcore.os.lstat(path);
+        } catch (ErrnoException e) {
+            throw new AssertionError(reason + "\n" + "Got: " + path + " does not exist");
+        }
+
+        StringBuilder sb = new StringBuilder();
+
+        if (!S_ISDIR(stat.st_mode)) {
+            sb.append("\nExpected type: ");
+            sb.append(S_IFDIR);
+            sb.append("\ngot type: ");
+            sb.append((stat.st_mode & S_IFMT));
+        }
+
+        if (stat.st_uid != uid) {
+            sb.append("\nExpected owner: ");
+            sb.append(uid);
+            sb.append("\nGot owner: ");
+            sb.append(stat.st_uid);
+        }
+
+        if (stat.st_gid != gid) {
+            sb.append("\nExpected group: ");
+            sb.append(gid);
+            sb.append("\nGot group: ");
+            sb.append(stat.st_gid);
+        }
+
+        if ((stat.st_mode & ~S_IFMT) != perms) {
+            sb.append("\nExpected permissions: ");
+            sb.append(Integer.toOctalString(perms));
+            sb.append("\nGot permissions: ");
+            sb.append(Integer.toOctalString(stat.st_mode & ~S_IFMT));
+        }
+
+        if (sb.length() > 0) {
+            throw new AssertionError(reason + sb.toString());
+        }
+    }
+
+    private static void assertStartsWith(String prefix, String actual) {
+        assertStartsWith("", prefix, actual);
+    }
+
+    private static void assertStartsWith(String description, String prefix, String actual) {
+        if (!actual.startsWith(prefix)) {
+            StringBuilder sb = new StringBuilder(description);
+            sb.append("\nExpected prefix: ");
+            sb.append(prefix);
+            sb.append("\n     got: ");
+            sb.append(actual);
+            sb.append('\n');
+            throw new AssertionError(sb.toString());
+        }
+    }
+
     private void assertNotInstalled(String pkgName) {
         try {
             ApplicationInfo info = getPm().getApplicationInfo(pkgName, 0);
@@ -467,30 +564,38 @@
 
     class InstallParams {
         Uri packageURI;
+
         PackageParser.Package pkg;
+
         InstallParams(String outFileName, int rawResId) {
             this.pkg = getParsedPackage(outFileName, rawResId);
             this.packageURI = Uri.fromFile(new File(pkg.mScanPath));
         }
+
         InstallParams(PackageParser.Package pkg) {
             this.packageURI = Uri.fromFile(new File(pkg.mScanPath));
             this.pkg = pkg;
         }
+
         long getApkSize() {
             File file = new File(pkg.mScanPath);
             return file.length();
         }
     }
 
-    private InstallParams sampleInstallFromRawResource(int flags, boolean cleanUp) {
-        return installFromRawResource("install.apk", R.raw.install, flags, cleanUp,
-                false, -1, PackageInfo.INSTALL_LOCATION_UNSPECIFIED);
+    private InstallParams sampleInstallFromRawResource(int flags, boolean cleanUp) throws Exception {
+        return installFromRawResource("install.apk", R.raw.install, flags, cleanUp, false, -1,
+                PackageInfo.INSTALL_LOCATION_UNSPECIFIED);
     }
 
     static final String PERM_PACKAGE = "package";
+
     static final String PERM_DEFINED = "defined";
+
     static final String PERM_UNDEFINED = "undefined";
+
     static final String PERM_USED = "used";
+
     static final String PERM_NOTUSED = "notused";
 
     private void assertPermissions(String[] cmds) {
@@ -522,7 +627,7 @@
                         assertEquals(pi.name, cmd);
                         assertNotNull(pkgInfo);
                         boolean found = false;
-                        for (int j=0; j<pkgInfo.permissions.length && !found; j++) {
+                        for (int j = 0; j < pkgInfo.permissions.length && !found; j++) {
                             if (pkgInfo.permissions[j].name.equals(cmd)) {
                                 found = true;
                             }
@@ -541,7 +646,7 @@
                     }
                     if (pkgInfo != null) {
                         boolean found = false;
-                        for (int j=0; j<pkgInfo.permissions.length && !found; j++) {
+                        for (int j = 0; j < pkgInfo.permissions.length && !found; j++) {
                             if (pkgInfo.permissions[j].name.equals(cmd)) {
                                 found = true;
                             }
@@ -552,7 +657,7 @@
                     }
                 } else if (mode == PERM_USED || mode == PERM_NOTUSED) {
                     boolean found = false;
-                    for (int j=0; j<pkgInfo.requestedPermissions.length && !found; j++) {
+                    for (int j = 0; j < pkgInfo.requestedPermissions.length && !found; j++) {
                         if (pkgInfo.requestedPermissions[j].equals(cmd)) {
                             found = true;
                         }
@@ -561,13 +666,11 @@
                         fail("Permission not requested: " + cmd);
                     }
                     if (mode == PERM_USED) {
-                        if (pm.checkPermission(cmd, pkg)
-                                != PackageManager.PERMISSION_GRANTED) {
+                        if (pm.checkPermission(cmd, pkg) != PackageManager.PERMISSION_GRANTED) {
                             fail("Permission not granted: " + cmd);
                         }
                     } else {
-                        if (pm.checkPermission(cmd, pkg)
-                                != PackageManager.PERMISSION_DENIED) {
+                        if (pm.checkPermission(cmd, pkg) != PackageManager.PERMISSION_DENIED) {
                             fail("Permission granted: " + cmd);
                         }
                     }
@@ -590,9 +693,8 @@
      * copies it into own data directory and invokes
      * PackageManager api to install it.
      */
-    private void installFromRawResource(InstallParams ip,
-            int flags, boolean cleanUp, boolean fail, int result,
-            int expInstallLocation) {
+    private void installFromRawResource(InstallParams ip, int flags, boolean cleanUp, boolean fail,
+            int result, int expInstallLocation) throws Exception {
         PackageManager pm = mContext.getPackageManager();
         PackageParser.Package pkg = ip.pkg;
         Uri packageURI = ip.packageURI;
@@ -632,26 +734,25 @@
      * copies it into own data directory and invokes
      * PackageManager api to install it.
      */
-    private InstallParams installFromRawResource(String outFileName,
-            int rawResId, int flags, boolean cleanUp, boolean fail, int result,
-            int expInstallLocation) {
+    private InstallParams installFromRawResource(String outFileName, int rawResId, int flags,
+            boolean cleanUp, boolean fail, int result, int expInstallLocation) throws Exception {
         InstallParams ip = new InstallParams(outFileName, rawResId);
         installFromRawResource(ip, flags, cleanUp, fail, result, expInstallLocation);
         return ip;
     }
 
     @LargeTest
-    public void testInstallNormalInternal() {
+    public void testInstallNormalInternal() throws Exception {
         sampleInstallFromRawResource(0, true);
     }
 
     @LargeTest
-    public void testInstallFwdLockedInternal() {
+    public void testInstallFwdLockedInternal() throws Exception {
         sampleInstallFromRawResource(PackageManager.INSTALL_FORWARD_LOCK, true);
     }
 
     @LargeTest
-    public void testInstallSdcard() {
+    public void testInstallSdcard() throws Exception {
         // Do not run on devices with emulated external storage.
         if (Environment.isExternalStorageEmulated()) {
             return;
@@ -661,14 +762,20 @@
         sampleInstallFromRawResource(PackageManager.INSTALL_EXTERNAL, true);
     }
 
-    /* ------------------------- Test replacing packages --------------*/
+    /* ------------------------- Test replacing packages -------------- */
     class ReplaceReceiver extends GenericReceiver {
         String pkgName;
+
         final static int INVALID = -1;
+
         final static int REMOVED = 1;
+
         final static int ADDED = 2;
+
         final static int REPLACED = 3;
+
         int removed = INVALID;
+
         // for updated system apps only
         boolean update = false;
 
@@ -721,7 +828,7 @@
      * PackageManager api to install first and then replace it
      * again.
      */
-    private void sampleReplaceFromRawResource(int flags) {
+    private void sampleReplaceFromRawResource(int flags) throws Exception {
         InstallParams ip = sampleInstallFromRawResource(flags, false);
         boolean replace = ((flags & PackageManager.INSTALL_REPLACE_EXISTING) != 0);
         Log.i(TAG, "replace=" + replace);
@@ -743,17 +850,17 @@
     }
 
     @LargeTest
-    public void testReplaceFailNormalInternal() {
+    public void testReplaceFailNormalInternal() throws Exception {
         sampleReplaceFromRawResource(0);
     }
 
     @LargeTest
-    public void testReplaceFailFwdLockedInternal() {
+    public void testReplaceFailFwdLockedInternal() throws Exception {
         sampleReplaceFromRawResource(PackageManager.INSTALL_FORWARD_LOCK);
     }
 
     @LargeTest
-    public void testReplaceFailSdcard() {
+    public void testReplaceFailSdcard() throws Exception {
         // Do not run on devices with emulated external storage.
         if (Environment.isExternalStorageEmulated()) {
             return;
@@ -763,43 +870,72 @@
     }
 
     @LargeTest
-    public void testReplaceNormalInternal() {
+    public void testReplaceNormalInternal() throws Exception {
         sampleReplaceFromRawResource(PackageManager.INSTALL_REPLACE_EXISTING);
     }
 
     @LargeTest
-    public void testReplaceFwdLockedInternal() {
-        sampleReplaceFromRawResource(PackageManager.INSTALL_REPLACE_EXISTING |
-                PackageManager.INSTALL_FORWARD_LOCK);
+    public void testReplaceFwdLockedInternal() throws Exception {
+        sampleReplaceFromRawResource(PackageManager.INSTALL_REPLACE_EXISTING
+                | PackageManager.INSTALL_FORWARD_LOCK);
     }
 
     @LargeTest
-    public void testReplaceSdcard() {
+    public void testReplaceSdcard() throws Exception {
         // Do not run on devices with emulated external storage.
         if (Environment.isExternalStorageEmulated()) {
             return;
         }
 
-        sampleReplaceFromRawResource(PackageManager.INSTALL_REPLACE_EXISTING |
-                PackageManager.INSTALL_EXTERNAL);
+        sampleReplaceFromRawResource(PackageManager.INSTALL_REPLACE_EXISTING
+                | PackageManager.INSTALL_EXTERNAL);
     }
 
-    /* -------------- Delete tests ---*/
-    class DeleteObserver extends IPackageDeleteObserver.Stub {
+    /* -------------- Delete tests --- */
+    private static class DeleteObserver extends IPackageDeleteObserver.Stub {
+        private CountDownLatch mLatch = new CountDownLatch(1);
 
-        public boolean succeeded;
-        private boolean doneFlag = false;
+        private int mReturnCode;
 
-        public boolean isDone() {
-            return doneFlag;
+        private final String mPackageName;
+
+        private String mObservedPackage;
+
+        public DeleteObserver(String packageName) {
+            mPackageName = packageName;
+        }
+
+        public boolean isSuccessful() {
+            return mReturnCode == PackageManager.DELETE_SUCCEEDED;
         }
 
         public void packageDeleted(String packageName, int returnCode) throws RemoteException {
-            synchronized(this) {
-                this.succeeded = returnCode == PackageManager.DELETE_SUCCEEDED;
-                doneFlag = true;
-                notifyAll();
+            mObservedPackage = packageName;
+
+            mReturnCode = returnCode;
+
+            mLatch.countDown();
+        }
+
+        public void waitForCompletion(long timeoutMillis) {
+            final long deadline = SystemClock.uptimeMillis() + timeoutMillis;
+
+            long waitTime = timeoutMillis;
+            while (waitTime > 0) {
+                try {
+                    boolean done = mLatch.await(waitTime, TimeUnit.MILLISECONDS);
+                    if (done) {
+                        assertEquals(mPackageName, mObservedPackage);
+                        return;
+                    }
+                } catch (InterruptedException e) {
+                    // TODO Auto-generated catch block
+                    e.printStackTrace();
+                }
+                waitTime = deadline - SystemClock.uptimeMillis();
             }
+
+            throw new AssertionError("Timeout waiting for package deletion");
         }
     }
 
@@ -827,53 +963,51 @@
         }
     }
 
-    public boolean invokeDeletePackage(final String pkgName, int flags,
-            GenericReceiver receiver) throws Exception {
-        DeleteObserver observer = new DeleteObserver();
-        final boolean received = false;
+    public boolean invokeDeletePackage(final String pkgName, int flags, GenericReceiver receiver)
+            throws Exception {
+        ApplicationInfo info = getPm().getApplicationInfo(pkgName,
+                PackageManager.GET_UNINSTALLED_PACKAGES);
+
         mContext.registerReceiver(receiver, receiver.filter);
         try {
-            // Wait on observer
-            synchronized(observer) {
-                synchronized (receiver) {
-                    getPm().deletePackage(pkgName, observer, flags);
-                    long waitTime = 0;
-                    while((!observer.isDone()) && (waitTime < MAX_WAIT_TIME) ) {
-                        observer.wait(WAIT_TIME_INCR);
-                        waitTime += WAIT_TIME_INCR;
-                    }
-                    if(!observer.isDone()) {
-                        throw new Exception("Timed out waiting for packageInstalled callback");
-                    }
-                    // Verify we received the broadcast
-                    waitTime = 0;
-                    while((!receiver.isDone()) && (waitTime < MAX_WAIT_TIME) ) {
-                        receiver.wait(WAIT_TIME_INCR);
-                        waitTime += WAIT_TIME_INCR;
-                    }
-                    if(!receiver.isDone()) {
-                        throw new Exception("Timed out waiting for PACKAGE_REMOVED notification");
-                    }
-                    return receiver.received;
-                }
+            DeleteObserver observer = new DeleteObserver(pkgName);
+
+            getPm().deletePackage(pkgName, observer, flags);
+            observer.waitForCompletion(MAX_WAIT_TIME);
+
+            assertUninstalled(info);
+
+            // Verify we received the broadcast
+            long waitTime = 0;
+            while ((!receiver.isDone()) && (waitTime < MAX_WAIT_TIME)) {
+                receiver.wait(WAIT_TIME_INCR);
+                waitTime += WAIT_TIME_INCR;
             }
+            if (!receiver.isDone()) {
+                throw new Exception("Timed out waiting for PACKAGE_REMOVED notification");
+            }
+            return receiver.received;
         } finally {
             mContext.unregisterReceiver(receiver);
         }
     }
 
-    public void deleteFromRawResource(int iFlags, int dFlags) {
+    private static void assertUninstalled(ApplicationInfo info) throws Exception {
+        File nativeLibraryFile = new File(info.nativeLibraryDir);
+        assertFalse("Native library directory should be erased", nativeLibraryFile.exists());
+    }
+
+    public void deleteFromRawResource(int iFlags, int dFlags) throws Exception {
         InstallParams ip = sampleInstallFromRawResource(iFlags, false);
         boolean retainData = ((dFlags & PackageManager.DELETE_KEEP_DATA) != 0);
         GenericReceiver receiver = new DeleteReceiver(ip.pkg.packageName);
-        DeleteObserver observer = new DeleteObserver();
         try {
             assertTrue(invokeDeletePackage(ip.pkg.packageName, dFlags, receiver));
             ApplicationInfo info = null;
             Log.i(TAG, "okay4");
             try {
-            info = getPm().getApplicationInfo(ip.pkg.packageName,
-                    PackageManager.GET_UNINSTALLED_PACKAGES);
+                info = getPm().getApplicationInfo(ip.pkg.packageName,
+                        PackageManager.GET_UNINSTALLED_PACKAGES);
             } catch (NameNotFoundException e) {
                 info = null;
             }
@@ -893,17 +1027,17 @@
     }
 
     @LargeTest
-    public void testDeleteNormalInternal() {
+    public void testDeleteNormalInternal() throws Exception {
         deleteFromRawResource(0, 0);
     }
 
     @LargeTest
-    public void testDeleteFwdLockedInternal() {
+    public void testDeleteFwdLockedInternal() throws Exception {
         deleteFromRawResource(PackageManager.INSTALL_FORWARD_LOCK, 0);
     }
 
     @LargeTest
-    public void testDeleteSdcard() {
+    public void testDeleteSdcard() throws Exception {
         // Do not run on devices with emulated external storage.
         if (Environment.isExternalStorageEmulated()) {
             return;
@@ -913,17 +1047,17 @@
     }
 
     @LargeTest
-    public void testDeleteNormalInternalRetainData() {
+    public void testDeleteNormalInternalRetainData() throws Exception {
         deleteFromRawResource(0, PackageManager.DELETE_KEEP_DATA);
     }
 
     @LargeTest
-    public void testDeleteFwdLockedInternalRetainData() {
+    public void testDeleteFwdLockedInternalRetainData() throws Exception {
         deleteFromRawResource(PackageManager.INSTALL_FORWARD_LOCK, PackageManager.DELETE_KEEP_DATA);
     }
 
     @LargeTest
-    public void testDeleteSdcardRetainData() {
+    public void testDeleteSdcardRetainData() throws Exception {
         // Do not run on devices with emulated external storage.
         if (Environment.isExternalStorageEmulated()) {
             return;
@@ -932,10 +1066,11 @@
         deleteFromRawResource(PackageManager.INSTALL_EXTERNAL, PackageManager.DELETE_KEEP_DATA);
     }
 
-    /* sdcard mount/unmount tests ******/
+    /* sdcard mount/unmount tests ***** */
 
     class SdMountReceiver extends GenericReceiver {
         String pkgNames[];
+
         boolean status = true;
 
         SdMountReceiver(String[] pkgNames) {
@@ -970,6 +1105,7 @@
 
     class SdUnMountReceiver extends GenericReceiver {
         String pkgNames[];
+
         boolean status = true;
 
         SdUnMountReceiver(String[] pkgNames) {
@@ -1081,14 +1217,14 @@
         sm.registerListener(observer);
         try {
             // Wait on observer
-            synchronized(observer) {
+            synchronized (observer) {
                 getMs().unmountVolume(path, true, false);
                 long waitTime = 0;
-                while((!observer.isDone()) && (waitTime < MAX_WAIT_TIME) ) {
+                while ((!observer.isDone()) && (waitTime < MAX_WAIT_TIME)) {
                     observer.wait(WAIT_TIME_INCR);
                     waitTime += WAIT_TIME_INCR;
                 }
-                if(!observer.isDone()) {
+                if (!observer.isDone()) {
                     throw new Exception("Timed out waiting for unmount media notification");
                 }
                 return true;
@@ -1101,7 +1237,7 @@
         }
     }
 
-    private boolean mountFromRawResource() {
+    private boolean mountFromRawResource() throws Exception {
         // Install pkg on sdcard
         InstallParams ip = sampleInstallFromRawResource(PackageManager.INSTALL_EXTERNAL, false);
         if (localLOGV) Log.i(TAG, "Installed pkg on sdcard");
@@ -1128,7 +1264,7 @@
                 long waitTime = 0;
                 // Verify we received the broadcast
                 waitTime = 0;
-                while((!receiver.isDone()) && (waitTime < MAX_WAIT_TIME) ) {
+                while ((!receiver.isDone()) && (waitTime < MAX_WAIT_TIME)) {
                     receiver.wait(WAIT_TIME_INCR);
                     waitTime += WAIT_TIME_INCR;
                 }
@@ -1141,7 +1277,9 @@
             failStr(e);
             return false;
         } finally {
-            if (registeredReceiver) mContext.unregisterReceiver(receiver);
+            if (registeredReceiver) {
+                mContext.unregisterReceiver(receiver);
+            }
             // Restore original media state
             if (origState) {
                 mountMedia();
@@ -1159,7 +1297,7 @@
      * Make sure the installed package is available.
      */
     @LargeTest
-    public void testMountSdNormalInternal() {
+    public void testMountSdNormalInternal() throws Exception {
         // Do not run on devices with emulated external storage.
         if (Environment.isExternalStorageEmulated()) {
             return;
@@ -1168,19 +1306,38 @@
         assertTrue(mountFromRawResource());
     }
 
-    void cleanUpInstall(InstallParams ip) {
+    void cleanUpInstall(InstallParams ip) throws Exception {
         if (ip == null) {
             return;
         }
         Runtime.getRuntime().gc();
-        Log.i(TAG, "Deleting package : " + ip.pkg.packageName);
-        getPm().deletePackage(ip.pkg.packageName, null, 0);
-        File outFile = new File(ip.pkg.mScanPath);
-        if (outFile != null && outFile.exists()) {
-            outFile.delete();
+
+        final String packageName = ip.pkg.packageName;
+        Log.i(TAG, "Deleting package : " + packageName);
+
+        ApplicationInfo info = null;
+        try {
+            info = getPm().getApplicationInfo(packageName, PackageManager.GET_UNINSTALLED_PACKAGES);
+        } catch (NameNotFoundException ignored) {
+        }
+
+        DeleteObserver observer = new DeleteObserver(packageName);
+        getPm().deletePackage(packageName, observer, 0);
+        observer.waitForCompletion(MAX_WAIT_TIME);
+
+        try {
+            if (info != null) {
+                assertUninstalled(info);
+            }
+        } finally {
+            File outFile = new File(ip.pkg.mScanPath);
+            if (outFile != null && outFile.exists()) {
+                outFile.delete();
+            }
         }
     }
-    void cleanUpInstall(String pkgName) {
+
+    private void cleanUpInstall(String pkgName) throws Exception {
         if (pkgName == null) {
             return;
         }
@@ -1188,20 +1345,25 @@
         try {
             ApplicationInfo info = getPm().getApplicationInfo(pkgName,
                     PackageManager.GET_UNINSTALLED_PACKAGES);
+
             if (info != null) {
-                getPm().deletePackage(pkgName, null, 0);
+                DeleteObserver observer = new DeleteObserver(pkgName);
+                getPm().deletePackage(pkgName, observer, 0);
+                observer.waitForCompletion(MAX_WAIT_TIME);
+                assertUninstalled(info);
             }
-        } catch (NameNotFoundException e) {}
+        } catch (NameNotFoundException e) {
+        }
     }
 
     @LargeTest
-    public void testManifestInstallLocationInternal() {
+    public void testManifestInstallLocationInternal() throws Exception {
         installFromRawResource("install.apk", R.raw.install_loc_internal,
                 0, true, false, -1, PackageInfo.INSTALL_LOCATION_INTERNAL_ONLY);
     }
 
     @LargeTest
-    public void testManifestInstallLocationSdcard() {
+    public void testManifestInstallLocationSdcard() throws Exception {
         // Do not run on devices with emulated external storage.
         if (Environment.isExternalStorageEmulated()) {
             return;
@@ -1212,19 +1374,19 @@
     }
 
     @LargeTest
-    public void testManifestInstallLocationAuto() {
+    public void testManifestInstallLocationAuto() throws Exception {
         installFromRawResource("install.apk", R.raw.install_loc_auto,
                 0, true, false, -1, PackageInfo.INSTALL_LOCATION_AUTO);
     }
 
     @LargeTest
-    public void testManifestInstallLocationUnspecified() {
+    public void testManifestInstallLocationUnspecified() throws Exception {
         installFromRawResource("install.apk", R.raw.install_loc_unspecified,
                 0, true, false, -1, PackageInfo.INSTALL_LOCATION_UNSPECIFIED);
     }
 
     @LargeTest
-    public void testManifestInstallLocationFwdLockedFlagSdcard() {
+    public void testManifestInstallLocationFwdLockedFlagSdcard() throws Exception {
         // Do not run on devices with emulated external storage.
         if (Environment.isExternalStorageEmulated()) {
             return;
@@ -1237,15 +1399,14 @@
     }
 
     @LargeTest
-    public void testManifestInstallLocationFwdLockedSdcard() {
+    public void testManifestInstallLocationFwdLockedSdcard() throws Exception {
         // Do not run on devices with emulated external storage.
         if (Environment.isExternalStorageEmulated()) {
             return;
         }
 
         installFromRawResource("install.apk", R.raw.install_loc_sdcard,
-                PackageManager.INSTALL_FORWARD_LOCK, true, false,
-                -1,
+                PackageManager.INSTALL_FORWARD_LOCK, true, false, -1,
                 PackageInfo.INSTALL_LOCATION_PREFER_EXTERNAL);
     }
 
@@ -1255,7 +1416,7 @@
      * the old install location.
      */
     @LargeTest
-    public void testReplaceFlagInternalSdcard() {
+    public void testReplaceFlagInternalSdcard() throws Exception {
         // Do not run on devices with emulated external storage.
         if (Environment.isExternalStorageEmulated()) {
             return;
@@ -1282,7 +1443,7 @@
      * install location is retained.
      */
     @LargeTest
-    public void testReplaceFlagSdcardInternal() {
+    public void testReplaceFlagSdcardInternal() throws Exception {
         // Do not run on devices with emulated external storage.
         if (Environment.isExternalStorageEmulated()) {
             return;
@@ -1304,7 +1465,7 @@
     }
 
     @LargeTest
-    public void testManifestInstallLocationReplaceInternalSdcard() {
+    public void testManifestInstallLocationReplaceInternalSdcard() throws Exception {
         // Do not run on devices with emulated external storage.
         if (Environment.isExternalStorageEmulated()) {
             return;
@@ -1332,7 +1493,7 @@
     }
 
     @LargeTest
-    public void testManifestInstallLocationReplaceSdcardInternal() {
+    public void testManifestInstallLocationReplaceSdcardInternal() throws Exception {
         // Do not run on devices with emulated external storage.
         if (Environment.isExternalStorageEmulated()) {
             return;
@@ -1360,9 +1521,13 @@
 
     class MoveReceiver extends GenericReceiver {
         String pkgName;
+
         final static int INVALID = -1;
+
         final static int REMOVED = 1;
+
         final static int ADDED = 2;
+
         int removed = INVALID;
 
         MoveReceiver(String pkgName) {
@@ -1406,17 +1571,21 @@
 
     private class PackageMoveObserver extends IPackageMoveObserver.Stub {
         public int returnCode;
+
         private boolean doneFlag = false;
+
         public String packageName;
+
         public PackageMoveObserver(String pkgName) {
             packageName = pkgName;
         }
+
         public void packageMoved(String packageName, int returnCode) {
             Log.i("DEBUG_MOVE::", "pkg = " + packageName + ", " + "ret = " + returnCode);
             if (!packageName.equals(this.packageName)) {
                 return;
             }
-            synchronized(this) {
+            synchronized (this) {
                 this.returnCode = returnCode;
                 doneFlag = true;
                 notifyAll();
@@ -1428,22 +1597,22 @@
         }
     }
 
-    public boolean invokeMovePackage(String pkgName, int flags,
-            GenericReceiver receiver) throws Exception {
+    public boolean invokeMovePackage(String pkgName, int flags, GenericReceiver receiver)
+            throws Exception {
         PackageMoveObserver observer = new PackageMoveObserver(pkgName);
         final boolean received = false;
         mContext.registerReceiver(receiver, receiver.filter);
         try {
             // Wait on observer
-            synchronized(observer) {
+            synchronized (observer) {
                 synchronized (receiver) {
                     getPm().movePackage(pkgName, observer, flags);
                     long waitTime = 0;
-                    while((!observer.isDone()) && (waitTime < MAX_WAIT_TIME) ) {
+                    while ((!observer.isDone()) && (waitTime < MAX_WAIT_TIME)) {
                         observer.wait(WAIT_TIME_INCR);
                         waitTime += WAIT_TIME_INCR;
                     }
-                    if(!observer.isDone()) {
+                    if (!observer.isDone()) {
                         throw new Exception("Timed out waiting for pkgmove callback");
                     }
                     if (observer.returnCode != PackageManager.MOVE_SUCCEEDED) {
@@ -1451,11 +1620,11 @@
                     }
                     // Verify we received the broadcast
                     waitTime = 0;
-                    while((!receiver.isDone()) && (waitTime < MAX_WAIT_TIME) ) {
+                    while ((!receiver.isDone()) && (waitTime < MAX_WAIT_TIME)) {
                         receiver.wait(WAIT_TIME_INCR);
                         waitTime += WAIT_TIME_INCR;
                     }
-                    if(!receiver.isDone()) {
+                    if (!receiver.isDone()) {
                         throw new Exception("Timed out waiting for MOVE notifications");
                     }
                     return receiver.received;
@@ -1465,18 +1634,19 @@
             mContext.unregisterReceiver(receiver);
         }
     }
+
     private boolean invokeMovePackageFail(String pkgName, int flags, int errCode) throws Exception {
         PackageMoveObserver observer = new PackageMoveObserver(pkgName);
         try {
             // Wait on observer
-            synchronized(observer) {
+            synchronized (observer) {
                 getPm().movePackage(pkgName, observer, flags);
                 long waitTime = 0;
-                while((!observer.isDone()) && (waitTime < MAX_WAIT_TIME) ) {
+                while ((!observer.isDone()) && (waitTime < MAX_WAIT_TIME)) {
                     observer.wait(WAIT_TIME_INCR);
                     waitTime += WAIT_TIME_INCR;
                 }
-                if(!observer.isDone()) {
+                if (!observer.isDone()) {
                     throw new Exception("Timed out waiting for pkgmove callback");
                 }
                 assertEquals(errCode, observer.returnCode);
@@ -1489,7 +1659,8 @@
     private int getDefaultInstallLoc() {
         int origDefaultLoc = PackageInfo.INSTALL_LOCATION_AUTO;
         try {
-            origDefaultLoc = Settings.System.getInt(mContext.getContentResolver(), Settings.Secure.DEFAULT_INSTALL_LOCATION);
+            origDefaultLoc = Settings.System.getInt(mContext.getContentResolver(),
+                    Settings.Secure.DEFAULT_INSTALL_LOCATION);
         } catch (SettingNotFoundException e1) {
         }
         return origDefaultLoc;
@@ -1499,6 +1670,7 @@
         Settings.System.putInt(mContext.getContentResolver(),
                 Settings.Secure.DEFAULT_INSTALL_LOCATION, loc);
     }
+
     /*
      * Tests for moving apps between internal and external storage
      */
@@ -1509,9 +1681,8 @@
      * again.
      */
 
-    private void moveFromRawResource(String outFileName,
-            int rawResId, int installFlags, int moveFlags, boolean cleanUp,
-            boolean fail, int result) {
+    private void moveFromRawResource(String outFileName, int rawResId, int installFlags,
+            int moveFlags, boolean cleanUp, boolean fail, int result) throws Exception {
         int origDefaultLoc = getDefaultInstallLoc();
         InstallParams ip = null;
         try {
@@ -1528,8 +1699,7 @@
             } else {
                 // Create receiver based on expRetCode
                 MoveReceiver receiver = new MoveReceiver(ip.pkg.packageName);
-                boolean retCode = invokeMovePackage(ip.pkg.packageName, moveFlags,
-                        receiver);
+                boolean retCode = invokeMovePackage(ip.pkg.packageName, moveFlags, receiver);
                 assertTrue(retCode);
                 ApplicationInfo info = getPm().getApplicationInfo(ip.pkg.packageName, 0);
                 assertNotNull("ApplicationInfo for recently installed application should exist",
@@ -1537,16 +1707,16 @@
                 if ((moveFlags & PackageManager.MOVE_INTERNAL) != 0) {
                     assertTrue("ApplicationInfo.FLAG_EXTERNAL_STORAGE flag should NOT be set",
                             (info.flags & ApplicationInfo.FLAG_EXTERNAL_STORAGE) == 0);
-                    assertTrue("ApplicationInfo.nativeLibraryDir should start with " + info.dataDir,
-                            info.nativeLibraryDir.startsWith(info.dataDir));
-                } else if ((moveFlags & PackageManager.MOVE_EXTERNAL_MEDIA) != 0){
+                    assertStartsWith("Native library dir should be in dataDir",
+                            info.dataDir, info.nativeLibraryDir);
+                } else if ((moveFlags & PackageManager.MOVE_EXTERNAL_MEDIA) != 0) {
                     assertTrue("ApplicationInfo.FLAG_EXTERNAL_STORAGE flag should be set",
                             (info.flags & ApplicationInfo.FLAG_EXTERNAL_STORAGE) != 0);
-                    assertTrue("ApplicationInfo.nativeLibraryDir should start with " + SECURE_CONTAINERS_PREFIX,
-                            info.nativeLibraryDir.startsWith(SECURE_CONTAINERS_PREFIX));
+                    assertStartsWith("Native library dir should point to ASEC",
+                            SECURE_CONTAINERS_PREFIX, info.nativeLibraryDir);
                     final File nativeLibSymLink = new File(info.dataDir, "lib");
-                    assertTrue("The data directory should have a 'lib' symlink that points to the ASEC container",
-                            nativeLibSymLink.getCanonicalPath().startsWith(SECURE_CONTAINERS_PREFIX));
+                    assertStartsWith("The data directory should have a 'lib' symlink that points to the ASEC container",
+                            SECURE_CONTAINERS_PREFIX, nativeLibSymLink.getCanonicalPath());
                 }
             }
         } catch (NameNotFoundException e) {
@@ -1561,15 +1731,16 @@
             setInstallLoc(origDefaultLoc);
         }
     }
+
     private void sampleMoveFromRawResource(int installFlags, int moveFlags, boolean fail,
-            int result) {
+            int result) throws Exception {
         moveFromRawResource("install.apk",
                 R.raw.install, installFlags, moveFlags, true,
                 fail, result);
     }
 
     @LargeTest
-    public void testMoveAppInternalToExternal() {
+    public void testMoveAppInternalToExternal() throws Exception {
         // Do not run on devices with emulated external storage.
         if (Environment.isExternalStorageEmulated()) {
             return;
@@ -1583,7 +1754,7 @@
     }
 
     @LargeTest
-    public void testMoveAppInternalToInternal() {
+    public void testMoveAppInternalToInternal() throws Exception {
         int installFlags = PackageManager.INSTALL_INTERNAL;
         int moveFlags = PackageManager.MOVE_INTERNAL;
         boolean fail = true;
@@ -1592,7 +1763,7 @@
     }
 
     @LargeTest
-    public void testMoveAppExternalToExternal() {
+    public void testMoveAppExternalToExternal() throws Exception {
         // Do not run on devices with emulated external storage.
         if (Environment.isExternalStorageEmulated()) {
             return;
@@ -1606,7 +1777,7 @@
     }
 
     @LargeTest
-    public void testMoveAppExternalToInternal() {
+    public void testMoveAppExternalToInternal() throws Exception {
         // Do not run on devices with emulated external storage.
         if (Environment.isExternalStorageEmulated()) {
             return;
@@ -1620,7 +1791,7 @@
     }
 
     @LargeTest
-    public void testMoveAppForwardLocked() {
+    public void testMoveAppForwardLocked() throws Exception {
         // Do not run on devices with emulated external storage.
         if (Environment.isExternalStorageEmulated()) {
             return;
@@ -1634,7 +1805,7 @@
     }
 
     @LargeTest
-    public void testMoveAppFailInternalToExternalDelete() {
+    public void testMoveAppFailInternalToExternalDelete() throws Exception {
         // Do not run on devices with emulated external storage.
         if (Environment.isExternalStorageEmulated()) {
             return;
@@ -1674,7 +1845,7 @@
      * and package installed on sdcard via package manager flag.
      */
     @LargeTest
-    public void testInstallSdcardUnmount() {
+    public void testInstallSdcardUnmount() throws Exception {
         // Do not run on devices with emulated external storage.
         if (Environment.isExternalStorageEmulated()) {
             return;
@@ -1704,7 +1875,7 @@
      * on sdcard. Make sure it gets installed on internal flash.
      */
     @LargeTest
-    public void testInstallManifestSdcardUnmount() {
+    public void testInstallManifestSdcardUnmount() throws Exception {
         // Do not run on devices with emulated external storage.
         if (Environment.isExternalStorageEmulated()) {
             return;
@@ -1727,22 +1898,22 @@
         }
     }
 
-   /*---------- Recommended install location tests ----*/
-   /* Precedence: FlagManifestExistingUser
-    * PrecedenceSuffixes:
-    * Flag : FlagI, FlagE, FlagF
-    * I - internal, E - external, F - forward locked, Flag suffix absent if not using any option.
-    * Manifest: ManifestI, ManifestE, ManifestA, Manifest suffix absent if not using any option.
-    * Existing: Existing suffix absent if not existing.
-    * User: UserI, UserE, UserA, User suffix absent if not existing.
-    *
-    */
+    /*---------- Recommended install location tests ----*/
+    /*
+     * PrecedenceSuffixes:
+     * Flag : FlagI, FlagE, FlagF
+     * I - internal, E - external, F - forward locked, Flag suffix absent if not using any option.
+     * Manifest: ManifestI, ManifestE, ManifestA, Manifest suffix absent if not using any option.
+     * Existing: Existing suffix absent if not existing.
+     * User: UserI, UserE, UserA, User suffix absent if not existing.
+     *
+     */
 
     /*
      * Install an app on internal flash
      */
     @LargeTest
-    public void testFlagI() {
+    public void testFlagI() throws Exception {
         sampleInstallFromRawResource(PackageManager.INSTALL_INTERNAL, true);
     }
 
@@ -1750,7 +1921,7 @@
      * Install an app on sdcard.
      */
     @LargeTest
-    public void testFlagE() {
+    public void testFlagE() throws Exception {
         // Do not run on devices with emulated external storage.
         if (Environment.isExternalStorageEmulated()) {
             return;
@@ -1763,7 +1934,7 @@
      * Install an app forward-locked.
      */
     @LargeTest
-    public void testFlagF() {
+    public void testFlagF() throws Exception {
         sampleInstallFromRawResource(PackageManager.INSTALL_FORWARD_LOCK, true);
     }
 
@@ -1771,7 +1942,7 @@
      * Install an app with both internal and external flags set. should fail
      */
     @LargeTest
-    public void testFlagIE() {
+    public void testFlagIE() throws Exception {
         installFromRawResource("install.apk", R.raw.install,
                 PackageManager.INSTALL_EXTERNAL | PackageManager.INSTALL_INTERNAL,
                 false,
@@ -1783,7 +1954,7 @@
      * Install an app with both internal and forward-lock flags set.
      */
     @LargeTest
-    public void testFlagIF() {
+    public void testFlagIF() throws Exception {
         sampleInstallFromRawResource(PackageManager.INSTALL_FORWARD_LOCK
                 | PackageManager.INSTALL_INTERNAL, true);
     }
@@ -1792,7 +1963,7 @@
      * Install an app with both external and forward-lock flags set.
      */
     @LargeTest
-    public void testFlagEF() {
+    public void testFlagEF() throws Exception {
         // Do not run on devices with emulated external storage.
         if (Environment.isExternalStorageEmulated()) {
             return;
@@ -1807,7 +1978,7 @@
      * lock. Should fail.
      */
     @LargeTest
-    public void testFlagIEF() {
+    public void testFlagIEF() throws Exception {
         installFromRawResource("install.apk", R.raw.install,
                 PackageManager.INSTALL_FORWARD_LOCK | PackageManager.INSTALL_INTERNAL |
                 PackageManager.INSTALL_EXTERNAL,
@@ -1816,66 +1987,66 @@
                 PackageInfo.INSTALL_LOCATION_AUTO);
     }
 
-   /*
-    * Install an app with both internal and manifest option set.
-    * should install on internal.
-    */
-   @LargeTest
-   public void testFlagIManifestI() {
-       installFromRawResource("install.apk", R.raw.install_loc_internal,
-               PackageManager.INSTALL_INTERNAL,
-               true,
-               false, -1,
-               PackageInfo.INSTALL_LOCATION_INTERNAL_ONLY);
-   }
-   /*
-    * Install an app with both internal and manifest preference for
-    * preferExternal. Should install on internal.
-    */
-   @LargeTest
-   public void testFlagIManifestE() {
-       installFromRawResource("install.apk", R.raw.install_loc_sdcard,
-               PackageManager.INSTALL_INTERNAL,
-               true,
-               false, -1,
-               PackageInfo.INSTALL_LOCATION_INTERNAL_ONLY);
-   }
-   /*
-    * Install an app with both internal and manifest preference for
-    * auto. should install internal.
-    */
-   @LargeTest
-   public void testFlagIManifestA() {
-       installFromRawResource("install.apk", R.raw.install_loc_auto,
-               PackageManager.INSTALL_INTERNAL,
-               true,
-               false, -1,
-               PackageInfo.INSTALL_LOCATION_INTERNAL_ONLY);
-   }
-   /*
-    * Install an app with both external and manifest option set.
-    * should install externally.
-    */
-   @LargeTest
-   public void testFlagEManifestI() {
+    /*
+     * Install an app with both internal and manifest option set.
+     * should install on internal.
+     */
+    @LargeTest
+    public void testFlagIManifestI() throws Exception {
+        installFromRawResource("install.apk", R.raw.install_loc_internal,
+                PackageManager.INSTALL_INTERNAL,
+                true,
+                false, -1,
+                PackageInfo.INSTALL_LOCATION_INTERNAL_ONLY);
+    }
+    /*
+     * Install an app with both internal and manifest preference for
+     * preferExternal. Should install on internal.
+     */
+    @LargeTest
+    public void testFlagIManifestE() throws Exception {
+        installFromRawResource("install.apk", R.raw.install_loc_sdcard,
+                PackageManager.INSTALL_INTERNAL,
+                true,
+                false, -1,
+                PackageInfo.INSTALL_LOCATION_INTERNAL_ONLY);
+    }
+    /*
+     * Install an app with both internal and manifest preference for
+     * auto. should install internal.
+     */
+    @LargeTest
+    public void testFlagIManifestA() throws Exception {
+        installFromRawResource("install.apk", R.raw.install_loc_auto,
+                PackageManager.INSTALL_INTERNAL,
+                true,
+                false, -1,
+                PackageInfo.INSTALL_LOCATION_INTERNAL_ONLY);
+    }
+    /*
+     * Install an app with both external and manifest option set.
+     * should install externally.
+     */
+    @LargeTest
+    public void testFlagEManifestI() throws Exception {
         // Do not run on devices with emulated external storage.
         if (Environment.isExternalStorageEmulated()) {
             return;
         }
 
-       installFromRawResource("install.apk", R.raw.install_loc_internal,
-               PackageManager.INSTALL_EXTERNAL,
-               true,
-               false, -1,
-               PackageInfo.INSTALL_LOCATION_PREFER_EXTERNAL);
-   }
+        installFromRawResource("install.apk", R.raw.install_loc_internal,
+                PackageManager.INSTALL_EXTERNAL,
+                true,
+                false, -1,
+                PackageInfo.INSTALL_LOCATION_PREFER_EXTERNAL);
+    }
 
-   /*
-    * Install an app with both external and manifest preference for
-    * preferExternal. Should install externally.
-    */
-   @LargeTest
-   public void testFlagEManifestE() {
+    /*
+     * Install an app with both external and manifest preference for
+     * preferExternal. Should install externally.
+     */
+    @LargeTest
+    public void testFlagEManifestE() throws Exception {
         // Do not run on devices with emulated external storage.
         if (Environment.isExternalStorageEmulated()) {
             return;
@@ -1893,7 +2064,7 @@
      * auto. should install on external media.
      */
     @LargeTest
-    public void testFlagEManifestA() {
+    public void testFlagEManifestA() throws Exception {
         // Do not run on devices with emulated external storage.
         if (Environment.isExternalStorageEmulated()) {
             return;
@@ -1911,7 +2082,7 @@
      * internal. should install internally.
      */
     @LargeTest
-    public void testFlagFManifestI() {
+    public void testFlagFManifestI() throws Exception {
         installFromRawResource("install.apk", R.raw.install_loc_internal,
                 PackageManager.INSTALL_FORWARD_LOCK,
                 true,
@@ -1924,7 +2095,7 @@
      * preferExternal. Should install externally.
      */
     @LargeTest
-    public void testFlagFManifestE() {
+    public void testFlagFManifestE() throws Exception {
         // Do not run on devices with emulated external storage.
         if (Environment.isExternalStorageEmulated()) {
             return;
@@ -1942,7 +2113,7 @@
      * should install externally.
      */
     @LargeTest
-    public void testFlagFManifestA() {
+    public void testFlagFManifestA() throws Exception {
         // Do not run on devices with emulated external storage.
         if (Environment.isExternalStorageEmulated()) {
             return;
@@ -1955,7 +2126,8 @@
                 PackageInfo.INSTALL_LOCATION_AUTO);
     }
 
-    /* The following test functions verify install location for existing apps.
+    /*
+     * The following test functions verify install location for existing apps.
      * ie existing app can be installed internally or externally. If install
      * flag is explicitly set it should override current location. If manifest location
      * is set, that should over ride current location too. if not the existing install
@@ -1963,7 +2135,7 @@
      * testFlagI/E/F/ExistingI/E -
      */
     @LargeTest
-    public void testFlagIExistingI() {
+    public void testFlagIExistingI() throws Exception {
         int iFlags = PackageManager.INSTALL_INTERNAL;
         int rFlags = PackageManager.INSTALL_INTERNAL | PackageManager.INSTALL_REPLACE_EXISTING;
         // First install.
@@ -1981,7 +2153,7 @@
     }
 
     @LargeTest
-    public void testFlagIExistingE() {
+    public void testFlagIExistingE() throws Exception {
         // Do not run on devices with emulated external storage.
         if (Environment.isExternalStorageEmulated()) {
             return;
@@ -2004,7 +2176,7 @@
     }
 
     @LargeTest
-    public void testFlagEExistingI() {
+    public void testFlagEExistingI() throws Exception {
         // Do not run on devices with emulated external storage.
         if (Environment.isExternalStorageEmulated()) {
             return;
@@ -2027,7 +2199,7 @@
     }
 
     @LargeTest
-    public void testFlagEExistingE() {
+    public void testFlagEExistingE() throws Exception {
         // Do not run on devices with emulated external storage.
         if (Environment.isExternalStorageEmulated()) {
             return;
@@ -2050,7 +2222,7 @@
     }
 
     @LargeTest
-    public void testFlagFExistingI() {
+    public void testFlagFExistingI() throws Exception {
         int iFlags = PackageManager.INSTALL_INTERNAL;
         int rFlags = PackageManager.INSTALL_FORWARD_LOCK | PackageManager.INSTALL_REPLACE_EXISTING;
         // First install.
@@ -2068,7 +2240,7 @@
     }
 
     @LargeTest
-    public void testFlagFExistingE() {
+    public void testFlagFExistingE() throws Exception {
         // Do not run on devices with emulated external storage.
         if (Environment.isExternalStorageEmulated()) {
             return;
@@ -2098,7 +2270,7 @@
      * TODO out of memory fall back behaviour.
      */
     @LargeTest
-    public void testManifestI() {
+    public void testManifestI() throws Exception {
         installFromRawResource("install.apk", R.raw.install_loc_internal,
                 0,
                 true,
@@ -2107,7 +2279,7 @@
     }
 
     @LargeTest
-    public void testManifestE() {
+    public void testManifestE() throws Exception {
         // Do not run on devices with emulated external storage.
         if (Environment.isExternalStorageEmulated()) {
             return;
@@ -2121,7 +2293,7 @@
     }
 
     @LargeTest
-    public void testManifestA() {
+    public void testManifestA() throws Exception {
         installFromRawResource("install.apk", R.raw.install_loc_auto,
                 0,
                 true,
@@ -2137,7 +2309,7 @@
      * testManifestI/E/AExistingI/E
      */
     @LargeTest
-    public void testManifestIExistingI() {
+    public void testManifestIExistingI() throws Exception {
         int iFlags = PackageManager.INSTALL_INTERNAL;
         int rFlags = PackageManager.INSTALL_REPLACE_EXISTING;
         // First install.
@@ -2155,7 +2327,7 @@
     }
 
     @LargeTest
-    public void testManifestIExistingE() {
+    public void testManifestIExistingE() throws Exception {
         // Do not run on devices with emulated external storage.
         if (Environment.isExternalStorageEmulated()) {
             return;
@@ -2178,7 +2350,7 @@
     }
 
     @LargeTest
-    public void testManifestEExistingI() {
+    public void testManifestEExistingI() throws Exception {
         // Do not run on devices with emulated external storage.
         if (Environment.isExternalStorageEmulated()) {
             return;
@@ -2201,7 +2373,7 @@
     }
 
     @LargeTest
-    public void testManifestEExistingE() {
+    public void testManifestEExistingE() throws Exception {
         // Do not run on devices with emulated external storage.
         if (Environment.isExternalStorageEmulated()) {
             return;
@@ -2224,7 +2396,7 @@
     }
 
     @LargeTest
-    public void testManifestAExistingI() {
+    public void testManifestAExistingI() throws Exception {
         int iFlags = PackageManager.INSTALL_INTERNAL;
         int rFlags = PackageManager.INSTALL_REPLACE_EXISTING;
         // First install.
@@ -2242,7 +2414,7 @@
     }
 
     @LargeTest
-    public void testManifestAExistingE() {
+    public void testManifestAExistingE() throws Exception {
         // Do not run on devices with emulated external storage.
         if (Environment.isExternalStorageEmulated()) {
             return;
@@ -2264,55 +2436,56 @@
                 PackageInfo.INSTALL_LOCATION_PREFER_EXTERNAL);
     }
 
-   /*
-    * The following set of tests check install location for existing
-    * application based on user setting.
-    */
-   private int getExpectedInstallLocation(int userSetting) {
-       int iloc = PackageInfo.INSTALL_LOCATION_UNSPECIFIED;
-       boolean enable = getUserSettingSetInstallLocation();
-       if (enable) {
-           if (userSetting == PackageHelper.APP_INSTALL_AUTO) {
-               iloc = PackageInfo.INSTALL_LOCATION_AUTO;
-           } else if (userSetting == PackageHelper.APP_INSTALL_EXTERNAL) {
-               iloc = PackageInfo.INSTALL_LOCATION_PREFER_EXTERNAL;
-           } else if (userSetting == PackageHelper.APP_INSTALL_INTERNAL) {
-               iloc = PackageInfo.INSTALL_LOCATION_INTERNAL_ONLY;
-           }
-       }
-       return iloc;
-   }
-   private void setExistingXUserX(int userSetting, int iFlags, int iloc) {
-       int rFlags = PackageManager.INSTALL_REPLACE_EXISTING;
-       // First install.
-       installFromRawResource("install.apk", R.raw.install,
-               iFlags,
-               false,
-               false, -1,
-               PackageInfo.INSTALL_LOCATION_UNSPECIFIED);
-       int origSetting = getDefaultInstallLoc();
-       try {
-           // Set user setting
-           setInstallLoc(userSetting);
-           // Replace now
-           installFromRawResource("install.apk", R.raw.install,
-                   rFlags,
-                   true,
-                   false, -1,
-                   iloc);
-       } finally {
-           setInstallLoc(origSetting);
-       }
-   }
-   @LargeTest
-   public void testExistingIUserI() {
-       int userSetting = PackageHelper.APP_INSTALL_INTERNAL;
-       int iFlags = PackageManager.INSTALL_INTERNAL;
-       setExistingXUserX(userSetting, iFlags, PackageInfo.INSTALL_LOCATION_INTERNAL_ONLY);
-   }
+    /*
+     * The following set of tests check install location for existing
+     * application based on user setting.
+     */
+    private int getExpectedInstallLocation(int userSetting) {
+        int iloc = PackageInfo.INSTALL_LOCATION_UNSPECIFIED;
+        boolean enable = getUserSettingSetInstallLocation();
+        if (enable) {
+            if (userSetting == PackageHelper.APP_INSTALL_AUTO) {
+                iloc = PackageInfo.INSTALL_LOCATION_AUTO;
+            } else if (userSetting == PackageHelper.APP_INSTALL_EXTERNAL) {
+                iloc = PackageInfo.INSTALL_LOCATION_PREFER_EXTERNAL;
+            } else if (userSetting == PackageHelper.APP_INSTALL_INTERNAL) {
+                iloc = PackageInfo.INSTALL_LOCATION_INTERNAL_ONLY;
+            }
+        }
+        return iloc;
+    }
+
+    private void setExistingXUserX(int userSetting, int iFlags, int iloc) throws Exception {
+        int rFlags = PackageManager.INSTALL_REPLACE_EXISTING;
+        // First install.
+        installFromRawResource("install.apk", R.raw.install,
+                iFlags,
+                false,
+                false, -1,
+                PackageInfo.INSTALL_LOCATION_UNSPECIFIED);
+        int origSetting = getDefaultInstallLoc();
+        try {
+            // Set user setting
+            setInstallLoc(userSetting);
+            // Replace now
+            installFromRawResource("install.apk", R.raw.install,
+                    rFlags,
+                    true,
+                    false, -1,
+                    iloc);
+        } finally {
+            setInstallLoc(origSetting);
+        }
+    }
+    @LargeTest
+    public void testExistingIUserI() throws Exception {
+        int userSetting = PackageHelper.APP_INSTALL_INTERNAL;
+        int iFlags = PackageManager.INSTALL_INTERNAL;
+        setExistingXUserX(userSetting, iFlags, PackageInfo.INSTALL_LOCATION_INTERNAL_ONLY);
+    }
 
     @LargeTest
-    public void testExistingIUserE() {
+    public void testExistingIUserE() throws Exception {
         // Do not run on devices with emulated external storage.
         if (Environment.isExternalStorageEmulated()) {
             return;
@@ -2323,15 +2496,15 @@
         setExistingXUserX(userSetting, iFlags, PackageInfo.INSTALL_LOCATION_INTERNAL_ONLY);
     }
 
-   @LargeTest
-   public void testExistingIUserA() {
-       int userSetting = PackageHelper.APP_INSTALL_AUTO;
-       int iFlags = PackageManager.INSTALL_INTERNAL;
-       setExistingXUserX(userSetting, iFlags, PackageInfo.INSTALL_LOCATION_INTERNAL_ONLY);
-   }
+    @LargeTest
+    public void testExistingIUserA() throws Exception {
+        int userSetting = PackageHelper.APP_INSTALL_AUTO;
+        int iFlags = PackageManager.INSTALL_INTERNAL;
+        setExistingXUserX(userSetting, iFlags, PackageInfo.INSTALL_LOCATION_INTERNAL_ONLY);
+    }
 
     @LargeTest
-    public void testExistingEUserI() {
+    public void testExistingEUserI() throws Exception {
         // Do not run on devices with emulated external storage.
         if (Environment.isExternalStorageEmulated()) {
             return;
@@ -2343,7 +2516,7 @@
     }
 
     @LargeTest
-    public void testExistingEUserE() {
+    public void testExistingEUserE() throws Exception {
         // Do not run on devices with emulated external storage.
         if (Environment.isExternalStorageEmulated()) {
             return;
@@ -2355,7 +2528,7 @@
     }
 
     @LargeTest
-    public void testExistingEUserA() {
+    public void testExistingEUserA() throws Exception {
         // Do not run on devices with emulated external storage.
         if (Environment.isExternalStorageEmulated()) {
             return;
@@ -2366,52 +2539,53 @@
         setExistingXUserX(userSetting, iFlags, PackageInfo.INSTALL_LOCATION_PREFER_EXTERNAL);
     }
 
-   /*
-    * The following set of tests verify that the user setting defines
-    * the install location.
-    *
-    */
-   private boolean getUserSettingSetInstallLocation() {
-       try {
-           return Settings.System.getInt(mContext.getContentResolver(), Settings.Secure.SET_INSTALL_LOCATION) != 0;
+    /*
+     * The following set of tests verify that the user setting defines
+     * the install location.
+     *
+     */
+    private boolean getUserSettingSetInstallLocation() {
+        try {
+            return Settings.System.getInt(mContext.getContentResolver(), Settings.Secure.SET_INSTALL_LOCATION) != 0;
 
-       } catch (SettingNotFoundException e1) {
-       }
-       return false;
-   }
+        } catch (SettingNotFoundException e1) {
+        }
+        return false;
+    }
 
-   private void setUserSettingSetInstallLocation(boolean value) {
-       Settings.System.putInt(mContext.getContentResolver(),
-               Settings.Secure.SET_INSTALL_LOCATION, value ? 1 : 0);
-   }
-   private void setUserX(boolean enable, int userSetting, int iloc) {
-       boolean origUserSetting = getUserSettingSetInstallLocation();
-       int origSetting = getDefaultInstallLoc();
-       try {
-           setUserSettingSetInstallLocation(enable);
-           // Set user setting
-           setInstallLoc(userSetting);
-           // Replace now
-           installFromRawResource("install.apk", R.raw.install,
-                   0,
-                   true,
-                   false, -1,
-                   iloc);
-       } finally {
-           // Restore original setting
-           setUserSettingSetInstallLocation(origUserSetting);
-           setInstallLoc(origSetting);
-       }
-   }
-   @LargeTest
-   public void testUserI() {
-       int userSetting = PackageHelper.APP_INSTALL_INTERNAL;
-       int iloc = getExpectedInstallLocation(userSetting);
-       setUserX(true, userSetting, iloc);
-   }
+    private void setUserSettingSetInstallLocation(boolean value) {
+        Settings.System.putInt(mContext.getContentResolver(),
+                Settings.Secure.SET_INSTALL_LOCATION, value ? 1 : 0);
+    }
+
+    private void setUserX(boolean enable, int userSetting, int iloc) throws Exception {
+        boolean origUserSetting = getUserSettingSetInstallLocation();
+        int origSetting = getDefaultInstallLoc();
+        try {
+            setUserSettingSetInstallLocation(enable);
+            // Set user setting
+            setInstallLoc(userSetting);
+            // Replace now
+            installFromRawResource("install.apk", R.raw.install,
+                    0,
+                    true,
+                    false, -1,
+                    iloc);
+        } finally {
+            // Restore original setting
+            setUserSettingSetInstallLocation(origUserSetting);
+            setInstallLoc(origSetting);
+        }
+    }
+    @LargeTest
+    public void testUserI() throws Exception {
+        int userSetting = PackageHelper.APP_INSTALL_INTERNAL;
+        int iloc = getExpectedInstallLocation(userSetting);
+        setUserX(true, userSetting, iloc);
+    }
 
     @LargeTest
-    public void testUserE() {
+    public void testUserE() throws Exception {
         // Do not run on devices with emulated external storage.
         if (Environment.isExternalStorageEmulated()) {
             return;
@@ -2422,25 +2596,26 @@
         setUserX(true, userSetting, iloc);
     }
 
-   @LargeTest
-   public void testUserA() {
-       int userSetting = PackageHelper.APP_INSTALL_AUTO;
-       int iloc = getExpectedInstallLocation(userSetting);
-       setUserX(true, userSetting, iloc);
-   }
-   /*
-    * The following set of tests turn on/off the basic
-    * user setting for turning on install location.
-    */
-   @LargeTest
-   public void testUserPrefOffUserI() {
-       int userSetting = PackageHelper.APP_INSTALL_INTERNAL;
-       int iloc = PackageInfo.INSTALL_LOCATION_UNSPECIFIED;
-       setUserX(false, userSetting, iloc);
-   }
+    @LargeTest
+    public void testUserA() throws Exception {
+        int userSetting = PackageHelper.APP_INSTALL_AUTO;
+        int iloc = getExpectedInstallLocation(userSetting);
+        setUserX(true, userSetting, iloc);
+    }
+
+    /*
+     * The following set of tests turn on/off the basic
+     * user setting for turning on install location.
+     */
+    @LargeTest
+    public void testUserPrefOffUserI() throws Exception {
+        int userSetting = PackageHelper.APP_INSTALL_INTERNAL;
+        int iloc = PackageInfo.INSTALL_LOCATION_UNSPECIFIED;
+        setUserX(false, userSetting, iloc);
+    }
 
     @LargeTest
-    public void testUserPrefOffUserE() {
+    public void testUserPrefOffUserE() throws Exception {
         // Do not run on devices with emulated external storage.
         if (Environment.isExternalStorageEmulated()) {
             return;
@@ -2451,12 +2626,12 @@
         setUserX(false, userSetting, iloc);
     }
 
-   @LargeTest
-   public void testUserPrefOffA() {
-       int userSetting = PackageHelper.APP_INSTALL_AUTO;
-       int iloc = PackageInfo.INSTALL_LOCATION_UNSPECIFIED;
-       setUserX(false, userSetting, iloc);
-   }
+    @LargeTest
+    public void testUserPrefOffA() throws Exception {
+        int userSetting = PackageHelper.APP_INSTALL_AUTO;
+        int iloc = PackageInfo.INSTALL_LOCATION_UNSPECIFIED;
+        setUserX(false, userSetting, iloc);
+    }
 
     static final String BASE_PERMISSIONS_DEFINED[] = new String[] {
         PERM_PACKAGE, "com.android.unit_tests.install_decl_perm",
@@ -2503,7 +2678,7 @@
      * Ensure that permissions are properly declared.
      */
     @LargeTest
-    public void testInstallDeclaresPermissions() {
+    public void testInstallDeclaresPermissions() throws Exception {
         InstallParams ip = null;
         InstallParams ip2 = null;
         try {
@@ -2629,7 +2804,7 @@
      * Ensure that permissions are properly declared.
      */
     @LargeTest
-    public void testInstallOnSdPermissionsUnmount() {
+    public void testInstallOnSdPermissionsUnmount() throws Exception {
         InstallParams ip = null;
         boolean origMediaState = checkMediaState(Environment.MEDIA_MOUNTED);
         try {
@@ -2661,7 +2836,7 @@
      * naming convention for secure containers.
      */
     @LargeTest
-    public void testInstallSdcardStaleContainer() {
+    public void testInstallSdcardStaleContainer() throws Exception {
         // Do not run on devices with emulated external storage.
         if (Environment.isExternalStorageEmulated()) {
             return;
@@ -2710,7 +2885,7 @@
      * and verified that the re-installation on internal storage takes precedence.
      */
     @LargeTest
-    public void testInstallSdcardStaleContainerReinstall() {
+    public void testInstallSdcardStaleContainerReinstall() throws Exception {
         // Do not run on devices with emulated external storage.
         if (Environment.isExternalStorageEmulated()) {
             return;
@@ -2740,7 +2915,7 @@
                     false, -1, PackageInfo.INSTALL_LOCATION_UNSPECIFIED);
             mountMedia();
             // Verify that the app installed is on internal storage.
-            assertInstall(pkg, 0, PackageInfo.INSTALL_LOCATION_INTERNAL_ONLY);            
+            assertInstall(pkg, 0, PackageInfo.INSTALL_LOCATION_INTERNAL_ONLY);
         } catch (Exception e) {
             failStr(e.getMessage());
         } finally {
@@ -2757,18 +2932,29 @@
      * different certificates.
      */
     private int APP1_UNSIGNED = R.raw.install_app1_unsigned;
+
     private int APP1_CERT1 = R.raw.install_app1_cert1;
+
     private int APP1_CERT2 = R.raw.install_app1_cert2;
+
     private int APP1_CERT1_CERT2 = R.raw.install_app1_cert1_cert2;
+
     private int APP1_CERT3_CERT4 = R.raw.install_app1_cert3_cert4;
+
     private int APP1_CERT3 = R.raw.install_app1_cert3;
+
     private int APP2_UNSIGNED = R.raw.install_app2_unsigned;
+
     private int APP2_CERT1 = R.raw.install_app2_cert1;
+
     private int APP2_CERT2 = R.raw.install_app2_cert2;
+
     private int APP2_CERT1_CERT2 = R.raw.install_app2_cert1_cert2;
+
     private int APP2_CERT3 = R.raw.install_app2_cert3;
 
-    private InstallParams replaceCerts(int apk1, int apk2, boolean cleanUp, boolean fail, int retCode) {
+    private InstallParams replaceCerts(int apk1, int apk2, boolean cleanUp, boolean fail,
+            int retCode) throws Exception {
         int rFlags = PackageManager.INSTALL_REPLACE_EXISTING;
         String apk1Name = "install1.apk";
         String apk2Name = "install2.apk";
@@ -2788,12 +2974,13 @@
         }
         return null;
     }
+
     /*
      * Test that an app signed with two certificates can be upgraded by the
      * same app signed with two certificates.
      */
     @LargeTest
-    public void testReplaceMatchAllCerts() {
+    public void testReplaceMatchAllCerts() throws Exception {
         replaceCerts(APP1_CERT1_CERT2, APP1_CERT1_CERT2, true, false, -1);
     }
 
@@ -2802,53 +2989,58 @@
      * by an app signed with a different certificate.
      */
     @LargeTest
-    public void testReplaceMatchNoCerts1() {
+    public void testReplaceMatchNoCerts1() throws Exception {
         replaceCerts(APP1_CERT1_CERT2, APP1_CERT3, true, true,
                 PackageManager.INSTALL_PARSE_FAILED_INCONSISTENT_CERTIFICATES);
     }
+
     /*
      * Test that an app signed with two certificates cannot be upgraded
      * by an app signed with a different certificate.
      */
     @LargeTest
-    public void testReplaceMatchNoCerts2() {
+    public void testReplaceMatchNoCerts2() throws Exception {
         replaceCerts(APP1_CERT1_CERT2, APP1_CERT3_CERT4, true, true,
                 PackageManager.INSTALL_PARSE_FAILED_INCONSISTENT_CERTIFICATES);
     }
+
     /*
      * Test that an app signed with two certificates cannot be upgraded by
      * an app signed with a subset of initial certificates.
      */
     @LargeTest
-    public void testReplaceMatchSomeCerts1() {
+    public void testReplaceMatchSomeCerts1() throws Exception {
         replaceCerts(APP1_CERT1_CERT2, APP1_CERT1, true, true,
                 PackageManager.INSTALL_PARSE_FAILED_INCONSISTENT_CERTIFICATES);
     }
+
     /*
      * Test that an app signed with two certificates cannot be upgraded by
      * an app signed with the last certificate.
      */
     @LargeTest
-    public void testReplaceMatchSomeCerts2() {
+    public void testReplaceMatchSomeCerts2() throws Exception {
         replaceCerts(APP1_CERT1_CERT2, APP1_CERT2, true, true,
                 PackageManager.INSTALL_PARSE_FAILED_INCONSISTENT_CERTIFICATES);
     }
+
     /*
      * Test that an app signed with a certificate can be upgraded by app
      * signed with a superset of certificates.
      */
     @LargeTest
-    public void testReplaceMatchMoreCerts() {
+    public void testReplaceMatchMoreCerts() throws Exception {
         replaceCerts(APP1_CERT1, APP1_CERT1_CERT2, true, true,
                 PackageManager.INSTALL_PARSE_FAILED_INCONSISTENT_CERTIFICATES);
     }
+
     /*
      * Test that an app signed with a certificate can be upgraded by app
      * signed with a superset of certificates. Then verify that the an app
      * signed with the original set of certs cannot upgrade the new one.
      */
     @LargeTest
-    public void testReplaceMatchMoreCertsReplaceSomeCerts() {
+    public void testReplaceMatchMoreCertsReplaceSomeCerts() throws Exception {
         InstallParams ip = replaceCerts(APP1_CERT1, APP1_CERT1_CERT2, false, true,
                 PackageManager.INSTALL_PARSE_FAILED_INCONSISTENT_CERTIFICATES);
         try {
@@ -2864,45 +3056,51 @@
             }
         }
     }
-    /*
-     * The following tests are related to testing the checkSignatures
-     * api.
+
+    /**
+     * The following tests are related to testing the checkSignatures api.
      */
-    private void checkSignatures(int apk1, int apk2, int expMatchResult) {
+    private void checkSignatures(int apk1, int apk2, int expMatchResult) throws Exception {
         checkSharedSignatures(apk1, apk2, true, false, -1, expMatchResult);
     }
+
     @LargeTest
-    public void testCheckSignaturesAllMatch() {
+    public void testCheckSignaturesAllMatch() throws Exception {
         int apk1 = APP1_CERT1_CERT2;
         int apk2 = APP2_CERT1_CERT2;
         checkSignatures(apk1, apk2, PackageManager.SIGNATURE_MATCH);
     }
+
     @LargeTest
-    public void testCheckSignaturesNoMatch() {
+    public void testCheckSignaturesNoMatch() throws Exception {
         int apk1 = APP1_CERT1;
         int apk2 = APP2_CERT2;
         checkSignatures(apk1, apk2, PackageManager.SIGNATURE_NO_MATCH);
     }
+
     @LargeTest
-    public void testCheckSignaturesSomeMatch1() {
+    public void testCheckSignaturesSomeMatch1() throws Exception {
         int apk1 = APP1_CERT1_CERT2;
         int apk2 = APP2_CERT1;
         checkSignatures(apk1, apk2, PackageManager.SIGNATURE_NO_MATCH);
     }
+
     @LargeTest
-    public void testCheckSignaturesSomeMatch2() {
+    public void testCheckSignaturesSomeMatch2() throws Exception {
         int apk1 = APP1_CERT1_CERT2;
         int apk2 = APP2_CERT2;
         checkSignatures(apk1, apk2, PackageManager.SIGNATURE_NO_MATCH);
     }
+
     @LargeTest
-    public void testCheckSignaturesMoreMatch() {
+    public void testCheckSignaturesMoreMatch() throws Exception {
         int apk1 = APP1_CERT1;
         int apk2 = APP2_CERT1_CERT2;
         checkSignatures(apk1, apk2, PackageManager.SIGNATURE_NO_MATCH);
     }
+
     @LargeTest
-    public void testCheckSignaturesUnknown() {
+    public void testCheckSignaturesUnknown() throws Exception {
         int apk1 = APP1_CERT1_CERT2;
         int apk2 = APP2_CERT1_CERT2;
         String apk1Name = "install1.apk";
@@ -2930,8 +3128,9 @@
             }
         }
     }
+
     @LargeTest
-    public void testInstallNoCertificates() {
+    public void testInstallNoCertificates() throws Exception {
         int apk1 = APP1_UNSIGNED;
         String apk1Name = "install1.apk";
         InstallParams ip1 = null;
@@ -2943,18 +3142,29 @@
         } finally {
         }
     }
-    /* The following tests are related to apps using shared uids signed
-     * with different certs.
+
+    /*
+     * The following tests are related to apps using shared uids signed with
+     * different certs.
      */
     private int SHARED1_UNSIGNED = R.raw.install_shared1_unsigned;
+
     private int SHARED1_CERT1 = R.raw.install_shared1_cert1;
+
     private int SHARED1_CERT2 = R.raw.install_shared1_cert2;
+
     private int SHARED1_CERT1_CERT2 = R.raw.install_shared1_cert1_cert2;
+
     private int SHARED2_UNSIGNED = R.raw.install_shared2_unsigned;
+
     private int SHARED2_CERT1 = R.raw.install_shared2_cert1;
+
     private int SHARED2_CERT2 = R.raw.install_shared2_cert2;
+
     private int SHARED2_CERT1_CERT2 = R.raw.install_shared2_cert1_cert2;
-    private void checkSharedSignatures(int apk1, int apk2, boolean cleanUp, boolean fail, int retCode, int expMatchResult) {
+
+    private void checkSharedSignatures(int apk1, int apk2, boolean cleanUp, boolean fail,
+            int retCode, int expMatchResult) throws Exception {
         String apk1Name = "install1.apk";
         String apk2Name = "install2.apk";
         PackageParser.Package pkg1 = getParsedPackage(apk1Name, apk1);
@@ -2964,16 +3174,16 @@
             // Clean up before testing first.
             cleanUpInstall(pkg1.packageName);
             cleanUpInstall(pkg2.packageName);
-            installFromRawResource(apk1Name, apk1, 0, false,
-                    false, -1, PackageInfo.INSTALL_LOCATION_UNSPECIFIED);
+            installFromRawResource(apk1Name, apk1, 0, false, false, -1,
+                    PackageInfo.INSTALL_LOCATION_UNSPECIFIED);
             if (fail) {
-                installFromRawResource(apk2Name, apk2, 0, false,
-                        true, retCode, PackageInfo.INSTALL_LOCATION_UNSPECIFIED);
+                installFromRawResource(apk2Name, apk2, 0, false, true, retCode,
+                        PackageInfo.INSTALL_LOCATION_UNSPECIFIED);
             } else {
-                installFromRawResource(apk2Name, apk2, 0, false,
-                        false, -1, PackageInfo.INSTALL_LOCATION_UNSPECIFIED);
-                int match = mContext.getPackageManager().checkSignatures(
-                        pkg1.packageName, pkg2.packageName);
+                installFromRawResource(apk2Name, apk2, 0, false, false, -1,
+                        PackageInfo.INSTALL_LOCATION_UNSPECIFIED);
+                int match = mContext.getPackageManager().checkSignatures(pkg1.packageName,
+                        pkg2.packageName);
                 assertEquals(expMatchResult, match);
             }
         } finally {
@@ -2983,8 +3193,9 @@
             }
         }
     }
+
     @LargeTest
-    public void testCheckSignaturesSharedAllMatch() {
+    public void testCheckSignaturesSharedAllMatch() throws Exception {
         int apk1 = SHARED1_CERT1_CERT2;
         int apk2 = SHARED2_CERT1_CERT2;
         boolean fail = false;
@@ -2992,8 +3203,9 @@
         int expMatchResult = PackageManager.SIGNATURE_MATCH;
         checkSharedSignatures(apk1, apk2, true, fail, retCode, expMatchResult);
     }
+
     @LargeTest
-    public void testCheckSignaturesSharedNoMatch() {
+    public void testCheckSignaturesSharedNoMatch() throws Exception {
         int apk1 = SHARED1_CERT1;
         int apk2 = SHARED2_CERT2;
         boolean fail = true;
@@ -3001,11 +3213,13 @@
         int expMatchResult = -1;
         checkSharedSignatures(apk1, apk2, true, fail, retCode, expMatchResult);
     }
+
     /*
-     * Test that an app signed with cert1 and cert2 cannot be replaced when signed with cert1 alone.
+     * Test that an app signed with cert1 and cert2 cannot be replaced when
+     * signed with cert1 alone.
      */
     @LargeTest
-    public void testCheckSignaturesSharedSomeMatch1() {
+    public void testCheckSignaturesSharedSomeMatch1() throws Exception {
         int apk1 = SHARED1_CERT1_CERT2;
         int apk2 = SHARED2_CERT1;
         boolean fail = true;
@@ -3013,11 +3227,13 @@
         int expMatchResult = -1;
         checkSharedSignatures(apk1, apk2, true, fail, retCode, expMatchResult);
     }
+
     /*
-     * Test that an app signed with cert1 and cert2 cannot be replaced when signed with cert2 alone.
+     * Test that an app signed with cert1 and cert2 cannot be replaced when
+     * signed with cert2 alone.
      */
     @LargeTest
-    public void testCheckSignaturesSharedSomeMatch2() {
+    public void testCheckSignaturesSharedSomeMatch2() throws Exception {
         int apk1 = SHARED1_CERT1_CERT2;
         int apk2 = SHARED2_CERT2;
         boolean fail = true;
@@ -3025,8 +3241,9 @@
         int expMatchResult = -1;
         checkSharedSignatures(apk1, apk2, true, fail, retCode, expMatchResult);
     }
+
     @LargeTest
-    public void testCheckSignaturesSharedUnknown() {
+    public void testCheckSignaturesSharedUnknown() throws Exception {
         int apk1 = SHARED1_CERT1_CERT2;
         int apk2 = SHARED2_CERT1_CERT2;
         String apk1Name = "install1.apk";
@@ -3052,23 +3269,25 @@
     }
 
     @LargeTest
-    public void testReplaceFirstSharedMatchAllCerts() {
+    public void testReplaceFirstSharedMatchAllCerts() throws Exception {
         int apk1 = SHARED1_CERT1;
         int apk2 = SHARED2_CERT1;
         int rapk1 = SHARED1_CERT1;
         checkSignatures(apk1, apk2, PackageManager.SIGNATURE_MATCH);
         replaceCerts(apk1, rapk1, true, false, -1);
     }
+
     @LargeTest
-    public void testReplaceSecondSharedMatchAllCerts() {
+    public void testReplaceSecondSharedMatchAllCerts() throws Exception {
         int apk1 = SHARED1_CERT1;
         int apk2 = SHARED2_CERT1;
         int rapk2 = SHARED2_CERT1;
         checkSignatures(apk1, apk2, PackageManager.SIGNATURE_MATCH);
         replaceCerts(apk2, rapk2, true, false, -1);
     }
+
     @LargeTest
-    public void testReplaceFirstSharedMatchSomeCerts() {
+    public void testReplaceFirstSharedMatchSomeCerts() throws Exception {
         int apk1 = SHARED1_CERT1_CERT2;
         int apk2 = SHARED2_CERT1_CERT2;
         int rapk1 = SHARED1_CERT1;
@@ -3078,8 +3297,9 @@
         installFromRawResource("install.apk", rapk1, PackageManager.INSTALL_REPLACE_EXISTING, true,
                 fail, retCode, PackageInfo.INSTALL_LOCATION_UNSPECIFIED);
     }
+
     @LargeTest
-    public void testReplaceSecondSharedMatchSomeCerts() {
+    public void testReplaceSecondSharedMatchSomeCerts() throws Exception {
         int apk1 = SHARED1_CERT1_CERT2;
         int apk2 = SHARED2_CERT1_CERT2;
         int rapk2 = SHARED2_CERT1;
@@ -3089,8 +3309,9 @@
         installFromRawResource("install.apk", rapk2, PackageManager.INSTALL_REPLACE_EXISTING, true,
                 fail, retCode, PackageInfo.INSTALL_LOCATION_UNSPECIFIED);
     }
+
     @LargeTest
-    public void testReplaceFirstSharedMatchNoCerts() {
+    public void testReplaceFirstSharedMatchNoCerts() throws Exception {
         int apk1 = SHARED1_CERT1;
         int apk2 = SHARED2_CERT1;
         int rapk1 = SHARED1_CERT2;
@@ -3100,8 +3321,9 @@
         installFromRawResource("install.apk", rapk1, PackageManager.INSTALL_REPLACE_EXISTING, true,
                 fail, retCode, PackageInfo.INSTALL_LOCATION_UNSPECIFIED);
     }
+
     @LargeTest
-    public void testReplaceSecondSharedMatchNoCerts() {
+    public void testReplaceSecondSharedMatchNoCerts() throws Exception {
         int apk1 = SHARED1_CERT1;
         int apk2 = SHARED2_CERT1;
         int rapk2 = SHARED2_CERT2;
@@ -3111,8 +3333,9 @@
         installFromRawResource("install.apk", rapk2, PackageManager.INSTALL_REPLACE_EXISTING, true,
                 fail, retCode, PackageInfo.INSTALL_LOCATION_UNSPECIFIED);
     }
+
     @LargeTest
-    public void testReplaceFirstSharedMatchMoreCerts() {
+    public void testReplaceFirstSharedMatchMoreCerts() throws Exception {
         int apk1 = SHARED1_CERT1;
         int apk2 = SHARED2_CERT1;
         int rapk1 = SHARED1_CERT1_CERT2;
@@ -3122,8 +3345,9 @@
         installFromRawResource("install.apk", rapk1, PackageManager.INSTALL_REPLACE_EXISTING, true,
                 fail, retCode, PackageInfo.INSTALL_LOCATION_UNSPECIFIED);
     }
+
     @LargeTest
-    public void testReplaceSecondSharedMatchMoreCerts() {
+    public void testReplaceSecondSharedMatchMoreCerts() throws Exception {
         int apk1 = SHARED1_CERT1;
         int apk2 = SHARED2_CERT1;
         int rapk2 = SHARED2_CERT1_CERT2;
@@ -3144,34 +3368,34 @@
      * features.
      */
     @LargeTest
-    public void testUsesFeatureUnknownFeature() {
+    public void testUsesFeatureUnknownFeature() throws Exception {
         int retCode = PackageManager.INSTALL_SUCCEEDED;
         installFromRawResource("install.apk", R.raw.install_uses_feature, 0, true, false, retCode,
                 PackageInfo.INSTALL_LOCATION_UNSPECIFIED);
     }
 
     @LargeTest
-    public void testInstallNonexistentFile() {
+    public void testInstallNonexistentFile() throws Exception {
         int retCode = PackageManager.INSTALL_FAILED_INVALID_URI;
         File invalidFile = new File("/nonexistent-file.apk");
         invokeInstallPackageFail(Uri.fromFile(invalidFile), 0, retCode);
     }
 
     @SmallTest
-    public void testGetVerifierDeviceIdentity() {
+    public void testGetVerifierDeviceIdentity() throws Exception {
         PackageManager pm = getPm();
         VerifierDeviceIdentity id = pm.getVerifierDeviceIdentity();
 
         assertNotNull("Verifier device identity should not be null", id);
     }
 
-    public void testGetInstalledPackages() {
+    public void testGetInstalledPackages() throws Exception {
         List<PackageInfo> packages = getPm().getInstalledPackages(0);
         assertNotNull("installed packages cannot be null", packages);
         assertTrue("installed packages cannot be empty", packages.size() > 0);
     }
 
-    public void testGetUnInstalledPackages() {
+    public void testGetUnInstalledPackages() throws Exception {
         List<PackageInfo> packages = getPm().getInstalledPackages(
                 PackageManager.GET_UNINSTALLED_PACKAGES);
         assertNotNull("installed packages cannot be null", packages);
@@ -3179,10 +3403,9 @@
     }
 
     /**
-     * Test that getInstalledPackages returns all the data specified in
-     * flags.
+     * Test that getInstalledPackages returns all the data specified in flags.
      */
-    public void testGetInstalledPackagesAll() {
+    public void testGetInstalledPackagesAll() throws Exception {
         int flags = PackageManager.GET_ACTIVITIES | PackageManager.GET_GIDS
                 | PackageManager.GET_CONFIGURATIONS | PackageManager.GET_INSTRUMENTATION
                 | PackageManager.GET_PERMISSIONS | PackageManager.GET_PROVIDERS
@@ -3218,7 +3441,7 @@
      * Test that getInstalledPackages returns all the data specified in
      * flags when the GET_UNINSTALLED_PACKAGES flag is set.
      */
-    public void testGetUnInstalledPackagesAll() {
+    public void testGetUnInstalledPackagesAll() throws Exception {
         int flags = PackageManager.GET_UNINSTALLED_PACKAGES
                 | PackageManager.GET_ACTIVITIES | PackageManager.GET_GIDS
                 | PackageManager.GET_CONFIGURATIONS | PackageManager.GET_INSTRUMENTATION
diff --git a/docs/downloads/training/BitmapFun.zip b/docs/downloads/training/BitmapFun.zip
index e7e71f9..e48bfd3 100644
--- a/docs/downloads/training/BitmapFun.zip
+++ b/docs/downloads/training/BitmapFun.zip
Binary files differ
diff --git a/docs/html/about/versions/jelly-bean.jd b/docs/html/about/versions/jelly-bean.jd
index db56fa4..485a1bb 100644
--- a/docs/html/about/versions/jelly-bean.jd
+++ b/docs/html/about/versions/jelly-bean.jd
@@ -1,29 +1,6 @@
 page.title=Android 4.1 for Developers
 @jd:body
 
-
-<!--<style type="text/css">
-#jd-content {
-  max-width:1024px;
-}
-#jd-content div.screenshot {
-  float:left;
-  clear:left;
-  padding:15px 30px 15px 0;
-}
-
-</style>
-
-<p></p>
-
-
-<div style="float:right;width:230px;padding:0px 0px 60px 34px;margin-top:-40px">
-<div>
-<img src="{@docRoot}images/android-jellybean-sm.png" xheight="402" width="280">
-</div>
-<p class="image-caption">Find out more about the Jelly Bean features for users at <a href="http://www.android.com">android.com</a></p>
-</div>-->
-
 <div style="float:right;width:320px;padding:0px 0px 0px 34px;clear:both">
 <div>
 <img src="{@docRoot}images/jb-android-4.1.png" height="426" width="390">
@@ -35,23 +12,9 @@
 improvements throughout the platform and added great new features
 for users and developers. This document provides a glimpse of what's new for developers.
 
-<p>See the <a href="{@docRoot}about/versions/android-4.1.html">Android 4.1 APIs</a> document for a detailed look at the new developer APIs,</p>
+<p>See the <a href="{@docRoot}about/versions/android-4.1.html">Android 4.1 APIs</a> document for a detailed look at the new developer APIs.</p>
 
-<!--
-<ul>
-  <li><a href="#performance">Fast, Smooth, Responsive</a></li>
-  <li><a href="#accessibility">Enhanced Accessibility</a></li>
-  <li><a href="#intl">Support for International Users</a></li>
-  <li><a href="#ui">Capabilities for Creating Beautiful UI</a></li>
-  <li><a href="#input">New Input Types and Capabilities</a></li>
-  <li><a href="#graphics">Animation and Graphics</a></li>
-  <li><a href="#connectivity">New Types of Connectivity</a></li>
-  <li><a href="#media">Media Capabilities</a></li>
-  <li><a href="#google">Google APIs and services</a></li>
-  </ul>
--->
-
-<p>Find out more about the Jelly Bean features for users at <a href="http://www.android.com/whatsnew">www.android.com</a></p>
+<p>Find out more about the Jelly Bean features for users at <a href="http://www.android.com/whatsnew">www.android.com</a>.</p>
 
 
 <h2 id="performance">Faster, Smoother, More Responsive</h2>
diff --git a/docs/html/guide/topics/appwidgets/index.jd b/docs/html/guide/topics/appwidgets/index.jd
index a46f9a7..5a4e03a 100644
--- a/docs/html/guide/topics/appwidgets/index.jd
+++ b/docs/html/guide/topics/appwidgets/index.jd
@@ -307,6 +307,7 @@
   <li>{@link android.widget.FrameLayout}</li>
   <li>{@link android.widget.LinearLayout}</li>
   <li>{@link android.widget.RelativeLayout}</li>
+  <li>{@link android.widget.GridLayout}</li>
 </ul>
 
 <p>And the following widget classes:</p>
@@ -327,6 +328,9 @@
 
 <p>Descendants of these classes are not supported.</p>
 
+<p>RemoteViews also supports {@link android.view.ViewStub}, which is an invisible, zero-sized View you can use 
+to lazily inflate layout resources at runtime.</p>
+
 
 <h3 id="AddingMargins">Adding margins to App Widgets</h3>
 
@@ -410,6 +414,25 @@
 done.
     (See <a href="#Configuring">Creating an App Widget Configuration
 Activity</a> below.)</dd> 
+
+<dt>
+  {@link android.appwidget.AppWidgetProvider#onAppWidgetOptionsChanged onAppWidgetOptionsChanged()} 
+</dt>
+<dd>
+This is called when the widget is first placed and any time the widget is resized. You can use this callback to show or hide content based on the widget's size ranges. You get the size ranges by calling {@link android.appwidget.AppWidgetManager#getAppWidgetOptions getAppWidgetOptions()}, which returns a  {@link android.os.Bundle} that includes the following:<br /><br />
+<ul>
+  <li>{@link android.appwidget.AppWidgetManager#OPTION_APPWIDGET_MIN_WIDTH}&mdash;Contains 
+the lower bound on the current width, in dp units, of a widget instance.</li>
+  <li>{@link android.appwidget.AppWidgetManager#OPTION_APPWIDGET_MIN_HEIGHT}&mdash;Contains 
+the lower bound on the current height, in dp units, of a widget instance.</li>
+  <li>{@link android.appwidget.AppWidgetManager#OPTION_APPWIDGET_MAX_WIDTH}&mdash;Contains
+ the upper bound on the current width, in dp units, of a widget instance.</li>
+  <li>{@link android.appwidget.AppWidgetManager#OPTION_APPWIDGET_MAX_HEIGHT}&mdash;Contains 
+the upper bound on the current width, in dp units, of a widget instance.</li>
+</ul>
+
+This callback was introduced in API Level 16 (Android 4.1). If you implement this callback, make sure that your app doesn't depend on it since it won't be called on older devices.
+</dd>
   <dt>{@link android.appwidget.AppWidgetProvider#onDeleted(Context,int[])}</dt>
     <dd>This is called every time an App Widget is deleted from the App Widget
 host.</dd>
@@ -533,12 +556,13 @@
 to receive the App Widget broadcasts directly, you can implement your own 
 {@link android.content.BroadcastReceiver} or override the 
 {@link android.appwidget.AppWidgetProvider#onReceive(Context,Intent)} callback. 
-The four Intents you need to care about are:</p>
+The Intents you need to care about are as follows:</p>
 <ul>
   <li>{@link android.appwidget.AppWidgetManager#ACTION_APPWIDGET_UPDATE}</li>
   <li>{@link android.appwidget.AppWidgetManager#ACTION_APPWIDGET_DELETED}</li>
   <li>{@link android.appwidget.AppWidgetManager#ACTION_APPWIDGET_ENABLED}</li>
   <li>{@link android.appwidget.AppWidgetManager#ACTION_APPWIDGET_DISABLED}</li>
+  <li>{@link android.appwidget.AppWidgetManager#ACTION_APPWIDGET_OPTIONS_CHANGED}</li>
 </ul>
 
 
diff --git a/docs/html/guide/topics/resources/providing-resources.jd b/docs/html/guide/topics/resources/providing-resources.jd
index b0d5d6f..b2c95b9 100644
--- a/docs/html/guide/topics/resources/providing-resources.jd
+++ b/docs/html/guide/topics/resources/providing-resources.jd
@@ -329,6 +329,31 @@
 indicates the current locale.</p>
       </td>
     </tr>
+    <tr id="LayoutDirectionQualifier">
+      <td>Layout Direction</td>
+      <td>Examples:<br/>
+        <code>ldrtl</code><br/>
+        <code>ldltr</code><br/>
+      </td>
+      <td><p>The layout direction of your application. {@code ldrtl} means "layout-direction-right-to-left".
+      {@code ldltr} means "layout-direction-left-to-right" and is the default implicit value.
+      </p>
+      <p>This can apply to any resource like layouts or values or drawables.
+      </p>
+      <p>For example, if you want to provide some specific layout for the Arabic language and some
+      generic layout for any other "right-to-left" language (like Persian or Hebrew) then you would have:
+      </p>
+<pre class="classic no-pretty-print">
+res/
+    layout/   <span style="color:black">
+        main.xml  </span>(This is the default layout)
+    layout-ar/  <span style="color:black">
+        main.xml  </span>(This is the specific layout for Arabic)
+    layout-ldrtl/  <span style="color:black">
+        main.xml  </span>(This applies to any "right-to-left" language, except for Arabic, because the ar language qualifier has a higher precedence.)
+</pre>
+      </td>
+    </tr>
     <tr id="SmallestScreenWidthQualifier">
       <td>smallestWidth</td>
       <td><code>sw&lt;N&gt;dp</code><br/><br/>
diff --git a/docs/html/training/displaying-bitmaps/cache-bitmap.jd b/docs/html/training/displaying-bitmaps/cache-bitmap.jd
index 94abe21..2a333cc 100644
--- a/docs/html/training/displaying-bitmaps/cache-bitmap.jd
+++ b/docs/html/training/displaying-bitmaps/cache-bitmap.jd
@@ -96,7 +96,7 @@
 <p>Here’s an example of setting up a {@link android.util.LruCache} for bitmaps:</p>
 
 <pre>
-private LruCache<String, Bitmap> mMemoryCache;
+private LruCache&lt;String, Bitmap&gt; mMemoryCache;
 
 &#64;Override
 protected void onCreate(Bundle savedInstanceState) {
@@ -109,7 +109,7 @@
     // Use 1/8th of the available memory for this memory cache.
     final int cacheSize = 1024 * 1024 * memClass / 8;
 
-    mMemoryCache = new LruCache<String, Bitmap>(cacheSize) {
+    mMemoryCache = new LruCache&lt;String, Bitmap&gt;(cacheSize) {
         &#64;Override
         protected int sizeOf(String key, Bitmap bitmap) {
             // The cache size will be measured in bytes rather than number of items.
@@ -159,7 +159,7 @@
 updated to add entries to the memory cache:</p>
 
 <pre>
-class BitmapWorkerTask extends AsyncTask<Integer, Void, Bitmap> {
+class BitmapWorkerTask extends AsyncTask&lt;Integer, Void, Bitmap&gt; {
     ...
     // Decode image in background.
     &#64;Override
@@ -179,7 +179,7 @@
 rely on images being available in this cache. Components like {@link android.widget.GridView} with
 larger datasets can easily fill up a memory cache. Your application could be interrupted by another
 task like a phone call, and while in the background it might be killed and the memory cache
-destroyed. Once the user resumes, your application it has to process each image again.</p>
+destroyed. Once the user resumes, your application has to process each image again.</p>
 
 <p>A disk cache can be used in these cases to persist processed bitmaps and help decrease loading
 times where images are no longer available in a memory cache. Of course, fetching images from disk
@@ -190,18 +190,14 @@
 appropriate place to store cached images if they are accessed more frequently, for example in an
 image gallery application.</p>
 
-<p>Included in the sample code of this class is a basic {@code DiskLruCache} implementation.
-However, a more robust and recommended {@code DiskLruCache} solution is included in the Android 4.0
-source code ({@code libcore/luni/src/main/java/libcore/io/DiskLruCache.java}). Back-porting this
-class for use on previous Android releases should be fairly straightforward (a <a
-href="http://www.google.com/search?q=disklrucache">quick search</a> shows others who have already
-implemented this solution).</p>
-
-<p>Here’s updated example code that uses the simple {@code DiskLruCache} included in the sample
-application of this class:</p>
+<p>The sample code of this class uses a {@code DiskLruCache} implementation that is pulled from the 
+<a href="https://android.googlesource.com/platform/libcore/+/master/luni/src/main/java/libcore/io/DiskLruCache.java">Android source</a>. Here’s updated example code that adds a disk cache in addition
+to the existing memory cache:</p>
 
 <pre>
-private DiskLruCache mDiskCache;
+private DiskLruCache mDiskLruCache;
+private final Object mDiskCacheLock = new Object();
+private boolean mDiskCacheStarting = true;
 private static final int DISK_CACHE_SIZE = 1024 * 1024 * 10; // 10MB
 private static final String DISK_CACHE_SUBDIR = "thumbnails";
 
@@ -210,12 +206,26 @@
     ...
     // Initialize memory cache
     ...
-    File cacheDir = getCacheDir(this, DISK_CACHE_SUBDIR);
-    mDiskCache = DiskLruCache.openCache(this, cacheDir, DISK_CACHE_SIZE);
+    // Initialize disk cache on background thread
+    File cacheDir = getDiskCacheDir(this, DISK_CACHE_SUBDIR);
+    new InitDiskCacheTask().execute(cacheDir);
     ...
 }
 
-class BitmapWorkerTask extends AsyncTask<Integer, Void, Bitmap> {
+class InitDiskCacheTask extends AsyncTask&lt;File, Void, Void&gt; {
+    &#64;Override
+    protected Void doInBackground(File... params) {
+        synchronized (mDiskCacheLock) {
+            File cacheDir = params[0];
+            mDiskLruCache = DiskLruCache.open(cacheDir, DISK_CACHE_SIZE);
+            mDiskCacheStarting = false; // Finished initialization
+            mDiskCacheLock.notifyAll(); // Wake any waiting threads
+        }
+        return null;
+    }
+}
+
+class BitmapWorkerTask extends AsyncTask&lt;Integer, Void, Bitmap&gt; {
     ...
     // Decode image in background.
     &#64;Override
@@ -232,7 +242,7 @@
         }
 
         // Add final bitmap to caches
-        addBitmapToCache(String.valueOf(imageKey, bitmap);
+        addBitmapToCache(imageKey, bitmap);
 
         return bitmap;
     }
@@ -246,28 +256,48 @@
     }
 
     // Also add to disk cache
-    if (!mDiskCache.containsKey(key)) {
-        mDiskCache.put(key, bitmap);
+    synchronized (mDiskCacheLock) {
+        if (mDiskLruCache != null && mDiskLruCache.get(key) == null) {
+            mDiskLruCache.put(key, bitmap);
+        }
     }
 }
 
 public Bitmap getBitmapFromDiskCache(String key) {
-    return mDiskCache.get(key);
+    synchronized (mDiskCacheLock) {
+        // Wait while disk cache is started from background thread
+        while (mDiskCacheStarting) {
+            try {
+                mDiskCacheLock.wait();
+            } catch (InterruptedException e) {}
+        }
+        if (mDiskLruCache != null) {
+            return mDiskLruCache.get(key);
+        }
+    }
+    return null;
 }
 
 // Creates a unique subdirectory of the designated app cache directory. Tries to use external
 // but if not mounted, falls back on internal storage.
-public static File getCacheDir(Context context, String uniqueName) {
+public static File getDiskCacheDir(Context context, String uniqueName) {
     // Check if media is mounted or storage is built-in, if so, try and use external cache dir
     // otherwise use internal cache dir
-    final String cachePath = Environment.getExternalStorageState() == Environment.MEDIA_MOUNTED
-            || !Environment.isExternalStorageRemovable() ?
-                    context.getExternalCacheDir().getPath() : context.getCacheDir().getPath();
+    final String cachePath =
+            Environment.MEDIA_MOUNTED.equals(Environment.getExternalStorageState()) ||
+                    !isExternalStorageRemovable() ? getExternalCacheDir(context).getPath() :
+                            context.getCacheDir().getPath();
 
     return new File(cachePath + File.separator + uniqueName);
 }
 </pre>
 
+<p class="note"><strong>Note:</strong> Even initializing the disk cache requires disk operations
+and therefore should not take place on the main thread. However, this does mean there's a chance
+the cache is accessed before initialization. To address this, in the above implementation, a lock
+object ensures that the app does not read from the disk cache until the cache has been
+initialized.</p>
+
 <p>While the memory cache is checked in the UI thread, the disk cache is checked in the background
 thread. Disk operations should never take place on the UI thread. When image processing is
 complete, the final bitmap is added to both the memory and disk cache for future use.</p>
@@ -292,7 +322,7 @@
 changes using a {@link android.app.Fragment}:</p>
 
 <pre>
-private LruCache<String, Bitmap> mMemoryCache;
+private LruCache&lt;String, Bitmap&gt; mMemoryCache;
 
 &#64;Override
 protected void onCreate(Bundle savedInstanceState) {
@@ -301,7 +331,7 @@
             RetainFragment.findOrCreateRetainFragment(getFragmentManager());
     mMemoryCache = RetainFragment.mRetainedCache;
     if (mMemoryCache == null) {
-        mMemoryCache = new LruCache<String, Bitmap>(cacheSize) {
+        mMemoryCache = new LruCache&lt;String, Bitmap&gt;(cacheSize) {
             ... // Initialize cache here as usual
         }
         mRetainFragment.mRetainedCache = mMemoryCache;
@@ -311,7 +341,7 @@
 
 class RetainFragment extends Fragment {
     private static final String TAG = "RetainFragment";
-    public LruCache<String, Bitmap> mRetainedCache;
+    public LruCache&lt;String, Bitmap&gt; mRetainedCache;
 
     public RetainFragment() {}
 
diff --git a/docs/html/training/displaying-bitmaps/display-bitmap.jd b/docs/html/training/displaying-bitmaps/display-bitmap.jd
index 5eac04c..4572c42 100644
--- a/docs/html/training/displaying-bitmaps/display-bitmap.jd
+++ b/docs/html/training/displaying-bitmaps/display-bitmap.jd
@@ -103,7 +103,8 @@
 }
 </pre>
 
-<p>The details {@link android.app.Fragment} holds the {@link android.widget.ImageView} children:</p>
+<p>Here is an implementation of the details {@link android.app.Fragment} which holds the {@link android.widget.ImageView} children. This might seem like a perfectly reasonable approach, but can
+you see the drawbacks of this implementation? How could it be improved?</p>
 
 <pre>
 public class ImageDetailFragment extends Fragment {
@@ -146,11 +147,11 @@
 }
 </pre>
 
-<p>Hopefully you noticed the issue with this implementation; The images are being read from
-resources on the UI thread which can lead to an application hanging and being force closed. Using an
-{@link android.os.AsyncTask} as described in the <a href="process-bitmap.html">Processing Bitmaps Off
-the UI Thread</a> lesson, it’s straightforward to move image loading and processing to a background
-thread:</p>
+<p>Hopefully you noticed the issue: the images are being read from resources on the UI thread,
+which can lead to an application hanging and being force closed. Using an
+{@link android.os.AsyncTask} as described in the <a href="process-bitmap.html">Processing Bitmaps
+Off the UI Thread</a> lesson, it’s straightforward to move image loading and processing to a
+background thread:</p>
 
 <pre>
 public class ImageDetailActivity extends FragmentActivity {
@@ -190,7 +191,7 @@
 <pre>
 public class ImageDetailActivity extends FragmentActivity {
     ...
-    private LruCache<String, Bitmap> mMemoryCache;
+    private LruCache&lt;String, Bitmap&gt; mMemoryCache;
 
     &#64;Override
     public void onCreate(Bundle savedInstanceState) {
@@ -229,7 +230,8 @@
 the way {@link android.widget.GridView} recycles its children views).</p>
 
 <p>To start with, here is a standard {@link android.widget.GridView} implementation with {@link
-android.widget.ImageView} children placed inside a {@link android.app.Fragment}:</p>
+android.widget.ImageView} children placed inside a {@link android.app.Fragment}. Again, this might
+seem like a perfectly reasonable approach, but what would make it better?</p>
 
 <pre>
 public class ImageGridFragment extends Fragment implements AdapterView.OnItemClickListener {
@@ -261,7 +263,7 @@
     }
 
     &#64;Override
-    public void onItemClick(AdapterView<?> parent, View v, int position, long id) {
+    public void onItemClick(AdapterView&lt;?&gt; parent, View v, int position, long id) {
         final Intent i = new Intent(getActivity(), ImageDetailActivity.class);
         i.putExtra(ImageDetailActivity.EXTRA_IMAGE, position);
         startActivity(i);
@@ -345,13 +347,13 @@
     }
 
     static class AsyncDrawable extends BitmapDrawable {
-        private final WeakReference<BitmapWorkerTask> bitmapWorkerTaskReference;
+        private final WeakReference&lt;BitmapWorkerTask&gt; bitmapWorkerTaskReference;
 
         public AsyncDrawable(Resources res, Bitmap bitmap,
                 BitmapWorkerTask bitmapWorkerTask) {
             super(res, bitmap);
             bitmapWorkerTaskReference =
-                new WeakReference<BitmapWorkerTask>(bitmapWorkerTask);
+                new WeakReference&lt;BitmapWorkerTask&gt;(bitmapWorkerTask);
         }
 
         public BitmapWorkerTask getBitmapWorkerTask() {
diff --git a/docs/html/training/displaying-bitmaps/index.jd b/docs/html/training/displaying-bitmaps/index.jd
index 78371ad..b91172b 100644
--- a/docs/html/training/displaying-bitmaps/index.jd
+++ b/docs/html/training/displaying-bitmaps/index.jd
@@ -43,8 +43,8 @@
   perform under this minimum memory limit. However, keep in mind many devices are configured with
   higher limits.</li>
   <li>Bitmaps take up a lot of memory, especially for rich images like photographs. For example, the
-  camera on the <a href="http://www.google.com/nexus/">Galaxy Nexus</a> takes photos up to 2592x1936
-  pixels (5 megapixels). If the bitmap configuration used is {@link
+  camera on the <a href="http://www.android.com/devices/detail/galaxy-nexus">Galaxy Nexus</a> takes 
+  photos up to 2592x1936 pixels (5 megapixels). If the bitmap configuration used is {@link
   android.graphics.Bitmap.Config ARGB_8888} (the default from the Android 2.3 onward) then loading
   this image into memory takes about 19MB of memory (2592*1936*4 bytes), immediately exhausting the
   per-app limit on some devices.</li>
@@ -75,4 +75,4 @@
     components like {@link android.support.v4.view.ViewPager} and {@link android.widget.GridView}
     using a background thread and bitmap cache.</dd>
 
-</dl>
\ No newline at end of file
+</dl>
diff --git a/docs/html/training/displaying-bitmaps/process-bitmap.jd b/docs/html/training/displaying-bitmaps/process-bitmap.jd
index d1e346c..d4fcff3 100644
--- a/docs/html/training/displaying-bitmaps/process-bitmap.jd
+++ b/docs/html/training/displaying-bitmaps/process-bitmap.jd
@@ -62,13 +62,13 @@
 
 <a name="BitmapWorkerTask"></a>
 <pre>
-class BitmapWorkerTask extends AsyncTask<Integer, Void, Bitmap> {
-    private final WeakReference<ImageView> imageViewReference;
+class BitmapWorkerTask extends AsyncTask&lt;Integer, Void, Bitmap&gt; {
+    private final WeakReference&lt;ImageView&gt; imageViewReference;
     private int data = 0;
 
     public BitmapWorkerTask(ImageView imageView) {
         // Use a WeakReference to ensure the ImageView can be garbage collected
-        imageViewReference = new WeakReference<ImageView>(imageView);
+        imageViewReference = new WeakReference&lt;ImageView&gt;(imageView);
     }
 
     // Decode image in background.
@@ -133,13 +133,13 @@
 <a name="AsyncDrawable"></a>
 <pre>
 static class AsyncDrawable extends BitmapDrawable {
-    private final WeakReference<BitmapWorkerTask> bitmapWorkerTaskReference;
+    private final WeakReference&lt;BitmapWorkerTask&gt; bitmapWorkerTaskReference;
 
     public AsyncDrawable(Resources res, Bitmap bitmap,
             BitmapWorkerTask bitmapWorkerTask) {
         super(res, bitmap);
         bitmapWorkerTaskReference =
-            new WeakReference<BitmapWorkerTask>(bitmapWorkerTask);
+            new WeakReference&lt;BitmapWorkerTask&gt;(bitmapWorkerTask);
     }
 
     public BitmapWorkerTask getBitmapWorkerTask() {
@@ -211,7 +211,7 @@
 
 <a name="BitmapWorkerTaskUpdated"></a>
 <pre>
-class BitmapWorkerTask extends AsyncTask<Integer, Void, Bitmap> {
+class BitmapWorkerTask extends AsyncTask&lt;Integer, Void, Bitmap&gt; {
     ...
 
     &#64;Override
@@ -236,4 +236,4 @@
 android.widget.GridView} components as well as any other components that recycle their child
 views. Simply call {@code loadBitmap} where you normally set an image to your {@link
 android.widget.ImageView}. For example, in a {@link android.widget.GridView} implementation this
-would be in the {@link android.widget.Adapter#getView getView()} method of the backing adapter.</p>
\ No newline at end of file
+would be in the {@link android.widget.Adapter#getView getView()} method of the backing adapter.</p>
diff --git a/graphics/java/android/graphics/drawable/BitmapDrawable.java b/graphics/java/android/graphics/drawable/BitmapDrawable.java
index e82ccd4..7a4a1ca 100644
--- a/graphics/java/android/graphics/drawable/BitmapDrawable.java
+++ b/graphics/java/android/graphics/drawable/BitmapDrawable.java
@@ -80,6 +80,7 @@
     @Deprecated
     public BitmapDrawable() {
         mBitmapState = new BitmapState((Bitmap) null);
+        mMutated = true;
     }
 
     /**
@@ -90,6 +91,7 @@
     public BitmapDrawable(Resources res) {
         mBitmapState = new BitmapState((Bitmap) null);
         mBitmapState.mTargetDensity = mTargetDensity;
+        mMutated = true;
     }
 
     /**
@@ -100,6 +102,7 @@
     @Deprecated
     public BitmapDrawable(Bitmap bitmap) {
         this(new BitmapState(bitmap), null);
+        mMutated = true;
     }
 
     /**
@@ -109,6 +112,7 @@
     public BitmapDrawable(Resources res, Bitmap bitmap) {
         this(new BitmapState(bitmap), res);
         mBitmapState.mTargetDensity = mTargetDensity;
+        mMutated = true;
     }
 
     /**
@@ -122,6 +126,7 @@
         if (mBitmap == null) {
             android.util.Log.w("BitmapDrawable", "BitmapDrawable cannot decode " + filepath);
         }
+        mMutated = true;
     }
 
     /**
@@ -134,6 +139,7 @@
         if (mBitmap == null) {
             android.util.Log.w("BitmapDrawable", "BitmapDrawable cannot decode " + filepath);
         }
+        mMutated = true;
     }
 
     /**
@@ -147,6 +153,7 @@
         if (mBitmap == null) {
             android.util.Log.w("BitmapDrawable", "BitmapDrawable cannot decode " + is);
         }
+        mMutated = true;
     }
 
     /**
@@ -159,6 +166,7 @@
         if (mBitmap == null) {
             android.util.Log.w("BitmapDrawable", "BitmapDrawable cannot decode " + is);
         }
+        mMutated = true;
     }
 
     /**
@@ -552,6 +560,7 @@
         } else {
             mTargetDensity = state.mTargetDensity;
         }
+        mMutated = false;
         setBitmap(state != null ? state.mBitmap : null);
     }
 }
diff --git a/graphics/java/android/graphics/drawable/ClipDrawable.java b/graphics/java/android/graphics/drawable/ClipDrawable.java
index bade9b4..723db6e 100644
--- a/graphics/java/android/graphics/drawable/ClipDrawable.java
+++ b/graphics/java/android/graphics/drawable/ClipDrawable.java
@@ -239,7 +239,11 @@
         return null;
     }
 
-    
+    @Override
+    public void setLayoutDirection(int layoutDirection) {
+        mClipState.mDrawable.setLayoutDirection(layoutDirection);
+        super.setLayoutDirection(layoutDirection);
+    }
 
     final static class ClipState extends ConstantState {
         Drawable mDrawable;
diff --git a/graphics/java/android/graphics/drawable/ColorDrawable.java b/graphics/java/android/graphics/drawable/ColorDrawable.java
index 88c9155..f8e3944 100644
--- a/graphics/java/android/graphics/drawable/ColorDrawable.java
+++ b/graphics/java/android/graphics/drawable/ColorDrawable.java
@@ -36,12 +36,14 @@
 public class ColorDrawable extends Drawable {
     private ColorState mState;
     private final Paint mPaint = new Paint();
+    private boolean mMutated;
 
     /**
      * Creates a new black ColorDrawable.
      */
     public ColorDrawable() {
         this(null);
+        mMutated = true;
     }
 
     /**
@@ -52,6 +54,7 @@
     public ColorDrawable(int color) {
         this(null);
         setColor(color);
+        mMutated = true;
     }
 
     private ColorDrawable(ColorState state) {
@@ -63,6 +66,21 @@
         return super.getChangingConfigurations() | mState.mChangingConfigurations;
     }
 
+    /**
+     * A mutable BitmapDrawable still shares its Bitmap with any other Drawable
+     * that comes from the same resource.
+     *
+     * @return This drawable.
+     */
+    @Override
+    public Drawable mutate() {
+        if (!mMutated && super.mutate() == this) {
+            mState = new ColorState(mState);
+            mMutated = true;
+        }
+        return this;
+    }
+
     @Override
     public void draw(Canvas canvas) {
         if ((mState.mUseColor >>> 24) != 0) {
@@ -165,6 +183,7 @@
             if (state != null) {
                 mBaseColor = state.mBaseColor;
                 mUseColor = state.mUseColor;
+                mChangingConfigurations = state.mChangingConfigurations;
             }
         }
 
diff --git a/graphics/java/android/graphics/drawable/Drawable.java b/graphics/java/android/graphics/drawable/Drawable.java
index 4bc5a5a..020a54f 100644
--- a/graphics/java/android/graphics/drawable/Drawable.java
+++ b/graphics/java/android/graphics/drawable/Drawable.java
@@ -376,8 +376,8 @@
     /**
      * Returns the resolved layout direction for this Drawable.
      *
-     * @return One of {@link View#LAYOUT_DIRECTION_LTR},
-     *   {@link View#LAYOUT_DIRECTION_RTL}
+     * @return One of {@link android.view.View#LAYOUT_DIRECTION_LTR},
+     *   {@link android.view.View#LAYOUT_DIRECTION_RTL}
      */
     public int getLayoutDirection() {
         return mLayoutDirection;
@@ -387,8 +387,8 @@
      * Set the layout direction for this drawable. Should be a resolved direction as the
      * Drawable as no capacity to do the resolution on his own.
      *
-     * @param layoutDirection One of {@link View#LAYOUT_DIRECTION_LTR},
-     *   {@link View#LAYOUT_DIRECTION_RTL},
+     * @param layoutDirection One of {@link android.view.View#LAYOUT_DIRECTION_LTR},
+     *   {@link android.view.View#LAYOUT_DIRECTION_RTL},
      *
      */
     public void setLayoutDirection(int layoutDirection) {
diff --git a/graphics/java/android/graphics/drawable/DrawableContainer.java b/graphics/java/android/graphics/drawable/DrawableContainer.java
index 15b2c0b..486390c 100644
--- a/graphics/java/android/graphics/drawable/DrawableContainer.java
+++ b/graphics/java/android/graphics/drawable/DrawableContainer.java
@@ -105,7 +105,7 @@
             mAlpha = alpha;
             if (mCurrDrawable != null) {
                 if (mEnterAnimationEnd == 0) {
-                    mCurrDrawable.setAlpha(alpha);
+                    mCurrDrawable.mutate().setAlpha(alpha);
                 } else {
                     animate(false);
                 }
@@ -118,7 +118,7 @@
         if (mDrawableContainerState.mDither != dither) {
             mDrawableContainerState.mDither = dither;
             if (mCurrDrawable != null) {
-                mCurrDrawable.setDither(mDrawableContainerState.mDither);
+                mCurrDrawable.mutate().setDither(mDrawableContainerState.mDither);
             }
         }
     }
@@ -128,7 +128,7 @@
         if (mColorFilter != cf) {
             mColorFilter = cf;
             if (mCurrDrawable != null) {
-                mCurrDrawable.setColorFilter(cf);
+                mCurrDrawable.mutate().setColorFilter(cf);
             }
         }
     }
@@ -176,7 +176,7 @@
         }
         if (mCurrDrawable != null) {
             mCurrDrawable.jumpToCurrentState();
-            mCurrDrawable.setAlpha(mAlpha);
+            mCurrDrawable.mutate().setAlpha(mAlpha);
         }
         if (mExitAnimationEnd != 0) {
             mExitAnimationEnd = 0;
@@ -312,6 +312,7 @@
             mCurrDrawable = d;
             mCurIndex = idx;
             if (d != null) {
+                d.mutate();
                 if (mDrawableContainerState.mEnterFadeDuration > 0) {
                     mEnterAnimationEnd = now + mDrawableContainerState.mEnterFadeDuration;
                 } else {
@@ -355,13 +356,13 @@
         if (mCurrDrawable != null) {
             if (mEnterAnimationEnd != 0) {
                 if (mEnterAnimationEnd <= now) {
-                    mCurrDrawable.setAlpha(mAlpha);
+                    mCurrDrawable.mutate().setAlpha(mAlpha);
                     mEnterAnimationEnd = 0;
                 } else {
                     int animAlpha = (int)((mEnterAnimationEnd-now)*255)
                             / mDrawableContainerState.mEnterFadeDuration;
                     if (DEBUG) android.util.Log.i(TAG, toString() + " cur alpha " + animAlpha);
-                    mCurrDrawable.setAlpha(((255-animAlpha)*mAlpha)/255);
+                    mCurrDrawable.mutate().setAlpha(((255-animAlpha)*mAlpha)/255);
                     animating = true;
                 }
             }
@@ -378,7 +379,7 @@
                     int animAlpha = (int)((mExitAnimationEnd-now)*255)
                             / mDrawableContainerState.mExitFadeDuration;
                     if (DEBUG) android.util.Log.i(TAG, toString() + " last alpha " + animAlpha);
-                    mLastDrawable.setAlpha((animAlpha*mAlpha)/255);
+                    mLastDrawable.mutate().setAlpha((animAlpha*mAlpha)/255);
                     animating = true;
                 }
             }
diff --git a/graphics/java/android/graphics/drawable/GradientDrawable.java b/graphics/java/android/graphics/drawable/GradientDrawable.java
index 5b50beb..21344f4 100644
--- a/graphics/java/android/graphics/drawable/GradientDrawable.java
+++ b/graphics/java/android/graphics/drawable/GradientDrawable.java
@@ -124,7 +124,7 @@
     
     private Paint mLayerPaint;    // internal, used if we use saveLayer()
     private boolean mRectIsDirty;   // internal state
-    private boolean mMutated;
+    private boolean mMutated = true;
     private Path mRingPath;
     private boolean mPathIsDirty = true;
 
@@ -1202,6 +1202,7 @@
         mGradientState = state;
         initializeWithState(state);
         mRectIsDirty = true;
+        mMutated = false;
     }
 
     private void initializeWithState(GradientState state) {
diff --git a/graphics/java/android/graphics/drawable/LayerDrawable.java b/graphics/java/android/graphics/drawable/LayerDrawable.java
index 383fe71..03531ac 100644
--- a/graphics/java/android/graphics/drawable/LayerDrawable.java
+++ b/graphics/java/android/graphics/drawable/LayerDrawable.java
@@ -590,6 +590,18 @@
         return this;
     }
 
+    @Override
+    public void setLayoutDirection(int layoutDirection) {
+        if (getLayoutDirection() != layoutDirection) {
+            final ChildDrawable[] array = mLayerState.mChildren;
+            final int N = mLayerState.mNum;
+            for (int i = 0; i < N; i++) {
+                array[i].mDrawable.setLayoutDirection(layoutDirection);
+            }
+        }
+        super.setLayoutDirection(layoutDirection);
+    }
+
     static class ChildDrawable {
         public Drawable mDrawable;
         public int mInsetL, mInsetT, mInsetR, mInsetB;
diff --git a/graphics/java/android/graphics/drawable/NinePatchDrawable.java b/graphics/java/android/graphics/drawable/NinePatchDrawable.java
index 62aea71..7a43496 100644
--- a/graphics/java/android/graphics/drawable/NinePatchDrawable.java
+++ b/graphics/java/android/graphics/drawable/NinePatchDrawable.java
@@ -77,6 +77,7 @@
     @Deprecated
     public NinePatchDrawable(Bitmap bitmap, byte[] chunk, Rect padding, String srcName) {
         this(new NinePatchState(new NinePatch(bitmap, chunk, srcName), padding), null);
+        mMutated = true;
     }
 
     /**
@@ -87,6 +88,7 @@
             Rect padding, String srcName) {
         this(new NinePatchState(new NinePatch(bitmap, chunk, srcName), padding), res);
         mNinePatchState.mTargetDensity = mTargetDensity;
+        mMutated = true;
     }
 
     /**
@@ -99,6 +101,7 @@
             Rect padding, Rect layoutInsets, String srcName) {
         this(new NinePatchState(new NinePatch(bitmap, chunk, srcName), padding, layoutInsets), res);
         mNinePatchState.mTargetDensity = mTargetDensity;
+        mMutated = true;
     }
 
     /**
@@ -109,6 +112,7 @@
     @Deprecated
     public NinePatchDrawable(NinePatch patch) {
         this(new NinePatchState(patch, new Rect()), null);
+        mMutated = true;
     }
 
     /**
@@ -118,6 +122,7 @@
     public NinePatchDrawable(Resources res, NinePatch patch) {
         this(new NinePatchState(patch, new Rect()), res);
         mNinePatchState.mTargetDensity = mTargetDensity;
+        mMutated = true;
     }
 
     private void setNinePatchState(NinePatchState state, Resources res) {
@@ -181,7 +186,7 @@
         }
     }
 
-    private Insets scaleFromDensity(Insets insets, int sdensity, int tdensity) {
+    private static Insets scaleFromDensity(Insets insets, int sdensity, int tdensity) {
         int left = Bitmap.scaleFromDensity(insets.left, sdensity, tdensity);
         int top = Bitmap.scaleFromDensity(insets.top, sdensity, tdensity);
         int right = Bitmap.scaleFromDensity(insets.right, sdensity, tdensity);
diff --git a/graphics/java/android/graphics/drawable/ShapeDrawable.java b/graphics/java/android/graphics/drawable/ShapeDrawable.java
index a3622a2..2ec1293 100644
--- a/graphics/java/android/graphics/drawable/ShapeDrawable.java
+++ b/graphics/java/android/graphics/drawable/ShapeDrawable.java
@@ -373,8 +373,16 @@
     @Override
     public Drawable mutate() {
         if (!mMutated && super.mutate() == this) {
-            mShapeState.mPaint = new Paint(mShapeState.mPaint);
-            mShapeState.mPadding = new Rect(mShapeState.mPadding);
+            if (mShapeState.mPaint != null) {
+                mShapeState.mPaint = new Paint(mShapeState.mPaint);
+            } else {
+                mShapeState.mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
+            }
+            if (mShapeState.mPadding != null) {
+                mShapeState.mPadding = new Rect(mShapeState.mPadding);
+            } else {
+                mShapeState.mPadding = new Rect();
+            }
             try {
                 mShapeState.mShape = mShapeState.mShape.clone();
             } catch (CloneNotSupportedException e) {
diff --git a/graphics/java/android/graphics/drawable/StateListDrawable.java b/graphics/java/android/graphics/drawable/StateListDrawable.java
index 384ca81..a5c3614 100644
--- a/graphics/java/android/graphics/drawable/StateListDrawable.java
+++ b/graphics/java/android/graphics/drawable/StateListDrawable.java
@@ -261,6 +261,15 @@
         return this;
     }
 
+    @Override
+    public void setLayoutDirection(int layoutDirection) {
+        final int numStates = getStateCount();
+        for (int i = 0; i < numStates; i++) {
+            getStateDrawable(i).setLayoutDirection(layoutDirection);
+        }
+        super.setLayoutDirection(layoutDirection);
+    }
+
     static final class StateListState extends DrawableContainerState {
         int[][] mStateSets;
 
diff --git a/graphics/java/android/renderscript/Matrix4f.java b/graphics/java/android/renderscript/Matrix4f.java
index a85d464..4600424 100644
--- a/graphics/java/android/renderscript/Matrix4f.java
+++ b/graphics/java/android/renderscript/Matrix4f.java
@@ -113,6 +113,34 @@
     }
 
     /**
+    * Sets the values of the matrix to those of the parameter
+    *
+    * @param src matrix to load the values from
+    * @hide
+    */
+    public void load(Matrix3f src) {
+        mMat[0] = src.mMat[0];
+        mMat[1] = src.mMat[1];
+        mMat[2] = src.mMat[2];
+        mMat[3] = 0;
+
+        mMat[4] = src.mMat[3];
+        mMat[5] = src.mMat[4];
+        mMat[6] = src.mMat[5];
+        mMat[7] = 0;
+
+        mMat[8] = src.mMat[6];
+        mMat[9] = src.mMat[7];
+        mMat[10] = src.mMat[8];
+        mMat[11] = 0;
+
+        mMat[12] = 0;
+        mMat[13] = 0;
+        mMat[14] = 0;
+        mMat[15] = 1;
+    }
+
+    /**
     * Sets current values to be a rotation matrix of certain angle
     * about a given axis
     *
diff --git a/graphics/java/android/renderscript/ScriptIntrinsicColorMatrix.java b/graphics/java/android/renderscript/ScriptIntrinsicColorMatrix.java
index 41e7e00..8cac28e 100644
--- a/graphics/java/android/renderscript/ScriptIntrinsicColorMatrix.java
+++ b/graphics/java/android/renderscript/ScriptIntrinsicColorMatrix.java
@@ -39,8 +39,7 @@
     }
 
     /**
-     * Supported elements types are float, float4, uchar, uchar4
-     *
+     * Supported elements types are uchar4
      *
      * @param rs
      * @param e
@@ -53,13 +52,98 @@
 
     }
 
-    public void setColorMatrix(Matrix4f m) {
-        mMatrix.load(m);
+    private void setMatrix() {
         FieldPacker fp = new FieldPacker(16*4);
-        fp.addMatrix(m);
+        fp.addMatrix(mMatrix);
         setVar(0, fp);
     }
 
+    /**
+     * Set the color matrix which will be applied to each cell of the image.
+     *
+     * @param m The 4x4 matrix to set.
+     */
+    public void setColorMatrix(Matrix4f m) {
+        mMatrix.load(m);
+        setMatrix();
+    }
+
+    /**
+     * Set the color matrix which will be applied to each cell of the image.
+     * This will set the alpha channel to be a copy.
+     *
+     * @param m The 3x3 matrix to set.
+     */
+    public void setColorMatrix(Matrix3f m) {
+        mMatrix.load(m);
+        setMatrix();
+    }
+
+    /**
+     * Set a color matrix to convert from RGB to luminance. The alpha channel
+     * will be a copy.
+     *
+     */
+    public void setGreyscale() {
+        mMatrix.loadIdentity();
+        mMatrix.set(0, 0, 0.299f);
+        mMatrix.set(1, 0, 0.587f);
+        mMatrix.set(2, 0, 0.114f);
+        mMatrix.set(0, 1, 0.299f);
+        mMatrix.set(1, 1, 0.587f);
+        mMatrix.set(2, 1, 0.114f);
+        mMatrix.set(0, 2, 0.299f);
+        mMatrix.set(1, 2, 0.587f);
+        mMatrix.set(2, 2, 0.114f);
+        setMatrix();
+    }
+
+    /**
+     * Set the matrix to convert from YUV to RGB with a direct copy of the 4th
+     * channel.
+     *
+     */
+    public void setYUVtoRGB() {
+        mMatrix.loadIdentity();
+        mMatrix.set(0, 0, 1.f);
+        mMatrix.set(1, 0, 0.f);
+        mMatrix.set(2, 0, 1.13983f);
+        mMatrix.set(0, 1, 1.f);
+        mMatrix.set(1, 1, -0.39465f);
+        mMatrix.set(2, 1, -0.5806f);
+        mMatrix.set(0, 2, 1.f);
+        mMatrix.set(1, 2, 2.03211f);
+        mMatrix.set(2, 2, 0.f);
+        setMatrix();
+    }
+
+    /**
+     * Set the matrix to convert from RGB to YUV with a direct copy of the 4th
+     * channel.
+     *
+     */
+    public void setRGBtoYUV() {
+        mMatrix.loadIdentity();
+        mMatrix.set(0, 0, 0.299f);
+        mMatrix.set(1, 0, 0.587f);
+        mMatrix.set(2, 0, 0.114f);
+        mMatrix.set(0, 1, -0.14713f);
+        mMatrix.set(1, 1, -0.28886f);
+        mMatrix.set(2, 1, 0.436f);
+        mMatrix.set(0, 2, 0.615f);
+        mMatrix.set(1, 2, -0.51499f);
+        mMatrix.set(2, 2, -0.10001f);
+        setMatrix();
+    }
+
+
+    /**
+     * Invoke the kernel and apply the matrix to each cell of ain and copy to
+     * aout.
+     *
+     * @param ain Input allocation
+     * @param aout Output allocation
+     */
     public void forEach(Allocation ain, Allocation aout) {
         forEach(0, ain, aout, null);
     }
diff --git a/graphics/java/android/renderscript/ScriptIntrinsicYuvToRGB.java b/graphics/java/android/renderscript/ScriptIntrinsicYuvToRGB.java
index ee5f938..b4a228b 100644
--- a/graphics/java/android/renderscript/ScriptIntrinsicYuvToRGB.java
+++ b/graphics/java/android/renderscript/ScriptIntrinsicYuvToRGB.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2008 The Android Open Source Project
+ * Copyright (C) 2012 The Android Open Source Project
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
diff --git a/include/android_runtime/android_view_Surface.h b/include/android_runtime/android_view_Surface.h
index e50186d..df0fe72 100644
--- a/include/android_runtime/android_view_Surface.h
+++ b/include/android_runtime/android_view_Surface.h
@@ -24,6 +24,7 @@
 namespace android {
 
 class Surface;
+class ISurfaceTexture;
 
 /* Gets the underlying ANativeWindow for a Surface. */
 extern sp<ANativeWindow> android_view_Surface_getNativeWindow(
@@ -35,6 +36,10 @@
 /* Gets the underlying Surface from a Surface Java object. */
 extern sp<Surface> android_view_Surface_getSurface(JNIEnv* env, jobject surfaceObj);
 
+/* Creates a Surface from an ISurfaceTexture. */
+extern jobject android_view_Surface_createFromISurfaceTexture(JNIEnv* env,
+        const sp<ISurfaceTexture>& surfaceTexture);
+
 } // namespace android
 
 #endif // _ANDROID_VIEW_SURFACE_H
diff --git a/libs/androidfw/ResourceTypes.cpp b/libs/androidfw/ResourceTypes.cpp
index 069dfa3..0107da4 100644
--- a/libs/androidfw/ResourceTypes.cpp
+++ b/libs/androidfw/ResourceTypes.cpp
@@ -2061,10 +2061,10 @@
         if (res.size() > 0) res.append("-");
         switch (screenLayout&ResTable_config::MASK_LAYOUTDIR) {
             case ResTable_config::LAYOUTDIR_LTR:
-                res.append("ltr");
+                res.append("ldltr");
                 break;
             case ResTable_config::LAYOUTDIR_RTL:
-                res.append("rtl");
+                res.append("ldrtl");
                 break;
             default:
                 res.appendFormat("layoutDir=%d",
diff --git a/libs/hwui/Android.mk b/libs/hwui/Android.mk
index c0f79df..e032ae4 100644
--- a/libs/hwui/Android.mk
+++ b/libs/hwui/Android.mk
@@ -16,6 +16,7 @@
 		Dither.cpp \
 		FboCache.cpp \
 		GradientCache.cpp \
+		Layer.cpp \
 		LayerCache.cpp \
 		LayerRenderer.cpp \
 		Matrix.cpp \
diff --git a/libs/hwui/Caches.h b/libs/hwui/Caches.h
index b9a6336..6d27d6e 100644
--- a/libs/hwui/Caches.h
+++ b/libs/hwui/Caches.h
@@ -68,6 +68,7 @@
 static const GLsizei gAlphaVertexStride = sizeof(AlphaVertex);
 static const GLsizei gAAVertexStride = sizeof(AAVertex);
 static const GLsizei gMeshTextureOffset = 2 * sizeof(float);
+static const GLsizei gVertexAlphaOffset = 2 * sizeof(float);
 static const GLsizei gVertexAAWidthOffset = 2 * sizeof(float);
 static const GLsizei gVertexAALengthOffset = 3 * sizeof(float);
 static const GLsizei gMeshCount = 4;
diff --git a/libs/hwui/DisplayListRenderer.cpp b/libs/hwui/DisplayListRenderer.cpp
index 2de70d462..755170f 100644
--- a/libs/hwui/DisplayListRenderer.cpp
+++ b/libs/hwui/DisplayListRenderer.cpp
@@ -149,6 +149,7 @@
     delete mTransformMatrix3D;
     delete mStaticMatrix;
     delete mAnimationMatrix;
+
     mTransformMatrix = NULL;
     mTransformCamera = NULL;
     mTransformMatrix3D = NULL;
@@ -156,50 +157,54 @@
     mAnimationMatrix = NULL;
 
     Caches& caches = Caches::getInstance();
+    caches.resourceCache.lock();
 
     for (size_t i = 0; i < mBitmapResources.size(); i++) {
-        caches.resourceCache.decrementRefcount(mBitmapResources.itemAt(i));
+        caches.resourceCache.decrementRefcountLocked(mBitmapResources.itemAt(i));
     }
-    mBitmapResources.clear();
 
     for (size_t i = 0; i < mOwnedBitmapResources.size(); i++) {
         SkBitmap* bitmap = mOwnedBitmapResources.itemAt(i);
-        caches.resourceCache.decrementRefcount(bitmap);
-        caches.resourceCache.destructor(bitmap);
+        caches.resourceCache.decrementRefcountLocked(bitmap);
+        caches.resourceCache.destructorLocked(bitmap);
     }
-    mOwnedBitmapResources.clear();
 
     for (size_t i = 0; i < mFilterResources.size(); i++) {
-        caches.resourceCache.decrementRefcount(mFilterResources.itemAt(i));
+        caches.resourceCache.decrementRefcountLocked(mFilterResources.itemAt(i));
     }
-    mFilterResources.clear();
 
     for (size_t i = 0; i < mShaders.size(); i++) {
-        caches.resourceCache.decrementRefcount(mShaders.itemAt(i));
-        caches.resourceCache.destructor(mShaders.itemAt(i));
+        caches.resourceCache.decrementRefcountLocked(mShaders.itemAt(i));
+        caches.resourceCache.destructorLocked(mShaders.itemAt(i));
     }
-    mShaders.clear();
+
+    for (size_t i = 0; i < mSourcePaths.size(); i++) {
+        caches.resourceCache.decrementRefcountLocked(mSourcePaths.itemAt(i));
+    }
+
+    caches.resourceCache.unlock();
 
     for (size_t i = 0; i < mPaints.size(); i++) {
         delete mPaints.itemAt(i);
     }
-    mPaints.clear();
 
     for (size_t i = 0; i < mPaths.size(); i++) {
         SkPath* path = mPaths.itemAt(i);
         caches.pathCache.remove(path);
         delete path;
     }
-    mPaths.clear();
-
-    for (size_t i = 0; i < mSourcePaths.size(); i++) {
-        caches.resourceCache.decrementRefcount(mSourcePaths.itemAt(i));
-    }
-    mSourcePaths.clear();
 
     for (size_t i = 0; i < mMatrices.size(); i++) {
         delete mMatrices.itemAt(i);
     }
+
+    mBitmapResources.clear();
+    mOwnedBitmapResources.clear();
+    mFilterResources.clear();
+    mShaders.clear();
+    mSourcePaths.clear();
+    mPaints.clear();
+    mPaths.clear();
     mMatrices.clear();
 }
 
@@ -223,35 +228,44 @@
     mReader.setMemory(buffer, mSize);
 
     Caches& caches = Caches::getInstance();
+    caches.resourceCache.lock();
 
     const Vector<SkBitmap*>& bitmapResources = recorder.getBitmapResources();
     for (size_t i = 0; i < bitmapResources.size(); i++) {
         SkBitmap* resource = bitmapResources.itemAt(i);
         mBitmapResources.add(resource);
-        caches.resourceCache.incrementRefcount(resource);
+        caches.resourceCache.incrementRefcountLocked(resource);
     }
 
     const Vector<SkBitmap*> &ownedBitmapResources = recorder.getOwnedBitmapResources();
     for (size_t i = 0; i < ownedBitmapResources.size(); i++) {
         SkBitmap* resource = ownedBitmapResources.itemAt(i);
         mOwnedBitmapResources.add(resource);
-        caches.resourceCache.incrementRefcount(resource);
+        caches.resourceCache.incrementRefcountLocked(resource);
     }
 
     const Vector<SkiaColorFilter*>& filterResources = recorder.getFilterResources();
     for (size_t i = 0; i < filterResources.size(); i++) {
         SkiaColorFilter* resource = filterResources.itemAt(i);
         mFilterResources.add(resource);
-        caches.resourceCache.incrementRefcount(resource);
+        caches.resourceCache.incrementRefcountLocked(resource);
     }
 
     const Vector<SkiaShader*>& shaders = recorder.getShaders();
     for (size_t i = 0; i < shaders.size(); i++) {
         SkiaShader* resource = shaders.itemAt(i);
         mShaders.add(resource);
-        caches.resourceCache.incrementRefcount(resource);
+        caches.resourceCache.incrementRefcountLocked(resource);
     }
 
+    const SortedVector<SkPath*>& sourcePaths = recorder.getSourcePaths();
+    for (size_t i = 0; i < sourcePaths.size(); i++) {
+        mSourcePaths.add(sourcePaths.itemAt(i));
+        caches.resourceCache.incrementRefcountLocked(sourcePaths.itemAt(i));
+    }
+
+    caches.resourceCache.unlock();
+
     const Vector<SkPaint*>& paints = recorder.getPaints();
     for (size_t i = 0; i < paints.size(); i++) {
         mPaints.add(paints.itemAt(i));
@@ -262,12 +276,6 @@
         mPaths.add(paths.itemAt(i));
     }
 
-    const SortedVector<SkPath*>& sourcePaths = recorder.getSourcePaths();
-    for (size_t i = 0; i < sourcePaths.size(); i++) {
-        mSourcePaths.add(sourcePaths.itemAt(i));
-        caches.resourceCache.incrementRefcount(sourcePaths.itemAt(i));
-    }
-
     const Vector<SkMatrix*>& matrices = recorder.getMatrices();
     for (size_t i = 0; i < matrices.size(); i++) {
         mMatrices.add(matrices.itemAt(i));
@@ -1004,29 +1012,39 @@
             }
             break;
             case DrawLayer: {
+                int oldAlpha = -1;
                 Layer* layer = (Layer*) getInt();
                 float x = getFloat();
                 float y = getFloat();
                 SkPaint* paint = getPaint(renderer);
-                if (mCaching) {
-                    paint->setAlpha(mMultipliedAlpha);
+                if (mCaching && mMultipliedAlpha < 255) {
+                    oldAlpha = layer->getAlpha();
+                    layer->setAlpha(mMultipliedAlpha);
                 }
                 DISPLAY_LIST_LOGD("%s%s %p, %.2f, %.2f, %p", (char*) indent, OP_NAMES[op],
                         layer, x, y, paint);
                 drawGlStatus |= renderer.drawLayer(layer, x, y, paint);
+                if (oldAlpha >= 0) {
+                    layer->setAlpha(oldAlpha);
+                }
             }
             break;
             case DrawBitmap: {
+                int oldAlpha = -1;
                 SkBitmap* bitmap = getBitmap();
                 float x = getFloat();
                 float y = getFloat();
                 SkPaint* paint = getPaint(renderer);
-                if (mCaching) {
+                if (mCaching && mMultipliedAlpha < 255) {
+                    oldAlpha = paint->getAlpha();
                     paint->setAlpha(mMultipliedAlpha);
                 }
                 DISPLAY_LIST_LOGD("%s%s %p, %.2f, %.2f, %p", (char*) indent, OP_NAMES[op],
                         bitmap, x, y, paint);
                 drawGlStatus |= renderer.drawBitmap(bitmap, x, y, paint);
+                if (oldAlpha >= 0) {
+                    paint->setAlpha(oldAlpha);
+                }
             }
             break;
             case DrawBitmapMatrix: {
@@ -1309,7 +1327,8 @@
 // Base structure
 ///////////////////////////////////////////////////////////////////////////////
 
-DisplayListRenderer::DisplayListRenderer() : mWriter(MIN_WRITER_SIZE),
+DisplayListRenderer::DisplayListRenderer():
+        mCaches(Caches::getInstance()), mWriter(MIN_WRITER_SIZE),
         mTranslateX(0.0f), mTranslateY(0.0f), mHasTranslate(false), mHasDrawOps(false) {
 }
 
@@ -1320,34 +1339,38 @@
 void DisplayListRenderer::reset() {
     mWriter.reset();
 
-    Caches& caches = Caches::getInstance();
+    mCaches.resourceCache.lock();
+
     for (size_t i = 0; i < mBitmapResources.size(); i++) {
-        caches.resourceCache.decrementRefcount(mBitmapResources.itemAt(i));
+        mCaches.resourceCache.decrementRefcountLocked(mBitmapResources.itemAt(i));
     }
-    mBitmapResources.clear();
 
     for (size_t i = 0; i < mOwnedBitmapResources.size(); i++) {
-        SkBitmap* bitmap = mOwnedBitmapResources.itemAt(i);
-        caches.resourceCache.decrementRefcount(bitmap);
+        mCaches.resourceCache.decrementRefcountLocked(mOwnedBitmapResources.itemAt(i));
     }
-    mOwnedBitmapResources.clear();
 
     for (size_t i = 0; i < mFilterResources.size(); i++) {
-        caches.resourceCache.decrementRefcount(mFilterResources.itemAt(i));
+        mCaches.resourceCache.decrementRefcountLocked(mFilterResources.itemAt(i));
     }
-    mFilterResources.clear();
 
     for (size_t i = 0; i < mShaders.size(); i++) {
-        caches.resourceCache.decrementRefcount(mShaders.itemAt(i));
+        mCaches.resourceCache.decrementRefcountLocked(mShaders.itemAt(i));
     }
-    mShaders.clear();
-    mShaderMap.clear();
 
     for (size_t i = 0; i < mSourcePaths.size(); i++) {
-        caches.resourceCache.decrementRefcount(mSourcePaths.itemAt(i));
+        mCaches.resourceCache.decrementRefcountLocked(mSourcePaths.itemAt(i));
     }
+
+    mCaches.resourceCache.unlock();
+
+    mBitmapResources.clear();
+    mOwnedBitmapResources.clear();
+    mFilterResources.clear();
     mSourcePaths.clear();
 
+    mShaders.clear();
+    mShaderMap.clear();
+
     mPaints.clear();
     mPaintMap.clear();
 
diff --git a/libs/hwui/DisplayListRenderer.h b/libs/hwui/DisplayListRenderer.h
index c8b3e47..8e4f2d3 100644
--- a/libs/hwui/DisplayListRenderer.h
+++ b/libs/hwui/DisplayListRenderer.h
@@ -763,7 +763,7 @@
             mPaths.add(pathCopy);
         }
         if (mSourcePaths.indexOf(path) < 0) {
-            Caches::getInstance().resourceCache.incrementRefcount(path);
+            mCaches.resourceCache.incrementRefcount(path);
             mSourcePaths.add(path);
         }
 
@@ -811,13 +811,13 @@
         // which doesn't seem worth the extra cycles for this unlikely case.
         addInt((int) bitmap);
         mBitmapResources.add(bitmap);
-        Caches::getInstance().resourceCache.incrementRefcount(bitmap);
+        mCaches.resourceCache.incrementRefcount(bitmap);
     }
 
     void addBitmapData(SkBitmap* bitmap) {
         addInt((int) bitmap);
         mOwnedBitmapResources.add(bitmap);
-        Caches::getInstance().resourceCache.incrementRefcount(bitmap);
+        mCaches.resourceCache.incrementRefcount(bitmap);
     }
 
     inline void addShader(SkiaShader* shader) {
@@ -833,7 +833,7 @@
             // replaceValueFor() performs an add if the entry doesn't exist
             mShaderMap.replaceValueFor(shader, shaderCopy);
             mShaders.add(shaderCopy);
-            Caches::getInstance().resourceCache.incrementRefcount(shaderCopy);
+            mCaches.resourceCache.incrementRefcount(shaderCopy);
         }
 
         addInt((int) shaderCopy);
@@ -842,7 +842,7 @@
     inline void addColorFilter(SkiaColorFilter* colorFilter) {
         addInt((int) colorFilter);
         mFilterResources.add(colorFilter);
-        Caches::getInstance().resourceCache.incrementRefcount(colorFilter);
+        mCaches.resourceCache.incrementRefcount(colorFilter);
     }
 
     Vector<SkBitmap*> mBitmapResources;
@@ -862,15 +862,16 @@
 
     Vector<SkMatrix*> mMatrices;
 
-    SkWriter32 mWriter;
     uint32_t mBufferSize;
 
     int mRestoreSaveCount;
 
+    Caches& mCaches;
+    SkWriter32 mWriter;
+
     float mTranslateX;
     float mTranslateY;
     bool mHasTranslate;
-
     bool mHasDrawOps;
 
     friend class DisplayList;
diff --git a/libs/hwui/Layer.cpp b/libs/hwui/Layer.cpp
new file mode 100644
index 0000000..31e169b
--- /dev/null
+++ b/libs/hwui/Layer.cpp
@@ -0,0 +1,51 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "OpenGLRenderer"
+
+#include <utils/Log.h>
+
+#include "Layer.h"
+#include "OpenGLRenderer.h"
+#include "Caches.h"
+
+namespace android {
+namespace uirenderer {
+
+Layer::~Layer() {
+    if (mesh) delete mesh;
+    if (meshIndices) delete meshIndices;
+    if (colorFilter) Caches::getInstance().resourceCache.decrementRefcount(colorFilter);
+}
+
+void Layer::setPaint(SkPaint* paint) {
+    OpenGLRenderer::getAlphaAndModeDirect(paint, &alpha, &mode);
+}
+
+void Layer::setColorFilter(SkiaColorFilter* filter) {
+    if (colorFilter) {
+        Caches::getInstance().resourceCache.decrementRefcount(colorFilter);
+    }
+    colorFilter = filter;
+    if (colorFilter) {
+        Caches::getInstance().resourceCache.incrementRefcount(colorFilter);
+    }
+}
+
+
+
+}; // namespace uirenderer
+}; // namespace android
diff --git a/libs/hwui/Layer.h b/libs/hwui/Layer.h
index f243177..76da671 100644
--- a/libs/hwui/Layer.h
+++ b/libs/hwui/Layer.h
@@ -45,6 +45,7 @@
  * A layer has dimensions and is backed by an OpenGL texture or FBO.
  */
 struct Layer {
+
     Layer(const uint32_t layerWidth, const uint32_t layerHeight) {
         mesh = NULL;
         meshIndices = NULL;
@@ -60,10 +61,7 @@
         displayList = NULL;
     }
 
-    ~Layer() {
-        if (mesh) delete mesh;
-        if (meshIndices) delete meshIndices;
-    }
+    ~Layer();
 
     /**
      * Sets this layer's region to a rectangle. Computes the appropriate
@@ -106,6 +104,8 @@
         texture.height = height;
     }
 
+    ANDROID_API void setPaint(SkPaint* paint);
+
     inline void setBlend(bool blend) {
         texture.blend = blend;
     }
@@ -191,9 +191,7 @@
         return colorFilter;
     }
 
-    inline void setColorFilter(SkiaColorFilter* filter) {
-        colorFilter = filter;
-    }
+    ANDROID_API void setColorFilter(SkiaColorFilter* filter);
 
     inline void bindTexture() {
         glBindTexture(renderTarget, texture.id);
diff --git a/libs/hwui/LayerRenderer.cpp b/libs/hwui/LayerRenderer.cpp
index f81640b..5a8f2b7 100644
--- a/libs/hwui/LayerRenderer.cpp
+++ b/libs/hwui/LayerRenderer.cpp
@@ -400,6 +400,8 @@
         caches.activeTexture(0);
         glBindTexture(GL_TEXTURE_2D, texture);
 
+        glPixelStorei(GL_PACK_ALIGNMENT, bitmap->bytesPerPixel());
+
         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
 
diff --git a/libs/hwui/OpenGLRenderer.cpp b/libs/hwui/OpenGLRenderer.cpp
index 7abcc63..9f8b87c 100644
--- a/libs/hwui/OpenGLRenderer.cpp
+++ b/libs/hwui/OpenGLRenderer.cpp
@@ -1141,6 +1141,10 @@
     mDescription.isAA = true;
 }
 
+void OpenGLRenderer::setupDrawAARect() {
+    mDescription.isAARect = true;
+}
+
 void OpenGLRenderer::setupDrawPoint(float pointSize) {
     mDescription.isPoint = true;
     mDescription.pointSize = pointSize;
@@ -1741,9 +1745,9 @@
 
 /**
  * This function uses a similar approach to that of AA lines in the drawLines() function.
- * We expand the rectangle by a half pixel in screen space on all sides, and use a fragment
- * shader to compute the translucency of the color, determined by whether a given pixel is
- * within that boundary region and how far into the region it is.
+ * We expand the rectangle by a half pixel in screen space on all sides. However, instead of using
+ * a fragment shader to compute the translucency of the color from its position, we simply use a
+ * varying parameter to define how far a given pixel is into the region.
  */
 void OpenGLRenderer::drawAARect(float left, float top, float right, float bottom,
         int color, SkXfermode::Mode mode) {
@@ -1755,10 +1759,8 @@
         Matrix4 *mat = mSnapshot->transform;
         float m00 = mat->data[Matrix4::kScaleX];
         float m01 = mat->data[Matrix4::kSkewY];
-        float m02 = mat->data[2];
         float m10 = mat->data[Matrix4::kSkewX];
-        float m11 = mat->data[Matrix4::kScaleX];
-        float m12 = mat->data[6];
+        float m11 = mat->data[Matrix4::kScaleY];
         float scaleX = sqrt(m00 * m00 + m01 * m01);
         float scaleY = sqrt(m10 * m10 + m11 * m11);
         inverseScaleX = (scaleX != 0) ? (inverseScaleX / scaleX) : 0;
@@ -1768,6 +1770,11 @@
     float boundarySizeX = .5 * inverseScaleX;
     float boundarySizeY = .5 * inverseScaleY;
 
+    float innerLeft = left + boundarySizeX;
+    float innerRight = right - boundarySizeX;
+    float innerTop = top + boundarySizeY;
+    float innerBottom = bottom - boundarySizeY;
+
     // Adjust the rect by the AA boundary padding
     left -= boundarySizeX;
     right += boundarySizeX;
@@ -1777,7 +1784,7 @@
     if (!quickReject(left, top, right, bottom)) {
         setupDraw();
         setupDrawNoTexture();
-        setupDrawAALine();
+        setupDrawAARect();
         setupDrawColor(color, ((color >> 24) & 0xFF) * mSnapshot->alpha);
         setupDrawColorFilter();
         setupDrawShader();
@@ -1788,34 +1795,52 @@
         setupDrawColorFilterUniforms();
         setupDrawShaderIdentityUniforms();
 
-        AAVertex rects[4];
-        AAVertex* aaVertices = &rects[0];
-        void* widthCoords = ((GLbyte*) aaVertices) + gVertexAAWidthOffset;
-        void* lengthCoords = ((GLbyte*) aaVertices) + gVertexAALengthOffset;
+        AlphaVertex rects[14];
+        AlphaVertex* aVertices = &rects[0];
+        void* alphaCoords = ((GLbyte*) aVertices) + gVertexAlphaOffset;
 
-        int widthSlot;
-        int lengthSlot;
+        bool force = mCaches.unbindMeshBuffer();
+        mCaches.bindPositionVertexPointer(force, mCaches.currentProgram->position,
+                aVertices, gAlphaVertexStride);
+        mCaches.resetTexCoordsVertexPointer();
+        mCaches.unbindIndicesBuffer();
 
-        float width = right - left;
-        float height = bottom - top;
+        int alphaSlot = mCaches.currentProgram->getAttrib("vtxAlpha");
+        glEnableVertexAttribArray(alphaSlot);
+        glVertexAttribPointer(alphaSlot, 1, GL_FLOAT, GL_FALSE, gAlphaVertexStride, alphaCoords);
 
-        float boundaryWidthProportion = .5 - ((width != 0) ? (2 * boundarySizeX) / width : 0);
-        float boundaryHeightProportion = .5 - ((height != 0) ? (2 * boundarySizeY) / height : 0);
-        setupDrawAALine((void*) aaVertices, widthCoords, lengthCoords,
-                boundaryWidthProportion, widthSlot, lengthSlot);
+        // draw left
+        AlphaVertex::set(aVertices++, left, bottom, 0);
+        AlphaVertex::set(aVertices++, innerLeft, innerBottom, 1);
+        AlphaVertex::set(aVertices++, left, top, 0);
+        AlphaVertex::set(aVertices++, innerLeft, innerTop, 1);
 
-        int boundaryLengthSlot = mCaches.currentProgram->getUniform("boundaryLength");
-        glUniform1f(boundaryLengthSlot, boundaryHeightProportion);
+        // draw top
+        AlphaVertex::set(aVertices++, right, top, 0);
+        AlphaVertex::set(aVertices++, innerRight, innerTop, 1);
 
-        AAVertex::set(aaVertices++, left, bottom, 1, 1);
-        AAVertex::set(aaVertices++, left, top, 1, 0);
-        AAVertex::set(aaVertices++, right, bottom, 0, 1);
-        AAVertex::set(aaVertices++, right, top, 0, 0);
+        // draw right
+        AlphaVertex::set(aVertices++, right, bottom, 0);
+        AlphaVertex::set(aVertices++, innerRight, innerBottom, 1);
+
+        // draw bottom
+        AlphaVertex::set(aVertices++, left, bottom, 0);
+        AlphaVertex::set(aVertices++, innerLeft, innerBottom, 1);
+
+        // draw inner rect (repeating last vertex to create degenerate bridge triangles)
+        // TODO: also consider drawing the inner rect without the blending-forced shader, if
+        // blending is expensive. Note: can't use drawColorRect() since it doesn't use vertex
+        // buffers like below, resulting in slightly different transformed coordinates.
+        AlphaVertex::set(aVertices++, innerLeft, innerBottom, 1);
+        AlphaVertex::set(aVertices++, innerLeft, innerTop, 1);
+        AlphaVertex::set(aVertices++, innerRight, innerBottom, 1);
+        AlphaVertex::set(aVertices++, innerRight, innerTop, 1);
+
         dirtyLayer(left, top, right, bottom, *mSnapshot->transform);
 
-        glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
+        glDrawArrays(GL_TRIANGLE_STRIP, 0, 14);
 
-        finishDrawAALine(widthSlot, lengthSlot);
+        glDisableVertexAttribArray(alphaSlot);
     }
 }
 
@@ -1870,10 +1895,8 @@
             Matrix4 *mat = mSnapshot->transform;
             float m00 = mat->data[Matrix4::kScaleX];
             float m01 = mat->data[Matrix4::kSkewY];
-            float m02 = mat->data[2];
             float m10 = mat->data[Matrix4::kSkewX];
-            float m11 = mat->data[Matrix4::kScaleX];
-            float m12 = mat->data[6];
+            float m11 = mat->data[Matrix4::kScaleY];
 
             float scaleX = sqrtf(m00 * m00 + m01 * m01);
             float scaleY = sqrtf(m10 * m10 + m11 * m11);
@@ -1955,6 +1978,10 @@
 
         // Find the normal to the line
         vec2 n = (b - a).copyNormalized() * halfStrokeWidth;
+        float x = n.x;
+        n.x = -n.y;
+        n.y = x;
+
         if (isHairLine) {
             if (isAA) {
                 float wideningFactor;
@@ -1979,14 +2006,10 @@
 
             float extendedNLength = extendedN.length();
             // We need to set this value on the shader prior to drawing
-            boundaryWidthProportion = extendedNLength / (halfStrokeWidth + extendedNLength);
+            boundaryWidthProportion = .5 - extendedNLength / (halfStrokeWidth + extendedNLength);
             n += extendedN;
         }
 
-        float x = n.x;
-        n.x = -n.y;
-        n.y = x;
-
         // aa lines expand the endpoint vertices to encompass the AA boundary
         if (isAA) {
             vec2 abVector = (b - a);
@@ -2570,17 +2593,13 @@
 
     mCaches.activeTexture(0);
 
-    int alpha;
-    SkXfermode::Mode mode;
-    getAlphaAndMode(paint, &alpha, &mode);
-
-    layer->setAlpha(alpha, mode);
-
     if (CC_LIKELY(!layer->region.isEmpty())) {
         if (layer->region.isRect()) {
             composeLayerRect(layer, layer->regionRect);
         } else if (layer->mesh) {
-            const float a = alpha / 255.0f;
+            const float a = layer->getAlpha() / 255.0f;
+            SkiaColorFilter *oldFilter = mColorFilter;
+            mColorFilter = layer->getColorFilter();
 
             setupDraw();
             setupDrawWithTexture();
@@ -2610,6 +2629,8 @@
 
             finishDrawTexture();
 
+            mColorFilter = oldFilter;
+
 #if DEBUG_LAYERS_AS_REGIONS
             drawRegionRects(layer->region);
 #endif
diff --git a/libs/hwui/OpenGLRenderer.h b/libs/hwui/OpenGLRenderer.h
index 4c7cf0a..7f9405f 100644
--- a/libs/hwui/OpenGLRenderer.h
+++ b/libs/hwui/OpenGLRenderer.h
@@ -227,6 +227,32 @@
      */
     void endMark() const;
 
+    /**
+     * Gets the alpha and xfermode out of a paint object. If the paint is null
+     * alpha will be 255 and the xfermode will be SRC_OVER. This method does
+     * not multiply the paint's alpha by the current snapshot's alpha.
+     *
+     * @param paint The paint to extract values from
+     * @param alpha Where to store the resulting alpha
+     * @param mode Where to store the resulting xfermode
+     */
+    static inline void getAlphaAndModeDirect(SkPaint* paint, int* alpha, SkXfermode::Mode* mode) {
+        if (paint) {
+            *mode = getXfermode(paint->getXfermode());
+
+            // Skia draws using the color's alpha channel if < 255
+            // Otherwise, it uses the paint's alpha
+            int color = paint->getColor();
+            *alpha = (color >> 24) & 0xFF;
+            if (*alpha == 255) {
+                *alpha = paint->getAlpha();
+            }
+        } else {
+            *mode = SkXfermode::kSrcOver_Mode;
+            *alpha = 255;
+        }
+    }
+
 protected:
     /**
      * Compose the layer defined in the current snapshot with the layer
@@ -291,32 +317,6 @@
     inline void getAlphaAndMode(SkPaint* paint, int* alpha, SkXfermode::Mode* mode);
 
     /**
-     * Gets the alpha and xfermode out of a paint object. If the paint is null
-     * alpha will be 255 and the xfermode will be SRC_OVER. This method does
-     * not multiply the paint's alpha by the current snapshot's alpha.
-     *
-     * @param paint The paint to extract values from
-     * @param alpha Where to store the resulting alpha
-     * @param mode Where to store the resulting xfermode
-     */
-    static inline void getAlphaAndModeDirect(SkPaint* paint, int* alpha, SkXfermode::Mode* mode) {
-        if (paint) {
-            *mode = getXfermode(paint->getXfermode());
-
-            // Skia draws using the color's alpha channel if < 255
-            // Otherwise, it uses the paint's alpha
-            int color = paint->getColor();
-            *alpha = (color >> 24) & 0xFF;
-            if (*alpha == 255) {
-                *alpha = paint->getAlpha();
-            }
-        } else {
-            *mode = SkXfermode::kSrcOver_Mode;
-            *alpha = 255;
-        }
-    }
-
-    /**
      * Safely retrieves the mode from the specified xfermode. If the specified
      * xfermode is null, the mode is assumed to be SkXfermode::kSrcOver_Mode.
      */
@@ -434,7 +434,6 @@
      * @param color The rectangle's ARGB color, defined as a packed 32 bits word
      * @param mode The Skia xfermode to use
      * @param ignoreTransform True if the current transform should be ignored
-     * @param ignoreBlending True if the blending is set by the caller
      */
     void drawColorRect(float left, float top, float right, float bottom,
             int color, SkXfermode::Mode mode, bool ignoreTransform = false);
@@ -649,6 +648,7 @@
     void setupDrawWithExternalTexture();
     void setupDrawNoTexture();
     void setupDrawAALine();
+    void setupDrawAARect();
     void setupDrawPoint(float pointSize);
     void setupDrawColor(int color);
     void setupDrawColor(int color, int alpha);
diff --git a/libs/hwui/Program.h b/libs/hwui/Program.h
index 1818f82..a3bfaa4 100644
--- a/libs/hwui/Program.h
+++ b/libs/hwui/Program.h
@@ -81,6 +81,8 @@
 
 #define PROGRAM_IS_SIMPLE_GRADIENT 41
 
+#define PROGRAM_IS_AA_RECT_SHIFT 42
+
 ///////////////////////////////////////////////////////////////////////////////
 // Types
 ///////////////////////////////////////////////////////////////////////////////
@@ -128,6 +130,7 @@
     bool isBitmapNpot;
 
     bool isAA;
+    bool isAARect;
 
     bool hasGradient;
     Gradient gradientType;
@@ -165,6 +168,7 @@
         hasTextureTransform = false;
 
         isAA = false;
+        isAARect = false;
 
         modulate = false;
 
@@ -260,6 +264,7 @@
         if (hasTextureTransform) key |= programid(0x1) << PROGRAM_HAS_TEXTURE_TRANSFORM_SHIFT;
         if (hasGammaCorrection) key |= programid(0x1) << PROGRAM_HAS_GAMMA_CORRECTION;
         if (isSimpleGradient) key |= programid(0x1) << PROGRAM_IS_SIMPLE_GRADIENT;
+        if (isAARect) key |= programid(0x1) << PROGRAM_IS_AA_RECT_SHIFT;
         return key;
     }
 
diff --git a/libs/hwui/ProgramCache.cpp b/libs/hwui/ProgramCache.cpp
index 8a9a2ac..0ed8008 100644
--- a/libs/hwui/ProgramCache.cpp
+++ b/libs/hwui/ProgramCache.cpp
@@ -43,6 +43,8 @@
 const char* gVS_Header_Attributes_AAParameters =
         "attribute float vtxWidth;\n"
         "attribute float vtxLength;\n";
+const char* gVS_Header_Attributes_AARectParameters =
+        "attribute float vtxAlpha;\n";
 const char* gVS_Header_Uniforms_TextureTransform =
         "uniform mat4 mainTextureTransform;\n";
 const char* gVS_Header_Uniforms =
@@ -65,6 +67,8 @@
 const char* gVS_Header_Varyings_IsAA =
         "varying float widthProportion;\n"
         "varying float lengthProportion;\n";
+const char* gVS_Header_Varyings_IsAARect =
+        "varying float alpha;\n";
 const char* gVS_Header_Varyings_HasBitmap =
         "varying highp vec2 outBitmapTexCoords;\n";
 const char* gVS_Header_Varyings_PointHasBitmap =
@@ -112,6 +116,8 @@
 const char* gVS_Main_AA =
         "    widthProportion = vtxWidth;\n"
         "    lengthProportion = vtxLength;\n";
+const char* gVS_Main_AARect =
+        "    alpha = vtxAlpha;\n";
 const char* gVS_Footer =
         "}\n\n";
 
@@ -242,6 +248,8 @@
 const char* gFS_Main_AccountForAA =
         "    fragColor *= (1.0 - smoothstep(boundaryWidth, 0.5, abs(0.5 - widthProportion)))\n"
         "               * (1.0 - smoothstep(boundaryLength, 0.5, abs(0.5 - lengthProportion)));\n";
+const char* gFS_Main_AccountForAARect =
+        "    fragColor *= alpha;\n";
 
 const char* gFS_Main_FetchTexture[2] = {
         // Don't modulate
@@ -439,7 +447,9 @@
     if (description.hasTexture || description.hasExternalTexture) {
         shader.append(gVS_Header_Attributes_TexCoords);
     }
-    if (description.isAA) {
+    if (description.isAARect) {
+        shader.append(gVS_Header_Attributes_AARectParameters);
+    } else if (description.isAA) {
         shader.append(gVS_Header_Attributes_AAParameters);
     }
     // Uniforms
@@ -460,7 +470,9 @@
     if (description.hasTexture || description.hasExternalTexture) {
         shader.append(gVS_Header_Varyings_HasTexture);
     }
-    if (description.isAA) {
+    if (description.isAARect) {
+        shader.append(gVS_Header_Varyings_IsAARect);
+    } else if (description.isAA) {
         shader.append(gVS_Header_Varyings_IsAA);
     }
     if (description.hasGradient) {
@@ -479,7 +491,9 @@
         } else if (description.hasTexture || description.hasExternalTexture) {
             shader.append(gVS_Main_OutTexCoords);
         }
-        if (description.isAA) {
+        if (description.isAARect) {
+            shader.append(gVS_Main_AARect);
+        } else if (description.isAA) {
             shader.append(gVS_Main_AA);
         }
         if (description.hasGradient) {
@@ -521,7 +535,9 @@
     if (description.hasTexture || description.hasExternalTexture) {
         shader.append(gVS_Header_Varyings_HasTexture);
     }
-    if (description.isAA) {
+    if (description.isAARect) {
+        shader.append(gVS_Header_Varyings_IsAARect);
+    } else if (description.isAA) {
         shader.append(gVS_Header_Varyings_IsAA);
     }
     if (description.hasGradient) {
@@ -562,7 +578,8 @@
 
     // Optimization for common cases
     if (!description.isAA && !blendFramebuffer &&
-            description.colorOp == ProgramDescription::kColorNone && !description.isPoint) {
+            description.colorOp == ProgramDescription::kColorNone &&
+            !description.isPoint && !description.isAARect) {
         bool fast = false;
 
         const bool noShader = !description.hasGradient && !description.hasBitmap;
@@ -654,7 +671,9 @@
                 shader.append(gFS_Main_FetchColor);
             }
         }
-        if (description.isAA) {
+        if (description.isAARect) {
+            shader.append(gFS_Main_AccountForAARect);
+        } else if (description.isAA) {
             shader.append(gFS_Main_AccountForAA);
         }
         if (description.hasGradient) {
diff --git a/libs/hwui/ResourceCache.cpp b/libs/hwui/ResourceCache.cpp
index 2153a8b..b0c57d1 100644
--- a/libs/hwui/ResourceCache.cpp
+++ b/libs/hwui/ResourceCache.cpp
@@ -38,7 +38,7 @@
 
 ResourceCache::ResourceCache() {
     Mutex::Autolock _l(mLock);
-    mCache = new KeyedVector<void *, ResourceReference *>();
+    mCache = new KeyedVector<void*, ResourceReference*>();
 }
 
 ResourceCache::~ResourceCache() {
@@ -46,15 +46,17 @@
     delete mCache;
 }
 
+void ResourceCache::lock() {
+    mLock.lock();
+}
+
+void ResourceCache::unlock() {
+    mLock.unlock();
+}
+
 void ResourceCache::incrementRefcount(void* resource, ResourceType resourceType) {
     Mutex::Autolock _l(mLock);
-    ssize_t index = mCache->indexOfKey(resource);
-    ResourceReference* ref = index >= 0 ? mCache->valueAt(index) : NULL;
-    if (ref == NULL || mCache->size() == 0) {
-        ref = new ResourceReference(resourceType);
-        mCache->add(resource, ref);
-    }
-    ref->refCount++;
+    incrementRefcountLocked(resource, resourceType);
 }
 
 void ResourceCache::incrementRefcount(SkBitmap* bitmapResource) {
@@ -77,18 +79,39 @@
     incrementRefcount((void*) filterResource, kColorFilter);
 }
 
-void ResourceCache::decrementRefcount(void* resource) {
-    Mutex::Autolock _l(mLock);
+void ResourceCache::incrementRefcountLocked(void* resource, ResourceType resourceType) {
     ssize_t index = mCache->indexOfKey(resource);
     ResourceReference* ref = index >= 0 ? mCache->valueAt(index) : NULL;
-    if (ref == NULL) {
-        // Should not get here - shouldn't get a call to decrement if we're not yet tracking it
-        return;
+    if (ref == NULL || mCache->size() == 0) {
+        ref = new ResourceReference(resourceType);
+        mCache->add(resource, ref);
     }
-    ref->refCount--;
-    if (ref->refCount == 0) {
-        deleteResourceReference(resource, ref);
-    }
+    ref->refCount++;
+}
+
+void ResourceCache::incrementRefcountLocked(SkBitmap* bitmapResource) {
+    SkSafeRef(bitmapResource->pixelRef());
+    SkSafeRef(bitmapResource->getColorTable());
+    incrementRefcountLocked((void*) bitmapResource, kBitmap);
+}
+
+void ResourceCache::incrementRefcountLocked(SkPath* pathResource) {
+    incrementRefcountLocked((void*) pathResource, kPath);
+}
+
+void ResourceCache::incrementRefcountLocked(SkiaShader* shaderResource) {
+    SkSafeRef(shaderResource->getSkShader());
+    incrementRefcountLocked((void*) shaderResource, kShader);
+}
+
+void ResourceCache::incrementRefcountLocked(SkiaColorFilter* filterResource) {
+    SkSafeRef(filterResource->getSkColorFilter());
+    incrementRefcountLocked((void*) filterResource, kColorFilter);
+}
+
+void ResourceCache::decrementRefcount(void* resource) {
+    Mutex::Autolock _l(mLock);
+    decrementRefcountLocked(resource);
 }
 
 void ResourceCache::decrementRefcount(SkBitmap* bitmapResource) {
@@ -111,27 +134,45 @@
     decrementRefcount((void*) filterResource);
 }
 
-void ResourceCache::recycle(SkBitmap* resource) {
-    Mutex::Autolock _l(mLock);
+void ResourceCache::decrementRefcountLocked(void* resource) {
     ssize_t index = mCache->indexOfKey(resource);
-    if (index < 0) {
-        // not tracking this resource; just recycle the pixel data
-        resource->setPixels(NULL, NULL);
-        return;
-    }
-    ResourceReference* ref = mCache->valueAt(index);
+    ResourceReference* ref = index >= 0 ? mCache->valueAt(index) : NULL;
     if (ref == NULL) {
-        // Should not get here - shouldn't get a call to recycle if we're not yet tracking it
+        // Should not get here - shouldn't get a call to decrement if we're not yet tracking it
         return;
     }
-    ref->recycled = true;
+    ref->refCount--;
     if (ref->refCount == 0) {
         deleteResourceReference(resource, ref);
     }
 }
 
+void ResourceCache::decrementRefcountLocked(SkBitmap* bitmapResource) {
+    SkSafeUnref(bitmapResource->pixelRef());
+    SkSafeUnref(bitmapResource->getColorTable());
+    decrementRefcountLocked((void*) bitmapResource);
+}
+
+void ResourceCache::decrementRefcountLocked(SkPath* pathResource) {
+    decrementRefcountLocked((void*) pathResource);
+}
+
+void ResourceCache::decrementRefcountLocked(SkiaShader* shaderResource) {
+    SkSafeUnref(shaderResource->getSkShader());
+    decrementRefcountLocked((void*) shaderResource);
+}
+
+void ResourceCache::decrementRefcountLocked(SkiaColorFilter* filterResource) {
+    SkSafeUnref(filterResource->getSkColorFilter());
+    decrementRefcountLocked((void*) filterResource);
+}
+
 void ResourceCache::destructor(SkPath* resource) {
     Mutex::Autolock _l(mLock);
+    destructorLocked(resource);
+}
+
+void ResourceCache::destructorLocked(SkPath* resource) {
     ssize_t index = mCache->indexOfKey(resource);
     ResourceReference* ref = index >= 0 ? mCache->valueAt(index) : NULL;
     if (ref == NULL) {
@@ -150,6 +191,10 @@
 
 void ResourceCache::destructor(SkBitmap* resource) {
     Mutex::Autolock _l(mLock);
+    destructorLocked(resource);
+}
+
+void ResourceCache::destructorLocked(SkBitmap* resource) {
     ssize_t index = mCache->indexOfKey(resource);
     ResourceReference* ref = index >= 0 ? mCache->valueAt(index) : NULL;
     if (ref == NULL) {
@@ -168,6 +213,10 @@
 
 void ResourceCache::destructor(SkiaShader* resource) {
     Mutex::Autolock _l(mLock);
+    destructorLocked(resource);
+}
+
+void ResourceCache::destructorLocked(SkiaShader* resource) {
     ssize_t index = mCache->indexOfKey(resource);
     ResourceReference* ref = index >= 0 ? mCache->valueAt(index) : NULL;
     if (ref == NULL) {
@@ -183,6 +232,10 @@
 
 void ResourceCache::destructor(SkiaColorFilter* resource) {
     Mutex::Autolock _l(mLock);
+    destructorLocked(resource);
+}
+
+void ResourceCache::destructorLocked(SkiaColorFilter* resource) {
     ssize_t index = mCache->indexOfKey(resource);
     ResourceReference* ref = index >= 0 ? mCache->valueAt(index) : NULL;
     if (ref == NULL) {
@@ -196,6 +249,29 @@
     }
 }
 
+void ResourceCache::recycle(SkBitmap* resource) {
+    Mutex::Autolock _l(mLock);
+    recycleLocked(resource);
+}
+
+void ResourceCache::recycleLocked(SkBitmap* resource) {
+    ssize_t index = mCache->indexOfKey(resource);
+    if (index < 0) {
+        // not tracking this resource; just recycle the pixel data
+        resource->setPixels(NULL, NULL);
+        return;
+    }
+    ResourceReference* ref = mCache->valueAt(index);
+    if (ref == NULL) {
+        // Should not get here - shouldn't get a call to recycle if we're not yet tracking it
+        return;
+    }
+    ref->recycled = true;
+    if (ref->refCount == 0) {
+        deleteResourceReference(resource, ref);
+    }
+}
+
 /**
  * This method should only be called while the mLock mutex is held (that mutex is grabbed
  * by the various destructor() and recycle() methods which call this method).
diff --git a/libs/hwui/ResourceCache.h b/libs/hwui/ResourceCache.h
index 8cf466b..60ffa7d 100644
--- a/libs/hwui/ResourceCache.h
+++ b/libs/hwui/ResourceCache.h
@@ -52,28 +52,59 @@
 };
 
 class ANDROID_API ResourceCache {
-    KeyedVector<void *, ResourceReference *>* mCache;
 public:
     ResourceCache();
     ~ResourceCache();
+
+    /**
+     * When using these two methods, make sure to only invoke the *Locked()
+     * variants of increment/decrementRefcount(), recyle() and destructor()
+     */
+    void lock();
+    void unlock();
+
     void incrementRefcount(SkPath* resource);
     void incrementRefcount(SkBitmap* resource);
     void incrementRefcount(SkiaShader* resource);
     void incrementRefcount(SkiaColorFilter* resource);
-    void incrementRefcount(const void* resource, ResourceType resourceType);
-    void decrementRefcount(void* resource);
+
+    void incrementRefcountLocked(SkPath* resource);
+    void incrementRefcountLocked(SkBitmap* resource);
+    void incrementRefcountLocked(SkiaShader* resource);
+    void incrementRefcountLocked(SkiaColorFilter* resource);
+
     void decrementRefcount(SkBitmap* resource);
     void decrementRefcount(SkPath* resource);
     void decrementRefcount(SkiaShader* resource);
     void decrementRefcount(SkiaColorFilter* resource);
-    void recycle(SkBitmap* resource);
+
+    void decrementRefcountLocked(SkBitmap* resource);
+    void decrementRefcountLocked(SkPath* resource);
+    void decrementRefcountLocked(SkiaShader* resource);
+    void decrementRefcountLocked(SkiaColorFilter* resource);
+
     void destructor(SkPath* resource);
     void destructor(SkBitmap* resource);
     void destructor(SkiaShader* resource);
     void destructor(SkiaColorFilter* resource);
+
+    void destructorLocked(SkPath* resource);
+    void destructorLocked(SkBitmap* resource);
+    void destructorLocked(SkiaShader* resource);
+    void destructorLocked(SkiaColorFilter* resource);
+
+    void recycle(SkBitmap* resource);
+    void recycleLocked(SkBitmap* resource);
+
 private:
     void deleteResourceReference(void* resource, ResourceReference* ref);
+
     void incrementRefcount(void* resource, ResourceType resourceType);
+    void incrementRefcountLocked(void* resource, ResourceType resourceType);
+
+    void decrementRefcount(void* resource);
+    void decrementRefcountLocked(void* resource);
+
     void logCache();
 
     /**
@@ -82,6 +113,8 @@
      * or a reference queue finalization thread.
      */
     mutable Mutex mLock;
+
+    KeyedVector<void*, ResourceReference*>* mCache;
 };
 
 }; // namespace uirenderer
diff --git a/media/java/android/media/AudioSystem.java b/media/java/android/media/AudioSystem.java
index 1ca0df4..f3a8558 100644
--- a/media/java/android/media/AudioSystem.java
+++ b/media/java/android/media/AudioSystem.java
@@ -188,6 +188,13 @@
      * AudioPolicyService methods
      */
 
+    //
+    // audio device definitions: must be kept in sync with values in system/core/audio.h
+    //
+
+    // reserved bits
+    public static final int DEVICE_BIT_IN = 0x80000000;
+    public static final int DEVICE_BIT_DEFAULT = 0x40000000;
     // output devices, be sure to update AudioManager.java also
     public static final int DEVICE_OUT_EARPIECE = 0x1;
     public static final int DEVICE_OUT_SPEAKER = 0x2;
@@ -204,8 +211,9 @@
     public static final int DEVICE_OUT_DGTL_DOCK_HEADSET = 0x1000;
     public static final int DEVICE_OUT_USB_ACCESSORY = 0x2000;
     public static final int DEVICE_OUT_USB_DEVICE = 0x4000;
+    public static final int DEVICE_OUT_REMOTE_SUBMIX = 0x8000;
 
-    public static final int DEVICE_OUT_DEFAULT = 0x8000;
+    public static final int DEVICE_OUT_DEFAULT = DEVICE_BIT_DEFAULT;
     public static final int DEVICE_OUT_ALL = (DEVICE_OUT_EARPIECE |
                                               DEVICE_OUT_SPEAKER |
                                               DEVICE_OUT_WIRED_HEADSET |
@@ -221,6 +229,7 @@
                                               DEVICE_OUT_DGTL_DOCK_HEADSET |
                                               DEVICE_OUT_USB_ACCESSORY |
                                               DEVICE_OUT_USB_DEVICE |
+                                              DEVICE_OUT_REMOTE_SUBMIX |
                                               DEVICE_OUT_DEFAULT);
     public static final int DEVICE_OUT_ALL_A2DP = (DEVICE_OUT_BLUETOOTH_A2DP |
                                                    DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES |
@@ -232,15 +241,36 @@
                                                   DEVICE_OUT_USB_DEVICE);
 
     // input devices
-    public static final int DEVICE_IN_COMMUNICATION = 0x10000;
-    public static final int DEVICE_IN_AMBIENT = 0x20000;
-    public static final int DEVICE_IN_BUILTIN_MIC1 = 0x40000;
-    public static final int DEVICE_IN_BUILTIN_MIC2 = 0x80000;
-    public static final int DEVICE_IN_MIC_ARRAY = 0x100000;
-    public static final int DEVICE_IN_BLUETOOTH_SCO_HEADSET = 0x200000;
-    public static final int DEVICE_IN_WIRED_HEADSET = 0x400000;
-    public static final int DEVICE_IN_AUX_DIGITAL = 0x800000;
-    public static final int DEVICE_IN_DEFAULT = 0x80000000;
+    public static final int DEVICE_IN_COMMUNICATION = DEVICE_BIT_IN | 0x1;
+    public static final int DEVICE_IN_AMBIENT = DEVICE_BIT_IN | 0x2;
+    public static final int DEVICE_IN_BUILTIN_MIC = DEVICE_BIT_IN | 0x4;
+    public static final int DEVICE_IN_BLUETOOTH_SCO_HEADSET = DEVICE_BIT_IN | 0x8;
+    public static final int DEVICE_IN_WIRED_HEADSET = DEVICE_BIT_IN | 0x10;
+    public static final int DEVICE_IN_AUX_DIGITAL = DEVICE_BIT_IN | 0x20;
+    public static final int DEVICE_IN_VOICE_CALL = DEVICE_BIT_IN | 0x40;
+    public static final int DEVICE_IN_BACK_MIC = DEVICE_BIT_IN | 0x80;
+    public static final int DEVICE_IN_REMOTE_SUBMIX = DEVICE_BIT_IN | 0x100;
+    public static final int DEVICE_IN_ANLG_DOCK_HEADSET = DEVICE_BIT_IN | 0x200;
+    public static final int DEVICE_IN_DGTL_DOCK_HEADSET = DEVICE_BIT_IN | 0x400;
+    public static final int DEVICE_IN_USB_ACCESSORY = DEVICE_BIT_IN | 0x800;
+    public static final int DEVICE_IN_USB_DEVICE = DEVICE_BIT_IN | 0x1000;
+    public static final int DEVICE_IN_DEFAULT = DEVICE_BIT_IN | DEVICE_BIT_DEFAULT;
+
+    public static final int DEVICE_IN_ALL = (DEVICE_IN_COMMUNICATION |
+                                             DEVICE_IN_AMBIENT |
+                                             DEVICE_IN_BUILTIN_MIC |
+                                             DEVICE_IN_BLUETOOTH_SCO_HEADSET |
+                                             DEVICE_IN_WIRED_HEADSET |
+                                             DEVICE_IN_AUX_DIGITAL |
+                                             DEVICE_IN_VOICE_CALL |
+                                             DEVICE_IN_BACK_MIC |
+                                             DEVICE_IN_REMOTE_SUBMIX |
+                                             DEVICE_IN_ANLG_DOCK_HEADSET |
+                                             DEVICE_IN_DGTL_DOCK_HEADSET |
+                                             DEVICE_IN_USB_ACCESSORY |
+                                             DEVICE_IN_USB_DEVICE |
+                                             DEVICE_IN_DEFAULT);
+    public static final int DEVICE_IN_ALL_SCO = DEVICE_IN_BLUETOOTH_SCO_HEADSET;
 
     // device states, must match AudioSystem::device_connection_state
     public static final int DEVICE_STATE_UNAVAILABLE = 0;
@@ -262,6 +292,7 @@
     public static final String DEVICE_OUT_DGTL_DOCK_HEADSET_NAME = "digital_dock";
     public static final String DEVICE_OUT_USB_ACCESSORY_NAME = "usb_accessory";
     public static final String DEVICE_OUT_USB_DEVICE_NAME = "usb_device";
+    public static final String DEVICE_OUT_REMOTE_SUBMIX_NAME = "remote_submix";
 
     public static String getDeviceName(int device)
     {
@@ -296,7 +327,9 @@
             return DEVICE_OUT_USB_ACCESSORY_NAME;
         case DEVICE_OUT_USB_DEVICE:
             return DEVICE_OUT_USB_DEVICE_NAME;
-        case DEVICE_IN_DEFAULT:
+        case DEVICE_OUT_REMOTE_SUBMIX:
+            return DEVICE_OUT_REMOTE_SUBMIX_NAME;
+        case DEVICE_OUT_DEFAULT:
         default:
             return "";
         }
diff --git a/media/java/android/media/MediaScanner.java b/media/java/android/media/MediaScanner.java
index 0d7b45e..88cf4ac 100644
--- a/media/java/android/media/MediaScanner.java
+++ b/media/java/android/media/MediaScanner.java
@@ -1415,7 +1415,8 @@
         long lastModifiedSeconds = file.lastModified() / 1000;
 
         if (!MediaFile.isAudioFileType(fileType) && !MediaFile.isVideoFileType(fileType) &&
-            !MediaFile.isImageFileType(fileType) && !MediaFile.isPlayListFileType(fileType)) {
+            !MediaFile.isImageFileType(fileType) && !MediaFile.isPlayListFileType(fileType) &&
+            !MediaFile.isDrmFileType(fileType)) {
 
             // no need to use the media scanner, but we need to update last modified and file size
             ContentValues values = new ContentValues();
diff --git a/media/java/android/media/RemoteDisplay.java b/media/java/android/media/RemoteDisplay.java
new file mode 100644
index 0000000..b463d26
--- /dev/null
+++ b/media/java/android/media/RemoteDisplay.java
@@ -0,0 +1,153 @@
+/*
+ * Copyright (C) 2012 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.media;
+
+import dalvik.system.CloseGuard;
+
+import android.os.Handler;
+import android.view.Surface;
+
+/**
+ * Listens for Wifi remote display connections managed by the media server.
+ *
+ * @hide
+ */
+public final class RemoteDisplay {
+    /* these constants must be kept in sync with IRemoteDisplayClient.h */
+
+    public static final int DISPLAY_FLAG_SECURE = 1 << 0;
+
+    public static final int DISPLAY_ERROR_UNKOWN = 1;
+    public static final int DISPLAY_ERROR_CONNECTION_DROPPED = 2;
+
+    private final CloseGuard mGuard = CloseGuard.get();
+    private final Listener mListener;
+    private final Handler mHandler;
+
+    private int mPtr;
+
+    private native int nativeListen(String iface);
+    private native void nativeDispose(int ptr);
+
+    private RemoteDisplay(Listener listener, Handler handler) {
+        mListener = listener;
+        mHandler = handler;
+    }
+
+    @Override
+    protected void finalize() throws Throwable {
+        try {
+            dispose(true);
+        } finally {
+            super.finalize();
+        }
+    }
+
+    /**
+     * Starts listening for displays to be connected on the specified interface.
+     *
+     * @param iface The interface address and port in the form "x.x.x.x:y".
+     * @param listener The listener to invoke when displays are connected or disconnected.
+     * @param handler The handler on which to invoke the listener.
+     */
+    public static RemoteDisplay listen(String iface, Listener listener, Handler handler) {
+        if (iface == null) {
+            throw new IllegalArgumentException("iface must not be null");
+        }
+        if (listener == null) {
+            throw new IllegalArgumentException("listener must not be null");
+        }
+        if (handler == null) {
+            throw new IllegalArgumentException("handler must not be null");
+        }
+
+        RemoteDisplay display = new RemoteDisplay(listener, handler);
+        display.startListening(iface);
+        return display;
+    }
+
+    /**
+     * Disconnects the remote display and stops listening for new connections.
+     */
+    public void dispose() {
+        dispose(false);
+    }
+
+    private void dispose(boolean finalized) {
+        if (mPtr != 0) {
+            if (mGuard != null) {
+                if (finalized) {
+                    mGuard.warnIfOpen();
+                } else {
+                    mGuard.close();
+                }
+            }
+
+            nativeDispose(mPtr);
+            mPtr = 0;
+        }
+    }
+
+    private void startListening(String iface) {
+        mPtr = nativeListen(iface);
+        if (mPtr == 0) {
+            throw new IllegalStateException("Could not start listening for "
+                    + "remote display connection on \"" + iface + "\"");
+        }
+        mGuard.open("dispose");
+    }
+
+    // Called from native.
+    private void notifyDisplayConnected(final Surface surface,
+            final int width, final int height, final int flags) {
+        mHandler.post(new Runnable() {
+            @Override
+            public void run() {
+                mListener.onDisplayConnected(surface, width, height, flags);
+            }
+        });
+    }
+
+    // Called from native.
+    private void notifyDisplayDisconnected() {
+        mHandler.post(new Runnable() {
+            @Override
+            public void run() {
+                mListener.onDisplayDisconnected();
+            }
+        });
+    }
+
+    // Called from native.
+    private void notifyDisplayError(final int error) {
+        mHandler.post(new Runnable() {
+            @Override
+            public void run() {
+                mListener.onDisplayError(error);
+            }
+        });
+    }
+
+    /**
+     * Listener invoked when the remote display connection changes state.
+     */
+    public interface Listener {
+        void onDisplayConnected(Surface surface, int width, int height, int flags);
+        void onDisplayDisconnected();
+        void onDisplayError(int error);
+    }
+}
diff --git a/media/mca/effect/java/android/media/effect/effects/BackDropperEffect.java b/media/mca/effect/java/android/media/effect/effects/BackDropperEffect.java
index d5c7aaa..f977e60 100644
--- a/media/mca/effect/java/android/media/effect/effects/BackDropperEffect.java
+++ b/media/mca/effect/java/android/media/effect/effects/BackDropperEffect.java
@@ -91,6 +91,9 @@
         if (parameterKey.equals("source")) {
             Filter background = mGraph.getFilter("background");
             background.setInputValue("sourceUrl", value);
+        } else if (parameterKey.equals("context")) {
+            Filter background = mGraph.getFilter("background");
+            background.setInputValue("context", value);
         }
     }
 
diff --git a/media/tests/EffectsTest/Android.mk b/media/tests/EffectsTest/Android.mk
new file mode 100755
index 0000000..25b4fe4
--- /dev/null
+++ b/media/tests/EffectsTest/Android.mk
@@ -0,0 +1,10 @@
+LOCAL_PATH:= $(call my-dir)
+include $(CLEAR_VARS)
+
+LOCAL_MODULE_TAGS := tests
+
+LOCAL_SRC_FILES := $(call all-subdir-java-files)
+
+LOCAL_PACKAGE_NAME := EffectsTest
+
+include $(BUILD_PACKAGE)
diff --git a/media/tests/EffectsTest/AndroidManifest.xml b/media/tests/EffectsTest/AndroidManifest.xml
new file mode 100755
index 0000000..9b59891
--- /dev/null
+++ b/media/tests/EffectsTest/AndroidManifest.xml
@@ -0,0 +1,57 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2009 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+    package="com.android.effectstest">
+
+   <uses-permission android:name="android.permission.RECORD_AUDIO" />
+   <uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS" />
+
+   <application>
+        <activity android:label="@string/app_name"
+                android:name="EffectsTest">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="android.intent.category.LAUNCHER"/>
+            </intent-filter>
+        </activity>
+
+        <activity android:label="@string/envreverb_test_name"
+                android:name="EnvReverbTest">
+        </activity>
+
+        <activity android:label="@string/presetrvb_test_name"
+                android:name="PresetReverbTest">
+        </activity>
+
+        <activity android:label="@string/equalizer_test_name"
+                android:name="EqualizerTest">
+        </activity>
+
+        <activity android:label="@string/virtualizer_test_name"
+                android:name="VirtualizerTest">
+        </activity>
+
+        <activity android:label="@string/bassboost_test_name"
+                android:name="BassBoostTest">
+        </activity>
+
+        <activity android:label="@string/visualizer_test_name"
+                android:name="VisualizerTest">
+        </activity>
+
+    </application>
+</manifest>
diff --git a/media/tests/EffectsTest/res/drawable/icon.png b/media/tests/EffectsTest/res/drawable/icon.png
new file mode 100755
index 0000000..64e3601
--- /dev/null
+++ b/media/tests/EffectsTest/res/drawable/icon.png
Binary files differ
diff --git a/media/tests/EffectsTest/res/drawable/stop.png b/media/tests/EffectsTest/res/drawable/stop.png
new file mode 100755
index 0000000..83f012c
--- /dev/null
+++ b/media/tests/EffectsTest/res/drawable/stop.png
Binary files differ
diff --git a/media/tests/EffectsTest/res/layout/bassboosttest.xml b/media/tests/EffectsTest/res/layout/bassboosttest.xml
new file mode 100755
index 0000000..0888e98
--- /dev/null
+++ b/media/tests/EffectsTest/res/layout/bassboosttest.xml
@@ -0,0 +1,192 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2009 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="fill_parent"
+    android:layout_height="fill_parent"
+    android:orientation="vertical">
+
+    <ImageView
+         android:src="@android:drawable/divider_horizontal_dark"
+         android:layout_width="fill_parent"
+         android:layout_height="wrap_content"
+         android:scaleType="fitXY"/>
+
+    <LinearLayout android:id="@+id/bbReleaseLayout"
+        android:orientation="horizontal"
+        android:layout_width="fill_parent"
+        android:layout_height="wrap_content"
+        android:layout_marginLeft="10dip"
+        android:layout_marginTop="10dip"
+        android:layout_marginRight="10dip"
+        android:layout_marginBottom="10dip" >
+
+        <TextView android:id="@+id/bbReleaseText"
+            android:layout_width="fill_parent"
+            android:layout_height="fill_parent"
+            android:layout_weight="1.0"
+            android:layout_gravity="center_vertical|left"
+            android:text="@string/effect_release"
+            style="@android:style/TextAppearance.Medium" />
+
+        <ToggleButton android:id="@+id/bbReleaseButton"
+            android:layout_width="wrap_content"
+            android:layout_height="fill_parent"
+            android:layout_gravity="center_vertical|right"
+            android:layout_weight="0.0" />
+
+    </LinearLayout>
+
+    <ImageView
+         android:src="@android:drawable/divider_horizontal_dark"
+         android:layout_width="fill_parent"
+         android:layout_height="wrap_content"
+         android:scaleType="fitXY"/>
+
+    <LinearLayout android:id="@+id/bbControlLayout"
+        android:orientation="horizontal"
+        android:layout_width="fill_parent"
+        android:layout_height="wrap_content"
+        android:layout_marginLeft="10dip"
+        android:layout_marginTop="10dip"
+        android:layout_marginRight="10dip"
+        android:layout_marginBottom="10dip" >
+
+        <TextView android:id="@+id/bbControlText"
+            android:layout_width="fill_parent"
+            android:layout_height="fill_parent"
+            android:layout_weight="1.0"
+            android:layout_gravity="center_vertical|left"
+            android:text="@string/effect_control"
+            style="@android:style/TextAppearance.Medium" />
+
+        <ToggleButton android:id="@+id/bassboostOnOff"
+            android:layout_width="wrap_content"
+            android:layout_height="fill_parent"
+            android:layout_gravity="center_vertical|right"
+            android:layout_weight="0.0" />
+
+    </LinearLayout>
+
+    <ImageView
+         android:src="@android:drawable/divider_horizontal_dark"
+         android:layout_width="fill_parent"
+         android:layout_height="wrap_content"
+         android:scaleType="fitXY"/>
+
+    <LinearLayout android:id="@+id/SessionFrame"
+        android:orientation="horizontal"
+        android:layout_width="fill_parent"
+        android:layout_height="wrap_content"
+        android:layout_marginLeft="10dip"
+        android:layout_marginTop="10dip"
+        android:layout_marginRight="10dip"
+        android:layout_marginBottom="10dip" >
+
+        <TextView android:id="@+id/sessionText"
+            android:layout_width="fill_parent"
+            android:layout_height="fill_parent"
+            android:layout_weight="0.5"
+            android:layout_gravity="center_vertical|left"
+            android:text="@string/session"
+            style="@android:style/TextAppearance.Medium" />
+
+        <EditText android:id="@+id/sessionEdit"
+            android:layout_width="fill_parent"
+            android:layout_height="wrap_content"
+            android:layout_weight="0.5"
+            android:layout_gravity="center_vertical|right" />
+    </LinearLayout>
+
+    <ImageView
+         android:src="@android:drawable/divider_horizontal_dark"
+         android:layout_width="fill_parent"
+         android:layout_height="wrap_content"
+         android:scaleType="fitXY"/>
+
+    <ScrollView
+        android:layout_width="fill_parent"
+        android:layout_height="wrap_content" >
+
+        <LinearLayout
+            android:layout_width="fill_parent"
+            android:layout_height="wrap_content"
+            android:orientation="vertical">
+
+            <LinearLayout
+                android:layout_width="fill_parent"
+                android:layout_height="wrap_content"
+                android:gravity="center_horizontal"
+                android:orientation="vertical"
+                android:layout_marginLeft="10dip"
+                android:layout_marginTop="10dip"
+                android:layout_marginRight="10dip"
+                android:layout_marginBottom="10dip"
+                >
+
+                <TextView android:id="@+id/bbStrengthName"
+                    android:layout_width="fill_parent"
+                    android:layout_height="wrap_content"
+                    android:text="@string/stength_name" />
+
+                <LinearLayout android:id="@+id/bbStrengthDesc"
+                    android:orientation="horizontal"
+                    android:layout_width="fill_parent"
+                    android:layout_height="wrap_content"
+                    android:layout_marginLeft="10dip"
+                    android:layout_marginTop="10dip"
+                    android:layout_marginRight="30dip"
+                    android:layout_marginBottom="10dip" >
+
+                    <TextView android:id="@+id/bbStrengthMin"
+                        android:layout_width="fill_parent"
+                        android:layout_height="fill_parent"
+                        android:layout_weight="1"
+                        android:layout_gravity="left"
+                        android:gravity="left"/>
+                    <TextView android:id="@+id/bbStrengthMax"
+                        android:layout_width="fill_parent"
+                        android:layout_height="fill_parent"
+                        android:layout_weight="1"
+                        android:layout_gravity="right"
+                        android:gravity="right"/>
+                </LinearLayout>
+
+                <SeekBar android:id="@+id/bbStrengthSeekBar"
+                    android:layout_width="fill_parent"
+                    android:layout_height="wrap_content"
+                    android:max="100"
+                    android:progress="50"
+                    android:layout_marginLeft="10dip"
+                    android:layout_marginRight="30dip" />
+
+                <TextView android:id="@+id/bbStrengthValue"
+                    android:layout_width="fill_parent"
+                    android:layout_height="wrap_content" />
+
+            </LinearLayout>
+
+            <ImageView
+                 android:src="@android:drawable/divider_horizontal_dark"
+                 android:layout_width="fill_parent"
+                 android:layout_height="wrap_content"
+                 android:scaleType="fitXY"/>
+
+        </LinearLayout>
+
+    </ScrollView>
+
+</LinearLayout>
diff --git a/media/tests/EffectsTest/res/layout/effectstest.xml b/media/tests/EffectsTest/res/layout/effectstest.xml
new file mode 100755
index 0000000..9af4eb6
--- /dev/null
+++ b/media/tests/EffectsTest/res/layout/effectstest.xml
@@ -0,0 +1,58 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2009 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="fill_parent"
+    android:layout_height="fill_parent"
+    android:orientation="vertical">
+
+    <Button android:id="@+id/env_reverb_actvity"
+        android:layout_width="fill_parent" android:layout_height="wrap_content"
+        android:text="@string/envreverb_test_name">
+    </Button>
+
+    <Button android:id="@+id/preset_reverb_actvity"
+        android:layout_width="fill_parent" android:layout_height="wrap_content"
+        android:text="@string/presetrvb_test_name">
+    </Button>
+
+    <Button android:id="@+id/equalizer_actvity"
+        android:layout_width="fill_parent" android:layout_height="wrap_content"
+        android:text="@string/equalizer_test_name">
+    </Button>
+
+    <Button android:id="@+id/virtualizer_actvity"
+        android:layout_width="fill_parent" android:layout_height="wrap_content"
+        android:text="@string/virtualizer_test_name">
+    </Button>
+
+    <Button android:id="@+id/bassboost_actvity"
+        android:layout_width="fill_parent" android:layout_height="wrap_content"
+        android:text="@string/bassboost_test_name">
+    </Button>
+
+    <Button android:id="@+id/visualizer_actvity"
+        android:layout_width="fill_parent" android:layout_height="wrap_content"
+        android:text="@string/visualizer_test_name">
+    </Button>
+
+    <ListView android:id="@+id/effect_list"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    android:drawSelectorOnTop="false"/>
+
+
+</LinearLayout>
diff --git a/media/tests/EffectsTest/res/layout/envreverbtest.xml b/media/tests/EffectsTest/res/layout/envreverbtest.xml
new file mode 100755
index 0000000..01c3240
--- /dev/null
+++ b/media/tests/EffectsTest/res/layout/envreverbtest.xml
@@ -0,0 +1,553 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2009 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="fill_parent"
+    android:layout_height="fill_parent"
+    android:orientation="vertical">
+
+    <ImageView
+         android:src="@android:drawable/divider_horizontal_dark"
+         android:layout_width="fill_parent"
+         android:layout_height="wrap_content"
+         android:scaleType="fitXY"/>
+
+    <LinearLayout android:id="@+id/rvbReleaseLayout"
+        android:orientation="horizontal"
+        android:layout_width="fill_parent"
+        android:layout_height="wrap_content"
+        android:layout_marginLeft="10dip"
+        android:layout_marginTop="10dip"
+        android:layout_marginRight="10dip"
+        android:layout_marginBottom="10dip" >
+
+        <TextView android:id="@+id/rvbReleaseText"
+            android:layout_width="fill_parent"
+            android:layout_height="fill_parent"
+            android:layout_weight="1.0"
+            android:layout_gravity="center_vertical|left"
+            android:text="@string/effect_release"
+            style="@android:style/TextAppearance.Medium" />
+
+        <ToggleButton android:id="@+id/rvbReleaseButton"
+            android:layout_width="wrap_content"
+            android:layout_height="fill_parent"
+            android:layout_gravity="center_vertical|right"
+            android:layout_weight="0.0" />
+
+    </LinearLayout>
+
+    <ImageView
+         android:src="@android:drawable/divider_horizontal_dark"
+         android:layout_width="fill_parent"
+         android:layout_height="wrap_content"
+         android:scaleType="fitXY"/>
+
+    <LinearLayout android:id="@+id/rvbControlLayout"
+        android:orientation="horizontal"
+        android:layout_width="fill_parent"
+        android:layout_height="wrap_content"
+        android:layout_marginLeft="10dip"
+        android:layout_marginTop="10dip"
+        android:layout_marginRight="10dip"
+        android:layout_marginBottom="10dip" >
+
+        <TextView android:id="@+id/rvbControlText"
+            android:layout_width="fill_parent"
+            android:layout_height="fill_parent"
+            android:layout_weight="1.0"
+            android:layout_gravity="center_vertical|left"
+            android:text="@string/effect_control"
+            style="@android:style/TextAppearance.Medium" />
+
+        <ToggleButton android:id="@+id/rvbOnOff"
+            android:layout_width="wrap_content"
+            android:layout_height="fill_parent"
+            android:layout_gravity="center_vertical|right"
+            android:layout_weight="0.0" />
+
+    </LinearLayout>
+
+    <ImageView
+         android:src="@android:drawable/divider_horizontal_dark"
+         android:layout_width="fill_parent"
+         android:layout_height="wrap_content"
+         android:scaleType="fitXY"/>
+
+    <LinearLayout android:id="@+id/auxFrame"
+        android:orientation="horizontal"
+        android:layout_width="fill_parent"
+        android:layout_height="wrap_content"
+        android:layout_marginLeft="3dip"
+        android:layout_marginTop="3dip"
+        android:layout_marginRight="3dip"
+        android:layout_marginBottom="3dip" >
+
+        <LinearLayout
+            android:layout_width="fill_parent"
+            android:layout_height="fill_parent"
+            android:layout_gravity="left"
+            android:layout_weight="1.0"
+            android:orientation="vertical"
+            android:layout_marginLeft="1dip"
+            android:layout_marginTop="1dip"
+            android:layout_marginRight="1dip"
+            android:layout_marginBottom="1dip"
+            >
+
+            <LinearLayout android:id="@+id/playPauseFrame"
+                android:orientation="horizontal"
+                android:layout_width="fill_parent"
+                android:layout_height="wrap_content"
+                android:layout_marginLeft="1dip"
+                android:layout_marginTop="1dip"
+                android:layout_marginRight="3dip"
+                android:layout_marginBottom="1dip" >
+
+                <ImageButton android:id="@+id/stop1"
+                    android:layout_width="wrap_content"
+                    android:layout_height="wrap_content"
+                    android:layout_gravity="center_vertical|left"
+                    android:layout_weight="0.0"
+                    android:src="@drawable/stop"/>
+
+                 <ImageButton android:id="@+id/playPause1"
+                    android:layout_width="wrap_content"
+                    android:layout_height="wrap_content"
+                    android:layout_gravity="center_vertical|center"
+                    android:layout_weight="0.0"
+                    android:src="@android:drawable/ic_media_play"/>
+
+                 <ToggleButton android:id="@+id/attachButton"
+                    android:layout_width="wrap_content"
+                    android:layout_height="wrap_content"
+                    android:layout_gravity="center_vertical|right"
+                    android:layout_weight="0.0"
+                    android:textOff="@string/effect_attach_off"
+                    android:textOn="@string/effect_attach_on" />
+             </LinearLayout>
+
+             <TextView android:id="@+id/sessionText"
+                android:layout_width="fill_parent"
+                android:layout_height="wrap_content" />
+
+        </LinearLayout>
+
+        <LinearLayout
+            android:layout_width="fill_parent"
+            android:layout_height="fill_parent"
+            android:orientation="vertical"
+            android:layout_gravity="right"
+            android:layout_weight="1.0"
+            android:layout_marginLeft="3dip"
+            android:layout_marginTop="3dip"
+            android:layout_marginRight="1dip"
+            android:layout_marginBottom="3dip"
+            >
+
+            <TextView android:id="@+id/sendLevelText"
+                android:layout_width="fill_parent"
+                android:layout_height="wrap_content"
+                android:text="@string/send_level_name" />
+
+            <SeekBar android:id="@+id/sendLevelSeekBar"
+                android:layout_width="fill_parent"
+                android:layout_height="wrap_content"
+                android:max="100"
+                android:progress="50"
+                android:layout_marginLeft="10dip"
+                android:layout_marginRight="30dip" />
+
+            <TextView android:id="@+id/sendLevelValue"
+                android:layout_width="fill_parent"
+                android:layout_height="wrap_content" />
+
+        </LinearLayout>
+    </LinearLayout>
+
+    <ImageView
+         android:src="@android:drawable/divider_horizontal_dark"
+         android:layout_width="fill_parent"
+         android:layout_height="wrap_content"
+         android:scaleType="fitXY"/>
+
+    <ScrollView
+        android:layout_width="fill_parent"
+        android:layout_height="wrap_content" >
+
+        <LinearLayout
+            android:layout_width="fill_parent"
+            android:layout_height="wrap_content"
+            android:orientation="vertical">
+
+            <LinearLayout
+                android:layout_width="fill_parent"
+                android:layout_height="wrap_content"
+                android:gravity="center_horizontal"
+                android:orientation="vertical"
+                android:layout_marginLeft="10dip"
+                android:layout_marginTop="10dip"
+                android:layout_marginRight="10dip"
+                android:layout_marginBottom="10dip"
+                >
+
+                <TextView android:id="@+id/rvbParam1Name"
+                    android:layout_width="fill_parent"
+                    android:layout_height="wrap_content"
+                    android:text="@string/rvb_param_1_name" />
+
+                <SeekBar android:id="@+id/rvbParam1SeekBar"
+                    android:layout_width="fill_parent"
+                    android:layout_height="wrap_content"
+                    android:max="100"
+                    android:progress="50"
+                    android:layout_marginLeft="10dip"
+                    android:layout_marginRight="30dip" />
+
+                <TextView android:id="@+id/rvbParam1Value"
+                    android:layout_width="fill_parent"
+                    android:layout_height="wrap_content" />
+
+            </LinearLayout>
+
+            <ImageView
+                 android:src="@android:drawable/divider_horizontal_dark"
+                 android:layout_width="fill_parent"
+                 android:layout_height="wrap_content"
+                 android:scaleType="fitXY"/>
+
+            <LinearLayout
+                android:layout_width="fill_parent"
+                android:layout_height="wrap_content"
+                android:gravity="center_horizontal"
+                android:orientation="vertical"
+                android:layout_marginLeft="10dip"
+                android:layout_marginTop="10dip"
+                android:layout_marginRight="10dip"
+                android:layout_marginBottom="10dip"
+                >
+
+                <TextView android:id="@+id/rvbParam2Name"
+                    android:layout_width="fill_parent"
+                    android:layout_height="wrap_content"
+                    android:text="@string/rvb_param_2_name" />
+
+                <SeekBar android:id="@+id/rvbParam2SeekBar"
+                    android:layout_width="fill_parent"
+                    android:layout_height="wrap_content"
+                    android:max="100"
+                    android:progress="50"
+                    android:layout_marginLeft="10dip"
+                    android:layout_marginRight="30dip" />
+
+                <TextView android:id="@+id/rvbParam2Value"
+                    android:layout_width="fill_parent"
+                    android:layout_height="wrap_content" />
+
+            </LinearLayout>
+
+            <ImageView
+                 android:src="@android:drawable/divider_horizontal_dark"
+                 android:layout_width="fill_parent"
+                 android:layout_height="wrap_content"
+                 android:scaleType="fitXY"/>
+
+            <LinearLayout
+                android:layout_width="fill_parent"
+                android:layout_height="wrap_content"
+                android:gravity="center_horizontal"
+                android:orientation="vertical"
+                android:layout_marginLeft="10dip"
+                android:layout_marginTop="10dip"
+                android:layout_marginRight="10dip"
+                android:layout_marginBottom="10dip"
+                >
+
+                <TextView android:id="@+id/rvbParam3Name"
+                    android:layout_width="fill_parent"
+                    android:layout_height="wrap_content"
+                    android:text="@string/rvb_param_3_name" />
+
+                <SeekBar android:id="@+id/rvbParam3SeekBar"
+                    android:layout_width="fill_parent"
+                    android:layout_height="wrap_content"
+                    android:max="100"
+                    android:progress="50"
+                    android:layout_marginLeft="10dip"
+                    android:layout_marginRight="30dip" />
+
+                <TextView android:id="@+id/rvbParam3Value"
+                    android:layout_width="fill_parent"
+                    android:layout_height="wrap_content" />
+
+            </LinearLayout>
+
+            <ImageView
+                 android:src="@android:drawable/divider_horizontal_dark"
+                 android:layout_width="fill_parent"
+                 android:layout_height="wrap_content"
+                 android:scaleType="fitXY"/>
+
+            <LinearLayout
+                android:layout_width="fill_parent"
+                android:layout_height="wrap_content"
+                android:gravity="center_horizontal"
+                android:orientation="vertical"
+                android:layout_marginLeft="10dip"
+                android:layout_marginTop="10dip"
+                android:layout_marginRight="10dip"
+                android:layout_marginBottom="10dip"
+                >
+
+                <TextView android:id="@+id/rvbParam4Name"
+                    android:layout_width="fill_parent"
+                    android:layout_height="wrap_content"
+                    android:text="@string/rvb_param_4_name" />
+
+                <SeekBar android:id="@+id/rvbParam4SeekBar"
+                    android:layout_width="fill_parent"
+                    android:layout_height="wrap_content"
+                    android:max="100"
+                    android:progress="50"
+                    android:layout_marginLeft="10dip"
+                    android:layout_marginRight="30dip" />
+
+                <TextView android:id="@+id/rvbParam4Value"
+                    android:layout_width="fill_parent"
+                    android:layout_height="wrap_content" />
+
+            </LinearLayout>
+            <ImageView
+                 android:src="@android:drawable/divider_horizontal_dark"
+                 android:layout_width="fill_parent"
+                 android:layout_height="wrap_content"
+                 android:scaleType="fitXY"/>
+
+            <LinearLayout
+                android:layout_width="fill_parent"
+                android:layout_height="wrap_content"
+                android:gravity="center_horizontal"
+                android:orientation="vertical"
+                android:layout_marginLeft="10dip"
+                android:layout_marginTop="10dip"
+                android:layout_marginRight="10dip"
+                android:layout_marginBottom="10dip"
+                >
+
+                <TextView android:id="@+id/rvbParam5Name"
+                    android:layout_width="fill_parent"
+                    android:layout_height="wrap_content"
+                    android:text="@string/rvb_param_5_name" />
+
+                <SeekBar android:id="@+id/rvbParam5SeekBar"
+                    android:layout_width="fill_parent"
+                    android:layout_height="wrap_content"
+                    android:max="100"
+                    android:progress="50"
+                    android:layout_marginLeft="10dip"
+                    android:layout_marginRight="30dip" />
+
+                <TextView android:id="@+id/rvbParam5Value"
+                    android:layout_width="fill_parent"
+                    android:layout_height="wrap_content" />
+
+            </LinearLayout>
+            <ImageView
+                 android:src="@android:drawable/divider_horizontal_dark"
+                 android:layout_width="fill_parent"
+                 android:layout_height="wrap_content"
+                 android:scaleType="fitXY"/>
+
+            <LinearLayout
+                android:layout_width="fill_parent"
+                android:layout_height="wrap_content"
+                android:gravity="center_horizontal"
+                android:orientation="vertical"
+                android:layout_marginLeft="10dip"
+                android:layout_marginTop="10dip"
+                android:layout_marginRight="10dip"
+                android:layout_marginBottom="10dip"
+                >
+
+                <TextView android:id="@+id/rvbParam6Name"
+                    android:layout_width="fill_parent"
+                    android:layout_height="wrap_content"
+                    android:text="@string/rvb_param_6_name" />
+
+                <SeekBar android:id="@+id/rvbParam6SeekBar"
+                    android:layout_width="fill_parent"
+                    android:layout_height="wrap_content"
+                    android:max="100"
+                    android:progress="50"
+                    android:layout_marginLeft="10dip"
+                    android:layout_marginRight="30dip" />
+
+                <TextView android:id="@+id/rvbParam6Value"
+                    android:layout_width="fill_parent"
+                    android:layout_height="wrap_content" />
+
+            </LinearLayout>
+            <ImageView
+                 android:src="@android:drawable/divider_horizontal_dark"
+                 android:layout_width="fill_parent"
+                 android:layout_height="wrap_content"
+                 android:scaleType="fitXY"/>
+
+            <LinearLayout
+                android:layout_width="fill_parent"
+                android:layout_height="wrap_content"
+                android:gravity="center_horizontal"
+                android:orientation="vertical"
+                android:layout_marginLeft="10dip"
+                android:layout_marginTop="10dip"
+                android:layout_marginRight="10dip"
+                android:layout_marginBottom="10dip"
+                >
+
+                <TextView android:id="@+id/rvbParam7Name"
+                    android:layout_width="fill_parent"
+                    android:layout_height="wrap_content"
+                    android:text="@string/rvb_param_7_name" />
+
+                <SeekBar android:id="@+id/rvbParam7SeekBar"
+                    android:layout_width="fill_parent"
+                    android:layout_height="wrap_content"
+                    android:max="100"
+                    android:progress="50"
+                    android:layout_marginLeft="10dip"
+                    android:layout_marginRight="30dip" />
+
+                <TextView android:id="@+id/rvbParam7Value"
+                    android:layout_width="fill_parent"
+                    android:layout_height="wrap_content" />
+
+            </LinearLayout>
+            <ImageView
+                 android:src="@android:drawable/divider_horizontal_dark"
+                 android:layout_width="fill_parent"
+                 android:layout_height="wrap_content"
+                 android:scaleType="fitXY"/>
+
+            <LinearLayout
+                android:layout_width="fill_parent"
+                android:layout_height="wrap_content"
+                android:gravity="center_horizontal"
+                android:orientation="vertical"
+                android:layout_marginLeft="10dip"
+                android:layout_marginTop="10dip"
+                android:layout_marginRight="10dip"
+                android:layout_marginBottom="10dip"
+                >
+
+                <TextView android:id="@+id/rvbParam8Name"
+                    android:layout_width="fill_parent"
+                    android:layout_height="wrap_content"
+                    android:text="@string/rvb_param_8_name" />
+
+                <SeekBar android:id="@+id/rvbParam8SeekBar"
+                    android:layout_width="fill_parent"
+                    android:layout_height="wrap_content"
+                    android:max="100"
+                    android:progress="50"
+                    android:layout_marginLeft="10dip"
+                    android:layout_marginRight="30dip" />
+
+                <TextView android:id="@+id/rvbParam8Value"
+                    android:layout_width="fill_parent"
+                    android:layout_height="wrap_content" />
+
+            </LinearLayout>
+            <ImageView
+                 android:src="@android:drawable/divider_horizontal_dark"
+                 android:layout_width="fill_parent"
+                 android:layout_height="wrap_content"
+                 android:scaleType="fitXY"/>
+
+            <LinearLayout
+                android:layout_width="fill_parent"
+                android:layout_height="wrap_content"
+                android:gravity="center_horizontal"
+                android:orientation="vertical"
+                android:layout_marginLeft="10dip"
+                android:layout_marginTop="10dip"
+                android:layout_marginRight="10dip"
+                android:layout_marginBottom="10dip"
+                >
+
+                <TextView android:id="@+id/rvbParam9Name"
+                    android:layout_width="fill_parent"
+                    android:layout_height="wrap_content"
+                    android:text="@string/rvb_param_9_name" />
+
+                <SeekBar android:id="@+id/rvbParam9SeekBar"
+                    android:layout_width="fill_parent"
+                    android:layout_height="wrap_content"
+                    android:max="100"
+                    android:progress="50"
+                    android:layout_marginLeft="10dip"
+                    android:layout_marginRight="30dip" />
+
+                <TextView android:id="@+id/rvbParam9Value"
+                    android:layout_width="fill_parent"
+                    android:layout_height="wrap_content" />
+
+            </LinearLayout>
+            <ImageView
+                 android:src="@android:drawable/divider_horizontal_dark"
+                 android:layout_width="fill_parent"
+                 android:layout_height="wrap_content"
+                 android:scaleType="fitXY"/>
+
+            <LinearLayout
+                android:layout_width="fill_parent"
+                android:layout_height="wrap_content"
+                android:gravity="center_horizontal"
+                android:orientation="vertical"
+                android:layout_marginLeft="10dip"
+                android:layout_marginTop="10dip"
+                android:layout_marginRight="10dip"
+                android:layout_marginBottom="10dip"
+                >
+
+                <TextView android:id="@+id/rvbParam10Name"
+                    android:layout_width="fill_parent"
+                    android:layout_height="wrap_content"
+                    android:text="@string/rvb_param_10_name" />
+
+                <SeekBar android:id="@+id/rvbParam10SeekBar"
+                    android:layout_width="fill_parent"
+                    android:layout_height="wrap_content"
+                    android:max="100"
+                    android:progress="50"
+                    android:layout_marginLeft="10dip"
+                    android:layout_marginRight="30dip" />
+
+                <TextView android:id="@+id/rvbParam10Value"
+                    android:layout_width="fill_parent"
+                    android:layout_height="wrap_content" />
+
+            </LinearLayout>
+        </LinearLayout>
+
+    </ScrollView>
+
+    <ImageView
+         android:src="@android:drawable/divider_horizontal_dark"
+         android:layout_width="fill_parent"
+         android:layout_height="wrap_content"
+         android:scaleType="fitXY"/>
+
+</LinearLayout>
diff --git a/media/tests/EffectsTest/res/layout/equalizertest.xml b/media/tests/EffectsTest/res/layout/equalizertest.xml
new file mode 100755
index 0000000..2223c48
--- /dev/null
+++ b/media/tests/EffectsTest/res/layout/equalizertest.xml
@@ -0,0 +1,468 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2009 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="fill_parent"
+    android:layout_height="fill_parent"
+    android:orientation="vertical">
+
+    <ImageView
+         android:src="@android:drawable/divider_horizontal_dark"
+         android:layout_width="fill_parent"
+         android:layout_height="wrap_content"
+         android:scaleType="fitXY"/>
+
+    <LinearLayout android:id="@+id/eqReleaseLayout"
+        android:orientation="horizontal"
+        android:layout_width="fill_parent"
+        android:layout_height="wrap_content"
+        android:layout_marginLeft="10dip"
+        android:layout_marginTop="10dip"
+        android:layout_marginRight="10dip"
+        android:layout_marginBottom="10dip" >
+
+        <TextView android:id="@+id/eqReleaseText"
+            android:layout_width="fill_parent"
+            android:layout_height="fill_parent"
+            android:layout_weight="1.0"
+            android:layout_gravity="center_vertical|left"
+            android:text="@string/effect_release"
+            style="@android:style/TextAppearance.Medium" />
+
+        <ToggleButton android:id="@+id/eqReleaseButton"
+            android:layout_width="wrap_content"
+            android:layout_height="fill_parent"
+            android:layout_gravity="center_vertical|right"
+            android:layout_weight="0.0" />
+
+    </LinearLayout>
+
+    <ImageView
+         android:src="@android:drawable/divider_horizontal_dark"
+         android:layout_width="fill_parent"
+         android:layout_height="wrap_content"
+         android:scaleType="fitXY"/>
+
+    <LinearLayout android:id="@+id/eqControlLayout"
+        android:orientation="horizontal"
+        android:layout_width="fill_parent"
+        android:layout_height="wrap_content"
+        android:layout_marginLeft="10dip"
+        android:layout_marginTop="10dip"
+        android:layout_marginRight="10dip"
+        android:layout_marginBottom="10dip" >
+
+        <TextView android:id="@+id/eqControlText"
+            android:layout_width="fill_parent"
+            android:layout_height="fill_parent"
+            android:layout_weight="1.0"
+            android:layout_gravity="center_vertical|left"
+            android:text="@string/effect_control"
+            style="@android:style/TextAppearance.Medium" />
+
+        <ToggleButton android:id="@+id/equalizerOnOff"
+            android:layout_width="wrap_content"
+            android:layout_height="fill_parent"
+            android:layout_gravity="center_vertical|right"
+            android:layout_weight="0.0" />
+
+    </LinearLayout>
+
+    <ImageView
+         android:src="@android:drawable/divider_horizontal_dark"
+         android:layout_width="fill_parent"
+         android:layout_height="wrap_content"
+         android:scaleType="fitXY"/>
+
+    <LinearLayout android:id="@+id/SessionFrame"
+        android:orientation="horizontal"
+        android:layout_width="fill_parent"
+        android:layout_height="wrap_content"
+        android:layout_marginLeft="10dip"
+        android:layout_marginTop="10dip"
+        android:layout_marginRight="10dip"
+        android:layout_marginBottom="10dip" >
+
+        <TextView android:id="@+id/sessionText"
+            android:layout_width="fill_parent"
+            android:layout_height="fill_parent"
+            android:layout_weight="0.5"
+            android:layout_gravity="center_vertical|left"
+            android:text="@string/session"
+            style="@android:style/TextAppearance.Medium" />
+
+        <EditText android:id="@+id/sessionEdit"
+            android:layout_width="fill_parent"
+            android:layout_height="wrap_content"
+            android:layout_weight="0.5"
+            android:layout_gravity="center_vertical|right" />
+    </LinearLayout>
+
+    <ImageView
+         android:src="@android:drawable/divider_horizontal_dark"
+         android:layout_width="fill_parent"
+         android:layout_height="wrap_content"
+         android:scaleType="fitXY"/>
+
+    <ScrollView
+        android:layout_width="fill_parent"
+        android:layout_height="wrap_content" >
+
+        <LinearLayout
+            android:layout_width="fill_parent"
+            android:layout_height="wrap_content"
+            android:orientation="vertical">
+
+            <LinearLayout
+                android:layout_width="fill_parent"
+                android:layout_height="wrap_content"
+                android:gravity="center_horizontal"
+                android:orientation="vertical"
+                android:layout_marginLeft="10dip"
+                android:layout_marginTop="10dip"
+                android:layout_marginRight="10dip"
+                android:layout_marginBottom="10dip"
+                >
+
+                <TextView android:id="@+id/eqParam1Name"
+                    android:layout_width="fill_parent"
+                    android:layout_height="wrap_content"
+                    android:text="@string/eq_param_1_name" />
+
+                <LinearLayout android:id="@+id/eqParam1Desc"
+                    android:orientation="horizontal"
+                    android:layout_width="fill_parent"
+                    android:layout_height="wrap_content"
+                    android:layout_marginLeft="10dip"
+                    android:layout_marginTop="10dip"
+                    android:layout_marginRight="10dip"
+                    android:layout_marginBottom="10dip" >
+
+                    <TextView android:id="@+id/eqParam1Min"
+                        android:layout_width="fill_parent"
+                        android:layout_height="fill_parent"
+                        android:layout_weight="1.0" />
+                    <TextView android:id="@+id/eqParam1Center"
+                        android:layout_width="fill_parent"
+                        android:layout_height="fill_parent"
+                        android:layout_weight="1.0" />
+                    <TextView android:id="@+id/eqParam1Max"
+                        android:layout_width="fill_parent"
+                        android:layout_height="fill_parent"
+                        android:layout_weight="1.0" />
+                </LinearLayout>
+
+                <SeekBar android:id="@+id/eqParam1SeekBar"
+                    android:layout_width="fill_parent"
+                    android:layout_height="wrap_content"
+                    android:max="100"
+                    android:progress="50"
+                    android:layout_marginLeft="10dip"
+                    android:layout_marginRight="30dip" />
+
+                <TextView android:id="@+id/eqParam1Value"
+                    android:layout_width="fill_parent"
+                    android:layout_height="wrap_content" />
+
+            </LinearLayout>
+
+            <ImageView
+                 android:src="@android:drawable/divider_horizontal_dark"
+                 android:layout_width="fill_parent"
+                 android:layout_height="wrap_content"
+                 android:scaleType="fitXY"/>
+
+            <LinearLayout
+                android:layout_width="fill_parent"
+                android:layout_height="wrap_content"
+                android:gravity="center_horizontal"
+                android:orientation="vertical"
+                android:layout_marginLeft="10dip"
+                android:layout_marginTop="10dip"
+                android:layout_marginRight="10dip"
+                android:layout_marginBottom="10dip"
+                >
+
+                <TextView android:id="@+id/eqParam2Name"
+                    android:layout_width="fill_parent"
+                    android:layout_height="wrap_content"
+                    android:text="@string/eq_param_2_name" />
+
+                <LinearLayout android:id="@+id/eqParam2Desc"
+                    android:orientation="horizontal"
+                    android:layout_width="fill_parent"
+                    android:layout_height="wrap_content"
+                    android:layout_marginLeft="10dip"
+                    android:layout_marginTop="10dip"
+                    android:layout_marginRight="10dip"
+                    android:layout_marginBottom="10dip" >
+
+                    <TextView android:id="@+id/eqParam2Min"
+                        android:layout_width="fill_parent"
+                        android:layout_height="fill_parent"
+                        android:layout_weight="1.0" />
+                    <TextView android:id="@+id/eqParam2Center"
+                        android:layout_width="fill_parent"
+                        android:layout_height="fill_parent"
+                        android:layout_weight="1.0" />
+                    <TextView android:id="@+id/eqParam2Max"
+                        android:layout_width="fill_parent"
+                        android:layout_height="fill_parent"
+                        android:layout_weight="1.0" />
+
+                </LinearLayout>
+
+                <SeekBar android:id="@+id/eqParam2SeekBar"
+                    android:layout_width="fill_parent"
+                    android:layout_height="wrap_content"
+                    android:max="100"
+                    android:progress="50"
+                    android:layout_marginLeft="10dip"
+                    android:layout_marginRight="30dip" />
+
+                <TextView android:id="@+id/eqParam2Value"
+                    android:layout_width="fill_parent"
+                    android:layout_height="wrap_content" />
+
+            </LinearLayout>
+
+            <ImageView
+                 android:src="@android:drawable/divider_horizontal_dark"
+                 android:layout_width="fill_parent"
+                 android:layout_height="wrap_content"
+                 android:scaleType="fitXY"/>
+
+            <LinearLayout
+                android:layout_width="fill_parent"
+                android:layout_height="wrap_content"
+                android:gravity="center_horizontal"
+                android:orientation="vertical"
+                android:layout_marginLeft="10dip"
+                android:layout_marginTop="10dip"
+                android:layout_marginRight="10dip"
+                android:layout_marginBottom="10dip"
+                >
+
+                <TextView android:id="@+id/eqParam3Name"
+                    android:layout_width="fill_parent"
+                    android:layout_height="wrap_content"
+                    android:text="@string/eq_param_3_name" />
+
+                <LinearLayout android:id="@+id/eqParam3Desc"
+                    android:orientation="horizontal"
+                    android:layout_width="fill_parent"
+                    android:layout_height="wrap_content"
+                    android:layout_marginLeft="10dip"
+                    android:layout_marginTop="10dip"
+                    android:layout_marginRight="10dip"
+                    android:layout_marginBottom="10dip" >
+
+                    <TextView android:id="@+id/eqParam3Min"
+                        android:layout_width="fill_parent"
+                        android:layout_height="fill_parent"
+                        android:layout_weight="1.0" />
+                    <TextView android:id="@+id/eqParam3Center"
+                        android:layout_width="fill_parent"
+                        android:layout_height="fill_parent"
+                        android:layout_weight="1.0" />
+                    <TextView android:id="@+id/eqParam3Max"
+                        android:layout_width="fill_parent"
+                        android:layout_height="fill_parent"
+                        android:layout_weight="1.0" />
+
+                </LinearLayout>
+
+                <SeekBar android:id="@+id/eqParam3SeekBar"
+                    android:layout_width="fill_parent"
+                    android:layout_height="wrap_content"
+                    android:max="100"
+                    android:progress="50"
+                    android:layout_marginLeft="10dip"
+                    android:layout_marginRight="30dip" />
+
+                <TextView android:id="@+id/eqParam3Value"
+                    android:layout_width="fill_parent"
+                    android:layout_height="wrap_content" />
+
+            </LinearLayout>
+
+            <ImageView
+                 android:src="@android:drawable/divider_horizontal_dark"
+                 android:layout_width="fill_parent"
+                 android:layout_height="wrap_content"
+                 android:scaleType="fitXY"/>
+
+            <LinearLayout
+                android:layout_width="fill_parent"
+                android:layout_height="wrap_content"
+                android:gravity="center_horizontal"
+                android:orientation="vertical"
+                android:layout_marginLeft="10dip"
+                android:layout_marginTop="10dip"
+                android:layout_marginRight="10dip"
+                android:layout_marginBottom="10dip"
+                >
+
+                <TextView android:id="@+id/eqParam4Name"
+                    android:layout_width="fill_parent"
+                    android:layout_height="wrap_content"
+                    android:text="@string/eq_param_4_name" />
+
+                <LinearLayout android:id="@+id/eqParam4Desc"
+                    android:orientation="horizontal"
+                    android:layout_width="fill_parent"
+                    android:layout_height="wrap_content"
+                    android:layout_marginLeft="10dip"
+                    android:layout_marginTop="10dip"
+                    android:layout_marginRight="10dip"
+                    android:layout_marginBottom="10dip" >
+
+                    <TextView android:id="@+id/eqParam4Min"
+                        android:layout_width="fill_parent"
+                        android:layout_height="fill_parent"
+                        android:layout_weight="1.0" />
+                    <TextView android:id="@+id/eqParam4Center"
+                        android:layout_width="fill_parent"
+                        android:layout_height="fill_parent"
+                        android:layout_weight="1.0" />
+                    <TextView android:id="@+id/eqParam4Max"
+                        android:layout_width="fill_parent"
+                        android:layout_height="fill_parent"
+                        android:layout_weight="1.0" />
+
+                </LinearLayout>
+
+                <SeekBar android:id="@+id/eqParam4SeekBar"
+                    android:layout_width="fill_parent"
+                    android:layout_height="wrap_content"
+                    android:max="100"
+                    android:progress="50"
+                    android:layout_marginLeft="10dip"
+                    android:layout_marginRight="30dip" />
+
+                <TextView android:id="@+id/eqParam4Value"
+                    android:layout_width="fill_parent"
+                    android:layout_height="wrap_content" />
+
+            </LinearLayout>
+
+            <ImageView
+                 android:src="@android:drawable/divider_horizontal_dark"
+                 android:layout_width="fill_parent"
+                 android:layout_height="wrap_content"
+                 android:scaleType="fitXY"/>
+
+            <LinearLayout
+                android:layout_width="fill_parent"
+                android:layout_height="wrap_content"
+                android:gravity="center_horizontal"
+                android:orientation="vertical"
+                android:layout_marginLeft="10dip"
+                android:layout_marginTop="10dip"
+                android:layout_marginRight="10dip"
+                android:layout_marginBottom="10dip"
+                >
+
+                <TextView android:id="@+id/eqParam5Name"
+                    android:layout_width="fill_parent"
+                    android:layout_height="wrap_content"
+                    android:text="@string/eq_param_5_name" />
+
+                <LinearLayout android:id="@+id/eqParam5Desc"
+                    android:orientation="horizontal"
+                    android:layout_width="fill_parent"
+                    android:layout_height="wrap_content"
+                    android:layout_marginLeft="10dip"
+                    android:layout_marginTop="10dip"
+                    android:layout_marginRight="10dip"
+                    android:layout_marginBottom="10dip" >
+
+                    <TextView android:id="@+id/eqParam5Min"
+                        android:layout_width="fill_parent"
+                        android:layout_height="fill_parent"
+                        android:layout_weight="1.0" />
+                    <TextView android:id="@+id/eqParam5Center"
+                        android:layout_width="fill_parent"
+                        android:layout_height="fill_parent"
+                        android:layout_weight="1.0" />
+                    <TextView android:id="@+id/eqParam5Max"
+                        android:layout_width="fill_parent"
+                        android:layout_height="fill_parent"
+                        android:layout_weight="1.0" />
+
+                </LinearLayout>
+
+                <SeekBar android:id="@+id/eqParam5SeekBar"
+                    android:layout_width="fill_parent"
+                    android:layout_height="wrap_content"
+                    android:max="100"
+                    android:progress="50"
+                    android:layout_marginLeft="10dip"
+                    android:layout_marginRight="30dip" />
+
+                <TextView android:id="@+id/eqParam5Value"
+                    android:layout_width="fill_parent"
+                    android:layout_height="wrap_content" />
+
+            </LinearLayout>
+
+                        <ImageView
+                 android:src="@android:drawable/divider_horizontal_dark"
+                 android:layout_width="fill_parent"
+                 android:layout_height="wrap_content"
+                 android:scaleType="fitXY"/>
+
+            <LinearLayout
+                android:layout_width="fill_parent"
+                android:layout_height="wrap_content"
+                android:gravity="center_horizontal"
+                android:orientation="vertical"
+                android:layout_marginLeft="10dip"
+                android:layout_marginTop="10dip"
+                android:layout_marginRight="10dip"
+                android:layout_marginBottom="10dip"
+                >
+
+                <TextView android:id="@+id/eqParam6Name"
+                    android:layout_width="fill_parent"
+                    android:layout_height="wrap_content"
+                    android:text="@string/eq_param_6_name" />
+
+                <SeekBar android:id="@+id/eqParam6SeekBar"
+                    android:layout_width="fill_parent"
+                    android:layout_height="wrap_content"
+                    android:max="100"
+                    android:progress="50"
+                    android:layout_marginLeft="10dip"
+                    android:layout_marginRight="30dip" />
+
+                <TextView android:id="@+id/eqParam6Value"
+                    android:layout_width="fill_parent"
+                    android:layout_height="wrap_content" />
+
+            </LinearLayout>
+
+            <ImageView
+                 android:src="@android:drawable/divider_horizontal_dark"
+                 android:layout_width="fill_parent"
+                 android:layout_height="wrap_content"
+                 android:scaleType="fitXY"/>
+
+        </LinearLayout>
+
+    </ScrollView>
+
+</LinearLayout>
diff --git a/media/tests/EffectsTest/res/layout/presetreverbtest.xml b/media/tests/EffectsTest/res/layout/presetreverbtest.xml
new file mode 100755
index 0000000..b648899
--- /dev/null
+++ b/media/tests/EffectsTest/res/layout/presetreverbtest.xml
@@ -0,0 +1,177 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2010 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="fill_parent"
+    android:layout_height="fill_parent"
+    android:orientation="vertical">
+
+    <ImageView
+         android:src="@android:drawable/divider_horizontal_dark"
+         android:layout_width="fill_parent"
+         android:layout_height="wrap_content"
+         android:scaleType="fitXY"/>
+
+    <LinearLayout android:id="@+id/presetrvbReleaseLayout"
+        android:orientation="horizontal"
+        android:layout_width="fill_parent"
+        android:layout_height="wrap_content"
+        android:layout_marginLeft="10dip"
+        android:layout_marginTop="10dip"
+        android:layout_marginRight="10dip"
+        android:layout_marginBottom="10dip" >
+
+        <TextView android:id="@+id/presetrvbReleaseText"
+            android:layout_width="fill_parent"
+            android:layout_height="fill_parent"
+            android:layout_weight="1.0"
+            android:layout_gravity="center_vertical|left"
+            android:text="@string/effect_release"
+            style="@android:style/TextAppearance.Medium" />
+
+        <ToggleButton android:id="@+id/presetrvbReleaseButton"
+            android:layout_width="wrap_content"
+            android:layout_height="fill_parent"
+            android:layout_gravity="center_vertical|right"
+            android:layout_weight="0.0" />
+
+    </LinearLayout>
+
+    <ImageView
+         android:src="@android:drawable/divider_horizontal_dark"
+         android:layout_width="fill_parent"
+         android:layout_height="wrap_content"
+         android:scaleType="fitXY"/>
+
+    <LinearLayout android:id="@+id/presetrvbControlLayout"
+        android:orientation="horizontal"
+        android:layout_width="fill_parent"
+        android:layout_height="wrap_content"
+        android:layout_marginLeft="10dip"
+        android:layout_marginTop="10dip"
+        android:layout_marginRight="10dip"
+        android:layout_marginBottom="10dip" >
+
+        <TextView android:id="@+id/presetrvbControlText"
+            android:layout_width="fill_parent"
+            android:layout_height="fill_parent"
+            android:layout_weight="1.0"
+            android:layout_gravity="center_vertical|left"
+            android:text="@string/effect_control"
+            style="@android:style/TextAppearance.Medium" />
+
+        <ToggleButton android:id="@+id/presetrvbOnOff"
+            android:layout_width="wrap_content"
+            android:layout_height="fill_parent"
+            android:layout_gravity="center_vertical|right"
+            android:layout_weight="0.0" />
+
+    </LinearLayout>
+
+    <ImageView
+         android:src="@android:drawable/divider_horizontal_dark"
+         android:layout_width="fill_parent"
+         android:layout_height="wrap_content"
+         android:scaleType="fitXY"/>
+
+    <LinearLayout android:id="@+id/SessionFrame"
+        android:orientation="horizontal"
+        android:layout_width="fill_parent"
+        android:layout_height="wrap_content"
+        android:layout_marginLeft="10dip"
+        android:layout_marginTop="10dip"
+        android:layout_marginRight="10dip"
+        android:layout_marginBottom="10dip" >
+
+        <TextView android:id="@+id/sessionText"
+            android:layout_width="fill_parent"
+            android:layout_height="fill_parent"
+            android:layout_weight="0.5"
+            android:layout_gravity="center_vertical|left"
+            android:text="@string/session"
+            style="@android:style/TextAppearance.Medium" />
+
+        <EditText android:id="@+id/sessionEdit"
+            android:layout_width="fill_parent"
+            android:layout_height="wrap_content"
+            android:layout_weight="0.5"
+            android:layout_gravity="center_vertical|right" />
+    </LinearLayout>
+
+  <ImageView
+       android:src="@android:drawable/divider_horizontal_dark"
+       android:layout_width="fill_parent"
+       android:layout_height="wrap_content"
+       android:scaleType="fitXY"/>
+
+    <ScrollView
+        android:layout_width="fill_parent"
+        android:layout_height="wrap_content" >
+
+        <LinearLayout
+            android:layout_width="fill_parent"
+            android:layout_height="wrap_content"
+            android:orientation="vertical">
+
+
+            <ImageView
+                 android:src="@android:drawable/divider_horizontal_dark"
+                 android:layout_width="fill_parent"
+                 android:layout_height="wrap_content"
+                 android:scaleType="fitXY"/>
+
+
+        <LinearLayout
+            android:layout_width="fill_parent"
+            android:layout_height="wrap_content"
+            android:gravity="center_horizontal"
+            android:orientation="vertical"
+            android:layout_marginLeft="10dip"
+            android:layout_marginTop="10dip"
+            android:layout_marginRight="10dip"
+            android:layout_marginBottom="10dip"
+            >
+
+            <TextView android:id="@+id/presetrvbParam1Name"
+                android:layout_width="fill_parent"
+                android:layout_height="wrap_content"
+                android:text="@string/presetrvb_param_1_name" />
+
+            <SeekBar android:id="@+id/presetrvbParam1SeekBar"
+                android:layout_width="fill_parent"
+                android:layout_height="wrap_content"
+                android:max="100"
+                android:progress="50"
+                android:layout_marginLeft="10dip"
+                android:layout_marginRight="30dip" />
+
+            <TextView android:id="@+id/presetrvbParam1Value"
+                android:layout_width="fill_parent"
+                android:layout_height="wrap_content" />
+
+        </LinearLayout>
+
+        <ImageView
+             android:src="@android:drawable/divider_horizontal_dark"
+             android:layout_width="fill_parent"
+             android:layout_height="wrap_content"
+             android:scaleType="fitXY"/>
+
+        </LinearLayout>
+
+    </ScrollView>
+
+</LinearLayout>
diff --git a/media/tests/EffectsTest/res/layout/virtualizertest.xml b/media/tests/EffectsTest/res/layout/virtualizertest.xml
new file mode 100755
index 0000000..c9203de
--- /dev/null
+++ b/media/tests/EffectsTest/res/layout/virtualizertest.xml
@@ -0,0 +1,192 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2009 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="fill_parent"
+    android:layout_height="fill_parent"
+    android:orientation="vertical">
+
+    <ImageView
+         android:src="@android:drawable/divider_horizontal_dark"
+         android:layout_width="fill_parent"
+         android:layout_height="wrap_content"
+         android:scaleType="fitXY"/>
+
+    <LinearLayout android:id="@+id/virtReleaseLayout"
+        android:orientation="horizontal"
+        android:layout_width="fill_parent"
+        android:layout_height="wrap_content"
+        android:layout_marginLeft="10dip"
+        android:layout_marginTop="10dip"
+        android:layout_marginRight="10dip"
+        android:layout_marginBottom="10dip" >
+
+        <TextView android:id="@+id/virtReleaseText"
+            android:layout_width="fill_parent"
+            android:layout_height="fill_parent"
+            android:layout_weight="1.0"
+            android:layout_gravity="center_vertical|left"
+            android:text="@string/effect_release"
+            style="@android:style/TextAppearance.Medium" />
+
+        <ToggleButton android:id="@+id/virtReleaseButton"
+            android:layout_width="wrap_content"
+            android:layout_height="fill_parent"
+            android:layout_gravity="center_vertical|right"
+            android:layout_weight="0.0" />
+
+    </LinearLayout>
+
+    <ImageView
+         android:src="@android:drawable/divider_horizontal_dark"
+         android:layout_width="fill_parent"
+         android:layout_height="wrap_content"
+         android:scaleType="fitXY"/>
+
+    <LinearLayout android:id="@+id/virtControlLayout"
+        android:orientation="horizontal"
+        android:layout_width="fill_parent"
+        android:layout_height="wrap_content"
+        android:layout_marginLeft="10dip"
+        android:layout_marginTop="10dip"
+        android:layout_marginRight="10dip"
+        android:layout_marginBottom="10dip" >
+
+        <TextView android:id="@+id/virtControlText"
+            android:layout_width="fill_parent"
+            android:layout_height="fill_parent"
+            android:layout_weight="1.0"
+            android:layout_gravity="center_vertical|left"
+            android:text="@string/effect_control"
+            style="@android:style/TextAppearance.Medium" />
+
+        <ToggleButton android:id="@+id/virtualizerOnOff"
+            android:layout_width="wrap_content"
+            android:layout_height="fill_parent"
+            android:layout_gravity="center_vertical|right"
+            android:layout_weight="0.0" />
+
+    </LinearLayout>
+
+    <ImageView
+         android:src="@android:drawable/divider_horizontal_dark"
+         android:layout_width="fill_parent"
+         android:layout_height="wrap_content"
+         android:scaleType="fitXY"/>
+
+    <LinearLayout android:id="@+id/SessionFrame"
+        android:orientation="horizontal"
+        android:layout_width="fill_parent"
+        android:layout_height="wrap_content"
+        android:layout_marginLeft="10dip"
+        android:layout_marginTop="10dip"
+        android:layout_marginRight="10dip"
+        android:layout_marginBottom="10dip" >
+
+        <TextView android:id="@+id/sessionText"
+            android:layout_width="fill_parent"
+            android:layout_height="fill_parent"
+            android:layout_weight="0.5"
+            android:layout_gravity="center_vertical|left"
+            android:text="@string/session"
+            style="@android:style/TextAppearance.Medium" />
+
+        <EditText android:id="@+id/sessionEdit"
+            android:layout_width="fill_parent"
+            android:layout_height="wrap_content"
+            android:layout_weight="0.5"
+            android:layout_gravity="center_vertical|right" />
+    </LinearLayout>
+
+    <ImageView
+         android:src="@android:drawable/divider_horizontal_dark"
+         android:layout_width="fill_parent"
+         android:layout_height="wrap_content"
+         android:scaleType="fitXY"/>
+
+    <ScrollView
+        android:layout_width="fill_parent"
+        android:layout_height="wrap_content" >
+
+        <LinearLayout
+            android:layout_width="fill_parent"
+            android:layout_height="wrap_content"
+            android:orientation="vertical">
+
+            <LinearLayout
+                android:layout_width="fill_parent"
+                android:layout_height="wrap_content"
+                android:gravity="center_horizontal"
+                android:orientation="vertical"
+                android:layout_marginLeft="10dip"
+                android:layout_marginTop="10dip"
+                android:layout_marginRight="10dip"
+                android:layout_marginBottom="10dip"
+                >
+
+                <TextView android:id="@+id/virtStrengthName"
+                    android:layout_width="fill_parent"
+                    android:layout_height="wrap_content"
+                    android:text="@string/stength_name" />
+
+                <LinearLayout android:id="@+id/virtStrengthDesc"
+                    android:orientation="horizontal"
+                    android:layout_width="fill_parent"
+                    android:layout_height="wrap_content"
+                    android:layout_marginLeft="10dip"
+                    android:layout_marginTop="10dip"
+                    android:layout_marginRight="30dip"
+                    android:layout_marginBottom="10dip" >
+
+                    <TextView android:id="@+id/virtStrengthMin"
+                        android:layout_width="fill_parent"
+                        android:layout_height="fill_parent"
+                        android:layout_weight="1"
+                        android:layout_gravity="left"
+                        android:gravity="left"/>
+                    <TextView android:id="@+id/virtStrengthMax"
+                        android:layout_width="fill_parent"
+                        android:layout_height="fill_parent"
+                        android:layout_weight="1"
+                        android:layout_gravity="right"
+                        android:gravity="right"/>
+                </LinearLayout>
+
+                <SeekBar android:id="@+id/virtStrengthSeekBar"
+                    android:layout_width="fill_parent"
+                    android:layout_height="wrap_content"
+                    android:max="100"
+                    android:progress="50"
+                    android:layout_marginLeft="10dip"
+                    android:layout_marginRight="30dip" />
+
+                <TextView android:id="@+id/virtStrengthValue"
+                    android:layout_width="fill_parent"
+                    android:layout_height="wrap_content" />
+
+            </LinearLayout>
+
+            <ImageView
+                 android:src="@android:drawable/divider_horizontal_dark"
+                 android:layout_width="fill_parent"
+                 android:layout_height="wrap_content"
+                 android:scaleType="fitXY"/>
+
+        </LinearLayout>
+
+    </ScrollView>
+
+</LinearLayout>
diff --git a/media/tests/EffectsTest/res/layout/visualizertest.xml b/media/tests/EffectsTest/res/layout/visualizertest.xml
new file mode 100755
index 0000000..8611e8c
--- /dev/null
+++ b/media/tests/EffectsTest/res/layout/visualizertest.xml
@@ -0,0 +1,261 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2009 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="fill_parent"
+    android:layout_height="fill_parent"
+    android:orientation="vertical">
+
+    <ImageView
+         android:src="@android:drawable/divider_horizontal_dark"
+         android:layout_width="fill_parent"
+         android:layout_height="wrap_content"
+         android:scaleType="fitXY"/>
+
+    <LinearLayout android:id="@+id/visuReleaseLayout"
+        android:orientation="horizontal"
+        android:layout_width="fill_parent"
+        android:layout_height="wrap_content"
+        android:layout_marginLeft="10dip"
+        android:layout_marginTop="10dip"
+        android:layout_marginRight="10dip"
+        android:layout_marginBottom="10dip" >
+
+        <TextView android:id="@+id/visuReleaseText"
+            android:layout_width="fill_parent"
+            android:layout_height="fill_parent"
+            android:layout_weight="1.0"
+            android:layout_gravity="center_vertical|left"
+            android:text="@string/effect_release"
+            style="@android:style/TextAppearance.Medium" />
+
+        <ToggleButton android:id="@+id/visuReleaseButton"
+            android:layout_width="wrap_content"
+            android:layout_height="fill_parent"
+            android:layout_gravity="center_vertical|right"
+            android:layout_weight="0.0" />
+
+    </LinearLayout>
+
+    <ImageView
+         android:src="@android:drawable/divider_horizontal_dark"
+         android:layout_width="fill_parent"
+         android:layout_height="wrap_content"
+         android:scaleType="fitXY"/>
+
+    <LinearLayout android:id="@+id/visuControlLayout"
+        android:orientation="horizontal"
+        android:layout_width="fill_parent"
+        android:layout_height="wrap_content"
+        android:layout_marginLeft="10dip"
+        android:layout_marginTop="10dip"
+        android:layout_marginRight="10dip"
+        android:layout_marginBottom="10dip" >
+
+        <TextView android:id="@+id/visuControlText"
+            android:layout_width="fill_parent"
+            android:layout_height="fill_parent"
+            android:layout_weight="1.0"
+            android:layout_gravity="center_vertical|left"
+            android:text="@string/effect_control"
+            style="@android:style/TextAppearance.Medium" />
+
+        <ToggleButton android:id="@+id/visualizerOnOff"
+            android:layout_width="wrap_content"
+            android:layout_height="fill_parent"
+            android:layout_gravity="center_vertical|right"
+            android:layout_weight="0.0" />
+
+    </LinearLayout>
+
+    <ImageView
+         android:src="@android:drawable/divider_horizontal_dark"
+         android:layout_width="fill_parent"
+         android:layout_height="wrap_content"
+         android:scaleType="fitXY"/>
+
+    <LinearLayout android:id="@+id/SessionFrame"
+          android:orientation="horizontal"
+          android:layout_width="fill_parent"
+          android:layout_height="wrap_content"
+          android:layout_marginLeft="10dip"
+          android:layout_marginTop="10dip"
+          android:layout_marginRight="10dip"
+          android:layout_marginBottom="10dip" >
+
+        <TextView android:id="@+id/sessionText"
+            android:layout_width="fill_parent"
+            android:layout_height="fill_parent"
+            android:layout_weight="0.5"
+            android:layout_gravity="center_vertical|left"
+            android:text="@string/session"
+            style="@android:style/TextAppearance.Medium" />
+
+        <EditText android:id="@+id/sessionEdit"
+            android:layout_width="fill_parent"
+            android:layout_height="wrap_content"
+            android:layout_weight="0.5"
+            android:layout_gravity="center_vertical|right" />
+    </LinearLayout>
+
+    <ImageView
+         android:src="@android:drawable/divider_horizontal_dark"
+         android:layout_width="fill_parent"
+         android:layout_height="wrap_content"
+         android:scaleType="fitXY"/>
+
+    <LinearLayout android:id="@+id/visuCallbackLayout"
+        android:orientation="horizontal"
+        android:layout_width="fill_parent"
+        android:layout_height="wrap_content"
+        android:layout_marginLeft="10dip"
+        android:layout_marginTop="10dip"
+        android:layout_marginRight="10dip"
+        android:layout_marginBottom="10dip" >
+
+        <TextView android:id="@+id/visuCallbackText"
+            android:layout_width="fill_parent"
+            android:layout_height="fill_parent"
+          android:layout_weight="1.0"
+          android:layout_gravity="center_vertical|left"
+            android:text="@string/visu_callback"
+            style="@android:style/TextAppearance.Medium" />
+
+        <ToggleButton android:id="@+id/visuCallbackOnOff"
+            android:layout_width="wrap_content"
+            android:layout_height="fill_parent"
+          android:layout_gravity="center_vertical|right"
+          android:layout_weight="0.0" />
+
+    </LinearLayout>
+
+    <ImageView
+         android:src="@android:drawable/divider_horizontal_dark"
+         android:layout_width="fill_parent"
+         android:layout_height="wrap_content"
+         android:scaleType="fitXY"/>
+
+    <ScrollView
+        android:layout_width="fill_parent"
+        android:layout_height="wrap_content" >
+
+        <LinearLayout
+            android:layout_width="fill_parent"
+            android:layout_height="wrap_content"
+            android:orientation="vertical">
+
+            <LinearLayout
+            android:layout_width="fill_parent"
+            android:layout_height="wrap_content"
+            android:gravity="center_horizontal"
+            android:orientation="vertical"
+            android:layout_marginLeft="10dip"
+            android:layout_marginTop="10dip"
+            android:layout_marginRight="10dip"
+            android:layout_marginBottom="10dip"
+                >
+
+                <TextView android:id="@+id/waveformName"
+                    android:layout_width="fill_parent"
+                    android:layout_height="wrap_content"
+                    android:text="@string/waveform_name" />
+
+          <LinearLayout android:id="@+id/eqParam1Desc"
+              android:orientation="horizontal"
+              android:layout_width="fill_parent"
+              android:layout_height="wrap_content"
+              android:layout_marginLeft="10dip"
+              android:layout_marginTop="10dip"
+              android:layout_marginRight="10dip"
+              android:layout_marginBottom="10dip" >
+
+            <TextView android:id="@+id/waveformMin"
+                android:layout_width="fill_parent"
+                android:layout_height="fill_parent"
+                android:layout_weight="1.0" />
+            <TextView android:id="@+id/waveformCenter"
+                android:layout_width="fill_parent"
+                android:layout_height="fill_parent"
+                android:layout_weight="1.0" />
+            <TextView android:id="@+id/waveformMax"
+                android:layout_width="fill_parent"
+                android:layout_height="fill_parent"
+                android:layout_weight="1.0" />
+
+          </LinearLayout>
+
+            </LinearLayout>
+
+            <ImageView
+                 android:src="@android:drawable/divider_horizontal_dark"
+                 android:layout_width="fill_parent"
+                 android:layout_height="wrap_content"
+                 android:scaleType="fitXY"/>
+
+        <LinearLayout
+            android:layout_width="fill_parent"
+            android:layout_height="wrap_content"
+            android:gravity="center_horizontal"
+            android:orientation="vertical"
+            android:layout_marginLeft="10dip"
+            android:layout_marginTop="10dip"
+            android:layout_marginRight="10dip"
+            android:layout_marginBottom="10dip"
+            >
+
+          <TextView android:id="@+id/fftName"
+              android:layout_width="fill_parent"
+              android:layout_height="wrap_content"
+              android:text="@string/fft_name" />
+
+          <LinearLayout android:id="@+id/eqParam1Desc"
+              android:orientation="horizontal"
+              android:layout_width="fill_parent"
+              android:layout_height="wrap_content"
+              android:layout_marginLeft="10dip"
+              android:layout_marginTop="10dip"
+              android:layout_marginRight="10dip"
+              android:layout_marginBottom="10dip" >
+
+            <TextView android:id="@+id/fftMin"
+                android:layout_width="fill_parent"
+                android:layout_height="fill_parent"
+                android:layout_weight="1.0" />
+            <TextView android:id="@+id/fftCenter"
+                android:layout_width="fill_parent"
+                android:layout_height="fill_parent"
+                android:layout_weight="1.0" />
+            <TextView android:id="@+id/fftMax"
+                android:layout_width="fill_parent"
+                android:layout_height="fill_parent"
+                android:layout_weight="1.0" />
+
+          </LinearLayout>
+
+        </LinearLayout>
+
+        <ImageView
+             android:src="@android:drawable/divider_horizontal_dark"
+             android:layout_width="fill_parent"
+             android:layout_height="wrap_content"
+             android:scaleType="fitXY"/>
+
+
+        </LinearLayout>
+
+    </ScrollView>
+
+</LinearLayout>
diff --git a/media/tests/EffectsTest/res/raw/mp3_sample.mp3 b/media/tests/EffectsTest/res/raw/mp3_sample.mp3
new file mode 100644
index 0000000..a9d8635
--- /dev/null
+++ b/media/tests/EffectsTest/res/raw/mp3_sample.mp3
Binary files differ
diff --git a/media/tests/EffectsTest/res/raw/sine440_mo_16b_16k.wav b/media/tests/EffectsTest/res/raw/sine440_mo_16b_16k.wav
new file mode 100644
index 0000000..2538b4d6
--- /dev/null
+++ b/media/tests/EffectsTest/res/raw/sine440_mo_16b_16k.wav
Binary files differ
diff --git a/media/tests/EffectsTest/res/values/strings.xml b/media/tests/EffectsTest/res/values/strings.xml
new file mode 100755
index 0000000..2a85184
--- /dev/null
+++ b/media/tests/EffectsTest/res/values/strings.xml
@@ -0,0 +1,38 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+    <string name="app_name">Effects Test</string>
+    <string name="effect_control">Effect State</string>
+    <string name="effect_release">Effect Instantiated</string>
+    <string name="effect_bypass">Bypass</string>
+    <string name="envreverb_test_name">Environmental Reverb Test</string>
+    <string name="rvb_param_1_name">Room Level</string>
+    <string name="rvb_param_2_name">Room HF Level</string>
+    <string name="rvb_param_3_name">Decay Time</string>
+    <string name="rvb_param_4_name">Decay HF Ratio</string>
+    <string name="rvb_param_5_name">Reflections Level</string>
+    <string name="rvb_param_6_name">Reflections Delay</string>
+    <string name="rvb_param_7_name">Reverb Level</string>
+    <string name="rvb_param_8_name">Reverb Delay</string>
+    <string name="rvb_param_9_name">Diffusion</string>
+    <string name="rvb_param_10_name">Density</string>
+    <string name="presetrvb_test_name">Preset Reverb Test</string>
+    <string name="presetrvb_param_1_name">Presets</string>
+    <string name="equalizer_test_name">Equalizer Test</string>
+    <string name="session">Audio Session</string>
+    <string name="eq_param_1_name">Band 1 Level</string>
+    <string name="eq_param_2_name">Band 2 Level</string>
+    <string name="eq_param_3_name">Band 3 Level</string>
+    <string name="eq_param_4_name">Band 4 Level</string>
+    <string name="eq_param_5_name">Band 5 Level</string>
+    <string name="eq_param_6_name">Presets</string>
+    <string name="virtualizer_test_name">Virtualizer Test</string>
+    <string name="stength_name">Strength</string>
+    <string name="bassboost_test_name">Bass Boost Test</string>
+    <string name="visualizer_test_name">Visualizer Test</string>
+    <string name="visu_callback">Callback Mode</string>
+    <string name="waveform_name">PCM capture</string>
+    <string name="fft_name">FFT Capture</string>
+    <string name="effect_attach_off">Attach</string>
+    <string name="effect_attach_on">Detach</string>
+    <string name="send_level_name">Send Level</string>
+</resources>
diff --git a/media/tests/EffectsTest/src/com/android/effectstest/BassBoostTest.java b/media/tests/EffectsTest/src/com/android/effectstest/BassBoostTest.java
new file mode 100755
index 0000000..1a10d64
--- /dev/null
+++ b/media/tests/EffectsTest/src/com/android/effectstest/BassBoostTest.java
@@ -0,0 +1,276 @@
+/*
+ * Copyright (C) 2009 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.effectstest;
+
+import android.app.Activity;
+import android.content.Context;
+import android.content.Intent;
+import android.os.Bundle;
+import android.util.Log;
+import android.view.KeyEvent;
+import android.view.Menu;
+import android.view.View.OnClickListener;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.Button;
+import android.widget.TextView;
+import android.widget.EditText;
+import android.widget.SeekBar;
+import android.widget.ToggleButton;
+import android.widget.CompoundButton;
+import android.widget.CompoundButton.OnCheckedChangeListener;
+import java.nio.ByteOrder;
+import java.nio.ByteBuffer;
+import java.util.HashMap;
+import java.util.Map;
+
+import android.media.audiofx.BassBoost;
+import android.media.audiofx.AudioEffect;
+
+public class BassBoostTest extends Activity implements OnCheckedChangeListener {
+
+    private final static String TAG = "BassBoostTest";
+
+    private static int NUM_PARAMS = 1;
+
+    private EffectParameter mStrength;
+    private BassBoost mBassBoost = null;
+    ToggleButton mOnOffButton;
+    ToggleButton mReleaseButton;
+    EditText mSessionText;
+    static int sSession = 0;
+    EffectListner mEffectListener = new EffectListner();
+    private static HashMap<Integer, BassBoost> sInstances = new HashMap<Integer, BassBoost>(10);
+    String mSettings = "";
+
+    public BassBoostTest() {
+        Log.d(TAG, "contructor");
+    }
+
+    @Override
+    public void onCreate(Bundle icicle) {
+        super.onCreate(icicle);
+
+        SeekBar seekBar;
+        TextView textView;
+
+        setContentView(R.layout.bassboosttest);
+
+        mSessionText = (EditText) findViewById(R.id.sessionEdit);
+        mSessionText.setOnKeyListener(mSessionKeyListener);
+
+        mSessionText.setText(Integer.toString(sSession));
+
+        mReleaseButton = (ToggleButton)findViewById(R.id.bbReleaseButton);
+        mOnOffButton = (ToggleButton)findViewById(R.id.bassboostOnOff);
+
+        getEffect(sSession);
+
+        if (mBassBoost != null) {
+            mReleaseButton.setOnCheckedChangeListener(this);
+            mOnOffButton.setOnCheckedChangeListener(this);
+
+            textView = (TextView)findViewById(R.id.bbStrengthMin);
+            textView.setText("0");
+            textView = (TextView)findViewById(R.id.bbStrengthMax);
+            textView.setText("1000");
+            seekBar = (SeekBar)findViewById(R.id.bbStrengthSeekBar);
+            textView = (TextView)findViewById(R.id.bbStrengthValue);
+            mStrength = new BassBoostParam(mBassBoost, 0, 1000, seekBar, textView);
+            seekBar.setOnSeekBarChangeListener(mStrength);
+            mStrength.setEnabled(mBassBoost.getStrengthSupported());
+        }
+    }
+
+    @Override
+    public void onResume() {
+        super.onResume();
+    }
+
+    @Override
+    public void onPause() {
+        super.onPause();
+    }
+
+    private View.OnKeyListener mSessionKeyListener
+    = new View.OnKeyListener() {
+        public boolean onKey(View v, int keyCode, KeyEvent event) {
+            Log.d(TAG, "onKey() keyCode: "+keyCode+" event.getAction(): "+event.getAction());
+            if (event.getAction() == KeyEvent.ACTION_DOWN) {
+                switch (keyCode) {
+                    case KeyEvent.KEYCODE_DPAD_CENTER:
+                    case KeyEvent.KEYCODE_ENTER:
+                        try {
+                            sSession = Integer.parseInt(mSessionText.getText().toString());
+                            getEffect(sSession);
+                            if (mBassBoost != null) {
+                                mStrength.setEffect(mBassBoost);
+                                mStrength.setEnabled(mBassBoost.getStrengthSupported());
+                            }
+                        } catch (NumberFormatException e) {
+                            Log.d(TAG, "Invalid session #: "+mSessionText.getText().toString());
+                        }
+                        return true;
+                }
+            }
+            return false;
+        }
+    };
+
+    // OnCheckedChangeListener
+    public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
+        if (buttonView.getId() == R.id.bassboostOnOff) {
+            if (mBassBoost != null) {
+                mBassBoost.setEnabled(isChecked);
+                mStrength.updateDisplay();
+            }
+        }
+        if (buttonView.getId() == R.id.bbReleaseButton) {
+            if (isChecked) {
+                if (mBassBoost == null) {
+                    getEffect(sSession);
+                    if (mBassBoost != null) {
+                        mStrength.setEffect(mBassBoost);
+                        mStrength.setEnabled(mBassBoost.getStrengthSupported());
+                    }
+                }
+            } else {
+                if (mBassBoost != null) {
+                    mStrength.setEnabled(false);
+                    putEffect(sSession);
+                }
+            }
+        }
+    }
+
+    private class BassBoostParam extends EffectParameter {
+        private BassBoost mBassBoost;
+
+        public BassBoostParam(BassBoost bassboost, int min, int max, SeekBar seekBar, TextView textView) {
+            super (min, max, seekBar, textView, "o/oo");
+
+            mBassBoost = bassboost;
+            updateDisplay();
+        }
+
+        @Override
+        public void setParameter(Integer value) {
+            if (mBassBoost != null) {
+                mBassBoost.setStrength(value.shortValue());
+            }
+        }
+
+        @Override
+        public Integer getParameter() {
+            if (mBassBoost != null) {
+                return new Integer(mBassBoost.getRoundedStrength());
+            }
+            return new Integer(0);
+        }
+
+        @Override
+        public void setEffect(Object effect) {
+            mBassBoost = (BassBoost)effect;
+        }
+    }
+
+    public class EffectListner implements AudioEffect.OnEnableStatusChangeListener,
+        AudioEffect.OnControlStatusChangeListener, AudioEffect.OnParameterChangeListener
+   {
+        public EffectListner() {
+        }
+        public void onEnableStatusChange(AudioEffect effect, boolean enabled) {
+            Log.d(TAG,"onEnableStatusChange: "+ enabled);
+        }
+        public void onControlStatusChange(AudioEffect effect, boolean controlGranted) {
+            Log.d(TAG,"onControlStatusChange: "+ controlGranted);
+        }
+        public void onParameterChange(AudioEffect effect, int status, byte[] param, byte[] value) {
+            int p = byteArrayToInt(param, 0);
+            short v = byteArrayToShort(value, 0);
+
+            Log.d(TAG,"onParameterChange, status: "+status+" p: "+p+" v: "+v);
+        }
+
+        private int byteArrayToInt(byte[] valueBuf, int offset) {
+            ByteBuffer converter = ByteBuffer.wrap(valueBuf);
+            converter.order(ByteOrder.nativeOrder());
+            return converter.getInt(offset);
+
+        }
+        private short byteArrayToShort(byte[] valueBuf, int offset) {
+            ByteBuffer converter = ByteBuffer.wrap(valueBuf);
+            converter.order(ByteOrder.nativeOrder());
+            return converter.getShort(offset);
+
+        }
+
+    }
+
+    private void getEffect(int session) {
+        synchronized (sInstances) {
+            if (sInstances.containsKey(session)) {
+                mBassBoost = sInstances.get(session);
+            } else {
+                try{
+                    mBassBoost = new BassBoost(0, session);
+                } catch (IllegalArgumentException e) {
+                    Log.e(TAG,"BassBoost effect not supported");
+                } catch (IllegalStateException e) {
+                    Log.e(TAG,"BassBoost cannot get strength supported");
+                } catch (UnsupportedOperationException e) {
+                    Log.e(TAG,"BassBoost library not loaded");
+                } catch (RuntimeException e) {
+                    Log.e(TAG,"BassBoost effect not found");
+                }
+                sInstances.put(session, mBassBoost);
+            }
+            mReleaseButton.setEnabled(false);
+            mOnOffButton.setEnabled(false);
+
+            if (mBassBoost != null) {
+                if (mSettings != "") {
+                    mBassBoost.setProperties(new BassBoost.Settings(mSettings));
+                }
+                mBassBoost.setEnableStatusListener(mEffectListener);
+                mBassBoost.setControlStatusListener(mEffectListener);
+                mBassBoost.setParameterListener(mEffectListener);
+
+                mReleaseButton.setChecked(true);
+                mReleaseButton.setEnabled(true);
+
+                mOnOffButton.setChecked(mBassBoost.getEnabled());
+                mOnOffButton.setEnabled(true);
+            }
+        }
+    }
+
+    private void putEffect(int session) {
+        mOnOffButton.setChecked(false);
+        mOnOffButton.setEnabled(false);
+        synchronized (sInstances) {
+            if (mBassBoost != null) {
+                mSettings = mBassBoost.getProperties().toString();
+                mBassBoost.release();
+                Log.d(TAG,"BassBoost released");
+                mBassBoost = null;
+                sInstances.remove(session);
+            }
+        }
+    }
+
+}
diff --git a/media/tests/EffectsTest/src/com/android/effectstest/EffectParameter.java b/media/tests/EffectsTest/src/com/android/effectstest/EffectParameter.java
new file mode 100755
index 0000000..95077e7
--- /dev/null
+++ b/media/tests/EffectsTest/src/com/android/effectstest/EffectParameter.java
@@ -0,0 +1,89 @@
+/*
+ * Copyright (C) 2009 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.effectstest;
+
+import android.os.Bundle;
+import android.util.Log;
+import android.widget.TextView;
+import android.widget.SeekBar;
+
+
+abstract class EffectParameter implements SeekBar.OnSeekBarChangeListener {
+
+    private final static String TAG = "EffectParameter";
+
+    protected int mMin;
+    protected int mMax;
+    protected String mUnit;
+    protected SeekBar mSeekBar;
+    protected TextView mValueText;
+
+    public EffectParameter (int min, int max, SeekBar seekBar, TextView textView, String unit) {
+        mMin = min;
+        mMax = max;
+        mSeekBar = seekBar;
+        mValueText = textView;
+        mUnit = unit;
+        byte[] paramBuf = new byte[4];
+
+        mSeekBar.setMax(max-min);
+    }
+
+    public void displayValue(int value, boolean fromTouch) {
+        String text = Integer.toString(value)+" "+mUnit;
+        mValueText.setText(text);
+        if (!fromTouch) {
+            mSeekBar.setProgress(value - mMin);
+        }
+    }
+
+    public void updateDisplay() {
+        displayValue(getParameter(), false);
+    }
+
+    public abstract void setParameter(Integer value);
+
+    public abstract Integer getParameter();
+
+    public abstract void setEffect(Object effect);
+
+    // SeekBar.OnSeekBarChangeListener
+    public void onProgressChanged(SeekBar seekBar, int progress, boolean fromTouch) {
+
+        if (seekBar != mSeekBar) {
+            Log.e(TAG, "onProgressChanged called with wrong seekBar");
+            return;
+        }
+
+        int value = progress + mMin;
+        if (fromTouch) {
+            setParameter(value);
+        }
+
+        displayValue(getParameter(), fromTouch);
+    }
+
+    public void onStartTrackingTouch(SeekBar seekBar) {
+    }
+
+    public void onStopTrackingTouch(SeekBar seekBar) {
+    }
+
+    public void setEnabled(boolean e) {
+        mSeekBar.setEnabled(e);
+    }
+}
diff --git a/media/tests/EffectsTest/src/com/android/effectstest/EffectsTest.java b/media/tests/EffectsTest/src/com/android/effectstest/EffectsTest.java
new file mode 100755
index 0000000..6612766
--- /dev/null
+++ b/media/tests/EffectsTest/src/com/android/effectstest/EffectsTest.java
@@ -0,0 +1,185 @@
+/*
+ * Copyright (C) 2009 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.effectstest;
+
+import android.app.Activity;
+import android.content.Context;
+import android.content.Intent;
+import android.os.Bundle;
+import android.util.Log;
+import android.view.KeyEvent;
+import android.view.Menu;
+import android.view.View.OnClickListener;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.Button;
+import android.widget.TextView;
+import android.widget.ListView;
+import android.widget.BaseAdapter;
+import android.widget.LinearLayout;
+import android.media.audiofx.AudioEffect;
+import java.util.UUID;
+
+public class EffectsTest extends Activity {
+
+    private final static String TAG = "EffectsTest";
+
+
+    public EffectsTest() {
+        Log.d(TAG, "contructor");
+    }
+
+    @Override
+    public void onCreate(Bundle icicle) {
+        super.onCreate(icicle);
+        setContentView(R.layout.effectstest);
+
+        Button button = (Button) findViewById(R.id.env_reverb_actvity);
+        button.setOnClickListener(new OnClickListener() {
+            public void onClick(View v) {
+                startActivity(new Intent(EffectsTest.this, EnvReverbTest.class));
+            }
+        });
+
+        button = (Button) findViewById(R.id.preset_reverb_actvity);
+        button.setOnClickListener(new OnClickListener() {
+            public void onClick(View v) {
+                startActivity(new Intent(EffectsTest.this, PresetReverbTest.class));
+            }
+        });
+
+        button = (Button) findViewById(R.id.equalizer_actvity);
+        button.setOnClickListener(new OnClickListener() {
+            public void onClick(View v) {
+                startActivity(new Intent(EffectsTest.this, EqualizerTest.class));
+            }
+        });
+
+        button = (Button) findViewById(R.id.virtualizer_actvity);
+        button.setOnClickListener(new OnClickListener() {
+            public void onClick(View v) {
+                startActivity(new Intent(EffectsTest.this, VirtualizerTest.class));
+            }
+        });
+
+        button = (Button) findViewById(R.id.bassboost_actvity);
+        button.setOnClickListener(new OnClickListener() {
+            public void onClick(View v) {
+                startActivity(new Intent(EffectsTest.this, BassBoostTest.class));
+            }
+        });
+
+        button = (Button) findViewById(R.id.visualizer_actvity);
+        button.setOnClickListener(new OnClickListener() {
+            public void onClick(View v) {
+                startActivity(new Intent(EffectsTest.this, VisualizerTest.class));
+            }
+        });
+
+        AudioEffect.Descriptor[] descriptors = AudioEffect.queryEffects();
+
+        ListView list = (ListView) findViewById(R.id.effect_list);
+        list.setAdapter(new EffectListAdapter(this, descriptors));
+
+    }
+
+    private class EffectListAdapter extends BaseAdapter {
+
+        private Context mContext;
+
+        AudioEffect.Descriptor[] mDescriptors;
+
+        public EffectListAdapter(Context context, AudioEffect.Descriptor[] descriptors) {
+            Log.d(TAG, "EffectListAdapter contructor");
+            mContext = context;
+            mDescriptors = descriptors;
+            for (int i = 0; i < mDescriptors.length; i++) {
+                Log.d(TAG, "Effect: "+i+" name: "+ mDescriptors[i].name);
+            }
+        }
+
+         public int getCount() {
+            Log.d(TAG, "EffectListAdapter getCount(): "+mDescriptors.length);
+            return mDescriptors.length;
+        }
+
+        public Object getItem(int position) {
+            Log.d(TAG, "EffectListAdapter getItem() at: "+position+" name: "
+                    +mDescriptors[position].name);
+            return mDescriptors[position];
+        }
+
+        public long getItemId(int position) {
+            return position;
+        }
+
+        public View getView(int position, View convertView, ViewGroup parent) {
+            EffectView ev;
+            if (convertView == null) {
+                Log.d(TAG, "getView() new EffectView position: " + position);
+                ev = new EffectView(mContext, mDescriptors);
+            } else {
+                Log.d(TAG, "getView() convertView position: " + position);
+                ev = new EffectView(mContext, mDescriptors);
+                //ev = (EffectView) convertView;
+            }
+            ev.set(position);
+            return ev;
+        }
+    }
+
+    private class EffectView extends LinearLayout {
+        private Context mContext;
+        AudioEffect.Descriptor[] mDescriptors;
+
+        public EffectView(Context context, AudioEffect.Descriptor[] descriptors) {
+            super(context);
+
+            mContext = context;
+            mDescriptors = descriptors;
+            this.setOrientation(VERTICAL);
+        }
+
+        public void set(int position) {
+            TextView tv = new TextView(mContext);
+            tv.setText("Effect "+ position);
+            addView(tv, new LinearLayout.LayoutParams(
+                    LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT));
+            tv = new TextView(mContext);
+            tv.setText(" type: "+ mDescriptors[position].type.toString());
+            addView(tv, new LinearLayout.LayoutParams(
+                    LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT));
+            tv = new TextView(mContext);
+            tv.setText(" uuid: "+ mDescriptors[position].uuid.toString());
+            addView(tv, new LinearLayout.LayoutParams(
+                    LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT));
+            tv = new TextView(mContext);
+            tv.setText(" name: "+ mDescriptors[position].name);
+            addView(tv, new LinearLayout.LayoutParams(
+                    LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT));
+            tv = new TextView(mContext);
+            tv.setText(" vendor: "+ mDescriptors[position].implementor);
+            addView(tv, new LinearLayout.LayoutParams(
+                    LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT));
+            tv = new TextView(mContext);
+            tv.setText(" mode: "+ mDescriptors[position].connectMode);
+            addView(tv, new LinearLayout.LayoutParams(
+                    LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT));
+        }
+    }
+
+}
diff --git a/media/tests/EffectsTest/src/com/android/effectstest/EnvReverbTest.java b/media/tests/EffectsTest/src/com/android/effectstest/EnvReverbTest.java
new file mode 100755
index 0000000..594e844
--- /dev/null
+++ b/media/tests/EffectsTest/src/com/android/effectstest/EnvReverbTest.java
@@ -0,0 +1,568 @@
+/*
+ * Copyright (C) 2009 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.effectstest;
+
+import android.app.Activity;
+import android.content.Context;
+import android.content.Intent;
+import android.os.Bundle;
+import android.util.Log;
+import android.view.KeyEvent;
+import android.view.Menu;
+import android.view.View.OnClickListener;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.Button;
+import android.widget.TextView;
+import android.widget.SeekBar;
+import android.widget.ToggleButton;
+import android.widget.CompoundButton;
+import android.widget.CompoundButton.OnCheckedChangeListener;
+import android.widget.ImageButton;
+import android.widget.ImageView;
+import java.util.HashMap;
+import java.util.Map;
+
+import android.media.audiofx.EnvironmentalReverb;
+import android.media.audiofx.AudioEffect;
+import android.media.AudioManager;
+
+public class EnvReverbTest extends Activity implements OnCheckedChangeListener, SeekBar.OnSeekBarChangeListener {
+
+    private final static String TAG = "EnvReverbTest";
+
+    private static int NUM_PARAMS = 10;
+
+    private EffectParameter[] mParameters = new EffectParameter[NUM_PARAMS];
+    private EnvironmentalReverb mReverb;
+    ToggleButton mOnOffButton;
+    ToggleButton mReleaseButton;
+    ToggleButton mAttachButton;
+    private static HashMap<Integer, EnvironmentalReverb> sInstances = new HashMap<Integer, EnvironmentalReverb>(10);
+    static SimplePlayer sPlayerController = null;
+    SeekBar mSendLevelSeekBar;
+    TextView mSendLevelDisplay;
+    static float sSendLevel = linToExp(50,100);
+    static boolean sAttached = false;
+    String mSettings = "";
+
+    public EnvReverbTest() {
+        Log.d(TAG, "contructor");
+    }
+
+    @Override
+    public void onCreate(Bundle icicle) {
+        super.onCreate(icicle);
+        Log.d(TAG, "onCreate");
+        SeekBar seekBar;
+        TextView textView;
+        ToggleButton button;
+        setContentView(R.layout.envreverbtest);
+
+        ImageView playPause = (ImageView) findViewById(R.id.playPause1);
+        ImageView stop = (ImageView) findViewById(R.id.stop1);
+        textView = (TextView) findViewById(R.id.sessionText);
+        if (sPlayerController == null) {
+            sPlayerController = new SimplePlayer(this, R.id.playPause1, playPause,
+                    R.id.stop1, stop, textView,
+                    R.raw.mp3_sample, AudioManager.STREAM_MUSIC, 0);
+        } else {
+            sPlayerController.set(this, R.id.playPause1, playPause,
+                    R.id.stop1, stop, textView,
+                    AudioManager.STREAM_MUSIC, 0);
+        }
+
+        // send level
+        mSendLevelSeekBar = (SeekBar)findViewById(R.id.sendLevelSeekBar);
+        mSendLevelDisplay = (TextView)findViewById(R.id.sendLevelValue);
+        mSendLevelSeekBar.setMax(100);
+        mSendLevelSeekBar.setOnSeekBarChangeListener(this);
+        mSendLevelSeekBar.setProgress(expToLin(sSendLevel,100));
+        sPlayerController.setAuxEffectSendLevel(sSendLevel);
+
+        mOnOffButton = (ToggleButton)findViewById(R.id.rvbOnOff);
+        mReleaseButton = (ToggleButton)findViewById(R.id.rvbReleaseButton);
+        mAttachButton = (ToggleButton)findViewById(R.id.attachButton);
+
+        getEffect(0);
+
+        if (mReverb != null) {
+            mOnOffButton.setOnCheckedChangeListener(this);
+            mReleaseButton.setOnCheckedChangeListener(this);
+            mAttachButton.setOnCheckedChangeListener(this);
+
+//            button = (ToggleButton)findViewById(R.id.rvbBypass);
+//            button.setChecked(false);
+//            button.setOnCheckedChangeListener(this);
+
+            // Room level
+            seekBar = (SeekBar)findViewById(R.id.rvbParam1SeekBar);
+            textView = (TextView)findViewById(R.id.rvbParam1Value);
+            mParameters[0] = new RoomLevelParam(mReverb, seekBar, textView);
+            seekBar.setOnSeekBarChangeListener(mParameters[0]);
+
+            // Room HF level
+            seekBar = (SeekBar)findViewById(R.id.rvbParam2SeekBar);
+            textView = (TextView)findViewById(R.id.rvbParam2Value);
+            mParameters[1] = new RoomHFLevelParam(mReverb, seekBar, textView);
+            seekBar.setOnSeekBarChangeListener(mParameters[1]);
+
+            // Decay time
+            seekBar = (SeekBar)findViewById(R.id.rvbParam3SeekBar);
+            textView = (TextView)findViewById(R.id.rvbParam3Value);
+            mParameters[2] = new DecayTimeParam(mReverb, seekBar, textView);
+            seekBar.setOnSeekBarChangeListener(mParameters[2]);
+
+            // Decay HF ratio
+            seekBar = (SeekBar)findViewById(R.id.rvbParam4SeekBar);
+            textView = (TextView)findViewById(R.id.rvbParam4Value);
+            mParameters[3] = new DecayHFRatioParam(mReverb, seekBar, textView);
+            seekBar.setOnSeekBarChangeListener(mParameters[3]);
+
+            // Reflections level
+            seekBar = (SeekBar)findViewById(R.id.rvbParam5SeekBar);
+            textView = (TextView)findViewById(R.id.rvbParam5Value);
+            mParameters[4] = new ReflectionsLevelParam(mReverb, seekBar, textView);
+            seekBar.setOnSeekBarChangeListener(mParameters[4]);
+
+            // Reflections delay
+            seekBar = (SeekBar)findViewById(R.id.rvbParam6SeekBar);
+            textView = (TextView)findViewById(R.id.rvbParam6Value);
+            mParameters[5] = new ReflectionsDelayParam(mReverb, seekBar, textView);
+            seekBar.setOnSeekBarChangeListener(mParameters[5]);
+
+            // Reverb level
+            seekBar = (SeekBar)findViewById(R.id.rvbParam7SeekBar);
+            textView = (TextView)findViewById(R.id.rvbParam7Value);
+            mParameters[6] = new ReverbLevelParam(mReverb, seekBar, textView);
+            seekBar.setOnSeekBarChangeListener(mParameters[6]);
+
+            // Reverb delay
+            seekBar = (SeekBar)findViewById(R.id.rvbParam8SeekBar);
+            textView = (TextView)findViewById(R.id.rvbParam8Value);
+            mParameters[7] = new ReverbDelayParam(mReverb, seekBar, textView);
+            seekBar.setOnSeekBarChangeListener(mParameters[7]);
+
+            // Diffusion
+            seekBar = (SeekBar)findViewById(R.id.rvbParam9SeekBar);
+            textView = (TextView)findViewById(R.id.rvbParam9Value);
+            mParameters[8] = new DiffusionParam(mReverb, seekBar, textView);
+            seekBar.setOnSeekBarChangeListener(mParameters[8]);
+
+            // Density
+            seekBar = (SeekBar)findViewById(R.id.rvbParam10SeekBar);
+            textView = (TextView)findViewById(R.id.rvbParam10Value);
+            mParameters[9] = new DensityParam(mReverb, seekBar, textView);
+            seekBar.setOnSeekBarChangeListener(mParameters[9]);
+        }
+    }
+    @Override
+    public void onResume() {
+        super.onResume();
+        Log.d(TAG, "onResume");
+    }
+
+    @Override
+    public void onPause() {
+        super.onPause();
+    }
+
+    // OnCheckedChangeListener
+    public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
+        if (buttonView.getId() == R.id.rvbOnOff) {
+            if (mReverb != null) {
+                mReverb.setEnabled(isChecked);
+                Log.d(TAG,"onCheckedChanged: rvbOnOff");
+                for (int i = 0 ; i < mParameters.length; i++) {
+                    mParameters[i].updateDisplay();
+                }
+            }
+        }
+        if (buttonView.getId() == R.id.rvbReleaseButton) {
+            if (isChecked) {
+                if (mReverb == null) {
+                    getEffect(0);
+                    for (int i = 0 ; i < mParameters.length; i++) {
+                        mParameters[i].setEffect(mReverb);
+                        mParameters[i].setEnabled(true);
+                    }
+                }
+            } else {
+                if (mReverb != null) {
+                    for (int i = 0 ; i < mParameters.length; i++) {
+                        mParameters[i].setEnabled(false);
+                    }
+                    putEffect(0);
+                }
+            }
+        }
+//        if (buttonView.getId() == R.id.rvbBypass) {
+//            // REVERB_PARAM_BYPASS parametervalue is 11 in EffectEnvironmentalReverApi.h
+//            if (mReverb != null) {
+//                if (isChecked) {
+//                    mReverb.setParameter((int)11, (int)1);
+//                } else {
+//                    mReverb.setParameter((int)11, (int)0);
+//                }
+//            }
+//        }
+        if (buttonView.getId() == R.id.attachButton) {
+            if (mReverb != null) {
+                if (isChecked) {
+                    sPlayerController.attachAuxEffect(mReverb.getId());
+                    sAttached = true;
+                } else {
+                    sPlayerController.attachAuxEffect(0);
+                    sAttached = false;
+                }
+            }
+        }
+    }
+
+    // SeekBar.OnSeekBarChangeListener
+    public void onProgressChanged(SeekBar seekBar, int progress, boolean fromTouch) {
+
+        if (seekBar != mSendLevelSeekBar) {
+            Log.e(TAG, "onProgressChanged called with wrong seekBar");
+            return;
+        }
+
+        sSendLevel = linToExp(progress,100);
+        if (fromTouch) {
+            sPlayerController.setAuxEffectSendLevel(sSendLevel);
+        }
+        String text = Float.toString(sSendLevel);
+        mSendLevelDisplay.setText(text);
+        if (!fromTouch) {
+            seekBar.setProgress(progress);
+        }
+    }
+
+    static float linToExp(int lin, int range) {
+        if (lin == 0) return 0;
+        return (float)Math.pow((double)10,(double)72*(lin-range)/(20*range));
+    }
+
+    static int expToLin(float exp, int range) {
+        if (exp == 0) return 0;
+        return (int)(20*range*Math.log10((double)exp)/72 + range);
+    }
+
+    public void onStartTrackingTouch(SeekBar seekBar) {
+    }
+
+    public void onStopTrackingTouch(SeekBar seekBar) {
+    }
+
+    private class EnvReverbParam extends EffectParameter {
+        private EnvironmentalReverb mReverb;
+
+        public EnvReverbParam(EnvironmentalReverb reverb, int min, int max, SeekBar seekBar, TextView textView, String unit) {
+            super (min, max, seekBar, textView, unit);
+            mReverb = reverb;
+            updateDisplay();
+        }
+
+        @Override
+        public void setParameter(Integer value) {
+        }
+
+        @Override
+        public Integer getParameter() {
+            return new Integer(0);
+        }
+
+        @Override
+        public void setEffect(Object reverb) {
+            mReverb = (EnvironmentalReverb)reverb;
+        }
+    }
+
+    private class RoomLevelParam extends EnvReverbParam {
+
+        public RoomLevelParam(EnvironmentalReverb reverb, SeekBar seekBar, TextView textView) {
+            super (reverb, -9600, 0, seekBar, textView, "mB");
+        }
+
+        @Override
+        public void setParameter(Integer value) {
+            if (mReverb != null) {
+                mReverb.setRoomLevel(value.shortValue());
+            }
+        }
+
+        @Override
+        public Integer getParameter() {
+            if (mReverb != null) {
+                return new Integer(mReverb.getRoomLevel());
+            }
+            return new Integer(0);
+        }
+    }
+
+    private class RoomHFLevelParam extends EnvReverbParam {
+
+        public RoomHFLevelParam(EnvironmentalReverb reverb, SeekBar seekBar, TextView textView) {
+            super (reverb, -4000, 0, seekBar, textView, "mB");
+        }
+
+        @Override
+        public void setParameter(Integer value) {
+            if (mReverb != null) {
+                mReverb.setRoomHFLevel(value.shortValue());
+            }
+        }
+
+        @Override
+        public Integer getParameter() {
+            if (mReverb != null) {
+                return new Integer(mReverb.getRoomHFLevel());
+            }
+            return new Integer(0);
+        }
+    }
+
+    private class DecayTimeParam extends EnvReverbParam {
+
+        public DecayTimeParam(EnvironmentalReverb reverb, SeekBar seekBar, TextView textView) {
+            super (reverb, 200, 4000, seekBar, textView, "ms");
+        }
+
+        @Override
+        public void setParameter(Integer value) {
+            if (mReverb != null) {
+                mReverb.setDecayTime(value.intValue());
+            }
+        }
+
+        @Override
+        public Integer getParameter() {
+            if (mReverb != null) {
+                return mReverb.getDecayTime();
+            }
+            return new Integer(0);
+        }
+    }
+
+    private class DecayHFRatioParam extends EnvReverbParam {
+
+        public DecayHFRatioParam(EnvironmentalReverb reverb, SeekBar seekBar, TextView textView) {
+            super (reverb, 100, 1000, seekBar, textView, "permilles");
+        }
+
+        @Override
+        public void setParameter(Integer value) {
+            if (mReverb != null) {
+                mReverb.setDecayHFRatio(value.shortValue());
+            }
+        }
+
+        @Override
+        public Integer getParameter() {
+            if (mReverb != null) {
+                return new Integer(mReverb.getDecayHFRatio());
+            }
+            return new Integer(0);
+        }
+    }
+
+    private class ReflectionsLevelParam extends EnvReverbParam {
+
+        public ReflectionsLevelParam(EnvironmentalReverb reverb, SeekBar seekBar, TextView textView) {
+            super (reverb, -9600, 0, seekBar, textView, "mB");
+        }
+
+        @Override
+        public void setParameter(Integer value) {
+            if (mReverb != null) {
+                mReverb.setReflectionsLevel(value.shortValue());
+            }
+        }
+
+        @Override
+        public Integer getParameter() {
+            if (mReverb != null) {
+                return new Integer(mReverb.getReflectionsLevel());
+            }
+            return new Integer(0);
+        }
+    }
+
+    private class ReflectionsDelayParam extends EnvReverbParam {
+
+        public ReflectionsDelayParam(EnvironmentalReverb reverb, SeekBar seekBar, TextView textView) {
+            super (reverb, 0, 65, seekBar, textView, "ms");
+        }
+
+        @Override
+        public void setParameter(Integer value) {
+            if (mReverb != null) {
+                mReverb.setReflectionsDelay(value.intValue());
+            }
+        }
+
+        @Override
+        public Integer getParameter() {
+            if (mReverb != null) {
+                return mReverb.getReflectionsDelay();
+            }
+            return new Integer(0);
+        }
+    }
+
+    private class ReverbLevelParam extends EnvReverbParam {
+
+        public ReverbLevelParam(EnvironmentalReverb reverb, SeekBar seekBar, TextView textView) {
+            super (reverb, -9600, 2000, seekBar, textView, "mB");
+        }
+
+        @Override
+        public void setParameter(Integer value) {
+            if (mReverb != null) {
+                mReverb.setReverbLevel(value.shortValue());
+            }
+        }
+
+        @Override
+        public Integer getParameter() {
+            if (mReverb != null) {
+                return new Integer(mReverb.getReverbLevel());
+            }
+            return new Integer(0);
+        }
+    }
+
+    private class ReverbDelayParam extends EnvReverbParam {
+
+        public ReverbDelayParam(EnvironmentalReverb reverb, SeekBar seekBar, TextView textView) {
+            super (reverb, 0, 65, seekBar, textView, "ms");
+        }
+
+        @Override
+        public void setParameter(Integer value) {
+            if (mReverb != null) {
+                mReverb.setReverbDelay(value.intValue());
+            }
+        }
+
+        @Override
+        public Integer getParameter() {
+            if (mReverb != null) {
+                return mReverb.getReverbDelay();
+            }
+            return new Integer(0);
+        }
+    }
+
+    private class DiffusionParam extends EnvReverbParam {
+
+        public DiffusionParam(EnvironmentalReverb reverb, SeekBar seekBar, TextView textView) {
+            super (reverb, 0, 1000, seekBar, textView, "permilles");
+        }
+
+        @Override
+        public void setParameter(Integer value) {
+            if (mReverb != null) {
+                mReverb.setDiffusion(value.shortValue());
+            }
+        }
+
+        @Override
+        public Integer getParameter() {
+            if (mReverb != null) {
+                return new Integer(mReverb.getDiffusion());
+            }
+            return new Integer(0);
+        }
+    }
+
+    private class DensityParam extends EnvReverbParam {
+
+        public DensityParam(EnvironmentalReverb reverb, SeekBar seekBar, TextView textView) {
+            super (reverb, 0, 1000, seekBar, textView, "permilles");
+        }
+
+        @Override
+        public void setParameter(Integer value) {
+            if (mReverb != null) {
+                mReverb.setDensity(value.shortValue());
+            }
+        }
+
+        @Override
+        public Integer getParameter() {
+            if (mReverb != null) {
+                return new Integer(mReverb.getDensity());
+            }
+            return new Integer(0);
+        }
+    }
+
+    private void getEffect(int session) {
+        synchronized (sInstances) {
+            if (sInstances.containsKey(session)) {
+                mReverb = sInstances.get(session);
+            } else {
+                try{
+                    mReverb = new EnvironmentalReverb(0, session);
+                } catch (IllegalArgumentException e) {
+                    Log.e(TAG,"Reverb effect not supported");
+                } catch (UnsupportedOperationException e) {
+                    Log.e(TAG,"Reverb library not loaded");
+                } catch (RuntimeException e) {
+                    Log.e(TAG,"Reverb effect not found");
+                }
+                Log.d(TAG, "new reverb: "+mReverb);
+                sInstances.put(session, mReverb);
+            }
+        }
+        mReleaseButton.setEnabled(false);
+        mOnOffButton.setEnabled(false);
+        mAttachButton.setEnabled(false);
+        if (mReverb != null) {
+            if (mSettings != "") {
+                mReverb.setProperties(new EnvironmentalReverb.Settings(mSettings));
+            }
+            mReleaseButton.setChecked(true);
+            mReleaseButton.setEnabled(true);
+            mOnOffButton.setChecked(mReverb.getEnabled());
+            mOnOffButton.setEnabled(true);
+            mAttachButton.setChecked(false);
+            mAttachButton.setEnabled(true);
+            if (sAttached) {
+                mAttachButton.setChecked(true);
+                sPlayerController.attachAuxEffect(mReverb.getId());
+            }
+        }
+    }
+
+    private void putEffect(int session) {
+        mOnOffButton.setChecked(false);
+        mOnOffButton.setEnabled(false);
+        mAttachButton.setChecked(false);
+        mAttachButton.setEnabled(false);
+        synchronized (sInstances) {
+            if (mReverb != null) {
+                mSettings = mReverb.getProperties().toString();
+                mReverb.release();
+                Log.d(TAG,"Reverb released, settings: "+mSettings);
+                mReverb = null;
+                sInstances.remove(session);
+            }
+        }
+    }
+}
diff --git a/media/tests/EffectsTest/src/com/android/effectstest/EqualizerTest.java b/media/tests/EffectsTest/src/com/android/effectstest/EqualizerTest.java
new file mode 100755
index 0000000..f30a26f
--- /dev/null
+++ b/media/tests/EffectsTest/src/com/android/effectstest/EqualizerTest.java
@@ -0,0 +1,407 @@
+/*
+ * Copyright (C) 2009 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.effectstest;
+
+import android.app.Activity;
+import android.content.Context;
+import android.content.Intent;
+import android.os.Bundle;
+import android.util.Log;
+import android.view.KeyEvent;
+import android.view.Menu;
+import android.view.View.OnClickListener;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.Button;
+import android.widget.TextView;
+import android.widget.EditText;
+import android.widget.SeekBar;
+import android.widget.ToggleButton;
+import android.widget.CompoundButton;
+import android.widget.CompoundButton.OnCheckedChangeListener;
+import java.nio.ByteOrder;
+import java.nio.ByteBuffer;
+import java.util.HashMap;
+import java.util.Map;
+
+
+import android.media.audiofx.Equalizer;
+import android.media.audiofx.AudioEffect;
+
+public class EqualizerTest extends Activity implements OnCheckedChangeListener {
+
+    private final static String TAG = "EqualizerTest";
+
+    private static int NUM_BANDS = 5;
+    private static int NUM_PARAMS = NUM_BANDS + 1;
+
+    private EffectParameter[] mParameters = new EffectParameter[NUM_PARAMS];
+    private Equalizer mEqualizer;
+    ToggleButton mOnOffButton;
+    ToggleButton mReleaseButton;
+    EditText mSessionText;
+    static int sSession = 0;
+    EffectListner mEffectListener = new EffectListner();
+    private static HashMap<Integer, Equalizer> sInstances = new HashMap<Integer, Equalizer>(10);
+    String mSettings = "";
+
+    public EqualizerTest() {
+        Log.d(TAG, "contructor");
+    }
+
+    @Override
+    public void onCreate(Bundle icicle) {
+        super.onCreate(icicle);
+
+        SeekBar seekBar;
+        TextView textView;
+
+        setContentView(R.layout.equalizertest);
+
+        mSessionText = (EditText) findViewById(R.id.sessionEdit);
+        mSessionText.setOnKeyListener(mSessionKeyListener);
+
+        mSessionText.setText(Integer.toString(sSession));
+
+        mReleaseButton = (ToggleButton)findViewById(R.id.eqReleaseButton);
+        mOnOffButton = (ToggleButton)findViewById(R.id.equalizerOnOff);
+
+        getEffect(sSession);
+
+        if (mEqualizer != null) {
+            mReleaseButton.setOnCheckedChangeListener(this);
+            mOnOffButton.setOnCheckedChangeListener(this);
+
+            short[] bandLevelRange = mEqualizer.getBandLevelRange();
+            int centerFreq;
+            int []freqRange;
+
+            // Band 1 level
+            centerFreq = mEqualizer.getCenterFreq((short)0);
+            freqRange = mEqualizer.getBandFreqRange((short)0);
+            displayFreq(R.id.eqParam1Center, centerFreq);
+            displayFreq(R.id.eqParam1Min, freqRange[0]);
+            displayFreq(R.id.eqParam1Max, freqRange[1]);
+            seekBar = (SeekBar)findViewById(R.id.eqParam1SeekBar);
+            textView = (TextView)findViewById(R.id.eqParam1Value);
+            mParameters[0] = new BandLevelParam(mEqualizer, 0, bandLevelRange[0], bandLevelRange[1], seekBar, textView);
+            seekBar.setOnSeekBarChangeListener(mParameters[0]);
+
+            // Band 2 level
+            centerFreq = mEqualizer.getCenterFreq((short)1);
+            freqRange = mEqualizer.getBandFreqRange((short)1);
+            displayFreq(R.id.eqParam2Center, centerFreq);
+            displayFreq(R.id.eqParam2Min, freqRange[0]);
+            displayFreq(R.id.eqParam2Max, freqRange[1]);
+            seekBar = (SeekBar)findViewById(R.id.eqParam2SeekBar);
+            textView = (TextView)findViewById(R.id.eqParam2Value);
+            mParameters[1] = new BandLevelParam(mEqualizer, 1, bandLevelRange[0], bandLevelRange[1], seekBar, textView);
+            seekBar.setOnSeekBarChangeListener(mParameters[1]);
+
+            // Band 3 level
+            centerFreq = mEqualizer.getCenterFreq((short)2);
+            freqRange = mEqualizer.getBandFreqRange((short)2);
+            displayFreq(R.id.eqParam3Center, centerFreq);
+            displayFreq(R.id.eqParam3Min, freqRange[0]);
+            displayFreq(R.id.eqParam3Max, freqRange[1]);
+            seekBar = (SeekBar)findViewById(R.id.eqParam3SeekBar);
+            textView = (TextView)findViewById(R.id.eqParam3Value);
+            mParameters[2] = new BandLevelParam(mEqualizer, 2, bandLevelRange[0], bandLevelRange[1], seekBar, textView);
+            seekBar.setOnSeekBarChangeListener(mParameters[2]);
+
+            // Band 4 level
+            centerFreq = mEqualizer.getCenterFreq((short)3);
+            freqRange = mEqualizer.getBandFreqRange((short)3);
+            displayFreq(R.id.eqParam4Center, centerFreq);
+            displayFreq(R.id.eqParam4Min, freqRange[0]);
+            displayFreq(R.id.eqParam4Max, freqRange[1]);
+            seekBar = (SeekBar)findViewById(R.id.eqParam4SeekBar);
+            textView = (TextView)findViewById(R.id.eqParam4Value);
+            mParameters[3] = new BandLevelParam(mEqualizer, 3, bandLevelRange[0], bandLevelRange[1], seekBar, textView);
+            seekBar.setOnSeekBarChangeListener(mParameters[3]);
+
+            // Band 5 level
+            centerFreq = mEqualizer.getCenterFreq((short)4);
+            freqRange = mEqualizer.getBandFreqRange((short)4);
+            displayFreq(R.id.eqParam5Center, centerFreq);
+            displayFreq(R.id.eqParam5Min, freqRange[0]);
+            displayFreq(R.id.eqParam5Max, freqRange[1]);
+            seekBar = (SeekBar)findViewById(R.id.eqParam5SeekBar);
+            textView = (TextView)findViewById(R.id.eqParam5Value);
+            mParameters[4] = new BandLevelParam(mEqualizer, 4, bandLevelRange[0], bandLevelRange[1], seekBar, textView);
+            seekBar.setOnSeekBarChangeListener(mParameters[4]);
+
+            // Presets
+            short numPresets = mEqualizer.getNumberOfPresets();
+            seekBar = (SeekBar)findViewById(R.id.eqParam6SeekBar);
+            textView = (TextView)findViewById(R.id.eqParam6Value);
+            mParameters[5] = new PresetParam(mEqualizer, (short)0, (short)(numPresets-1), seekBar, textView);
+            seekBar.setOnSeekBarChangeListener(mParameters[5]);
+        }
+    }
+
+    @Override
+    public void onResume() {
+        super.onResume();
+    }
+
+    @Override
+    public void onPause() {
+        super.onPause();
+    }
+
+    private View.OnKeyListener mSessionKeyListener
+    = new View.OnKeyListener() {
+        public boolean onKey(View v, int keyCode, KeyEvent event) {
+            if (event.getAction() == KeyEvent.ACTION_DOWN) {
+                switch (keyCode) {
+                    case KeyEvent.KEYCODE_DPAD_CENTER:
+                    case KeyEvent.KEYCODE_ENTER:
+                        try {
+                            sSession = Integer.parseInt(mSessionText.getText().toString());
+                            getEffect(sSession);
+                            if (mEqualizer != null) {
+                                for (int i = 0 ; i < mParameters.length; i++) {
+                                    mParameters[i].setEffect(mEqualizer);
+                                    mParameters[i].setEnabled(true);
+                                }
+                            }
+                        } catch (NumberFormatException e) {
+                            Log.d(TAG, "Invalid session #: "+mSessionText.getText().toString());
+                        }
+
+                        return true;
+                }
+            }
+            return false;
+        }
+    };
+
+    // OnCheckedChangeListener
+    public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
+        if (buttonView.getId() == R.id.equalizerOnOff) {
+            if (mEqualizer != null) {
+                mEqualizer.setEnabled(isChecked);
+                updateBands();
+            }
+        }
+        if (buttonView.getId() == R.id.eqReleaseButton) {
+            if (isChecked) {
+                if (mEqualizer == null) {
+                    getEffect(sSession);
+                    if (mEqualizer != null) {
+                        for (int i = 0 ; i < mParameters.length; i++) {
+                            mParameters[i].setEffect(mEqualizer);
+                            mParameters[i].setEnabled(true);
+                        }
+                    }
+                }
+            } else {
+                if (mEqualizer != null) {
+                    for (int i = 0 ; i < mParameters.length; i++) {
+                        mParameters[i].setEnabled(false);
+                    }
+                    putEffect(sSession);
+                }
+            }
+        }
+    }
+
+    protected void updateBands() {
+        for (int i = 0 ; i < NUM_BANDS; i++) {
+            mParameters[i].updateDisplay();
+        }
+    }
+
+    private void displayFreq(int viewId, int freq) {
+        TextView textView = (TextView)findViewById(viewId);
+        String text = Integer.toString(freq/1000)+" Hz";
+        textView.setText(text);
+    }
+
+    private class EqualizerParam extends EffectParameter {
+        private Equalizer mEqualizer;
+
+        public EqualizerParam(Equalizer equalizer, int min, int max, SeekBar seekBar, TextView textView, String unit) {
+            super (min, max, seekBar, textView, unit);
+
+            mEqualizer = equalizer;
+            updateDisplay();
+        }
+
+        @Override
+        public void setParameter(Integer value) {
+        }
+
+        @Override
+        public Integer getParameter() {
+            return new Integer(0);
+        }
+
+        @Override
+        public void setEffect(Object eq) {
+            mEqualizer = (Equalizer)eq;
+        }
+    }
+
+    private class BandLevelParam extends EqualizerParam {
+        private int mBand;
+
+        public BandLevelParam(Equalizer equalizer, int band, short min, short max, SeekBar seekBar, TextView textView) {
+            super (equalizer, min, max, seekBar, textView, "mB");
+
+            mBand = band;
+            mEqualizer = equalizer;
+            updateDisplay();
+        }
+
+        @Override
+        public void setParameter(Integer value) {
+            if (mEqualizer != null) {
+                mEqualizer.setBandLevel((short)mBand, value.shortValue());
+            }
+        }
+
+        @Override
+        public Integer getParameter() {
+            if (mEqualizer != null) {
+                return new Integer(mEqualizer.getBandLevel((short)mBand));
+            }
+            return new Integer(0);
+        }
+    }
+
+    private class PresetParam extends EqualizerParam {
+
+        public PresetParam(Equalizer equalizer, short min, short max, SeekBar seekBar, TextView textView) {
+            super (equalizer, min, max, seekBar, textView, "");
+
+            mEqualizer = equalizer;
+            updateDisplay();
+        }
+
+        @Override
+        public void setParameter(Integer value) {
+            if (mEqualizer != null) {
+                mEqualizer.usePreset(value.shortValue());
+            }
+        }
+
+        @Override
+        public Integer getParameter() {
+            if (mEqualizer != null) {
+                return new Integer(mEqualizer.getCurrentPreset());
+            }
+            return new Integer(0);
+        }
+
+        @Override
+        public void displayValue(int value, boolean fromTouch) {
+            String text = mEqualizer.getPresetName((short)value);
+            mValueText.setText(text);
+            if (!fromTouch) {
+                mSeekBar.setProgress(value - mMin);
+            } else {
+                updateBands();
+            }
+        }
+    }
+
+    public class EffectListner implements AudioEffect.OnEnableStatusChangeListener,
+    AudioEffect.OnControlStatusChangeListener,
+    Equalizer.OnParameterChangeListener
+   {
+        public EffectListner() {
+        }
+        public void onEnableStatusChange(AudioEffect effect, boolean enabled) {
+            Log.d(TAG,"onEnableStatusChange: "+ enabled);
+        }
+        public void onControlStatusChange(AudioEffect effect, boolean controlGranted) {
+            Log.d(TAG,"onControlStatusChange: "+ controlGranted);
+        }
+
+        public void onParameterChange(Equalizer effect, int status, int param1, int param2, int value) {
+            Log.d(TAG,"onParameterChange EQ, status: "+status+" p1: "+param1+" p2: "+param2+" v: "+value);
+        }
+
+        private int byteArrayToInt(byte[] valueBuf, int offset) {
+            ByteBuffer converter = ByteBuffer.wrap(valueBuf);
+            converter.order(ByteOrder.nativeOrder());
+            return converter.getInt(offset);
+
+        }
+        private short byteArrayToShort(byte[] valueBuf, int offset) {
+            ByteBuffer converter = ByteBuffer.wrap(valueBuf);
+            converter.order(ByteOrder.nativeOrder());
+            return converter.getShort(offset);
+
+        }
+    }
+
+    private void getEffect(int session) {
+        synchronized (sInstances) {
+            if (sInstances.containsKey(session)) {
+                mEqualizer = sInstances.get(session);
+            } else {
+                try{
+                    mEqualizer = new Equalizer(0, session);
+                } catch (IllegalArgumentException e) {
+                    Log.e(TAG,"Equalizer effect not supported");
+                } catch (UnsupportedOperationException e) {
+                    Log.e(TAG,"Equalizer library not loaded");
+                } catch (IllegalStateException e) {
+                    Log.e(TAG,"Equalizer cannot get presets");
+                } catch (RuntimeException e) {
+                    Log.e(TAG,"Equalizer effect not found");
+                }
+                sInstances.put(session, mEqualizer);
+            }
+        }
+        mReleaseButton.setEnabled(false);
+        mOnOffButton.setEnabled(false);
+        if (mEqualizer != null) {
+            if (mSettings != "") {
+                Log.d(TAG,"Equalizer settings: "+mSettings);
+                mEqualizer.setProperties(new Equalizer.Settings(mSettings));
+            }
+
+            mEqualizer.setEnableStatusListener(mEffectListener);
+            mEqualizer.setControlStatusListener(mEffectListener);
+            mEqualizer.setParameterListener(mEffectListener);
+
+            mReleaseButton.setChecked(true);
+            mReleaseButton.setEnabled(true);
+
+            mOnOffButton.setChecked(mEqualizer.getEnabled());
+            mOnOffButton.setEnabled(true);
+        }
+    }
+
+    private void putEffect(int session) {
+//        mOnOffButton.setChecked(false);
+        mOnOffButton.setEnabled(false);
+        synchronized (sInstances) {
+            if (mEqualizer != null) {
+                mSettings = mEqualizer.getProperties().toString();
+                mEqualizer.release();
+                Log.d(TAG,"Equalizer released, settings: "+mSettings);
+                mEqualizer = null;
+                sInstances.remove(session);
+            }
+        }
+    }
+}
diff --git a/media/tests/EffectsTest/src/com/android/effectstest/PresetReverbTest.java b/media/tests/EffectsTest/src/com/android/effectstest/PresetReverbTest.java
new file mode 100755
index 0000000..91d7948
--- /dev/null
+++ b/media/tests/EffectsTest/src/com/android/effectstest/PresetReverbTest.java
@@ -0,0 +1,298 @@
+/*
+ * Copyright (C) 2009 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.effectstest;
+
+import android.app.Activity;
+import android.content.Context;
+import android.content.Intent;
+import android.os.Bundle;
+import android.util.Log;
+import android.view.KeyEvent;
+import android.view.Menu;
+import android.view.View.OnClickListener;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.Button;
+import android.widget.TextView;
+import android.widget.EditText;
+import android.widget.SeekBar;
+import android.widget.ToggleButton;
+import android.widget.CompoundButton;
+import android.widget.CompoundButton.OnCheckedChangeListener;
+import java.nio.ByteOrder;
+import java.nio.ByteBuffer;
+import java.util.HashMap;
+import java.util.Map;
+
+import android.media.audiofx.PresetReverb;
+import android.media.audiofx.AudioEffect;
+
+public class PresetReverbTest extends Activity implements OnCheckedChangeListener {
+
+    private final static String TAG = "PresetReverbTest";
+
+    private static int NUM_PARAMS = 1;
+
+    private EffectParameter[] mParameters = new EffectParameter[NUM_PARAMS];
+    private PresetReverb mPresetReverb;
+    ToggleButton mOnOffButton;
+    ToggleButton mReleaseButton;
+    EditText mSessionText;
+    static int sSession = 0;
+    EffectListner mEffectListener = new EffectListner();
+    private static HashMap<Integer, PresetReverb> sInstances = new HashMap<Integer, PresetReverb>(10);
+    String mSettings = "";
+
+    public PresetReverbTest() {
+        Log.d(TAG, "contructor");
+    }
+
+    private static String[] sPresetNames = {
+        "NONE",         //PresetReverb.PRESET_NONE
+        "SMALLROOM",    //PresetReverb.PRESET_SMALLROOM
+        "MEDIUMROOM",   //PresetReverb.PRESET_MEDIUMROOM
+        "LARGEROOM",    //PresetReverb.PRESET_LARGEROOM
+        "MEDIUMHALL",   //PresetReverb.PRESET_MEDIUMHALL
+        "LARGEHALL",    //PresetReverb.PRESET_LARGEHALL
+        "PLATE",        //PresetReverb.PRESET_PLATE
+    };
+
+    @Override
+    public void onCreate(Bundle icicle) {
+        super.onCreate(icicle);
+
+        setContentView(R.layout.presetreverbtest);
+
+        mSessionText = (EditText) findViewById(R.id.sessionEdit);
+        mSessionText.setOnKeyListener(mSessionKeyListener);
+
+        mSessionText.setText(Integer.toString(sSession));
+
+        mReleaseButton = (ToggleButton)findViewById(R.id.presetrvbReleaseButton);
+        mOnOffButton = (ToggleButton)findViewById(R.id.presetrvbOnOff);
+
+        getEffect(sSession);
+
+        if (mPresetReverb != null) {
+            mReleaseButton.setOnCheckedChangeListener(this);
+            mOnOffButton.setOnCheckedChangeListener(this);
+            // Presets
+            SeekBar seekBar = (SeekBar)findViewById(R.id.presetrvbParam1SeekBar);
+            TextView textView = (TextView)findViewById(R.id.presetrvbParam1Value);
+            mParameters[0] = new PresetParam(mPresetReverb, (short)0, (short)(sPresetNames.length - 1), seekBar, textView);
+            seekBar.setOnSeekBarChangeListener(mParameters[0]);
+        }
+    }
+
+    @Override
+    public void onResume() {
+        super.onResume();
+    }
+
+    @Override
+    public void onPause() {
+        super.onPause();
+    }
+
+    private View.OnKeyListener mSessionKeyListener
+    = new View.OnKeyListener() {
+        public boolean onKey(View v, int keyCode, KeyEvent event) {
+            if (event.getAction() == KeyEvent.ACTION_DOWN) {
+                switch (keyCode) {
+                    case KeyEvent.KEYCODE_DPAD_CENTER:
+                    case KeyEvent.KEYCODE_ENTER:
+                        try {
+                            sSession = Integer.parseInt(mSessionText.getText().toString());
+                            getEffect(sSession);
+                            if (mPresetReverb != null) {
+                                for (int i = 0 ; i < mParameters.length; i++) {
+                                    mParameters[i].setEffect(mPresetReverb);
+                                    mParameters[i].setEnabled(true);
+                                    mParameters[i].updateDisplay();
+                                }
+                            }
+                        } catch (NumberFormatException e) {
+                            Log.d(TAG, "Invalid session #: "+mSessionText.getText().toString());
+                        }
+
+                        return true;
+                }
+            }
+            return false;
+        }
+    };
+
+    // OnCheckedChangeListener
+    public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
+        if (buttonView.getId() == R.id.presetrvbOnOff) {
+            if (mPresetReverb != null) {
+                mPresetReverb.setEnabled(isChecked);
+                updateParams();
+            }
+        }
+        if (buttonView.getId() == R.id.presetrvbReleaseButton) {
+            if (isChecked) {
+                if (mPresetReverb == null) {
+                    getEffect(sSession);
+                    if (mPresetReverb != null) {
+                        for (int i = 0 ; i < mParameters.length; i++) {
+                            mParameters[i].setEffect(mPresetReverb);
+                            mParameters[i].setEnabled(true);
+                            mParameters[i].updateDisplay();
+                        }
+                    }
+                }
+            } else {
+                if (mPresetReverb != null) {
+                    for (int i = 0 ; i < mParameters.length; i++) {
+                        mParameters[i].setEnabled(false);
+                    }
+                    putEffect(sSession);
+                }
+            }
+        }
+    }
+
+    private class PresetParam extends EffectParameter {
+        private PresetReverb mPresetReverb;
+
+        public PresetParam(PresetReverb presetrvb, short min, short max, SeekBar seekBar, TextView textView) {
+            super (min, max, seekBar, textView, "");
+
+            mPresetReverb = presetrvb;
+            updateDisplay();
+        }
+
+        @Override
+        public void setParameter(Integer value) {
+            if (mPresetReverb != null) {
+                mPresetReverb.setPreset(value.shortValue());
+            }
+        }
+
+        @Override
+        public Integer getParameter() {
+            if (mPresetReverb != null) {
+                return new Integer(mPresetReverb.getPreset());
+            }
+            return new Integer(0);
+        }
+
+        @Override
+        public void displayValue(int value, boolean fromTouch) {
+            mValueText.setText(sPresetNames[value]);
+            if (!fromTouch) {
+                mSeekBar.setProgress(value - mMin);
+            } else {
+                updateParams();
+            }
+        }
+
+        @Override
+        public void setEffect(Object presetrvb) {
+            mPresetReverb = (PresetReverb)presetrvb;
+        }
+
+    }
+
+    protected void updateParams() {
+        for (int i = 0 ; i < mParameters.length; i++) {
+            mParameters[i].updateDisplay();
+        }
+    }
+
+    public class EffectListner implements AudioEffect.OnEnableStatusChangeListener,
+    AudioEffect.OnControlStatusChangeListener,
+    PresetReverb.OnParameterChangeListener
+   {
+        public EffectListner() {
+        }
+        public void onEnableStatusChange(AudioEffect effect, boolean enabled) {
+            Log.d(TAG,"onEnableStatusChange: "+ enabled);
+        }
+        public void onControlStatusChange(AudioEffect effect, boolean controlGranted) {
+            Log.d(TAG,"onControlStatusChange: "+ controlGranted);
+        }
+
+        public void onParameterChange(PresetReverb effect, int status, int param, short value) {
+            Log.d(TAG,"onParameterChange, status: "+status+" p: "+param+" v: "+value);
+        }
+
+        private int byteArrayToInt(byte[] valueBuf, int offset) {
+            ByteBuffer converter = ByteBuffer.wrap(valueBuf);
+            converter.order(ByteOrder.nativeOrder());
+            return converter.getInt(offset);
+
+        }
+        private short byteArrayToShort(byte[] valueBuf, int offset) {
+            ByteBuffer converter = ByteBuffer.wrap(valueBuf);
+            converter.order(ByteOrder.nativeOrder());
+            return converter.getShort(offset);
+
+        }
+    }
+
+    private void getEffect(int session) {
+        synchronized (sInstances) {
+            if (sInstances.containsKey(session)) {
+                mPresetReverb = sInstances.get(session);
+            } else {
+                try{
+                    mPresetReverb = new PresetReverb(0, session);
+                } catch (IllegalArgumentException e) {
+                    Log.e(TAG,"PresetReverb effect not supported");
+                } catch (UnsupportedOperationException e) {
+                    Log.e(TAG,"PresetReverb library not loaded");
+                } catch (RuntimeException e) {
+                    Log.e(TAG,"PresetReverb effect not found");
+                }
+                sInstances.put(session, mPresetReverb);
+            }
+        }
+        mReleaseButton.setEnabled(false);
+        mOnOffButton.setEnabled(false);
+
+        if (mPresetReverb != null) {
+            if (mSettings != "") {
+                mPresetReverb.setProperties(new PresetReverb.Settings(mSettings));
+            }
+            mPresetReverb.setEnableStatusListener(mEffectListener);
+            mPresetReverb.setControlStatusListener(mEffectListener);
+            mPresetReverb.setParameterListener(mEffectListener);
+
+            mReleaseButton.setChecked(true);
+            mReleaseButton.setEnabled(true);
+
+            mOnOffButton.setChecked(mPresetReverb.getEnabled());
+            mOnOffButton.setEnabled(true);
+        }
+    }
+
+    private void putEffect(int session) {
+        mOnOffButton.setChecked(false);
+        mOnOffButton.setEnabled(false);
+        synchronized (sInstances) {
+            if (mPresetReverb != null) {
+                mSettings = mPresetReverb.getProperties().toString();
+                mPresetReverb.release();
+                Log.d(TAG,"PresetReverb released");
+                mPresetReverb = null;
+                sInstances.remove(session);
+            }
+        }
+    }
+}
diff --git a/media/tests/EffectsTest/src/com/android/effectstest/SimplePlayer.java b/media/tests/EffectsTest/src/com/android/effectstest/SimplePlayer.java
new file mode 100644
index 0000000..119a604
--- /dev/null
+++ b/media/tests/EffectsTest/src/com/android/effectstest/SimplePlayer.java
@@ -0,0 +1,197 @@
+/*
+ * Copyright (C) 2009 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.effectstest;
+
+import android.content.Context;
+import android.content.res.AssetFileDescriptor;
+import android.os.Bundle;
+import android.util.Log;
+import android.view.KeyEvent;
+import android.view.Menu;
+import android.view.View.OnClickListener;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.Button;
+import android.widget.TextView;
+import android.widget.EditText;
+import android.widget.SeekBar;
+import android.widget.ToggleButton;
+import android.widget.CompoundButton;
+import android.widget.CompoundButton.OnCheckedChangeListener;
+import android.widget.ImageButton;
+import android.widget.ImageView;
+import android.media.AudioManager;
+import android.media.MediaPlayer;
+import java.nio.ByteOrder;
+import java.nio.ByteBuffer;
+import java.io.IOException;
+import java.util.HashMap;
+import java.util.Map;
+
+public class SimplePlayer implements OnClickListener {
+
+    private final static String TAG = "SimplePlayer";
+
+    int mPlayPauseButtonId;
+    int mStopButtonId;
+    Context mContext;
+    ImageView mPlayPauseButton;
+    int mPlayImageResource;
+    int mPauseImageResource;
+    String mFileName;
+    int mFileResId;
+    MediaPlayer mMediaPlayer;
+    int mStreamType;
+    int mSession;
+    float mSendLevel = (float)0.5;
+    int mEffectId = 0;
+    TextView mSessionText;
+
+    SimplePlayer(Context context, int playPausebuttonId, ImageView playPausebutton,
+                int stopButtonId, ImageView stopButton, TextView sessionText, String fileName, int stream, int session)
+    {
+        set(context, playPausebuttonId, playPausebutton, stopButtonId, stopButton, sessionText, stream, session);
+        mFileName = fileName;
+    }
+
+    SimplePlayer(Context context, int playPausebuttonId, ImageView playPausebutton,
+            int stopButtonId, ImageView stopButton, TextView sessionText, int fileResId, int stream, int session) {
+        set(context, playPausebuttonId, playPausebutton, stopButtonId, stopButton, sessionText, stream, session);
+        mFileResId = fileResId;
+        mFileName = "";
+    }
+
+    public void set(Context context, int playPausebuttonId, ImageView playPausebutton,
+            int stopButtonId, ImageView stopButton, TextView sessionText, int stream, int session) {
+        mContext = context;
+        mPlayPauseButtonId = playPausebuttonId;
+        mStopButtonId = stopButtonId;
+        mPlayPauseButton = (ImageButton) playPausebutton;
+        ImageButton stop = (ImageButton) stopButton;
+
+        mPlayPauseButton.setOnClickListener(this);
+        mPlayPauseButton.requestFocus();
+        stop.setOnClickListener(this);
+
+        mPlayImageResource = android.R.drawable.ic_media_play;
+        mPauseImageResource = android.R.drawable.ic_media_pause;
+        mStreamType = stream;
+        mSession = session;
+        mSessionText = sessionText;
+    }
+
+
+    public void onClick(View v) {
+        if (v.getId() == mPlayPauseButtonId) {
+            playOrPause();
+        } else if (v.getId() == mStopButtonId) {
+            stop();
+        }
+    }
+
+    public void playOrPause() {
+        if (mMediaPlayer == null || !mMediaPlayer.isPlaying()){
+              if (mMediaPlayer == null) {
+                  try {
+                      mMediaPlayer = new MediaPlayer();
+                      if (mSession != 0) {
+                          mMediaPlayer.setAudioSessionId(mSession);
+                          Log.d(TAG, "mMediaPlayer.setAudioSessionId(): "+ mSession);
+                      }
+
+                      if (mFileName.equals("")) {
+                          Log.d(TAG, "Playing from resource");
+                          AssetFileDescriptor afd = mContext.getResources().openRawResourceFd(mFileResId);
+                          mMediaPlayer.setDataSource(afd.getFileDescriptor(), afd.getStartOffset(), afd.getLength());
+                          afd.close();
+                      } else {
+                          Log.d(TAG, "Playing file: "+mFileName);
+                          mMediaPlayer.setDataSource(mFileName);
+                      }
+                      mMediaPlayer.setAudioStreamType(mStreamType);
+                      mMediaPlayer.prepare();
+                      mMediaPlayer.setLooping(true);
+                  } catch (IOException ex) {
+                      Log.e(TAG, "mMediaPlayercreate failed:", ex);
+                      mMediaPlayer = null;
+                  } catch (IllegalArgumentException ex) {
+                      Log.e(TAG, "mMediaPlayercreate failed:", ex);
+                      mMediaPlayer = null;
+                  } catch (SecurityException ex) {
+                      Log.e(TAG, "mMediaPlayercreate failed:", ex);
+                      mMediaPlayer = null;
+                  }
+
+                  if (mMediaPlayer != null) {
+                      mMediaPlayer.setAuxEffectSendLevel(mSendLevel);
+                      mMediaPlayer.attachAuxEffect(mEffectId);
+                      mMediaPlayer.setOnCompletionListener(new MediaPlayer.OnCompletionListener() {
+                          public void onCompletion(MediaPlayer mp) {
+                              updatePlayPauseButton();
+                          }
+                      });
+                      mSessionText.setText("Session: "+Integer.toString(mMediaPlayer.getAudioSessionId()));
+                  }
+              }
+              if (mMediaPlayer != null) {
+                  mMediaPlayer.start();
+              }
+          } else {
+              mMediaPlayer.pause();
+          }
+          updatePlayPauseButton();
+    }
+
+    public void stop() {
+      if (mMediaPlayer != null) {
+          mMediaPlayer.stop();
+          mMediaPlayer.release();
+          mMediaPlayer = null;
+      }
+      updatePlayPauseButton();
+    }
+
+    public boolean isPlaying() {
+        if (mMediaPlayer != null) {
+            return mMediaPlayer.isPlaying();
+        } else {
+            return false;
+        }
+    }
+
+    public void updatePlayPauseButton() {
+        mPlayPauseButton.setImageResource(isPlaying() ? mPauseImageResource : mPlayImageResource);
+    }
+
+    public void attachAuxEffect(int effectId) {
+        mEffectId = effectId;
+        if (mMediaPlayer != null) {
+            Log.d(TAG,"attach effect: "+effectId);
+            mMediaPlayer.attachAuxEffect(effectId);
+        }
+    }
+    public void setAuxEffectSendLevel(float level) {
+        mSendLevel = level;
+        if (mMediaPlayer != null) {
+            mMediaPlayer.setAuxEffectSendLevel(level);
+        }
+    }
+
+    public void setContext(Context context) {
+        mContext = context;
+    }
+}
diff --git a/media/tests/EffectsTest/src/com/android/effectstest/VirtualizerTest.java b/media/tests/EffectsTest/src/com/android/effectstest/VirtualizerTest.java
new file mode 100755
index 0000000..bb32e6f
--- /dev/null
+++ b/media/tests/EffectsTest/src/com/android/effectstest/VirtualizerTest.java
@@ -0,0 +1,271 @@
+/*
+ * Copyright (C) 2009 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.effectstest;
+
+import android.app.Activity;
+import android.content.Context;
+import android.content.Intent;
+import android.os.Bundle;
+import android.util.Log;
+import android.view.KeyEvent;
+import android.view.Menu;
+import android.view.View.OnClickListener;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.Button;
+import android.widget.TextView;
+import android.widget.EditText;
+import android.widget.SeekBar;
+import android.widget.ToggleButton;
+import android.widget.CompoundButton;
+import android.widget.CompoundButton.OnCheckedChangeListener;
+import java.nio.ByteOrder;
+import java.nio.ByteBuffer;
+import java.util.HashMap;
+import java.util.Map;
+
+import android.media.audiofx.Virtualizer;
+import android.media.audiofx.AudioEffect;
+
+public class VirtualizerTest extends Activity implements OnCheckedChangeListener {
+
+    private final static String TAG = "VirtualizerTest";
+
+    private static int NUM_PARAMS = 1;
+
+    private EffectParameter mStrength;
+    private Virtualizer mVirtualizer;
+    ToggleButton mOnOffButton;
+    ToggleButton mReleaseButton;
+    EditText mSessionText;
+    static int sSession = 0;
+    EffectListner mEffectListener = new EffectListner();
+    private static HashMap<Integer, Virtualizer> sInstances = new HashMap<Integer, Virtualizer>(10);
+    String mSettings = "";
+
+    public VirtualizerTest() {
+        Log.d(TAG, "contructor");
+    }
+
+    @Override
+    public void onCreate(Bundle icicle) {
+        super.onCreate(icicle);
+
+        SeekBar seekBar;
+        TextView textView;
+
+        setContentView(R.layout.virtualizertest);
+
+        mSessionText = (EditText) findViewById(R.id.sessionEdit);
+        mSessionText.setOnKeyListener(mSessionKeyListener);
+        mSessionText.setText(Integer.toString(sSession));
+
+        mReleaseButton = (ToggleButton)findViewById(R.id.virtReleaseButton);
+        mOnOffButton = (ToggleButton)findViewById(R.id.virtualizerOnOff);
+
+        getEffect(sSession);
+
+        if (mVirtualizer != null) {
+            mReleaseButton.setOnCheckedChangeListener(this);
+            mOnOffButton.setOnCheckedChangeListener(this);
+            textView = (TextView)findViewById(R.id.virtStrengthMin);
+            textView.setText("0");
+            textView = (TextView)findViewById(R.id.virtStrengthMax);
+            textView.setText("1000");
+            seekBar = (SeekBar)findViewById(R.id.virtStrengthSeekBar);
+            textView = (TextView)findViewById(R.id.virtStrengthValue);
+            mStrength = new VirtualizerParam(mVirtualizer, 0, 1000, seekBar, textView);
+            seekBar.setOnSeekBarChangeListener(mStrength);
+            mStrength.setEnabled(mVirtualizer.getStrengthSupported());
+        }
+    }
+
+    @Override
+    public void onResume() {
+        super.onResume();
+    }
+
+    @Override
+    public void onPause() {
+        super.onPause();
+    }
+
+    private View.OnKeyListener mSessionKeyListener
+    = new View.OnKeyListener() {
+        public boolean onKey(View v, int keyCode, KeyEvent event) {
+            if (event.getAction() == KeyEvent.ACTION_DOWN) {
+                switch (keyCode) {
+                    case KeyEvent.KEYCODE_DPAD_CENTER:
+                    case KeyEvent.KEYCODE_ENTER:
+                        try {
+                            sSession = Integer.parseInt(mSessionText.getText().toString());
+                            getEffect(sSession);
+                            if (mVirtualizer != null) {
+                                mStrength.setEffect(mVirtualizer);
+                                mStrength.setEnabled(mVirtualizer.getStrengthSupported());
+                            }
+                        } catch (NumberFormatException e) {
+                            Log.d(TAG, "Invalid session #: "+mSessionText.getText().toString());
+                        }
+                        return true;
+                }
+            }
+            return false;
+        }
+    };
+
+    // OnCheckedChangeListener
+    public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
+        if (buttonView.getId() == R.id.virtualizerOnOff) {
+            if (mVirtualizer != null) {
+                mVirtualizer.setEnabled(isChecked);
+                mStrength.updateDisplay();
+            }
+        }
+        if (buttonView.getId() == R.id.virtReleaseButton) {
+            if (isChecked) {
+                if (mVirtualizer == null) {
+                    getEffect(sSession);
+                    if (mVirtualizer != null) {
+                        mStrength.setEffect(mVirtualizer);
+                        mStrength.setEnabled(mVirtualizer.getStrengthSupported());
+                    }
+                }
+            } else {
+                if (mVirtualizer != null) {
+                    mStrength.setEnabled(false);
+                    putEffect(sSession);
+                }
+            }
+        }
+    }
+
+    private class VirtualizerParam extends EffectParameter {
+        private Virtualizer mVirtualizer;
+
+        public VirtualizerParam(Virtualizer virtualizer, int min, int max, SeekBar seekBar, TextView textView) {
+            super (min, max, seekBar, textView, "o/oo");
+
+            mVirtualizer = virtualizer;
+            updateDisplay();
+        }
+
+        @Override
+        public void setParameter(Integer value) {
+            if (mVirtualizer != null) {
+                mVirtualizer.setStrength(value.shortValue());
+            }
+        }
+
+        @Override
+        public Integer getParameter() {
+            if (mVirtualizer != null) {
+                return new Integer(mVirtualizer.getRoundedStrength());
+            }
+            return new Integer(0);
+        }
+
+        @Override
+        public void setEffect(Object effect) {
+            mVirtualizer = (Virtualizer)effect;
+        }
+    }
+
+    public class EffectListner implements AudioEffect.OnEnableStatusChangeListener,
+        AudioEffect.OnControlStatusChangeListener, AudioEffect.OnParameterChangeListener
+   {
+        public EffectListner() {
+        }
+        public void onEnableStatusChange(AudioEffect effect, boolean enabled) {
+            Log.d(TAG,"onEnableStatusChange: "+ enabled);
+        }
+        public void onControlStatusChange(AudioEffect effect, boolean controlGranted) {
+            Log.d(TAG,"onControlStatusChange: "+ controlGranted);
+        }
+        public void onParameterChange(AudioEffect effect, int status, byte[] param, byte[] value) {
+            int p = byteArrayToInt(param, 0);
+            short v = byteArrayToShort(value, 0);
+
+            Log.d(TAG,"onParameterChange, status: "+status+" p: "+p+" v: "+v);
+        }
+
+        private int byteArrayToInt(byte[] valueBuf, int offset) {
+            ByteBuffer converter = ByteBuffer.wrap(valueBuf);
+            converter.order(ByteOrder.nativeOrder());
+            return converter.getInt(offset);
+
+        }
+        private short byteArrayToShort(byte[] valueBuf, int offset) {
+            ByteBuffer converter = ByteBuffer.wrap(valueBuf);
+            converter.order(ByteOrder.nativeOrder());
+            return converter.getShort(offset);
+
+        }
+    }
+
+    private void getEffect(int session) {
+        synchronized (sInstances) {
+            if (sInstances.containsKey(session)) {
+                mVirtualizer = sInstances.get(session);
+            } else {
+                try{
+                    mVirtualizer = new Virtualizer(0, session);
+                } catch (IllegalArgumentException e) {
+                    Log.e(TAG,"Virtualizer effect not supported");
+                } catch (IllegalStateException e) {
+                    Log.e(TAG,"Virtualizer cannot get strength supported");
+                } catch (UnsupportedOperationException e) {
+                    Log.e(TAG,"Virtualizer library not loaded");
+                } catch (RuntimeException e) {
+                    Log.e(TAG,"Virtualizer effect not found");
+                }
+                sInstances.put(session, mVirtualizer);
+            }
+        }
+        mReleaseButton.setEnabled(false);
+        mOnOffButton.setEnabled(false);
+
+        if (mVirtualizer != null) {
+            if (mSettings != "") {
+                mVirtualizer.setProperties(new Virtualizer.Settings(mSettings));
+            }
+            mVirtualizer.setEnableStatusListener(mEffectListener);
+            mVirtualizer.setControlStatusListener(mEffectListener);
+            mVirtualizer.setParameterListener(mEffectListener);
+
+            mReleaseButton.setChecked(true);
+            mReleaseButton.setEnabled(true);
+
+            mOnOffButton.setChecked(mVirtualizer.getEnabled());
+            mOnOffButton.setEnabled(true);
+        }
+    }
+
+    private void putEffect(int session) {
+        mOnOffButton.setChecked(false);
+        mOnOffButton.setEnabled(false);
+        synchronized (sInstances) {
+            if (mVirtualizer != null) {
+                mSettings = mVirtualizer.getProperties().toString();
+                mVirtualizer.release();
+                Log.d(TAG,"Virtualizer released");
+                mVirtualizer = null;
+                sInstances.remove(session);
+            }
+        }
+    }
+}
diff --git a/media/tests/EffectsTest/src/com/android/effectstest/VisualizerTest.java b/media/tests/EffectsTest/src/com/android/effectstest/VisualizerTest.java
new file mode 100755
index 0000000..60583e0
--- /dev/null
+++ b/media/tests/EffectsTest/src/com/android/effectstest/VisualizerTest.java
@@ -0,0 +1,296 @@
+/*
+ * Copyright (C) 2009 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.effectstest;
+
+import android.app.Activity;
+import android.content.Context;
+import android.content.Intent;
+import android.media.audiofx.Visualizer;
+import android.os.Bundle;
+import android.os.Handler;
+import android.os.Looper;
+import android.os.Message;
+import android.util.Log;
+import android.view.KeyEvent;
+import android.view.Menu;
+import android.view.View;
+import android.view.View.OnClickListener;
+import android.view.ViewGroup;
+import android.widget.Button;
+import android.widget.CompoundButton;
+import android.widget.CompoundButton.OnCheckedChangeListener;
+import android.widget.EditText;
+import android.widget.TextView;
+import android.widget.ToggleButton;
+import android.widget.SeekBar;
+
+import java.nio.ByteOrder;
+import java.nio.ByteBuffer;
+import java.util.HashMap;
+import java.util.Map;
+
+public class VisualizerTest extends Activity implements OnCheckedChangeListener {
+
+    private final static String TAG = "Visualizer Test";
+
+    private Visualizer mVisualizer;
+    ToggleButton mOnOffButton;
+    ToggleButton mReleaseButton;
+    boolean mEnabled;
+    EditText mSessionText;
+    static int sSession = 0;
+    int mCaptureSize;
+    ToggleButton mCallbackButton;
+    boolean mCallbackOn;
+    VisualizerListener mVisualizerListener;
+    private static HashMap<Integer, Visualizer> sInstances = new HashMap<Integer, Visualizer>(10);
+    private VisualizerTestHandler mVisualizerTestHandler = null;
+
+    public VisualizerTest() {
+        Log.d(TAG, "contructor");
+    }
+
+    @Override
+    public void onCreate(Bundle icicle) {
+        super.onCreate(icicle);
+
+        TextView textView;
+
+        setContentView(R.layout.visualizertest);
+
+        mSessionText = (EditText) findViewById(R.id.sessionEdit);
+        mSessionText.setOnKeyListener(mSessionKeyListener);
+        mSessionText.setText(Integer.toString(sSession));
+
+        mReleaseButton = (ToggleButton)findViewById(R.id.visuReleaseButton);
+        mOnOffButton = (ToggleButton)findViewById(R.id.visualizerOnOff);
+        mCallbackButton = (ToggleButton)findViewById(R.id.visuCallbackOnOff);
+        mCallbackOn = false;
+        mCallbackButton.setChecked(mCallbackOn);
+
+        mVisualizerTestHandler = new VisualizerTestHandler();
+        mVisualizerListener = new VisualizerListener();
+
+        getEffect(sSession);
+
+        if (mVisualizer != null) {
+            mReleaseButton.setOnCheckedChangeListener(this);
+            mOnOffButton.setOnCheckedChangeListener(this);
+            mCallbackButton.setOnCheckedChangeListener(this);
+        }
+    }
+
+    private static final int MSG_START_CAPTURE = 0;
+    private static final int MSG_STOP_CAPTURE = 1;
+    private static final int MSG_NEW_CAPTURE = 2;
+    private static final int CAPTURE_PERIOD_MS = 100;
+
+    private class VisualizerTestHandler extends Handler {
+        boolean mActive = false;
+        @Override
+        public void handleMessage(Message msg) {
+            switch (msg.what) {
+            case MSG_START_CAPTURE:
+                if (!mActive) {
+                    Log.d(TAG, "Start capture");
+                    mActive = true;
+                    sendMessageDelayed(obtainMessage(MSG_NEW_CAPTURE, 0, 0, null), CAPTURE_PERIOD_MS);
+                }
+                break;
+            case MSG_STOP_CAPTURE:
+                if (mActive) {
+                    Log.d(TAG, "Stop capture");
+                    mActive = false;
+                }
+                break;
+            case MSG_NEW_CAPTURE:
+                if (mActive && mVisualizer != null) {
+                    if (mCaptureSize > 0) {
+                        byte[] data = new byte[mCaptureSize];
+                        if (mVisualizer.getWaveForm(data) == Visualizer.SUCCESS) {
+                            int len = data.length < mCaptureSize ? data.length : mCaptureSize;
+                            displayVal(R.id.waveformMin, data[0]);
+                            displayVal(R.id.waveformMax, data[len-1]);
+                            displayVal(R.id.waveformCenter, data[len/2]);
+                        };
+                        if (mVisualizer.getFft(data) == Visualizer.SUCCESS) {
+                            int len = data.length < mCaptureSize ? data.length : mCaptureSize;
+                            displayVal(R.id.fftMin, data[0]);
+                            displayVal(R.id.fftMax, data[len-1]);
+                            displayVal(R.id.fftCenter, data[len/2]);
+                        };
+                    }
+                    sendMessageDelayed(obtainMessage(MSG_NEW_CAPTURE, 0, 0, null), CAPTURE_PERIOD_MS);
+                }
+                break;
+            }
+        }
+    }
+
+    private class VisualizerListener implements Visualizer.OnDataCaptureListener {
+
+        public VisualizerListener() {
+        }
+        public void onWaveFormDataCapture(Visualizer visualizer, byte[] waveform, int samplingRate) {
+            if (visualizer == mVisualizer) {
+                if (waveform.length > 0) {
+                    Log.d(TAG, "onWaveFormDataCapture(): "+waveform[0]+" smp rate: "+samplingRate/1000);
+                    displayVal(R.id.waveformMin, waveform[0]);
+                    displayVal(R.id.waveformMax, waveform[waveform.length - 1]);
+                    displayVal(R.id.waveformCenter, waveform[waveform.length/2]);
+                }
+            }
+        }
+        public void onFftDataCapture(Visualizer visualizer, byte[] fft, int samplingRate) {
+            if (visualizer == mVisualizer) {
+                if (fft.length > 0) {
+                    Log.d(TAG, "onFftDataCapture(): "+fft[0]);
+                    displayVal(R.id.fftMin, fft[0]);
+                    displayVal(R.id.fftMax, fft[fft.length - 1]);
+                    displayVal(R.id.fftCenter, fft[fft.length/2]);
+                }
+            }
+        }
+    }
+
+    @Override
+    public void onResume() {
+        super.onResume();
+    }
+
+    @Override
+    public void onPause() {
+        super.onPause();
+    }
+
+    private View.OnKeyListener mSessionKeyListener
+    = new View.OnKeyListener() {
+        public boolean onKey(View v, int keyCode, KeyEvent event) {
+            if (event.getAction() == KeyEvent.ACTION_DOWN) {
+                switch (keyCode) {
+                    case KeyEvent.KEYCODE_DPAD_CENTER:
+                    case KeyEvent.KEYCODE_ENTER:
+                        try {
+                            sSession = Integer.parseInt(mSessionText.getText().toString());
+                            getEffect(sSession);
+                        } catch (NumberFormatException e) {
+                            Log.d(TAG, "Invalid session #: "+mSessionText.getText().toString());
+                        }
+
+                        return true;
+                }
+            }
+            return false;
+        }
+    };
+
+    // OnCheckedChangeListener
+    public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
+        if (buttonView.getId() == R.id.visualizerOnOff) {
+            if (mVisualizer != null) {
+                mEnabled = isChecked;
+                mCallbackButton.setEnabled(!mEnabled);
+                if (mCallbackOn && mEnabled) {
+                    mVisualizer.setDataCaptureListener(mVisualizerListener,
+                            10000,
+                            true,
+                            true);
+                }
+                mVisualizer.setEnabled(mEnabled);
+                if (mCallbackOn) {
+                    if (!mEnabled) {
+                        mVisualizer.setDataCaptureListener(null,
+                                10000,
+                                false,
+                                false);
+                    }
+                } else {
+                    int msg = isChecked ? MSG_START_CAPTURE : MSG_STOP_CAPTURE;
+                    mVisualizerTestHandler.sendMessage(
+                            mVisualizerTestHandler.obtainMessage(msg, 0, 0, null));
+                }
+            }
+        }
+        if (buttonView.getId() == R.id.visuReleaseButton) {
+            if (isChecked) {
+                if (mVisualizer == null) {
+                    getEffect(sSession);
+                }
+            } else {
+                if (mVisualizer != null) {
+                    putEffect(sSession);
+                }
+            }
+        }
+        if (buttonView.getId() == R.id.visuCallbackOnOff) {
+            mCallbackOn = isChecked;
+        }
+    }
+
+    private void displayVal(int viewId, int val) {
+        TextView textView = (TextView)findViewById(viewId);
+        String text = Integer.toString(val);
+        textView.setText(text);
+    }
+
+
+    private void getEffect(int session) {
+        synchronized (sInstances) {
+            if (sInstances.containsKey(session)) {
+                mVisualizer = sInstances.get(session);
+            } else {
+                try{
+                    mVisualizer = new Visualizer(session);
+                } catch (UnsupportedOperationException e) {
+                    Log.e(TAG,"Visualizer library not loaded");
+                    throw (new RuntimeException("Cannot initialize effect"));
+                } catch (RuntimeException e) {
+                    throw e;
+                }
+                sInstances.put(session, mVisualizer);
+            }
+        }
+        mReleaseButton.setEnabled(false);
+        mOnOffButton.setEnabled(false);
+        if (mVisualizer != null) {
+            mCaptureSize = mVisualizer.getCaptureSize();
+
+            mReleaseButton.setChecked(true);
+            mReleaseButton.setEnabled(true);
+
+            mEnabled = mVisualizer.getEnabled();
+            mOnOffButton.setChecked(mEnabled);
+            mOnOffButton.setEnabled(true);
+
+            mCallbackButton.setEnabled(!mEnabled);
+        }
+    }
+
+    private void putEffect(int session) {
+        mOnOffButton.setChecked(false);
+        mOnOffButton.setEnabled(false);
+        synchronized (sInstances) {
+            if (mVisualizer != null) {
+                mVisualizer.release();
+                Log.d(TAG,"Visualizer released");
+                mVisualizer = null;
+                sInstances.remove(session);
+            }
+        }
+    }
+
+}
diff --git a/packages/SettingsProvider/res/values/defaults.xml b/packages/SettingsProvider/res/values/defaults.xml
index b3d9ea3..92261da 100644
--- a/packages/SettingsProvider/res/values/defaults.xml
+++ b/packages/SettingsProvider/res/values/defaults.xml
@@ -35,6 +35,7 @@
 
     <bool name="def_bluetooth_on">false</bool>
     <bool name="def_install_non_market_apps">false</bool>
+    <bool name="def_package_verifier_enable">true</bool>
     <!-- Comma-separated list of location providers.
          Network location is off by default because it requires
          user opt-in via Setup Wizard or Settings.
@@ -128,6 +129,15 @@
     <!-- Default for Settings.Secure.TOUCH_EXPLORATION_ENABLED -->
     <bool name="def_touch_exploration_enabled">false</bool>
 
+    <!-- Default value for Settings.Secure.ACCESSIBILITY_DISPLAY_MAGNIFICATION_SCALE -->
+    <fraction name="def_accessibility_display_magnification_scale">200%</fraction>
+
+    <!-- Default value for Settings.Secure.ACCESSIBILITY_DISPLAY_MAGNIFICATION_ENABLED -->
+    <bool name="def_accessibility_display_magnification_enabled">false</bool>
+
+    <!-- Default value for Settings.Secure.ACCESSIBILITY_DISPLAY_MAGNIFICATION_AUTO_UPDATE -->
+    <bool name="def_accessibility_display_magnification_auto_update">true</bool>
+
     <!-- Default for Settings.System.USER_ROTATION -->
     <integer name="def_user_rotation">0</integer>
 
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java b/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java
index 2785991..05673c3 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java
@@ -30,7 +30,9 @@
 import android.media.AudioManager;
 import android.media.AudioService;
 import android.net.ConnectivityManager;
+import android.os.Environment;
 import android.os.SystemProperties;
+import android.os.UserHandle;
 import android.provider.Settings;
 import android.provider.Settings.Secure;
 import android.telephony.TelephonyManager;
@@ -48,6 +50,7 @@
 import org.xmlpull.v1.XmlPullParser;
 import org.xmlpull.v1.XmlPullParserException;
 
+import java.io.File;
 import java.io.IOException;
 import java.util.HashSet;
 import java.util.List;
@@ -64,15 +67,21 @@
     // database gets upgraded properly. At a minimum, please confirm that 'upgradeVersion'
     // is properly propagated through your change.  Not doing so will result in a loss of user
     // settings.
-    private static final int DATABASE_VERSION = 81;
+    private static final int DATABASE_VERSION = 87;
 
     private Context mContext;
+    private int mUserHandle;
 
     private static final HashSet<String> mValidTables = new HashSet<String>();
 
+    private static final String TABLE_SYSTEM = "system";
+    private static final String TABLE_SECURE = "secure";
+    private static final String TABLE_GLOBAL = "global";
+
     static {
-        mValidTables.add("system");
-        mValidTables.add("secure");
+        mValidTables.add(TABLE_SYSTEM);
+        mValidTables.add(TABLE_SECURE);
+        mValidTables.add(TABLE_GLOBAL);
         mValidTables.add("bluetooth_devices");
         mValidTables.add("bookmarks");
 
@@ -82,9 +91,23 @@
         mValidTables.add("old_favorites");
     }
 
-    public DatabaseHelper(Context context) {
-        super(context, DATABASE_NAME, null, DATABASE_VERSION);
+    static String dbNameForUser(final int userHandle) {
+        // The owner gets the unadorned db name;
+        if (userHandle == UserHandle.USER_OWNER) {
+            return DATABASE_NAME;
+        } else {
+            // Place the database in the user-specific data tree so that it's
+            // cleaned up automatically when the user is deleted.
+            File databaseFile = new File(
+                    Environment.getUserSystemDirectory(userHandle), DATABASE_NAME);
+            return databaseFile.getPath();
+        }
+    }
+
+    public DatabaseHelper(Context context, int userHandle) {
+        super(context, dbNameForUser(userHandle), null, DATABASE_VERSION);
         mContext = context;
+        mUserHandle = userHandle;
         setWriteAheadLoggingEnabled(true);
     }
 
@@ -101,6 +124,15 @@
         db.execSQL("CREATE INDEX secureIndex1 ON secure (name);");
     }
 
+    private void createGlobalTable(SQLiteDatabase db) {
+        db.execSQL("CREATE TABLE global (" +
+                "_id INTEGER PRIMARY KEY AUTOINCREMENT," +
+                "name TEXT UNIQUE ON CONFLICT REPLACE," +
+                "value TEXT" +
+                ");");
+        db.execSQL("CREATE INDEX globalIndex1 ON global (name);");
+    }
+
     @Override
     public void onCreate(SQLiteDatabase db) {
         db.execSQL("CREATE TABLE system (" +
@@ -112,6 +144,11 @@
 
         createSecureTable(db);
 
+        // Only create the global table for the singleton 'owner' user
+        if (mUserHandle == UserHandle.USER_OWNER) {
+            createGlobalTable(db);
+        }
+
         db.execSQL("CREATE TABLE bluetooth_devices (" +
                     "_id INTEGER PRIMARY KEY," +
                     "name TEXT," +
@@ -271,7 +308,7 @@
                     Settings.Secure.WIFI_WATCHDOG_PING_DELAY_MS,
                     Settings.Secure.WIFI_WATCHDOG_PING_TIMEOUT_MS,
                 };
-            moveFromSystemToSecure(db, settingsToMove);
+            moveSettingsToNewTable(db, TABLE_SYSTEM, TABLE_SECURE, settingsToMove, false);
             upgradeVersion = 28;
         }
 
@@ -637,7 +674,7 @@
                    "lockscreen.lockedoutpermanently",
                    "lockscreen.password_salt"
            };
-           moveFromSystemToSecure(db, settingsToMove);
+           moveSettingsToNewTable(db, TABLE_SYSTEM, TABLE_SECURE, settingsToMove, false);
            upgradeVersion = 52;
        }
 
@@ -687,7 +724,7 @@
                     Secure.SET_INSTALL_LOCATION,
                     Secure.DEFAULT_INSTALL_LOCATION
             };
-            moveFromSystemToSecure(db, settingsToMove);
+            moveSettingsToNewTable(db, TABLE_SYSTEM, TABLE_SECURE, settingsToMove, false);
             db.beginTransaction();
             SQLiteStatement stmt = null;
             try {
@@ -1013,7 +1050,7 @@
             SQLiteStatement stmt = null;
             Cursor c = null;
             try {
-                c = db.query("secure", new String[] {"_id", "value"},
+                c = db.query(TABLE_SECURE, new String[] {"_id", "value"},
                         "name='lockscreen.disabled'",
                         null, null, null, null);
                 // only set default if it has not yet been set
@@ -1089,14 +1126,14 @@
             // toggle touch exploration. Note that the user has already manually
             // enabled the services and touch exploration which means the she has
             // given consent to have these services work in touch exploration mode.
-            final boolean accessibilityEnabled = getIntValueFromTable(db, "secure",
+            final boolean accessibilityEnabled = getIntValueFromTable(db, TABLE_SECURE,
                     Settings.Secure.ACCESSIBILITY_ENABLED, 0) == 1;
-            final boolean touchExplorationEnabled = getIntValueFromTable(db, "secure",
+            final boolean touchExplorationEnabled = getIntValueFromTable(db, TABLE_SECURE,
                     Settings.Secure.TOUCH_EXPLORATION_ENABLED, 0) == 1;
             if (accessibilityEnabled && touchExplorationEnabled) {
-                String enabledServices = getStringValueFromTable(db, "secure",
+                String enabledServices = getStringValueFromTable(db, TABLE_SECURE,
                         Settings.Secure.ENABLED_ACCESSIBILITY_SERVICES, "");
-                String touchExplorationGrantedServices = getStringValueFromTable(db, "secure",
+                String touchExplorationGrantedServices = getStringValueFromTable(db, TABLE_SECURE,
                         Settings.Secure.TOUCH_EXPLORATION_GRANTED_ACCESSIBILITY_SERVICES, "");
                 if (TextUtils.isEmpty(touchExplorationGrantedServices)
                         && !TextUtils.isEmpty(enabledServices)) {
@@ -1137,6 +1174,7 @@
                         R.string.def_screensaver_component);
                 loadStringSetting(stmt, Settings.Secure.SCREENSAVER_COMPONENTS,
                         R.string.def_screensaver_component);
+
                 db.setTransactionSuccessful();
             } finally {
                 db.endTransaction();
@@ -1145,11 +1183,135 @@
             upgradeVersion = 81;
         }
 
+        if (upgradeVersion == 81) {
+            // Add package verification setting
+            db.beginTransaction();
+            SQLiteStatement stmt = null;
+            try {
+                stmt = db.compileStatement("INSERT OR REPLACE INTO secure(name,value)"
+                        + " VALUES(?,?);");
+                loadBooleanSetting(stmt, Settings.Secure.PACKAGE_VERIFIER_ENABLE,
+                        R.bool.def_package_verifier_enable);
+                db.setTransactionSuccessful();
+            } finally {
+                db.endTransaction();
+                if (stmt != null) stmt.close();
+            }
+            upgradeVersion = 82;
+        }
+
+        if (upgradeVersion == 82) {
+            // Move to per-user settings dbs
+            db.beginTransaction();
+            SQLiteStatement stmt = null;
+            try {
+                // Migrate now-global settings. Note that this happens before
+                // new users can be created.
+                createGlobalTable(db);
+                String[] settingsToMove = hashsetToStringArray(SettingsProvider.sSystemGlobalKeys);
+                moveSettingsToNewTable(db, TABLE_SYSTEM, TABLE_GLOBAL, settingsToMove, false);
+                settingsToMove = hashsetToStringArray(SettingsProvider.sSecureGlobalKeys);
+                moveSettingsToNewTable(db, TABLE_SECURE, TABLE_GLOBAL, settingsToMove, false);
+
+                db.setTransactionSuccessful();
+            } finally {
+                db.endTransaction();
+                if (stmt != null) stmt.close();
+            }
+            upgradeVersion = 83;
+        }
+
+        if (upgradeVersion == 83) {
+            // 1. Setting whether screen magnification is enabled.
+            // 2. Setting for screen magnification scale.
+            // 3. Setting for screen magnification auto update.
+            db.beginTransaction();
+            SQLiteStatement stmt = null;
+            try {
+                stmt = db.compileStatement("INSERT INTO secure(name,value) VALUES(?,?);");
+                loadBooleanSetting(stmt,
+                        Settings.Secure.ACCESSIBILITY_DISPLAY_MAGNIFICATION_ENABLED,
+                        R.bool.def_accessibility_display_magnification_enabled);
+                stmt.close();
+                stmt = db.compileStatement("INSERT INTO secure(name,value) VALUES(?,?);");
+                loadFractionSetting(stmt, Settings.Secure.ACCESSIBILITY_DISPLAY_MAGNIFICATION_SCALE,
+                        R.fraction.def_accessibility_display_magnification_scale, 1);
+                stmt.close();
+                stmt = db.compileStatement("INSERT INTO secure(name,value) VALUES(?,?);");
+                loadBooleanSetting(stmt,
+                        Settings.Secure.ACCESSIBILITY_DISPLAY_MAGNIFICATION_AUTO_UPDATE,
+                        R.bool.def_accessibility_display_magnification_auto_update);
+
+                db.setTransactionSuccessful();
+            } finally {
+                db.endTransaction();
+                if (stmt != null) stmt.close();
+            }
+            upgradeVersion = 84;
+        }
+
+        if (upgradeVersion == 84) {
+            db.beginTransaction();
+            SQLiteStatement stmt = null;
+            try {
+                // Patch up the slightly-wrong key migration from 82 -> 83 for those
+                // devices that missed it, ignoring if the move is redundant
+                String[] settingsToMove = {
+                        Settings.Secure.ADB_ENABLED,
+                        Settings.Secure.BLUETOOTH_ON,
+                        Settings.Secure.DATA_ROAMING,
+                        Settings.Secure.DEVICE_PROVISIONED,
+                        Settings.Secure.INSTALL_NON_MARKET_APPS,
+                        Settings.Secure.USB_MASS_STORAGE_ENABLED
+                };
+                moveSettingsToNewTable(db, TABLE_SECURE, TABLE_GLOBAL, settingsToMove, true);
+                db.setTransactionSuccessful();
+            } finally {
+                db.endTransaction();
+                if (stmt != null) stmt.close();
+            }
+            upgradeVersion = 85;
+        }
+
+        if (upgradeVersion == 85) {
+            db.beginTransaction();
+            try {
+                // Fix up the migration, ignoring already-migrated elements, to snap up to
+                // date with new changes to the set of global versus system/secure settings
+                String[] settingsToMove = { Settings.System.STAY_ON_WHILE_PLUGGED_IN };
+                moveSettingsToNewTable(db, TABLE_SYSTEM, TABLE_GLOBAL, settingsToMove, true);
+
+                db.setTransactionSuccessful();
+            } finally {
+                db.endTransaction();
+            }
+            upgradeVersion = 86;
+        }
+
+        if (upgradeVersion == 86) {
+            db.beginTransaction();
+            try {
+                String[] settingsToMove = {
+                        Settings.Secure.PACKAGE_VERIFIER_ENABLE,
+                        Settings.Secure.PACKAGE_VERIFIER_TIMEOUT,
+                        Settings.Secure.PACKAGE_VERIFIER_DEFAULT_RESPONSE
+                };
+                moveSettingsToNewTable(db, TABLE_SECURE, TABLE_GLOBAL, settingsToMove, true);
+
+                db.setTransactionSuccessful();
+            } finally {
+                db.endTransaction();
+            }
+            upgradeVersion = 87;
+        }
+
         // *** Remember to update DATABASE_VERSION above!
 
         if (upgradeVersion != currentVersion) {
             Log.w(TAG, "Got stuck trying to upgrade from version " + upgradeVersion
                     + ", must wipe the settings provider");
+            db.execSQL("DROP TABLE IF EXISTS global");
+            db.execSQL("DROP TABLE IF EXISTS globalIndex1");
             db.execSQL("DROP TABLE IF EXISTS system");
             db.execSQL("DROP INDEX IF EXISTS systemIndex1");
             db.execSQL("DROP TABLE IF EXISTS secure");
@@ -1170,18 +1332,25 @@
         }
     }
 
-    private void moveFromSystemToSecure(SQLiteDatabase db, String [] settingsToMove) {
-        // Copy settings values from 'system' to 'secure' and delete them from 'system'
+    private String[] hashsetToStringArray(HashSet<String> set) {
+        String[] array = new String[set.size()];
+        return set.toArray(array);
+    }
+
+    private void moveSettingsToNewTable(SQLiteDatabase db,
+            String sourceTable, String destTable,
+            String[] settingsToMove, boolean doIgnore) {
+        // Copy settings values from the source table to the dest, and remove from the source
         SQLiteStatement insertStmt = null;
         SQLiteStatement deleteStmt = null;
 
         db.beginTransaction();
         try {
-            insertStmt =
-                db.compileStatement("INSERT INTO secure (name,value) SELECT name,value FROM "
-                    + "system WHERE name=?");
-            deleteStmt = db.compileStatement("DELETE FROM system WHERE name=?");
-
+            insertStmt = db.compileStatement("INSERT "
+                    + (doIgnore ? " OR IGNORE " : "")
+                    + " INTO " + destTable + " (name,value) SELECT name,value FROM "
+                    + sourceTable + " WHERE name=?");
+            deleteStmt = db.compileStatement("DELETE FROM " + sourceTable + " WHERE name=?");
 
             for (String setting : settingsToMove) {
                 insertStmt.bindString(1, setting);
@@ -1203,7 +1372,7 @@
     }
 
     private void upgradeLockPatternLocation(SQLiteDatabase db) {
-        Cursor c = db.query("system", new String[] {"_id", "value"}, "name='lock_pattern'",
+        Cursor c = db.query(TABLE_SYSTEM, new String[] {"_id", "value"}, "name='lock_pattern'",
                 null, null, null, null);
         if (c.getCount() > 0) {
             c.moveToFirst();
@@ -1220,7 +1389,7 @@
                 }
             }
             c.close();
-            db.delete("system", "name='lock_pattern'", null);
+            db.delete(TABLE_SYSTEM, "name='lock_pattern'", null);
         } else {
             c.close();
         }
@@ -1228,7 +1397,7 @@
 
     private void upgradeScreenTimeoutFromNever(SQLiteDatabase db) {
         // See if the timeout is -1 (for "Never").
-        Cursor c = db.query("system", new String[] { "_id", "value" }, "name=? AND value=?",
+        Cursor c = db.query(TABLE_SYSTEM, new String[] { "_id", "value" }, "name=? AND value=?",
                 new String[] { Settings.System.SCREEN_OFF_TIMEOUT, "-1" },
                 null, null, null);
 
@@ -1497,6 +1666,10 @@
     private void loadSettings(SQLiteDatabase db) {
         loadSystemSettings(db);
         loadSecureSettings(db);
+        // The global table only exists for the 'owner' user
+        if (mUserHandle == UserHandle.USER_OWNER) {
+            loadGlobalSettings(db);
+        }
     }
 
     private void loadSystemSettings(SQLiteDatabase db) {
@@ -1507,10 +1680,6 @@
 
             loadBooleanSetting(stmt, Settings.System.DIM_SCREEN,
                     R.bool.def_dim_screen);
-            loadSetting(stmt, Settings.System.STAY_ON_WHILE_PLUGGED_IN,
-                    ("1".equals(SystemProperties.get("ro.kernel.qemu")) ||
-                        mContext.getResources().getBoolean(R.bool.def_stay_on_while_plugged_in))
-                     ? 1 : 0);
             loadIntegerSetting(stmt, Settings.System.SCREEN_OFF_TIMEOUT,
                     R.integer.def_screen_off_timeout);
 
@@ -1529,21 +1698,6 @@
             // Set default tty mode
             loadSetting(stmt, Settings.System.TTY_MODE, 0);
 
-            loadBooleanSetting(stmt, Settings.System.AIRPLANE_MODE_ON,
-                    R.bool.def_airplane_mode_on);
-
-            loadStringSetting(stmt, Settings.System.AIRPLANE_MODE_RADIOS,
-                    R.string.def_airplane_mode_radios);
-
-            loadStringSetting(stmt, Settings.System.AIRPLANE_MODE_TOGGLEABLE_RADIOS,
-                    R.string.airplane_mode_toggleable_radios);
-
-            loadBooleanSetting(stmt, Settings.System.AUTO_TIME,
-                    R.bool.def_auto_time); // Sync time to NITZ
-
-            loadBooleanSetting(stmt, Settings.System.AUTO_TIME_ZONE,
-                    R.bool.def_auto_time_zone); // Sync timezone to NITZ
-
             loadIntegerSetting(stmt, Settings.System.SCREEN_BRIGHTNESS,
                     R.integer.def_screen_brightness);
 
@@ -1567,9 +1721,6 @@
 
             loadIntegerSetting(stmt, Settings.System.POINTER_SPEED,
                     R.integer.def_pointer_speed);
-
-            loadIntegerSetting(stmt, Settings.System.WIFI_SLEEP_POLICY,
-                    R.integer.def_wifi_sleep_policy);
         } finally {
             if (stmt != null) stmt.close();
         }
@@ -1624,36 +1775,12 @@
             stmt = db.compileStatement("INSERT OR IGNORE INTO secure(name,value)"
                     + " VALUES(?,?);");
 
-            loadBooleanSetting(stmt, Settings.Secure.BLUETOOTH_ON,
-                    R.bool.def_bluetooth_on);
-
-            // Data roaming default, based on build
-            loadSetting(stmt, Settings.Secure.DATA_ROAMING,
-                    "true".equalsIgnoreCase(
-                            SystemProperties.get("ro.com.android.dataroaming",
-                                    "false")) ? 1 : 0);
-
-            // Mobile Data default, based on build
-            loadSetting(stmt, Settings.Secure.MOBILE_DATA,
-                    "true".equalsIgnoreCase(
-                            SystemProperties.get("ro.com.android.mobiledata",
-                                    "true")) ? 1 : 0);
-
-            loadBooleanSetting(stmt, Settings.Secure.INSTALL_NON_MARKET_APPS,
-                    R.bool.def_install_non_market_apps);
+            loadBooleanSetting(stmt, Settings.Secure.PACKAGE_VERIFIER_ENABLE,
+                R.bool.def_package_verifier_enable);
 
             loadStringSetting(stmt, Settings.Secure.LOCATION_PROVIDERS_ALLOWED,
                     R.string.def_location_providers_allowed);
 
-            loadBooleanSetting(stmt, Settings.Secure.ASSISTED_GPS_ENABLED,
-                    R.bool.assisted_gps_enabled);
-
-            loadIntegerSetting(stmt, Settings.Secure.NETWORK_PREFERENCE,
-                    R.integer.def_network_preference);
-
-            loadBooleanSetting(stmt, Settings.Secure.USB_MASS_STORAGE_ENABLED,
-                    R.bool.def_usb_mass_storage_enabled);
-
             loadBooleanSetting(stmt, Settings.Secure.WIFI_ON,
                     R.bool.def_wifi_on);
             loadBooleanSetting(stmt, Settings.Secure.WIFI_NETWORKS_AVAILABLE_NOTIFICATION_ON,
@@ -1674,10 +1801,6 @@
             }
             loadSetting(stmt, Settings.Secure.PREFERRED_NETWORK_MODE, type);
 
-            // Enable or disable Cell Broadcast SMS
-            loadSetting(stmt, Settings.Secure.CDMA_CELL_BROADCAST_SMS,
-                    RILConstants.CDMA_CELL_BROADCAST_SMS_DISABLED);
-
             // Don't do this.  The SystemServer will initialize ADB_ENABLED from a
             // persistent system property instead.
             //loadSetting(stmt, Settings.Secure.ADB_ENABLED, 0);
@@ -1706,20 +1829,6 @@
             loadStringSetting(stmt, Settings.Secure.ACCESSIBILITY_WEB_CONTENT_KEY_BINDINGS,
                     R.string.def_accessibility_web_content_key_bindings);
 
-            final int maxBytes = mContext.getResources().getInteger(
-                    R.integer.def_download_manager_max_bytes_over_mobile);
-            if (maxBytes > 0) {
-                loadSetting(stmt, Settings.Secure.DOWNLOAD_MAX_BYTES_OVER_MOBILE,
-                        Integer.toString(maxBytes));
-            }
-
-            final int recommendedMaxBytes = mContext.getResources().getInteger(
-                    R.integer.def_download_manager_recommended_max_bytes_over_mobile);
-            if (recommendedMaxBytes > 0) {
-                loadSetting(stmt, Settings.Secure.DOWNLOAD_RECOMMENDED_MAX_BYTES_OVER_MOBILE,
-                        Integer.toString(recommendedMaxBytes));
-            }
-
             loadIntegerSetting(stmt, Settings.Secure.LONG_PRESS_TIMEOUT,
                     R.integer.def_long_press_timeout_millis);
 
@@ -1739,15 +1848,6 @@
                         R.bool.def_lockscreen_disabled);
             }
 
-            loadBooleanSetting(stmt, Settings.Secure.DEVICE_PROVISIONED,
-                    R.bool.def_device_provisioned);
-
-            loadBooleanSetting(stmt, Settings.Secure.NETSTATS_ENABLED,
-                    R.bool.def_netstats_enabled);
-
-            loadIntegerSetting(stmt, Settings.Secure.WIFI_MAX_DHCP_RETRY_COUNT,
-                    R.integer.def_max_dhcp_retries);
-
             loadBooleanSetting(stmt, Settings.Secure.SCREENSAVER_ENABLED,
                     R.bool.def_screensaver_enabled);
             loadBooleanSetting(stmt, Settings.Secure.SCREENSAVER_ACTIVATE_ON_DOCK,
@@ -1758,6 +1858,16 @@
                     R.string.def_screensaver_component);
             loadStringSetting(stmt, Settings.Secure.SCREENSAVER_DEFAULT_COMPONENT,
                     R.string.def_screensaver_component);
+
+            loadBooleanSetting(stmt, Settings.Secure.ACCESSIBILITY_DISPLAY_MAGNIFICATION_ENABLED,
+                    R.bool.def_accessibility_display_magnification_enabled);
+
+            loadFractionSetting(stmt, Settings.Secure.ACCESSIBILITY_DISPLAY_MAGNIFICATION_SCALE,
+                    R.fraction.def_accessibility_display_magnification_scale, 1);
+
+            loadBooleanSetting(stmt,
+                    Settings.Secure.ACCESSIBILITY_DISPLAY_MAGNIFICATION_AUTO_UPDATE,
+                    R.bool.def_accessibility_display_magnification_auto_update);
         } finally {
             if (stmt != null) stmt.close();
         }
@@ -1771,6 +1881,97 @@
                 R.string.def_backup_transport);
     }
 
+    private void loadGlobalSettings(SQLiteDatabase db) {
+        SQLiteStatement stmt = null;
+        try {
+            stmt = db.compileStatement("INSERT OR IGNORE INTO global(name,value)"
+                    + " VALUES(?,?);");
+
+            // --- Previously in 'system'
+            loadBooleanSetting(stmt, Settings.Global.AIRPLANE_MODE_ON,
+                    R.bool.def_airplane_mode_on);
+
+            loadStringSetting(stmt, Settings.Global.AIRPLANE_MODE_RADIOS,
+                    R.string.def_airplane_mode_radios);
+
+            loadStringSetting(stmt, Settings.Global.AIRPLANE_MODE_TOGGLEABLE_RADIOS,
+                    R.string.airplane_mode_toggleable_radios);
+
+            loadBooleanSetting(stmt, Settings.Global.ASSISTED_GPS_ENABLED,
+                    R.bool.assisted_gps_enabled);
+
+            loadBooleanSetting(stmt, Settings.Global.AUTO_TIME,
+                    R.bool.def_auto_time); // Sync time to NITZ
+
+            loadBooleanSetting(stmt, Settings.Global.AUTO_TIME_ZONE,
+                    R.bool.def_auto_time_zone); // Sync timezone to NITZ
+
+            loadSetting(stmt, Settings.Global.STAY_ON_WHILE_PLUGGED_IN,
+                    ("1".equals(SystemProperties.get("ro.kernel.qemu")) ||
+                        mContext.getResources().getBoolean(R.bool.def_stay_on_while_plugged_in))
+                     ? 1 : 0);
+
+            loadIntegerSetting(stmt, Settings.Global.WIFI_SLEEP_POLICY,
+                    R.integer.def_wifi_sleep_policy);
+
+            // --- Previously in 'secure'
+            loadBooleanSetting(stmt, Settings.Global.BLUETOOTH_ON,
+                    R.bool.def_bluetooth_on);
+
+            // Enable or disable Cell Broadcast SMS
+            loadSetting(stmt, Settings.Global.CDMA_CELL_BROADCAST_SMS,
+                    RILConstants.CDMA_CELL_BROADCAST_SMS_DISABLED);
+
+            // Data roaming default, based on build
+            loadSetting(stmt, Settings.Global.DATA_ROAMING,
+                    "true".equalsIgnoreCase(
+                            SystemProperties.get("ro.com.android.dataroaming",
+                                    "false")) ? 1 : 0);
+
+            loadBooleanSetting(stmt, Settings.Global.DEVICE_PROVISIONED,
+                    R.bool.def_device_provisioned);
+
+            final int maxBytes = mContext.getResources().getInteger(
+                    R.integer.def_download_manager_max_bytes_over_mobile);
+            if (maxBytes > 0) {
+                loadSetting(stmt, Settings.Global.DOWNLOAD_MAX_BYTES_OVER_MOBILE,
+                        Integer.toString(maxBytes));
+            }
+
+            final int recommendedMaxBytes = mContext.getResources().getInteger(
+                    R.integer.def_download_manager_recommended_max_bytes_over_mobile);
+            if (recommendedMaxBytes > 0) {
+                loadSetting(stmt, Settings.Global.DOWNLOAD_RECOMMENDED_MAX_BYTES_OVER_MOBILE,
+                        Integer.toString(recommendedMaxBytes));
+            }
+
+            // Mobile Data default, based on build
+            loadSetting(stmt, Settings.Global.MOBILE_DATA,
+                    "true".equalsIgnoreCase(
+                            SystemProperties.get("ro.com.android.mobiledata",
+                                    "true")) ? 1 : 0);
+
+            loadBooleanSetting(stmt, Settings.Global.NETSTATS_ENABLED,
+                    R.bool.def_netstats_enabled);
+
+            loadBooleanSetting(stmt, Settings.Global.INSTALL_NON_MARKET_APPS,
+                    R.bool.def_install_non_market_apps);
+
+            loadIntegerSetting(stmt, Settings.Global.NETWORK_PREFERENCE,
+                    R.integer.def_network_preference);
+
+            loadBooleanSetting(stmt, Settings.Global.USB_MASS_STORAGE_ENABLED,
+                    R.bool.def_usb_mass_storage_enabled);
+
+            loadIntegerSetting(stmt, Settings.Global.WIFI_MAX_DHCP_RETRY_COUNT,
+                    R.integer.def_max_dhcp_retries);
+
+            // --- New global settings start here
+        } finally {
+            if (stmt != null) stmt.close();
+        }
+    }
+
     private void loadSetting(SQLiteStatement stmt, String key, Object value) {
         stmt.bindString(1, key);
         stmt.bindString(2, value.toString());
@@ -1797,7 +1998,7 @@
     }
 
     private int getIntValueFromSystem(SQLiteDatabase db, String name, int defaultValue) {
-        return getIntValueFromTable(db, "system", name, defaultValue);
+        return getIntValueFromTable(db, TABLE_SYSTEM, name, defaultValue);
     }
 
     private int getIntValueFromTable(SQLiteDatabase db, String table, String name,
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsBackupAgent.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsBackupAgent.java
index 0165977..1096540 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsBackupAgent.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsBackupAgent.java
@@ -563,7 +563,7 @@
                 getContentResolver().insert(contentUri, contentValues);
             }
 
-            if (DEBUG) {
+            if (DEBUG || true) {
                 Log.d(TAG, "Restored setting: " + key + "=" + value);
             }
         }
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
index 1fa3695..f859f41 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
@@ -18,53 +18,73 @@
 
 import java.io.FileNotFoundException;
 import java.security.SecureRandom;
+import java.util.HashSet;
 import java.util.concurrent.atomic.AtomicBoolean;
 import java.util.concurrent.atomic.AtomicInteger;
 
+import android.app.ActivityManagerNative;
 import android.app.backup.BackupManager;
+import android.content.BroadcastReceiver;
 import android.content.ContentProvider;
 import android.content.ContentUris;
 import android.content.ContentValues;
 import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
 import android.content.pm.PackageManager;
+import android.content.pm.UserInfo;
 import android.content.res.AssetFileDescriptor;
 import android.database.Cursor;
 import android.database.sqlite.SQLiteDatabase;
 import android.database.sqlite.SQLiteException;
 import android.database.sqlite.SQLiteQueryBuilder;
+import android.database.sqlite.SQLiteStatement;
 import android.media.RingtoneManager;
 import android.net.Uri;
+import android.os.Binder;
 import android.os.Bundle;
 import android.os.FileObserver;
 import android.os.ParcelFileDescriptor;
+import android.os.RemoteException;
 import android.os.SystemProperties;
+import android.os.UserHandle;
+import android.os.UserManager;
 import android.provider.DrmStore;
 import android.provider.MediaStore;
 import android.provider.Settings;
 import android.text.TextUtils;
 import android.util.Log;
 import android.util.LruCache;
+import android.util.Slog;
+import android.util.SparseArray;
 
 public class SettingsProvider extends ContentProvider {
     private static final String TAG = "SettingsProvider";
     private static final boolean LOCAL_LOGV = false;
 
+    private static final String TABLE_SYSTEM = "system";
+    private static final String TABLE_SECURE = "secure";
+    private static final String TABLE_GLOBAL = "global";
     private static final String TABLE_FAVORITES = "favorites";
     private static final String TABLE_OLD_FAVORITES = "old_favorites";
 
     private static final String[] COLUMN_VALUE = new String[] { "value" };
 
-    // Cache for settings, access-ordered for acting as LRU.
+    // Caches for each user's settings, access-ordered for acting as LRU.
     // Guarded by themselves.
     private static final int MAX_CACHE_ENTRIES = 200;
-    private static final SettingsCache sSystemCache = new SettingsCache("system");
-    private static final SettingsCache sSecureCache = new SettingsCache("secure");
+    private static final SparseArray<SettingsCache> sSystemCaches
+            = new SparseArray<SettingsCache>();
+    private static final SparseArray<SettingsCache> sSecureCaches
+            = new SparseArray<SettingsCache>();
+    private static final SettingsCache sGlobalCache = new SettingsCache(TABLE_GLOBAL);
 
     // The count of how many known (handled by SettingsProvider)
-    // database mutations are currently being handled.  Used by
-    // sFileObserver to not reload the database when it's ourselves
+    // database mutations are currently being handled for this user.
+    // Used by file observers to not reload the database when it's ourselves
     // modifying it.
-    private static final AtomicInteger sKnownMutationsInFlight = new AtomicInteger(0);
+    private static final SparseArray<AtomicInteger> sKnownMutationsInFlight
+            = new SparseArray<AtomicInteger>();
 
     // Over this size we don't reject loading or saving settings but
     // we do consider them broken/malicious and don't keep them in
@@ -77,10 +97,132 @@
     // want to cache the existence of a key, but not store its value.
     private static final Bundle TOO_LARGE_TO_CACHE_MARKER = Bundle.forPair("_dummy", null);
 
-    protected DatabaseHelper mOpenHelper;
+    // Each defined user has their own settings
+    protected final SparseArray<DatabaseHelper> mOpenHelpers = new SparseArray<DatabaseHelper>();
+    //protected DatabaseHelper mOpenHelper;
+    private UserManager mUserManager;
     private BackupManager mBackupManager;
 
     /**
+     * Settings which need to be treated as global/shared in multi-user environments.
+     */
+    static final HashSet<String> sSecureGlobalKeys;
+    static final HashSet<String> sSystemGlobalKeys;
+    static {
+        // Keys (name column) from the 'secure' table that are now in the owner user's 'global'
+        // table, shared across all users
+        // These must match Settings.Secure.MOVED_TO_GLOBAL
+        sSecureGlobalKeys = new HashSet<String>();
+        sSecureGlobalKeys.add(Settings.Secure.ADB_ENABLED);
+        sSecureGlobalKeys.add(Settings.Secure.ASSISTED_GPS_ENABLED);
+        sSecureGlobalKeys.add(Settings.Secure.BLUETOOTH_ON);
+        sSecureGlobalKeys.add(Settings.Secure.CDMA_CELL_BROADCAST_SMS);
+        sSecureGlobalKeys.add(Settings.Secure.CDMA_ROAMING_MODE);
+        sSecureGlobalKeys.add(Settings.Secure.CDMA_SUBSCRIPTION_MODE);
+        sSecureGlobalKeys.add(Settings.Secure.DATA_ACTIVITY_TIMEOUT_MOBILE);
+        sSecureGlobalKeys.add(Settings.Secure.DATA_ACTIVITY_TIMEOUT_WIFI);
+        sSecureGlobalKeys.add(Settings.Secure.DATA_ROAMING);
+        sSecureGlobalKeys.add(Settings.Secure.DEVELOPMENT_SETTINGS_ENABLED);
+        sSecureGlobalKeys.add(Settings.Secure.DEVICE_PROVISIONED);
+        sSecureGlobalKeys.add(Settings.Secure.DISPLAY_DENSITY_FORCED);
+        sSecureGlobalKeys.add(Settings.Secure.DISPLAY_SIZE_FORCED);
+        sSecureGlobalKeys.add(Settings.Secure.DOWNLOAD_MAX_BYTES_OVER_MOBILE);
+        sSecureGlobalKeys.add(Settings.Secure.DOWNLOAD_RECOMMENDED_MAX_BYTES_OVER_MOBILE);
+        sSecureGlobalKeys.add(Settings.Secure.INSTALL_NON_MARKET_APPS);
+        sSecureGlobalKeys.add(Settings.Secure.MOBILE_DATA);
+        sSecureGlobalKeys.add(Settings.Secure.NETSTATS_DEV_BUCKET_DURATION);
+        sSecureGlobalKeys.add(Settings.Secure.NETSTATS_DEV_DELETE_AGE);
+        sSecureGlobalKeys.add(Settings.Secure.NETSTATS_DEV_PERSIST_BYTES);
+        sSecureGlobalKeys.add(Settings.Secure.NETSTATS_DEV_ROTATE_AGE);
+        sSecureGlobalKeys.add(Settings.Secure.NETSTATS_ENABLED);
+        sSecureGlobalKeys.add(Settings.Secure.NETSTATS_GLOBAL_ALERT_BYTES);
+        sSecureGlobalKeys.add(Settings.Secure.NETSTATS_POLL_INTERVAL);
+        sSecureGlobalKeys.add(Settings.Secure.NETSTATS_REPORT_XT_OVER_DEV);
+        sSecureGlobalKeys.add(Settings.Secure.NETSTATS_SAMPLE_ENABLED);
+        sSecureGlobalKeys.add(Settings.Secure.NETSTATS_TIME_CACHE_MAX_AGE);
+        sSecureGlobalKeys.add(Settings.Secure.NETSTATS_UID_BUCKET_DURATION);
+        sSecureGlobalKeys.add(Settings.Secure.NETSTATS_UID_DELETE_AGE);
+        sSecureGlobalKeys.add(Settings.Secure.NETSTATS_UID_PERSIST_BYTES);
+        sSecureGlobalKeys.add(Settings.Secure.NETSTATS_UID_ROTATE_AGE);
+        sSecureGlobalKeys.add(Settings.Secure.NETSTATS_UID_TAG_BUCKET_DURATION);
+        sSecureGlobalKeys.add(Settings.Secure.NETSTATS_UID_TAG_DELETE_AGE);
+        sSecureGlobalKeys.add(Settings.Secure.NETSTATS_UID_TAG_PERSIST_BYTES);
+        sSecureGlobalKeys.add(Settings.Secure.NETSTATS_UID_TAG_ROTATE_AGE);
+        sSecureGlobalKeys.add(Settings.Secure.NETWORK_PREFERENCE);
+        sSecureGlobalKeys.add(Settings.Secure.NITZ_UPDATE_DIFF);
+        sSecureGlobalKeys.add(Settings.Secure.NITZ_UPDATE_SPACING);
+        sSecureGlobalKeys.add(Settings.Secure.NTP_SERVER);
+        sSecureGlobalKeys.add(Settings.Secure.NTP_TIMEOUT);
+        sSecureGlobalKeys.add(Settings.Secure.PDP_WATCHDOG_ERROR_POLL_COUNT);
+        sSecureGlobalKeys.add(Settings.Secure.PDP_WATCHDOG_LONG_POLL_INTERVAL_MS);
+        sSecureGlobalKeys.add(Settings.Secure.PDP_WATCHDOG_MAX_PDP_RESET_FAIL_COUNT);
+        sSecureGlobalKeys.add(Settings.Secure.PDP_WATCHDOG_POLL_INTERVAL_MS);
+        sSecureGlobalKeys.add(Settings.Secure.PDP_WATCHDOG_TRIGGER_PACKET_COUNT);
+        sSecureGlobalKeys.add(Settings.Secure.SAMPLING_PROFILER_MS);
+        sSecureGlobalKeys.add(Settings.Secure.SETUP_PREPAID_DATA_SERVICE_URL);
+        sSecureGlobalKeys.add(Settings.Secure.SETUP_PREPAID_DETECTION_REDIR_HOST);
+        sSecureGlobalKeys.add(Settings.Secure.SETUP_PREPAID_DETECTION_TARGET_URL);
+        sSecureGlobalKeys.add(Settings.Secure.TETHER_DUN_APN);
+        sSecureGlobalKeys.add(Settings.Secure.TETHER_DUN_REQUIRED);
+        sSecureGlobalKeys.add(Settings.Secure.TETHER_SUPPORTED);
+        sSecureGlobalKeys.add(Settings.Secure.THROTTLE_HELP_URI);
+        sSecureGlobalKeys.add(Settings.Secure.THROTTLE_MAX_NTP_CACHE_AGE_SEC);
+        sSecureGlobalKeys.add(Settings.Secure.THROTTLE_NOTIFICATION_TYPE);
+        sSecureGlobalKeys.add(Settings.Secure.THROTTLE_POLLING_SEC);
+        sSecureGlobalKeys.add(Settings.Secure.THROTTLE_RESET_DAY);
+        sSecureGlobalKeys.add(Settings.Secure.THROTTLE_THRESHOLD_BYTES);
+        sSecureGlobalKeys.add(Settings.Secure.THROTTLE_VALUE_KBITSPS);
+        sSecureGlobalKeys.add(Settings.Secure.USB_MASS_STORAGE_ENABLED);
+        sSecureGlobalKeys.add(Settings.Secure.USE_GOOGLE_MAIL);
+        sSecureGlobalKeys.add(Settings.Secure.WEB_AUTOFILL_QUERY_URL);
+        sSecureGlobalKeys.add(Settings.Secure.WIFI_COUNTRY_CODE);
+        sSecureGlobalKeys.add(Settings.Secure.WIFI_FRAMEWORK_SCAN_INTERVAL_MS);
+        sSecureGlobalKeys.add(Settings.Secure.WIFI_FREQUENCY_BAND);
+        sSecureGlobalKeys.add(Settings.Secure.WIFI_IDLE_MS);
+        sSecureGlobalKeys.add(Settings.Secure.WIFI_MAX_DHCP_RETRY_COUNT);
+        sSecureGlobalKeys.add(Settings.Secure.WIFI_MOBILE_DATA_TRANSITION_WAKELOCK_TIMEOUT_MS);
+        sSecureGlobalKeys.add(Settings.Secure.WIFI_NETWORKS_AVAILABLE_NOTIFICATION_ON);
+        sSecureGlobalKeys.add(Settings.Secure.WIFI_NETWORKS_AVAILABLE_REPEAT_DELAY);
+        sSecureGlobalKeys.add(Settings.Secure.WIFI_NUM_OPEN_NETWORKS_KEPT);
+        sSecureGlobalKeys.add(Settings.Secure.WIFI_ON);
+        sSecureGlobalKeys.add(Settings.Secure.WIFI_P2P_DEVICE_NAME);
+        sSecureGlobalKeys.add(Settings.Secure.WIFI_SAVED_STATE);
+        sSecureGlobalKeys.add(Settings.Secure.WIFI_SUPPLICANT_SCAN_INTERVAL_MS);
+        sSecureGlobalKeys.add(Settings.Secure.WIFI_SUSPEND_OPTIMIZATIONS_ENABLED);
+        sSecureGlobalKeys.add(Settings.Secure.WIFI_WATCHDOG_NUM_ARP_PINGS);
+        sSecureGlobalKeys.add(Settings.Secure.WIFI_WATCHDOG_ON);
+        sSecureGlobalKeys.add(Settings.Secure.WIFI_WATCHDOG_POOR_NETWORK_TEST_ENABLED);
+        sSecureGlobalKeys.add(Settings.Secure.WIFI_WATCHDOG_RSSI_FETCH_INTERVAL_MS);
+        sSecureGlobalKeys.add(Settings.Secure.WIMAX_NETWORKS_AVAILABLE_NOTIFICATION_ON);
+        sSecureGlobalKeys.add(Settings.Secure.WTF_IS_FATAL);
+
+        // Keys from the 'system' table now moved to 'global'
+        // These must match Settings.System.MOVED_TO_GLOBAL
+        sSystemGlobalKeys = new HashSet<String>();
+
+        sSystemGlobalKeys.add(Settings.System.AIRPLANE_MODE_ON);
+        sSystemGlobalKeys.add(Settings.System.AIRPLANE_MODE_RADIOS);
+        sSystemGlobalKeys.add(Settings.System.AIRPLANE_MODE_TOGGLEABLE_RADIOS);
+        sSystemGlobalKeys.add(Settings.System.AUTO_TIME);
+        sSystemGlobalKeys.add(Settings.System.AUTO_TIME_ZONE);
+        sSystemGlobalKeys.add(Settings.System.CAR_DOCK_SOUND);
+        sSystemGlobalKeys.add(Settings.System.CAR_UNDOCK_SOUND);
+        sSystemGlobalKeys.add(Settings.System.DESK_DOCK_SOUND);
+        sSystemGlobalKeys.add(Settings.System.DESK_UNDOCK_SOUND);
+        sSystemGlobalKeys.add(Settings.System.DOCK_SOUNDS_ENABLED);
+        sSystemGlobalKeys.add(Settings.System.LOCK_SOUND);
+        sSystemGlobalKeys.add(Settings.System.UNLOCK_SOUND);
+        sSystemGlobalKeys.add(Settings.System.LOW_BATTERY_SOUND);
+        sSystemGlobalKeys.add(Settings.System.POWER_SOUNDS_ENABLED);
+        sSystemGlobalKeys.add(Settings.System.STAY_ON_WHILE_PLUGGED_IN);
+        sSystemGlobalKeys.add(Settings.System.WIFI_SLEEP_POLICY);
+    }
+
+    private boolean settingMovedToGlobal(final String name) {
+        return sSecureGlobalKeys.contains(name) || sSystemGlobalKeys.contains(name);
+    }
+
+    /**
      * Decode a content URL into the table, projection, and arguments
      * used to access the corresponding database rows.
      */
@@ -107,7 +249,7 @@
                 if (!DatabaseHelper.isValidTable(this.table)) {
                     throw new IllegalArgumentException("Bad root path: " + this.table);
                 }
-                if ("system".equals(this.table) || "secure".equals(this.table)) {
+                if (TABLE_SYSTEM.equals(this.table) || TABLE_SECURE.equals(this.table)) {
                     this.where = Settings.NameValueTable.NAME + "=?";
                     this.args = new String[] { url.getPathSegments().get(1) };
                 } else {
@@ -144,7 +286,9 @@
             throw new IllegalArgumentException("Invalid URI: " + tableUri);
         }
         String table = tableUri.getPathSegments().get(0);
-        if ("system".equals(table) || "secure".equals(table)) {
+        if (TABLE_SYSTEM.equals(table) ||
+                TABLE_SECURE.equals(table) ||
+                TABLE_GLOBAL.equals(table)) {
             String name = values.getAsString(Settings.NameValueTable.NAME);
             return Uri.withAppendedPath(tableUri, name);
         } else {
@@ -159,18 +303,21 @@
      * contract class uses these to provide client-side caches.)
      * @param uri to send notifications for
      */
-    private void sendNotify(Uri uri) {
+    private void sendNotify(Uri uri, int userHandle) {
         // Update the system property *first*, so if someone is listening for
         // a notification and then using the contract class to get their data,
         // the system property will be updated and they'll get the new data.
 
         boolean backedUpDataChanged = false;
         String property = null, table = uri.getPathSegments().get(0);
-        if (table.equals("system")) {
-            property = Settings.System.SYS_PROP_SETTING_VERSION;
+        if (table.equals(TABLE_SYSTEM)) {
+            property = Settings.System.SYS_PROP_SETTING_VERSION + '_' + userHandle;
             backedUpDataChanged = true;
-        } else if (table.equals("secure")) {
-            property = Settings.Secure.SYS_PROP_SETTING_VERSION;
+        } else if (table.equals(TABLE_SECURE)) {
+            property = Settings.Secure.SYS_PROP_SETTING_VERSION + '_' + userHandle;
+            backedUpDataChanged = true;
+        } else if (table.equals(TABLE_GLOBAL)) {
+            property = Settings.Global.SYS_PROP_SETTING_VERSION;    // this one is global
             backedUpDataChanged = true;
         }
 
@@ -201,7 +348,7 @@
      * @throws SecurityException if the caller is forbidden to write.
      */
     private void checkWritePermissions(SqlArguments args) {
-        if ("secure".equals(args.table) &&
+        if ((TABLE_SECURE.equals(args.table) || TABLE_GLOBAL.equals(args.table)) &&
             getContext().checkCallingOrSelfPermission(
                     android.Manifest.permission.WRITE_SECURE_SETTINGS) !=
             PackageManager.PERMISSION_GRANTED) {
@@ -218,70 +365,147 @@
     // normally the exclusive owner of the database.  But we keep this
     // enabled all the time to minimize development-vs-user
     // differences in testing.
-    private static SettingsFileObserver sObserverInstance;
+    private static SparseArray<SettingsFileObserver> sObserverInstances
+            = new SparseArray<SettingsFileObserver>();
     private class SettingsFileObserver extends FileObserver {
         private final AtomicBoolean mIsDirty = new AtomicBoolean(false);
+        private final int mUserHandle;
         private final String mPath;
 
-        public SettingsFileObserver(String path) {
+        public SettingsFileObserver(int userHandle, String path) {
             super(path, FileObserver.CLOSE_WRITE |
                   FileObserver.CREATE | FileObserver.DELETE |
                   FileObserver.MOVED_TO | FileObserver.MODIFY);
+            mUserHandle = userHandle;
             mPath = path;
         }
 
         public void onEvent(int event, String path) {
-            int modsInFlight = sKnownMutationsInFlight.get();
+            int modsInFlight = sKnownMutationsInFlight.get(mUserHandle).get();
             if (modsInFlight > 0) {
                 // our own modification.
                 return;
             }
-            Log.d(TAG, "external modification to " + mPath + "; event=" + event);
+            Log.d(TAG, "User " + mUserHandle + " external modification to " + mPath
+                    + "; event=" + event);
             if (!mIsDirty.compareAndSet(false, true)) {
                 // already handled. (we get a few update events
                 // during an sqlite write)
                 return;
             }
-            Log.d(TAG, "updating our caches for " + mPath);
-            fullyPopulateCaches();
+            Log.d(TAG, "User " + mUserHandle + " updating our caches for " + mPath);
+            fullyPopulateCaches(mUserHandle);
             mIsDirty.set(false);
         }
     }
 
     @Override
     public boolean onCreate() {
-        mOpenHelper = new DatabaseHelper(getContext());
         mBackupManager = new BackupManager(getContext());
+        mUserManager = (UserManager) getContext().getSystemService(Context.USER_SERVICE);
 
-        if (!ensureAndroidIdIsSet()) {
-            return false;
+        synchronized (this) {
+            establishDbTrackingLocked(UserHandle.USER_OWNER);
+
+            IntentFilter userFilter = new IntentFilter();
+            userFilter.addAction(Intent.ACTION_USER_REMOVED);
+            getContext().registerReceiver(new BroadcastReceiver() {
+                @Override
+                public void onReceive(Context context, Intent intent) {
+                    if (intent.getAction().equals(Intent.ACTION_USER_REMOVED)) {
+                        final int userHandle = intent.getIntExtra(Intent.EXTRA_USER_HANDLE,
+                                UserHandle.USER_OWNER);
+                        if (userHandle != UserHandle.USER_OWNER) {
+                            onUserRemoved(userHandle);
+                        }
+                    }
+                }
+            }, userFilter);
+
+            if (!ensureAndroidIdIsSet()) {
+                return false;
+            }
         }
-
-        // Watch for external modifications to the database file,
-        // keeping our cache in sync.
-        SQLiteDatabase db = mOpenHelper.getWritableDatabase();
-        sObserverInstance = new SettingsFileObserver(db.getPath());
-        sObserverInstance.startWatching();
-        startAsyncCachePopulation();
         return true;
     }
 
-    private void startAsyncCachePopulation() {
-        new Thread("populate-settings-caches") {
-            public void run() {
-                fullyPopulateCaches();
+    void onUserRemoved(int userHandle) {
+        // the db file itself will be deleted automatically, but we need to tear down
+        // our caches and other internal bookkeeping.  Creation/deletion of a user's
+        // settings db infrastructure is synchronized on 'this'
+        synchronized (this) {
+            FileObserver observer = sObserverInstances.get(userHandle);
+            if (observer != null) {
+                observer.stopWatching();
+                sObserverInstances.delete(userHandle);
             }
-        }.start();
+
+            mOpenHelpers.delete(userHandle);
+            sSystemCaches.delete(userHandle);
+            sSecureCaches.delete(userHandle);
+            sKnownMutationsInFlight.delete(userHandle);
+
+            String property = Settings.System.SYS_PROP_SETTING_VERSION + '_' + userHandle;
+            SystemProperties.set(property, "");
+            property = Settings.Secure.SYS_PROP_SETTING_VERSION + '_' + userHandle;
+            SystemProperties.set(property, "");
+        }
     }
 
-    private void fullyPopulateCaches() {
-        fullyPopulateCache("secure", sSecureCache);
-        fullyPopulateCache("system", sSystemCache);
+    private void establishDbTrackingLocked(int userHandle) {
+        if (LOCAL_LOGV) {
+            Slog.i(TAG, "Installing settings db helper and caches for user " + userHandle);
+        }
+
+        DatabaseHelper dbhelper = new DatabaseHelper(getContext(), userHandle);
+        mOpenHelpers.append(userHandle, dbhelper);
+
+        // Watch for external modifications to the database files,
+        // keeping our caches in sync.
+        sSystemCaches.append(userHandle, new SettingsCache(TABLE_SYSTEM));
+        sSecureCaches.append(userHandle, new SettingsCache(TABLE_SECURE));
+        sKnownMutationsInFlight.append(userHandle, new AtomicInteger(0));
+        SQLiteDatabase db = dbhelper.getWritableDatabase();
+
+        // Now we can start observing it for changes
+        SettingsFileObserver observer = new SettingsFileObserver(userHandle, db.getPath());
+        sObserverInstances.append(userHandle, observer);
+        observer.startWatching();
+
+        startAsyncCachePopulation(userHandle);
+    }
+
+    class CachePrefetchThread extends Thread {
+        private int mUserHandle;
+
+        CachePrefetchThread(int userHandle) {
+            super("populate-settings-caches");
+            mUserHandle = userHandle;
+        }
+
+        @Override
+        public void run() {
+            fullyPopulateCaches(mUserHandle);
+        }
+    }
+
+    private void startAsyncCachePopulation(int userHandle) {
+        new CachePrefetchThread(userHandle).start();
+    }
+
+    private void fullyPopulateCaches(final int userHandle) {
+        DatabaseHelper dbHelper = mOpenHelpers.get(userHandle);
+        // Only populate the globals cache once, for the owning user
+        if (userHandle == UserHandle.USER_OWNER) {
+            fullyPopulateCache(dbHelper, TABLE_GLOBAL, sGlobalCache);
+        }
+        fullyPopulateCache(dbHelper, TABLE_SECURE, sSecureCaches.get(userHandle));
+        fullyPopulateCache(dbHelper, TABLE_SYSTEM, sSystemCaches.get(userHandle));
     }
 
     // Slurp all values (if sane in number & size) into cache.
-    private void fullyPopulateCache(String table, SettingsCache cache) {
-        SQLiteDatabase db = mOpenHelper.getReadableDatabase();
+    private void fullyPopulateCache(DatabaseHelper dbHelper, String table, SettingsCache cache) {
+        SQLiteDatabase db = dbHelper.getReadableDatabase();
         Cursor c = db.query(
             table,
             new String[] { Settings.NameValueTable.NAME, Settings.NameValueTable.VALUE },
@@ -337,23 +561,154 @@
         }
     }
 
+    // Lazy-initialize the settings caches for non-primary users
+    private SettingsCache getOrConstructCache(int callingUser, SparseArray<SettingsCache> which) {
+        synchronized (this) {
+            getOrEstablishDatabaseLocked(callingUser); // ignore return value; we don't need it
+            return which.get(callingUser);
+        }
+    }
+
+    // Lazy initialize the database helper and caches for this user, if necessary
+    private DatabaseHelper getOrEstablishDatabaseLocked(int callingUser) {
+        long oldId = Binder.clearCallingIdentity();
+        try {
+            DatabaseHelper dbHelper = mOpenHelpers.get(callingUser);
+            if (null == dbHelper) {
+                establishDbTrackingLocked(callingUser);
+                dbHelper = mOpenHelpers.get(callingUser);
+            }
+            return dbHelper;
+        } finally {
+            Binder.restoreCallingIdentity(oldId);
+        }
+    }
+
+    public SettingsCache cacheForTable(final int callingUser, String tableName) {
+        if (TABLE_SYSTEM.equals(tableName)) {
+            return getOrConstructCache(callingUser, sSystemCaches);
+        }
+        if (TABLE_SECURE.equals(tableName)) {
+            return getOrConstructCache(callingUser, sSecureCaches);
+        }
+        if (TABLE_GLOBAL.equals(tableName)) {
+            return sGlobalCache;
+        }
+        return null;
+    }
+
+    /**
+     * Used for wiping a whole cache on deletes when we're not
+     * sure what exactly was deleted or changed.
+     */
+    public void invalidateCache(final int callingUser, String tableName) {
+        SettingsCache cache = cacheForTable(callingUser, tableName);
+        if (cache == null) {
+            return;
+        }
+        synchronized (cache) {
+            cache.evictAll();
+            cache.mCacheFullyMatchesDisk = false;
+        }
+    }
+
     /**
      * Fast path that avoids the use of chatty remoted Cursors.
      */
     @Override
     public Bundle call(String method, String request, Bundle args) {
+        int callingUser = UserHandle.getCallingUserId();
+        if (args != null) {
+            int reqUser = args.getInt(Settings.CALL_METHOD_USER_KEY, callingUser);
+            if (reqUser != callingUser) {
+                getContext().enforceCallingPermission(
+                        android.Manifest.permission.INTERACT_ACROSS_USERS_FULL,
+                        "Not permitted to access settings for other users");
+                if (reqUser == UserHandle.USER_CURRENT) {
+                    try {
+                        reqUser = ActivityManagerNative.getDefault().getCurrentUser().id;
+                    } catch (RemoteException e) {
+                        // can't happen
+                    }
+                    if (LOCAL_LOGV) {
+                        Slog.v(TAG, "   USER_CURRENT resolved to " + reqUser);
+                    }
+                }
+                if (reqUser < 0) {
+                    throw new IllegalArgumentException("Bad user handle " + reqUser);
+                }
+                callingUser = reqUser;
+                if (LOCAL_LOGV) Slog.v(TAG, "   fetching setting for user " + callingUser);
+            }
+        }
+
+        // Note: we assume that get/put operations for moved-to-global names have already
+        // been directed to the new location on the caller side (otherwise we'd fix them
+        // up here).
+
+        DatabaseHelper dbHelper;
+        SettingsCache cache;
+
+        // Get methods
         if (Settings.CALL_METHOD_GET_SYSTEM.equals(method)) {
-            return lookupValue("system", sSystemCache, request);
+            if (LOCAL_LOGV) Slog.v(TAG, "call(system:" + request + ") for " + callingUser);
+            synchronized (this) {
+                dbHelper = getOrEstablishDatabaseLocked(callingUser);
+                cache = sSystemCaches.get(callingUser);
+            }
+            return lookupValue(dbHelper, TABLE_SYSTEM, cache, request);
         }
         if (Settings.CALL_METHOD_GET_SECURE.equals(method)) {
-            return lookupValue("secure", sSecureCache, request);
+            if (LOCAL_LOGV) Slog.v(TAG, "call(secure:" + request + ") for " + callingUser);
+            synchronized (this) {
+                dbHelper = getOrEstablishDatabaseLocked(callingUser);
+                cache = sSecureCaches.get(callingUser);
+            }
+            return lookupValue(dbHelper, TABLE_SECURE, cache, request);
         }
+        if (Settings.CALL_METHOD_GET_GLOBAL.equals(method)) {
+            if (LOCAL_LOGV) Slog.v(TAG, "call(global:" + request + ") for " + callingUser);
+            // fast path: owner db & cache are immutable after onCreate() so we need not
+            // guard on the attempt to look them up
+            return lookupValue(getOrEstablishDatabaseLocked(UserHandle.USER_OWNER), TABLE_GLOBAL,
+                    sGlobalCache, request);
+        }
+
+        // Put methods - new value is in the args bundle under the key named by
+        // the Settings.NameValueTable.VALUE static.
+        final String newValue = (args == null)
+                ? null : args.getString(Settings.NameValueTable.VALUE);
+        if (newValue == null) {
+            throw new IllegalArgumentException("Bad value for " + method);
+        }
+
+        final ContentValues values = new ContentValues();
+        values.put(Settings.NameValueTable.NAME, request);
+        values.put(Settings.NameValueTable.VALUE, newValue);
+        if (Settings.CALL_METHOD_PUT_SYSTEM.equals(method)) {
+            if (LOCAL_LOGV) Slog.v(TAG, "call_put(system:" + request + "=" + newValue + ") for " + callingUser);
+            insert(Settings.System.CONTENT_URI, values);
+        } else if (Settings.CALL_METHOD_PUT_SECURE.equals(method)) {
+            if (LOCAL_LOGV) Slog.v(TAG, "call_put(secure:" + request + "=" + newValue + ") for " + callingUser);
+            insert(Settings.Secure.CONTENT_URI, values);
+        } else if (Settings.CALL_METHOD_PUT_GLOBAL.equals(method)) {
+            if (LOCAL_LOGV) Slog.v(TAG, "call_put(global:" + request + "=" + newValue + ") for " + callingUser);
+            insert(Settings.Global.CONTENT_URI, values);
+        } else {
+            Slog.w(TAG, "call() with invalid method: " + method);
+        }
+
         return null;
     }
 
     // Looks up value 'key' in 'table' and returns either a single-pair Bundle,
     // possibly with a null value, or null on failure.
-    private Bundle lookupValue(String table, SettingsCache cache, String key) {
+    private Bundle lookupValue(DatabaseHelper dbHelper, String table,
+            final SettingsCache cache, String key) {
+        if (cache == null) {
+           Slog.e(TAG, "cache is null for user " + UserHandle.getCallingUserId() + " : key=" + key);
+           return null;
+        }
         synchronized (cache) {
             Bundle value = cache.get(key);
             if (value != null) {
@@ -372,7 +727,7 @@
             }
         }
 
-        SQLiteDatabase db = mOpenHelper.getReadableDatabase();
+        SQLiteDatabase db = dbHelper.getReadableDatabase();
         Cursor cursor = null;
         try {
             cursor = db.query(table, COLUMN_VALUE, "name=?", new String[]{key},
@@ -393,8 +748,14 @@
 
     @Override
     public Cursor query(Uri url, String[] select, String where, String[] whereArgs, String sort) {
+        final int callingUser = UserHandle.getCallingUserId();
+        if (LOCAL_LOGV) Slog.v(TAG, "query() for user " + callingUser);
         SqlArguments args = new SqlArguments(url, where, whereArgs);
-        SQLiteDatabase db = mOpenHelper.getReadableDatabase();
+        DatabaseHelper dbH;
+        synchronized (this) {
+            dbH = getOrEstablishDatabaseLocked(callingUser);
+        }
+        SQLiteDatabase db = dbH.getReadableDatabase();
 
         // The favorites table was moved from this provider to a provider inside Home
         // Home still need to query this table to upgrade from pre-cupcake builds
@@ -437,15 +798,22 @@
 
     @Override
     public int bulkInsert(Uri uri, ContentValues[] values) {
+        final int callingUser = UserHandle.getCallingUserId();
+        if (LOCAL_LOGV) Slog.v(TAG, "bulkInsert() for user " + callingUser);
         SqlArguments args = new SqlArguments(uri);
         if (TABLE_FAVORITES.equals(args.table)) {
             return 0;
         }
         checkWritePermissions(args);
-        SettingsCache cache = SettingsCache.forTable(args.table);
+        SettingsCache cache = cacheForTable(callingUser, args.table);
 
-        sKnownMutationsInFlight.incrementAndGet();
-        SQLiteDatabase db = mOpenHelper.getWritableDatabase();
+        final AtomicInteger mutationCount = sKnownMutationsInFlight.get(callingUser);
+        mutationCount.incrementAndGet();
+        DatabaseHelper dbH;
+        synchronized (this) {
+            dbH = getOrEstablishDatabaseLocked(callingUser);
+        }
+        SQLiteDatabase db = dbH.getWritableDatabase();
         db.beginTransaction();
         try {
             int numValues = values.length;
@@ -457,10 +825,10 @@
             db.setTransactionSuccessful();
         } finally {
             db.endTransaction();
-            sKnownMutationsInFlight.decrementAndGet();
+            mutationCount.decrementAndGet();
         }
 
-        sendNotify(uri);
+        sendNotify(uri, callingUser);
         return values.length;
     }
 
@@ -538,6 +906,22 @@
 
     @Override
     public Uri insert(Uri url, ContentValues initialValues) {
+        return insertForUser(url, initialValues, UserHandle.getCallingUserId());
+    }
+
+    // Settings.put*ForUser() always winds up here, so this is where we apply
+    // policy around permission to write settings for other users.
+    private Uri insertForUser(Uri url, ContentValues initialValues, int desiredUserHandle) {
+        final int callingUser = UserHandle.getCallingUserId();
+        if (callingUser != desiredUserHandle) {
+            getContext().enforceCallingPermission(
+                    android.Manifest.permission.INTERACT_ACROSS_USERS_FULL,
+                    "Not permitted to access settings for other users");
+        }
+
+        if (LOCAL_LOGV) Slog.v(TAG, "insert(" + url + ") for user " + desiredUserHandle
+                + " by " + callingUser);
+
         SqlArguments args = new SqlArguments(url);
         if (TABLE_FAVORITES.equals(args.table)) {
             return null;
@@ -551,28 +935,41 @@
             if (!parseProviderList(url, initialValues)) return null;
         }
 
-        SettingsCache cache = SettingsCache.forTable(args.table);
+        // The global table is stored under the owner, always
+        if (TABLE_GLOBAL.equals(args.table)) {
+            desiredUserHandle = UserHandle.USER_OWNER;
+        }
+
+        SettingsCache cache = cacheForTable(desiredUserHandle, args.table);
         String value = initialValues.getAsString(Settings.NameValueTable.VALUE);
         if (SettingsCache.isRedundantSetValue(cache, name, value)) {
             return Uri.withAppendedPath(url, name);
         }
 
-        sKnownMutationsInFlight.incrementAndGet();
-        SQLiteDatabase db = mOpenHelper.getWritableDatabase();
+        final AtomicInteger mutationCount = sKnownMutationsInFlight.get(desiredUserHandle);
+        mutationCount.incrementAndGet();
+        DatabaseHelper dbH;
+        synchronized (this) {
+            dbH = getOrEstablishDatabaseLocked(callingUser);
+        }
+        SQLiteDatabase db = dbH.getWritableDatabase();
         final long rowId = db.insert(args.table, null, initialValues);
-        sKnownMutationsInFlight.decrementAndGet();
+        mutationCount.decrementAndGet();
         if (rowId <= 0) return null;
 
         SettingsCache.populate(cache, initialValues);  // before we notify
 
         if (LOCAL_LOGV) Log.v(TAG, args.table + " <- " + initialValues);
+        // Note that we use the original url here, not the potentially-rewritten table name
         url = getUriFor(url, initialValues, rowId);
-        sendNotify(url);
+        sendNotify(url, desiredUserHandle);
         return url;
     }
 
     @Override
     public int delete(Uri url, String where, String[] whereArgs) {
+        final int callingUser = UserHandle.getCallingUserId();
+        if (LOCAL_LOGV) Slog.v(TAG, "delete() for user " + callingUser);
         SqlArguments args = new SqlArguments(url, where, whereArgs);
         if (TABLE_FAVORITES.equals(args.table)) {
             return 0;
@@ -581,36 +978,53 @@
         }
         checkWritePermissions(args);
 
-        sKnownMutationsInFlight.incrementAndGet();
-        SQLiteDatabase db = mOpenHelper.getWritableDatabase();
-        int count = db.delete(args.table, args.where, args.args);
-        sKnownMutationsInFlight.decrementAndGet();
-        if (count > 0) {
-            SettingsCache.invalidate(args.table);  // before we notify
-            sendNotify(url);
+        final AtomicInteger mutationCount = sKnownMutationsInFlight.get(callingUser);
+        mutationCount.incrementAndGet();
+        DatabaseHelper dbH;
+        synchronized (this) {
+            dbH = getOrEstablishDatabaseLocked(callingUser);
         }
-        startAsyncCachePopulation();
+        SQLiteDatabase db = dbH.getWritableDatabase();
+        int count = db.delete(args.table, args.where, args.args);
+        mutationCount.decrementAndGet();
+        if (count > 0) {
+            invalidateCache(callingUser, args.table);  // before we notify
+            sendNotify(url, callingUser);
+        }
+        startAsyncCachePopulation(callingUser);
         if (LOCAL_LOGV) Log.v(TAG, args.table + ": " + count + " row(s) deleted");
         return count;
     }
 
     @Override
     public int update(Uri url, ContentValues initialValues, String where, String[] whereArgs) {
+        // NOTE: update() is never called by the front-end Settings API, and updates that
+        // wind up affecting rows in Secure that are globally shared will not have the
+        // intended effect (the update will be invisible to the rest of the system).
+        // This should have no practical effect, since writes to the Secure db can only
+        // be done by system code, and that code should be using the correct API up front.
+        final int callingUser = UserHandle.getCallingUserId();
+        if (LOCAL_LOGV) Slog.v(TAG, "update() for user " + callingUser);
         SqlArguments args = new SqlArguments(url, where, whereArgs);
         if (TABLE_FAVORITES.equals(args.table)) {
             return 0;
         }
         checkWritePermissions(args);
 
-        sKnownMutationsInFlight.incrementAndGet();
-        SQLiteDatabase db = mOpenHelper.getWritableDatabase();
-        int count = db.update(args.table, initialValues, args.where, args.args);
-        sKnownMutationsInFlight.decrementAndGet();
-        if (count > 0) {
-            SettingsCache.invalidate(args.table);  // before we notify
-            sendNotify(url);
+        final AtomicInteger mutationCount = sKnownMutationsInFlight.get(callingUser);
+        mutationCount.incrementAndGet();
+        DatabaseHelper dbH;
+        synchronized (this) {
+            dbH = getOrEstablishDatabaseLocked(callingUser);
         }
-        startAsyncCachePopulation();
+        SQLiteDatabase db = dbH.getWritableDatabase();
+        int count = db.update(args.table, initialValues, args.where, args.args);
+        mutationCount.decrementAndGet();
+        if (count > 0) {
+            invalidateCache(callingUser, args.table);  // before we notify
+            sendNotify(url, callingUser);
+        }
+        startAsyncCachePopulation(callingUser);
         if (LOCAL_LOGV) Log.v(TAG, args.table + ": " + count + " row(s) <- " + initialValues);
         return count;
     }
@@ -772,16 +1186,6 @@
             return bundle;
         }
 
-        public static SettingsCache forTable(String tableName) {
-            if ("system".equals(tableName)) {
-                return SettingsProvider.sSystemCache;
-            }
-            if ("secure".equals(tableName)) {
-                return SettingsProvider.sSecureCache;
-            }
-            return null;
-        }
-
         /**
          * Populates a key in a given (possibly-null) cache.
          */
@@ -809,21 +1213,6 @@
         }
 
         /**
-         * Used for wiping a whole cache on deletes when we're not
-         * sure what exactly was deleted or changed.
-         */
-        public static void invalidate(String tableName) {
-            SettingsCache cache = SettingsCache.forTable(tableName);
-            if (cache == null) {
-                return;
-            }
-            synchronized (cache) {
-                cache.evictAll();
-                cache.mCacheFullyMatchesDisk = false;
-            }
-        }
-
-        /**
          * For suppressing duplicate/redundant settings inserts early,
          * checking our cache first (but without faulting it in),
          * before going to sqlite with the mutation.
diff --git a/packages/SystemUI/AndroidManifest.xml b/packages/SystemUI/AndroidManifest.xml
index 7176f32..22a97bd 100644
--- a/packages/SystemUI/AndroidManifest.xml
+++ b/packages/SystemUI/AndroidManifest.xml
@@ -16,6 +16,9 @@
     <uses-permission android:name="android.permission.REMOTE_AUDIO_PLAYBACK" />
 
     <uses-permission android:name="android.permission.MANAGE_USERS" />
+    <uses-permission android:name="android.permission.READ_PROFILE" />
+    <uses-permission android:name="android.permission.READ_CONTACTS" />
+    <uses-permission android:name="android.permission.CONFIGURE_WIFI_DISPLAY" />
 
     <!-- Networking and telephony -->
     <uses-permission android:name="android.permission.BLUETOOTH" />
@@ -193,5 +196,18 @@
                 <category android:name="android.intent.category.DREAM" />
             </intent-filter>
         </service>
+
+        <activity android:name=".Somnambulator"
+            android:label="@string/start_dreams"
+            android:icon="@mipmap/ic_dreams"
+            android:theme="@android:style/Theme.Wallpaper.NoTitleBar"
+            android:exported="true"
+            android:excludeFromRecents="true"
+            >
+            <intent-filter>
+                <action android:name="android.intent.action.CREATE_SHORTCUT" />
+                <category android:name="android.intent.category.DEFAULT" />
+            </intent-filter>
+        </activity>
     </application>
 </manifest>
diff --git a/packages/SystemUI/res/drawable-hdpi/ic_qs_airplane_enabled.png b/packages/SystemUI/res/drawable-hdpi/ic_qs_airplane_enabled.png
new file mode 100644
index 0000000..c47f70a
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/ic_qs_airplane_enabled.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/ic_qs_airplane_normal.png b/packages/SystemUI/res/drawable-hdpi/ic_qs_airplane_normal.png
new file mode 100644
index 0000000..c87e162
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/ic_qs_airplane_normal.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/ic_qs_bluetooth_enabled.png b/packages/SystemUI/res/drawable-hdpi/ic_qs_bluetooth_enabled.png
new file mode 100644
index 0000000..8baece6
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/ic_qs_bluetooth_enabled.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/ic_qs_bluetooth_normal.png b/packages/SystemUI/res/drawable-hdpi/ic_qs_bluetooth_normal.png
new file mode 100644
index 0000000..03f8b9c
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/ic_qs_bluetooth_normal.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/ic_qs_rssi_enabled.png b/packages/SystemUI/res/drawable-hdpi/ic_qs_rssi_enabled.png
new file mode 100644
index 0000000..8348455
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/ic_qs_rssi_enabled.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/ic_qs_rssi_normal.png b/packages/SystemUI/res/drawable-hdpi/ic_qs_rssi_normal.png
new file mode 100644
index 0000000..0dfcfd2
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/ic_qs_rssi_normal.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/ic_qs_wifi_enabled.png b/packages/SystemUI/res/drawable-hdpi/ic_qs_wifi_enabled.png
new file mode 100644
index 0000000..0276e42
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/ic_qs_wifi_enabled.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/ic_qs_wifi_normal.png b/packages/SystemUI/res/drawable-hdpi/ic_qs_wifi_normal.png
new file mode 100644
index 0000000..112279a
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/ic_qs_wifi_normal.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/ic_qs_airplane_enabled.png b/packages/SystemUI/res/drawable-mdpi/ic_qs_airplane_enabled.png
new file mode 100644
index 0000000..06ed0a8
--- /dev/null
+++ b/packages/SystemUI/res/drawable-mdpi/ic_qs_airplane_enabled.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/ic_qs_airplane_normal.png b/packages/SystemUI/res/drawable-mdpi/ic_qs_airplane_normal.png
new file mode 100644
index 0000000..1c83e5b
--- /dev/null
+++ b/packages/SystemUI/res/drawable-mdpi/ic_qs_airplane_normal.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/ic_qs_bluetooth_enabled.png b/packages/SystemUI/res/drawable-mdpi/ic_qs_bluetooth_enabled.png
new file mode 100644
index 0000000..9cff183
--- /dev/null
+++ b/packages/SystemUI/res/drawable-mdpi/ic_qs_bluetooth_enabled.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/ic_qs_bluetooth_normal.png b/packages/SystemUI/res/drawable-mdpi/ic_qs_bluetooth_normal.png
new file mode 100644
index 0000000..1e6c564
--- /dev/null
+++ b/packages/SystemUI/res/drawable-mdpi/ic_qs_bluetooth_normal.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/ic_qs_rssi_enabled.png b/packages/SystemUI/res/drawable-mdpi/ic_qs_rssi_enabled.png
new file mode 100644
index 0000000..afe6e98
--- /dev/null
+++ b/packages/SystemUI/res/drawable-mdpi/ic_qs_rssi_enabled.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/ic_qs_rssi_normal.png b/packages/SystemUI/res/drawable-mdpi/ic_qs_rssi_normal.png
new file mode 100644
index 0000000..3bec266
--- /dev/null
+++ b/packages/SystemUI/res/drawable-mdpi/ic_qs_rssi_normal.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/ic_qs_wifi_enabled.png b/packages/SystemUI/res/drawable-mdpi/ic_qs_wifi_enabled.png
new file mode 100644
index 0000000..6c94754
--- /dev/null
+++ b/packages/SystemUI/res/drawable-mdpi/ic_qs_wifi_enabled.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/ic_qs_wifi_normal.png b/packages/SystemUI/res/drawable-mdpi/ic_qs_wifi_normal.png
new file mode 100644
index 0000000..d6b47fc
--- /dev/null
+++ b/packages/SystemUI/res/drawable-mdpi/ic_qs_wifi_normal.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/ic_qs_airplane_enabled.png b/packages/SystemUI/res/drawable-xhdpi/ic_qs_airplane_enabled.png
new file mode 100644
index 0000000..7ee9290
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/ic_qs_airplane_enabled.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/ic_qs_airplane_normal.png b/packages/SystemUI/res/drawable-xhdpi/ic_qs_airplane_normal.png
new file mode 100644
index 0000000..41d74986
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/ic_qs_airplane_normal.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/ic_qs_bluetooth_enabled.png b/packages/SystemUI/res/drawable-xhdpi/ic_qs_bluetooth_enabled.png
new file mode 100644
index 0000000..8811e62
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/ic_qs_bluetooth_enabled.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/ic_qs_bluetooth_normal.png b/packages/SystemUI/res/drawable-xhdpi/ic_qs_bluetooth_normal.png
new file mode 100644
index 0000000..0026596
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/ic_qs_bluetooth_normal.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/ic_qs_rssi_enabled.png b/packages/SystemUI/res/drawable-xhdpi/ic_qs_rssi_enabled.png
new file mode 100644
index 0000000..4a2789d
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/ic_qs_rssi_enabled.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/ic_qs_rssi_normal.png b/packages/SystemUI/res/drawable-xhdpi/ic_qs_rssi_normal.png
new file mode 100644
index 0000000..ee4b21f
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/ic_qs_rssi_normal.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/ic_qs_wifi_enabled.png b/packages/SystemUI/res/drawable-xhdpi/ic_qs_wifi_enabled.png
new file mode 100644
index 0000000..114ee29
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/ic_qs_wifi_enabled.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/ic_qs_wifi_normal.png b/packages/SystemUI/res/drawable-xhdpi/ic_qs_wifi_normal.png
new file mode 100644
index 0000000..0719b21
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/ic_qs_wifi_normal.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable/ic_qs_battery.xml b/packages/SystemUI/res/drawable/ic_qs_battery.xml
new file mode 100644
index 0000000..4e2a265
--- /dev/null
+++ b/packages/SystemUI/res/drawable/ic_qs_battery.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2012 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.
+-->
+<clip
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:drawable="@drawable/stat_sys_battery_100"
+    android:clipOrientation="vertical"
+    android:gravity="bottom" />
diff --git a/packages/SystemUI/res/layout/quick_settings.xml b/packages/SystemUI/res/layout/quick_settings.xml
index 8c6258a..d89f279 100644
--- a/packages/SystemUI/res/layout/quick_settings.xml
+++ b/packages/SystemUI/res/layout/quick_settings.xml
@@ -19,14 +19,18 @@
     android:layout_width="match_parent"
     android:layout_height="wrap_content"
     android:id="@+id/settings_panel"
-    android:background="#80000080"
+    android:background="@drawable/notification_panel_bg"
     >
-    <ImageView
+    <!-- TODO: Put into ScrollView -->
+    <com.android.systemui.statusbar.phone.QuickSettingsContainerView
+        android:id="@+id/quick_settings_container"
         android:layout_width="match_parent"
         android:layout_height="wrap_content"
-        android:scaleType="centerInside"
-        android:src="@drawable/qs_coming_soon"
-        android:padding="4dp"
+        android:paddingBottom="@dimen/quick_settings_container_padding"
+        android:paddingLeft="@dimen/quick_settings_container_padding"
+        android:paddingRight="@dimen/quick_settings_container_padding"
+        android:animateLayoutChanges="true"
+        android:columnCount="@integer/quick_settings_num_columns"
         />
     <LinearLayout android:id="@+id/handle"
         android:layout_width="match_parent"
diff --git a/packages/SystemUI/res/layout/quick_settings_tile.xml b/packages/SystemUI/res/layout/quick_settings_tile.xml
new file mode 100644
index 0000000..a571393
--- /dev/null
+++ b/packages/SystemUI/res/layout/quick_settings_tile.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2012 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.
+-->
+<com.android.systemui.statusbar.phone.QuickSettingsTileView
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="wrap_content"
+    android:layout_height="@dimen/quick_settings_cell_height"
+    android:background="#1B1D1B" />
\ No newline at end of file
diff --git a/packages/SystemUI/res/layout/quick_settings_tile_airplane.xml b/packages/SystemUI/res/layout/quick_settings_tile_airplane.xml
new file mode 100644
index 0000000..3e3a9c2
--- /dev/null
+++ b/packages/SystemUI/res/layout/quick_settings_tile_airplane.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2012 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<TextView
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:id="@+id/airplane_mode_textview"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    android:layout_gravity="center"
+    android:gravity="center"
+    android:text="@string/quick_settings_airplane_mode_label"
+    android:textAppearance="@style/TextAppearance.QuickSettings.TileView"
+    />
\ No newline at end of file
diff --git a/packages/SystemUI/res/layout/quick_settings_tile_battery.xml b/packages/SystemUI/res/layout/quick_settings_tile_battery.xml
new file mode 100644
index 0000000..680a1bb
--- /dev/null
+++ b/packages/SystemUI/res/layout/quick_settings_tile_battery.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2012 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<TextView
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:id="@+id/battery_textview"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    android:layout_gravity="center"
+    android:gravity="center"
+    android:drawableTop="@drawable/ic_qs_battery"
+    android:text="@string/quick_settings_battery_label"
+    android:textAppearance="@style/TextAppearance.QuickSettings.TileView"
+    />
\ No newline at end of file
diff --git a/packages/SystemUI/res/layout/quick_settings_tile_bluetooth.xml b/packages/SystemUI/res/layout/quick_settings_tile_bluetooth.xml
new file mode 100644
index 0000000..4472484
--- /dev/null
+++ b/packages/SystemUI/res/layout/quick_settings_tile_bluetooth.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2012 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<TextView
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:id="@+id/bluetooth_textview"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    android:layout_gravity="center"
+    android:gravity="center"
+    android:text="@string/quick_settings_bluetooth_label"
+    android:textAppearance="@style/TextAppearance.QuickSettings.TileView"
+    />
\ No newline at end of file
diff --git a/packages/SystemUI/res/layout/quick_settings_tile_brightness.xml b/packages/SystemUI/res/layout/quick_settings_tile_brightness.xml
new file mode 100644
index 0000000..216930d
--- /dev/null
+++ b/packages/SystemUI/res/layout/quick_settings_tile_brightness.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2012 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<TextView
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    android:layout_gravity="center"
+    android:gravity="center"
+    android:drawableTop="@drawable/ic_sysbar_brightness"
+    android:text="@string/quick_settings_brightness_label"
+    android:textAppearance="@style/TextAppearance.QuickSettings.TileView"
+    />
\ No newline at end of file
diff --git a/packages/SystemUI/res/layout/quick_settings_tile_ime.xml b/packages/SystemUI/res/layout/quick_settings_tile_ime.xml
new file mode 100644
index 0000000..93db6db
--- /dev/null
+++ b/packages/SystemUI/res/layout/quick_settings_tile_ime.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2012 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<TextView
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    android:gravity="center"
+    android:text="@string/quick_settings_ime_label"
+    android:singleLine="true"
+    />
\ No newline at end of file
diff --git a/packages/SystemUI/res/layout/quick_settings_tile_location.xml b/packages/SystemUI/res/layout/quick_settings_tile_location.xml
new file mode 100644
index 0000000..1a40642
--- /dev/null
+++ b/packages/SystemUI/res/layout/quick_settings_tile_location.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2012 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<TextView
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:id="@+id/location_textview"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    android:layout_gravity="center"
+    android:gravity="center"
+    android:drawableTop="@drawable/stat_sys_gps_acquiring"
+    android:text="@string/quick_settings_location_label"
+    android:textAppearance="@style/TextAppearance.QuickSettings.TileView"
+    />
\ No newline at end of file
diff --git a/packages/SystemUI/res/layout/quick_settings_tile_media.xml b/packages/SystemUI/res/layout/quick_settings_tile_media.xml
new file mode 100644
index 0000000..0810d02
--- /dev/null
+++ b/packages/SystemUI/res/layout/quick_settings_tile_media.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2012 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<TextView
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    android:gravity="center"
+    android:text="@string/quick_settings_media_device_label"
+    android:singleLine="true"
+    />
\ No newline at end of file
diff --git a/packages/SystemUI/res/layout/quick_settings_tile_rssi.xml b/packages/SystemUI/res/layout/quick_settings_tile_rssi.xml
new file mode 100644
index 0000000..3e541cb
--- /dev/null
+++ b/packages/SystemUI/res/layout/quick_settings_tile_rssi.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2012 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<TextView
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:id="@+id/rssi_textview"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    android:layout_gravity="center"
+    android:gravity="center"
+    android:text="@string/quick_settings_rssi_label"
+    android:textAppearance="@style/TextAppearance.QuickSettings.TileView"
+    />
\ No newline at end of file
diff --git a/packages/SystemUI/res/layout/quick_settings_tile_settings.xml b/packages/SystemUI/res/layout/quick_settings_tile_settings.xml
new file mode 100644
index 0000000..1c2f827
--- /dev/null
+++ b/packages/SystemUI/res/layout/quick_settings_tile_settings.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2012 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<TextView
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    android:layout_gravity="center"
+    android:gravity="center"
+    android:drawableTop="@drawable/ic_notify_quicksettings"
+    android:text="@string/quick_settings_settings_label"
+    android:textAppearance="@style/TextAppearance.QuickSettings.TileView"
+    />
\ No newline at end of file
diff --git a/packages/SystemUI/res/layout/quick_settings_tile_time.xml b/packages/SystemUI/res/layout/quick_settings_tile_time.xml
new file mode 100644
index 0000000..ab0c52d
--- /dev/null
+++ b/packages/SystemUI/res/layout/quick_settings_tile_time.xml
@@ -0,0 +1,35 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2012 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.
+-->
+<LinearLayout
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="match_parent"
+    android:layout_height="wrap_content"
+    android:layout_gravity="center"
+    android:orientation="vertical">
+    <com.android.systemui.statusbar.policy.Clock
+        android:textAppearance="@style/TextAppearance.QuickSettings.Clock"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_gravity="center_horizontal"
+        android:singleLine="true"
+        />
+    <com.android.systemui.statusbar.policy.QuickSettingsDateView
+        android:textAppearance="@style/TextAppearance.QuickSettings.Date"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_gravity="center_horizontal"
+        />
+</LinearLayout>
\ No newline at end of file
diff --git a/packages/SystemUI/res/layout/quick_settings_tile_user.xml b/packages/SystemUI/res/layout/quick_settings_tile_user.xml
new file mode 100644
index 0000000..8edc978
--- /dev/null
+++ b/packages/SystemUI/res/layout/quick_settings_tile_user.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2012 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<TextView
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:id="@+id/user_textview"
+    android:layout_width="match_parent"
+    android:layout_height="wrap_content"
+    android:layout_gravity="center_horizontal|bottom"
+    android:gravity="center"
+    android:text="@string/quick_settings_user_label"
+    android:textAppearance="@style/TextAppearance.QuickSettings.TileView"
+    android:background="#33000000"
+    />
\ No newline at end of file
diff --git a/packages/SystemUI/res/layout/quick_settings_tile_wifi.xml b/packages/SystemUI/res/layout/quick_settings_tile_wifi.xml
new file mode 100644
index 0000000..42eb45a
--- /dev/null
+++ b/packages/SystemUI/res/layout/quick_settings_tile_wifi.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2012 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<TextView
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:id="@+id/wifi_textview"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    android:layout_gravity="center"
+    android:gravity="center"
+    android:text="@string/quick_settings_wifi_label"
+    android:textAppearance="@style/TextAppearance.QuickSettings.TileView"
+    />
\ No newline at end of file
diff --git a/packages/SystemUI/res/layout/quick_settings_tile_wifi_display.xml b/packages/SystemUI/res/layout/quick_settings_tile_wifi_display.xml
new file mode 100644
index 0000000..929dd94
--- /dev/null
+++ b/packages/SystemUI/res/layout/quick_settings_tile_wifi_display.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2012 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<TextView
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:id="@+id/wifi_display_textview"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    android:layout_gravity="center"
+    android:gravity="center"
+    android:drawableTop="@drawable/ic_qs_wifi_normal"
+    android:text="@string/quick_settings_wifi_display_label"
+    android:textAppearance="@style/TextAppearance.QuickSettings.TileView"
+    />
\ No newline at end of file
diff --git a/packages/SystemUI/res/layout/wifi_display_dialog.xml b/packages/SystemUI/res/layout/wifi_display_dialog.xml
new file mode 100644
index 0000000..a78096e
--- /dev/null
+++ b/packages/SystemUI/res/layout/wifi_display_dialog.xml
@@ -0,0 +1,38 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2012 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.
+-->
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="match_parent"
+    android:layout_height="wrap_content"
+    android:orientation="vertical">
+
+    <ListView android:id="@+id/list"
+        android:layout_width="match_parent"
+        android:layout_height="0dp"
+        android:layout_weight="2" />
+
+    <Button android:id="@+id/scan"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:layout_weight="1"
+        android:text="@string/wifi_display_scan" />
+
+    <Button android:id="@+id/disconnect"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:layout_weight="1"
+        android:text="@string/wifi_display_disconnect" />
+</LinearLayout>
diff --git a/packages/SystemUI/res/mipmap-hdpi/ic_dreams.png b/packages/SystemUI/res/mipmap-hdpi/ic_dreams.png
new file mode 100644
index 0000000..56cbac1
--- /dev/null
+++ b/packages/SystemUI/res/mipmap-hdpi/ic_dreams.png
Binary files differ
diff --git a/packages/SystemUI/res/mipmap-mdpi/ic_dreams.png b/packages/SystemUI/res/mipmap-mdpi/ic_dreams.png
new file mode 100644
index 0000000..ea3d991
--- /dev/null
+++ b/packages/SystemUI/res/mipmap-mdpi/ic_dreams.png
Binary files differ
diff --git a/packages/SystemUI/res/mipmap-xhdpi/ic_dreams.png b/packages/SystemUI/res/mipmap-xhdpi/ic_dreams.png
new file mode 100644
index 0000000..ddc7f66
--- /dev/null
+++ b/packages/SystemUI/res/mipmap-xhdpi/ic_dreams.png
Binary files differ
diff --git a/packages/SystemUI/res/values-af/strings.xml b/packages/SystemUI/res/values-af/strings.xml
index d5e4c0a..38ea24d 100644
--- a/packages/SystemUI/res/values-af/strings.xml
+++ b/packages/SystemUI/res/values-af/strings.xml
@@ -149,4 +149,6 @@
     <string name="accessibility_rotation_lock_off" msgid="4062780228931590069">"Die skerm sal outomaties draai."</string>
     <string name="accessibility_rotation_lock_on_landscape" msgid="6731197337665366273">"Skerm is in landskapsoriëntasie gesluit."</string>
     <string name="accessibility_rotation_lock_on_portrait" msgid="5809367521644012115">"Skerm is in portretoriëntasie gesluit."</string>
+    <!-- no translation found for jelly_bean_dream_name (5992026543636816792) -->
+    <skip />
 </resources>
diff --git a/packages/SystemUI/res/values-am/strings.xml b/packages/SystemUI/res/values-am/strings.xml
index 36b52e3..9c0b934 100644
--- a/packages/SystemUI/res/values-am/strings.xml
+++ b/packages/SystemUI/res/values-am/strings.xml
@@ -149,4 +149,6 @@
     <string name="accessibility_rotation_lock_off" msgid="4062780228931590069">"ማያ ገጽ በራስ ሰር ይዞራል።"</string>
     <string name="accessibility_rotation_lock_on_landscape" msgid="6731197337665366273">"ማያ ገጽ በወርድ ገፅ አቀማመጥ ተቆልፏል።"</string>
     <string name="accessibility_rotation_lock_on_portrait" msgid="5809367521644012115">"ማያ ገጽ በቁም ገፅ አቀማመጥ ተቆልፏል።"</string>
+    <!-- no translation found for jelly_bean_dream_name (5992026543636816792) -->
+    <skip />
 </resources>
diff --git a/packages/SystemUI/res/values-ar/strings.xml b/packages/SystemUI/res/values-ar/strings.xml
index 6540f0a..59a1083 100644
--- a/packages/SystemUI/res/values-ar/strings.xml
+++ b/packages/SystemUI/res/values-ar/strings.xml
@@ -149,4 +149,6 @@
     <string name="accessibility_rotation_lock_off" msgid="4062780228931590069">"سيتم تدوير الشاشة تلقائيًا."</string>
     <string name="accessibility_rotation_lock_on_landscape" msgid="6731197337665366273">"تم تأمين الشاشة في الاتجاه الأفقي."</string>
     <string name="accessibility_rotation_lock_on_portrait" msgid="5809367521644012115">"تم تأمين الشاشة في الاتجاه العمودي."</string>
+    <!-- no translation found for jelly_bean_dream_name (5992026543636816792) -->
+    <skip />
 </resources>
diff --git a/packages/SystemUI/res/values-be/strings.xml b/packages/SystemUI/res/values-be/strings.xml
index 8216e2b..394d237 100644
--- a/packages/SystemUI/res/values-be/strings.xml
+++ b/packages/SystemUI/res/values-be/strings.xml
@@ -151,4 +151,6 @@
     <string name="accessibility_rotation_lock_off" msgid="4062780228931590069">"Экран паварочваецца аўтаматычна."</string>
     <string name="accessibility_rotation_lock_on_landscape" msgid="6731197337665366273">"Экран заблакiраваны ў альбомнай арыентацыі."</string>
     <string name="accessibility_rotation_lock_on_portrait" msgid="5809367521644012115">"Экран заблакiраваны ў партрэтнай арыентацыі."</string>
+    <!-- no translation found for jelly_bean_dream_name (5992026543636816792) -->
+    <skip />
 </resources>
diff --git a/packages/SystemUI/res/values-bg/strings.xml b/packages/SystemUI/res/values-bg/strings.xml
index 56b8bb3..c24ac7f 100644
--- a/packages/SystemUI/res/values-bg/strings.xml
+++ b/packages/SystemUI/res/values-bg/strings.xml
@@ -149,4 +149,6 @@
     <string name="accessibility_rotation_lock_off" msgid="4062780228931590069">"Екранът ще се завърта автоматично."</string>
     <string name="accessibility_rotation_lock_on_landscape" msgid="6731197337665366273">"Екранът е заключен в хоризонтална ориентация."</string>
     <string name="accessibility_rotation_lock_on_portrait" msgid="5809367521644012115">"Екранът е заключен във вертикална ориентация."</string>
+    <!-- no translation found for jelly_bean_dream_name (5992026543636816792) -->
+    <skip />
 </resources>
diff --git a/packages/SystemUI/res/values-ca/strings.xml b/packages/SystemUI/res/values-ca/strings.xml
index 3eb078d..3b3c0bc 100644
--- a/packages/SystemUI/res/values-ca/strings.xml
+++ b/packages/SystemUI/res/values-ca/strings.xml
@@ -151,4 +151,6 @@
     <string name="accessibility_rotation_lock_off" msgid="4062780228931590069">"La pantalla girarà automàticament."</string>
     <string name="accessibility_rotation_lock_on_landscape" msgid="6731197337665366273">"La pantalla està bloquejada en orientació horitzontal."</string>
     <string name="accessibility_rotation_lock_on_portrait" msgid="5809367521644012115">"La pantalla està bloquejada en orientació vertical."</string>
+    <!-- no translation found for jelly_bean_dream_name (5992026543636816792) -->
+    <skip />
 </resources>
diff --git a/packages/SystemUI/res/values-cs/strings.xml b/packages/SystemUI/res/values-cs/strings.xml
index a7bf519..a471e98 100644
--- a/packages/SystemUI/res/values-cs/strings.xml
+++ b/packages/SystemUI/res/values-cs/strings.xml
@@ -151,4 +151,6 @@
     <string name="accessibility_rotation_lock_off" msgid="4062780228931590069">"Obrazovka se automaticky otočí."</string>
     <string name="accessibility_rotation_lock_on_landscape" msgid="6731197337665366273">"Obrazovka je uzamčena v orientaci na šířku."</string>
     <string name="accessibility_rotation_lock_on_portrait" msgid="5809367521644012115">"Obrazovka je uzamčena v orientaci na výšku."</string>
+    <!-- no translation found for jelly_bean_dream_name (5992026543636816792) -->
+    <skip />
 </resources>
diff --git a/packages/SystemUI/res/values-da/strings.xml b/packages/SystemUI/res/values-da/strings.xml
index 48cab36..6da3992 100644
--- a/packages/SystemUI/res/values-da/strings.xml
+++ b/packages/SystemUI/res/values-da/strings.xml
@@ -149,4 +149,6 @@
     <string name="accessibility_rotation_lock_off" msgid="4062780228931590069">"Skærmen roterer automatisk."</string>
     <string name="accessibility_rotation_lock_on_landscape" msgid="6731197337665366273">"Skærmen er nu låst i liggende retning."</string>
     <string name="accessibility_rotation_lock_on_portrait" msgid="5809367521644012115">"Skærmen er nu låst i stående retning."</string>
+    <!-- no translation found for jelly_bean_dream_name (5992026543636816792) -->
+    <skip />
 </resources>
diff --git a/packages/SystemUI/res/values-de/strings.xml b/packages/SystemUI/res/values-de/strings.xml
index 4bcbc31..7ae9ca6 100644
--- a/packages/SystemUI/res/values-de/strings.xml
+++ b/packages/SystemUI/res/values-de/strings.xml
@@ -151,4 +151,6 @@
     <string name="accessibility_rotation_lock_off" msgid="4062780228931590069">"Bildschirm wird automatisch gedreht."</string>
     <string name="accessibility_rotation_lock_on_landscape" msgid="6731197337665366273">"Bildschirm bleibt im Querformat."</string>
     <string name="accessibility_rotation_lock_on_portrait" msgid="5809367521644012115">"Bildschirm bleibt im Hochformat."</string>
+    <!-- no translation found for jelly_bean_dream_name (5992026543636816792) -->
+    <skip />
 </resources>
diff --git a/packages/SystemUI/res/values-el/strings.xml b/packages/SystemUI/res/values-el/strings.xml
index 2231a8c..7cd4fc2 100644
--- a/packages/SystemUI/res/values-el/strings.xml
+++ b/packages/SystemUI/res/values-el/strings.xml
@@ -151,4 +151,6 @@
     <string name="accessibility_rotation_lock_off" msgid="4062780228931590069">"Θα γίνεται αυτόματη περιστροφή της οθόνης."</string>
     <string name="accessibility_rotation_lock_on_landscape" msgid="6731197337665366273">"Η οθόνη έχει κλειδωθεί σε οριζόντιο προσανατολισμό."</string>
     <string name="accessibility_rotation_lock_on_portrait" msgid="5809367521644012115">"Η οθόνη έχει κλειδωθεί σε κατακόρυφο προσανατολισμό."</string>
+    <!-- no translation found for jelly_bean_dream_name (5992026543636816792) -->
+    <skip />
 </resources>
diff --git a/packages/SystemUI/res/values-en-rGB/strings.xml b/packages/SystemUI/res/values-en-rGB/strings.xml
index 671ac1b..1fb98f0 100644
--- a/packages/SystemUI/res/values-en-rGB/strings.xml
+++ b/packages/SystemUI/res/values-en-rGB/strings.xml
@@ -149,4 +149,6 @@
     <string name="accessibility_rotation_lock_off" msgid="4062780228931590069">"Screen will rotate automatically."</string>
     <string name="accessibility_rotation_lock_on_landscape" msgid="6731197337665366273">"Screen is locked in landscape orientation."</string>
     <string name="accessibility_rotation_lock_on_portrait" msgid="5809367521644012115">"Screen is locked in portrait orientation."</string>
+    <!-- no translation found for jelly_bean_dream_name (5992026543636816792) -->
+    <skip />
 </resources>
diff --git a/packages/SystemUI/res/values-es-rUS/strings.xml b/packages/SystemUI/res/values-es-rUS/strings.xml
index 87b0088..89c6a9c 100644
--- a/packages/SystemUI/res/values-es-rUS/strings.xml
+++ b/packages/SystemUI/res/values-es-rUS/strings.xml
@@ -151,4 +151,6 @@
     <string name="accessibility_rotation_lock_off" msgid="4062780228931590069">"La pantalla girará automáticamente."</string>
     <string name="accessibility_rotation_lock_on_landscape" msgid="6731197337665366273">"La pantalla está bloqueada en modo horizontal."</string>
     <string name="accessibility_rotation_lock_on_portrait" msgid="5809367521644012115">"La pantalla está bloqueada en modo vertical."</string>
+    <!-- no translation found for jelly_bean_dream_name (5992026543636816792) -->
+    <skip />
 </resources>
diff --git a/packages/SystemUI/res/values-es/strings.xml b/packages/SystemUI/res/values-es/strings.xml
index cd03d92..42441d5 100644
--- a/packages/SystemUI/res/values-es/strings.xml
+++ b/packages/SystemUI/res/values-es/strings.xml
@@ -149,4 +149,6 @@
     <string name="accessibility_rotation_lock_off" msgid="4062780228931590069">"La pantalla girará automáticamente."</string>
     <string name="accessibility_rotation_lock_on_landscape" msgid="6731197337665366273">"La pantalla está bloqueada en modo horizontal."</string>
     <string name="accessibility_rotation_lock_on_portrait" msgid="5809367521644012115">"La pantalla está bloqueada en modo vertical."</string>
+    <!-- no translation found for jelly_bean_dream_name (5992026543636816792) -->
+    <skip />
 </resources>
diff --git a/packages/SystemUI/res/values-et/strings.xml b/packages/SystemUI/res/values-et/strings.xml
index 4348bda..9df87db 100644
--- a/packages/SystemUI/res/values-et/strings.xml
+++ b/packages/SystemUI/res/values-et/strings.xml
@@ -149,4 +149,6 @@
     <string name="accessibility_rotation_lock_off" msgid="4062780228931590069">"Ekraani pööramine toimub automaatselt."</string>
     <string name="accessibility_rotation_lock_on_landscape" msgid="6731197337665366273">"Ekraan on lukustatud horisontaalsuunas."</string>
     <string name="accessibility_rotation_lock_on_portrait" msgid="5809367521644012115">"Ekraan on lukustatud vertikaalsuunas."</string>
+    <!-- no translation found for jelly_bean_dream_name (5992026543636816792) -->
+    <skip />
 </resources>
diff --git a/packages/SystemUI/res/values-fa/strings.xml b/packages/SystemUI/res/values-fa/strings.xml
index a55091d..bf9ac48 100644
--- a/packages/SystemUI/res/values-fa/strings.xml
+++ b/packages/SystemUI/res/values-fa/strings.xml
@@ -149,4 +149,6 @@
     <string name="accessibility_rotation_lock_off" msgid="4062780228931590069">"صفحه به صورت خودکار می‌چرخد."</string>
     <string name="accessibility_rotation_lock_on_landscape" msgid="6731197337665366273">"صفحه اکنون در جهت افقی قفل است."</string>
     <string name="accessibility_rotation_lock_on_portrait" msgid="5809367521644012115">"صفحه اکنون در جهت عمودی قفل است."</string>
+    <!-- no translation found for jelly_bean_dream_name (5992026543636816792) -->
+    <skip />
 </resources>
diff --git a/packages/SystemUI/res/values-fi/strings.xml b/packages/SystemUI/res/values-fi/strings.xml
index 5132502..ba23073 100644
--- a/packages/SystemUI/res/values-fi/strings.xml
+++ b/packages/SystemUI/res/values-fi/strings.xml
@@ -149,4 +149,6 @@
     <string name="accessibility_rotation_lock_off" msgid="4062780228931590069">"Ruutu kääntyy automaattisesti."</string>
     <string name="accessibility_rotation_lock_on_landscape" msgid="6731197337665366273">"Ruutu on lukittu vaakasuuntaan."</string>
     <string name="accessibility_rotation_lock_on_portrait" msgid="5809367521644012115">"Ruutu on lukittu pystysuuntaan."</string>
+    <!-- no translation found for jelly_bean_dream_name (5992026543636816792) -->
+    <skip />
 </resources>
diff --git a/packages/SystemUI/res/values-fr/strings.xml b/packages/SystemUI/res/values-fr/strings.xml
index 18f8c9d..b08b36a 100644
--- a/packages/SystemUI/res/values-fr/strings.xml
+++ b/packages/SystemUI/res/values-fr/strings.xml
@@ -151,4 +151,6 @@
     <string name="accessibility_rotation_lock_off" msgid="4062780228931590069">"L\'écran pivote automatiquement."</string>
     <string name="accessibility_rotation_lock_on_landscape" msgid="6731197337665366273">"L\'écran est verrouillé en mode paysage."</string>
     <string name="accessibility_rotation_lock_on_portrait" msgid="5809367521644012115">"L\'écran est verrouillé en mode portrait."</string>
+    <!-- no translation found for jelly_bean_dream_name (5992026543636816792) -->
+    <skip />
 </resources>
diff --git a/packages/SystemUI/res/values-hi/strings.xml b/packages/SystemUI/res/values-hi/strings.xml
index cfc0aec..d87bc05 100644
--- a/packages/SystemUI/res/values-hi/strings.xml
+++ b/packages/SystemUI/res/values-hi/strings.xml
@@ -149,4 +149,6 @@
     <string name="accessibility_rotation_lock_off" msgid="4062780228931590069">"स्‍क्रीन स्‍वचालित रूप से घूमेगी."</string>
     <string name="accessibility_rotation_lock_on_landscape" msgid="6731197337665366273">"स्‍क्रीन लैंडस्केप अभिविन्यास में लॉक है."</string>
     <string name="accessibility_rotation_lock_on_portrait" msgid="5809367521644012115">"स्‍क्रीन पोर्ट्रेट अभिविन्‍यास में लॉक है."</string>
+    <!-- no translation found for jelly_bean_dream_name (5992026543636816792) -->
+    <skip />
 </resources>
diff --git a/packages/SystemUI/res/values-hr/strings.xml b/packages/SystemUI/res/values-hr/strings.xml
index 7150c94..7b37372 100644
--- a/packages/SystemUI/res/values-hr/strings.xml
+++ b/packages/SystemUI/res/values-hr/strings.xml
@@ -149,4 +149,6 @@
     <string name="accessibility_rotation_lock_off" msgid="4062780228931590069">"Zaslon će se automatski zakrenuti."</string>
     <string name="accessibility_rotation_lock_on_landscape" msgid="6731197337665366273">"Zaslon je zaključan u pejzažnoj orijentaciji."</string>
     <string name="accessibility_rotation_lock_on_portrait" msgid="5809367521644012115">"Zaslon je zaključan u portretnoj orijentaciji."</string>
+    <!-- no translation found for jelly_bean_dream_name (5992026543636816792) -->
+    <skip />
 </resources>
diff --git a/packages/SystemUI/res/values-hu/strings.xml b/packages/SystemUI/res/values-hu/strings.xml
index 4d49939..9d9c73a 100644
--- a/packages/SystemUI/res/values-hu/strings.xml
+++ b/packages/SystemUI/res/values-hu/strings.xml
@@ -149,4 +149,6 @@
     <string name="accessibility_rotation_lock_off" msgid="4062780228931590069">"A képernyő automatikusan forogni fog."</string>
     <string name="accessibility_rotation_lock_on_landscape" msgid="6731197337665366273">"A képernyő zárolva van fekvő tájolásban."</string>
     <string name="accessibility_rotation_lock_on_portrait" msgid="5809367521644012115">"A képernyő zárolva van álló tájolásban."</string>
+    <!-- no translation found for jelly_bean_dream_name (5992026543636816792) -->
+    <skip />
 </resources>
diff --git a/packages/SystemUI/res/values-in/strings.xml b/packages/SystemUI/res/values-in/strings.xml
index 65e47dd..0f3e1b7 100644
--- a/packages/SystemUI/res/values-in/strings.xml
+++ b/packages/SystemUI/res/values-in/strings.xml
@@ -149,4 +149,6 @@
     <string name="accessibility_rotation_lock_off" msgid="4062780228931590069">"Layar akan diputar secara otomatis."</string>
     <string name="accessibility_rotation_lock_on_landscape" msgid="6731197337665366273">"Layar dikunci dalam orientasi lanskap."</string>
     <string name="accessibility_rotation_lock_on_portrait" msgid="5809367521644012115">"Layar dikunci dalam orientasi potret."</string>
+    <!-- no translation found for jelly_bean_dream_name (5992026543636816792) -->
+    <skip />
 </resources>
diff --git a/packages/SystemUI/res/values-it/strings.xml b/packages/SystemUI/res/values-it/strings.xml
index 49b0fb0..93429ed 100644
--- a/packages/SystemUI/res/values-it/strings.xml
+++ b/packages/SystemUI/res/values-it/strings.xml
@@ -151,4 +151,6 @@
     <string name="accessibility_rotation_lock_off" msgid="4062780228931590069">"Lo schermo ruoterà automaticamente."</string>
     <string name="accessibility_rotation_lock_on_landscape" msgid="6731197337665366273">"Lo schermo è bloccato in orientamento orizzontale."</string>
     <string name="accessibility_rotation_lock_on_portrait" msgid="5809367521644012115">"Lo schermo è bloccato in orientamento verticale."</string>
+    <!-- no translation found for jelly_bean_dream_name (5992026543636816792) -->
+    <skip />
 </resources>
diff --git a/packages/SystemUI/res/values-iw/strings.xml b/packages/SystemUI/res/values-iw/strings.xml
index 59730af..4495c2d 100644
--- a/packages/SystemUI/res/values-iw/strings.xml
+++ b/packages/SystemUI/res/values-iw/strings.xml
@@ -149,4 +149,6 @@
     <string name="accessibility_rotation_lock_off" msgid="4062780228931590069">"המסך יסתובב באופן אוטומטי."</string>
     <string name="accessibility_rotation_lock_on_landscape" msgid="6731197337665366273">"המסך נעול כעת לרוחב."</string>
     <string name="accessibility_rotation_lock_on_portrait" msgid="5809367521644012115">"המסך נעול כעת לאורך."</string>
+    <!-- no translation found for jelly_bean_dream_name (5992026543636816792) -->
+    <skip />
 </resources>
diff --git a/packages/SystemUI/res/values-ja/strings.xml b/packages/SystemUI/res/values-ja/strings.xml
index a9fe4ae..2f0d6da 100644
--- a/packages/SystemUI/res/values-ja/strings.xml
+++ b/packages/SystemUI/res/values-ja/strings.xml
@@ -68,7 +68,7 @@
     <string name="screenshot_saving_ticker" msgid="7403652894056693515">"スクリーンショットを保存中..."</string>
     <string name="screenshot_saving_title" msgid="8242282144535555697">"スクリーンショットを保存しています..."</string>
     <string name="screenshot_saving_text" msgid="2419718443411738818">"スクリーンショットを保存しています。"</string>
-    <string name="screenshot_saved_title" msgid="6461865960961414961">"スクリーンショットをキャプチャしました。"</string>
+    <string name="screenshot_saved_title" msgid="6461865960961414961">"スクリーンショットを取得しました。"</string>
     <string name="screenshot_saved_text" msgid="1152839647677558815">"タップしてスクリーンショットを表示します。"</string>
     <string name="screenshot_failed_title" msgid="705781116746922771">"スクリーンショットをキャプチャできませんでした。"</string>
     <string name="screenshot_failed_text" msgid="8134011269572415402">"スクリーンショットを保存できませんでした。ストレージが使用中の可能性があります。"</string>
@@ -151,4 +151,6 @@
     <string name="accessibility_rotation_lock_off" msgid="4062780228931590069">"画面は自動的に回転します。"</string>
     <string name="accessibility_rotation_lock_on_landscape" msgid="6731197337665366273">"画面は横向きにロックされています。"</string>
     <string name="accessibility_rotation_lock_on_portrait" msgid="5809367521644012115">"画面は縦向きにロックされています。"</string>
+    <!-- no translation found for jelly_bean_dream_name (5992026543636816792) -->
+    <skip />
 </resources>
diff --git a/packages/SystemUI/res/values-ko/strings.xml b/packages/SystemUI/res/values-ko/strings.xml
index bd1cf03..709e14d 100644
--- a/packages/SystemUI/res/values-ko/strings.xml
+++ b/packages/SystemUI/res/values-ko/strings.xml
@@ -149,4 +149,6 @@
     <string name="accessibility_rotation_lock_off" msgid="4062780228931590069">"화면이 자동으로 회전됩니다."</string>
     <string name="accessibility_rotation_lock_on_landscape" msgid="6731197337665366273">"화면이 가로 방향으로 잠겨 있습니다."</string>
     <string name="accessibility_rotation_lock_on_portrait" msgid="5809367521644012115">"화면이 세로 방향으로 잠겨 있습니다."</string>
+    <!-- no translation found for jelly_bean_dream_name (5992026543636816792) -->
+    <skip />
 </resources>
diff --git a/packages/SystemUI/res/values-land/config.xml b/packages/SystemUI/res/values-land/config.xml
index bbae18d..6476d88 100644
--- a/packages/SystemUI/res/values-land/config.xml
+++ b/packages/SystemUI/res/values-land/config.xml
@@ -23,5 +23,11 @@
     <!-- Whether we're using the tablet-optimized recents interface (we use this
      value at runtime for some things) -->
     <integer name="status_bar_recents_bg_gradient_degrees">90</integer>
+
+    <!-- The number of columns in the QuickSettings -->
+    <integer name="quick_settings_num_columns">6</integer>
+
+    <!-- The number of columns that the top level tiles span in the QuickSettings -->
+    <integer name="quick_settings_user_time_settings_tile_span">2</integer>
 </resources>
 
diff --git a/packages/SystemUI/res/values-land/dimens.xml b/packages/SystemUI/res/values-land/dimens.xml
index e7c8b1f..ab71371 100644
--- a/packages/SystemUI/res/values-land/dimens.xml
+++ b/packages/SystemUI/res/values-land/dimens.xml
@@ -37,4 +37,7 @@
     <!-- Where to place the app icon over the thumbnail -->
     <dimen name="status_bar_recents_app_icon_left_margin">8dp</dimen>
     <dimen name="status_bar_recents_app_icon_top_margin">8dp</dimen>
+
+    <!-- The fixed height of each tile -->
+    <dimen name="quick_settings_cell_height">100dp</dimen>
 </resources>
diff --git a/packages/SystemUI/res/values-lt/strings.xml b/packages/SystemUI/res/values-lt/strings.xml
index a5a11e2..73de676 100644
--- a/packages/SystemUI/res/values-lt/strings.xml
+++ b/packages/SystemUI/res/values-lt/strings.xml
@@ -149,4 +149,6 @@
     <string name="accessibility_rotation_lock_off" msgid="4062780228931590069">"Ekranas bus sukamas automatiškai."</string>
     <string name="accessibility_rotation_lock_on_landscape" msgid="6731197337665366273">"Užrakintas ekranas yra horizontalios orientacijos."</string>
     <string name="accessibility_rotation_lock_on_portrait" msgid="5809367521644012115">"Užrakintas ekranas yra vertikalios orientacijos."</string>
+    <!-- no translation found for jelly_bean_dream_name (5992026543636816792) -->
+    <skip />
 </resources>
diff --git a/packages/SystemUI/res/values-lv/strings.xml b/packages/SystemUI/res/values-lv/strings.xml
index c18b03f..ddc2dbb 100644
--- a/packages/SystemUI/res/values-lv/strings.xml
+++ b/packages/SystemUI/res/values-lv/strings.xml
@@ -149,4 +149,6 @@
     <string name="accessibility_rotation_lock_off" msgid="4062780228931590069">"Ekrāns tiks pagriezts automātiski."</string>
     <string name="accessibility_rotation_lock_on_landscape" msgid="6731197337665366273">"Ekrāns tagad ir bloķēts ainavas orientācijā."</string>
     <string name="accessibility_rotation_lock_on_portrait" msgid="5809367521644012115">"Ekrāns tagad ir bloķēts portreta orientācijā."</string>
+    <!-- no translation found for jelly_bean_dream_name (5992026543636816792) -->
+    <skip />
 </resources>
diff --git a/packages/SystemUI/res/values-ms/strings.xml b/packages/SystemUI/res/values-ms/strings.xml
index ef926ac..191ee63 100644
--- a/packages/SystemUI/res/values-ms/strings.xml
+++ b/packages/SystemUI/res/values-ms/strings.xml
@@ -149,4 +149,6 @@
     <string name="accessibility_rotation_lock_off" msgid="4062780228931590069">"Skrin akan berputar secara automatik."</string>
     <string name="accessibility_rotation_lock_on_landscape" msgid="6731197337665366273">"Skrin dikunci dalam orientasi landskap."</string>
     <string name="accessibility_rotation_lock_on_portrait" msgid="5809367521644012115">"Skrin dikunci dalam orientasi potret."</string>
+    <!-- no translation found for jelly_bean_dream_name (5992026543636816792) -->
+    <skip />
 </resources>
diff --git a/packages/SystemUI/res/values-nb/strings.xml b/packages/SystemUI/res/values-nb/strings.xml
index e7005fa..8aa5f26 100644
--- a/packages/SystemUI/res/values-nb/strings.xml
+++ b/packages/SystemUI/res/values-nb/strings.xml
@@ -149,4 +149,6 @@
     <string name="accessibility_rotation_lock_off" msgid="4062780228931590069">"Skjermen roterer automatisk."</string>
     <string name="accessibility_rotation_lock_on_landscape" msgid="6731197337665366273">"Skjermen er låst i liggende retning."</string>
     <string name="accessibility_rotation_lock_on_portrait" msgid="5809367521644012115">"Skjermen er låst i stående retning."</string>
+    <!-- no translation found for jelly_bean_dream_name (5992026543636816792) -->
+    <skip />
 </resources>
diff --git a/packages/SystemUI/res/values-nl/strings.xml b/packages/SystemUI/res/values-nl/strings.xml
index d5e8444..b740dd4 100644
--- a/packages/SystemUI/res/values-nl/strings.xml
+++ b/packages/SystemUI/res/values-nl/strings.xml
@@ -149,4 +149,6 @@
     <string name="accessibility_rotation_lock_off" msgid="4062780228931590069">"Scherm wordt automatisch geroteerd."</string>
     <string name="accessibility_rotation_lock_on_landscape" msgid="6731197337665366273">"Het scherm is nu vergrendeld in liggende stand."</string>
     <string name="accessibility_rotation_lock_on_portrait" msgid="5809367521644012115">"Het scherm is nu vergrendeld in staande stand."</string>
+    <!-- no translation found for jelly_bean_dream_name (5992026543636816792) -->
+    <skip />
 </resources>
diff --git a/packages/SystemUI/res/values-pl/strings.xml b/packages/SystemUI/res/values-pl/strings.xml
index 7639c84..e60c3b9 100644
--- a/packages/SystemUI/res/values-pl/strings.xml
+++ b/packages/SystemUI/res/values-pl/strings.xml
@@ -149,4 +149,6 @@
     <string name="accessibility_rotation_lock_off" msgid="4062780228931590069">"Ekran zostanie obrócony automatycznie."</string>
     <string name="accessibility_rotation_lock_on_landscape" msgid="6731197337665366273">"Ekran jest zablokowany w orientacji poziomej."</string>
     <string name="accessibility_rotation_lock_on_portrait" msgid="5809367521644012115">"Ekran jest zablokowany w orientacji pionowej."</string>
+    <!-- no translation found for jelly_bean_dream_name (5992026543636816792) -->
+    <skip />
 </resources>
diff --git a/packages/SystemUI/res/values-pt-rPT/strings.xml b/packages/SystemUI/res/values-pt-rPT/strings.xml
index 4b41ca0..b2e008c 100644
--- a/packages/SystemUI/res/values-pt-rPT/strings.xml
+++ b/packages/SystemUI/res/values-pt-rPT/strings.xml
@@ -149,4 +149,6 @@
     <string name="accessibility_rotation_lock_off" msgid="4062780228931590069">"O ecrã será rodado automaticamente."</string>
     <string name="accessibility_rotation_lock_on_landscape" msgid="6731197337665366273">"O ecrã está bloqueado na orientação horizontal."</string>
     <string name="accessibility_rotation_lock_on_portrait" msgid="5809367521644012115">"O ecrã está bloqueado na orientação vertical."</string>
+    <!-- no translation found for jelly_bean_dream_name (5992026543636816792) -->
+    <skip />
 </resources>
diff --git a/packages/SystemUI/res/values-pt/strings.xml b/packages/SystemUI/res/values-pt/strings.xml
index b88e096..966495a 100644
--- a/packages/SystemUI/res/values-pt/strings.xml
+++ b/packages/SystemUI/res/values-pt/strings.xml
@@ -151,4 +151,6 @@
     <string name="accessibility_rotation_lock_off" msgid="4062780228931590069">"A tela girará automaticamente."</string>
     <string name="accessibility_rotation_lock_on_landscape" msgid="6731197337665366273">"A tela está bloqueada na orientação paisagem."</string>
     <string name="accessibility_rotation_lock_on_portrait" msgid="5809367521644012115">"A tela está bloqueada na orientação retrato."</string>
+    <!-- no translation found for jelly_bean_dream_name (5992026543636816792) -->
+    <skip />
 </resources>
diff --git a/packages/SystemUI/res/values-rm/strings.xml b/packages/SystemUI/res/values-rm/strings.xml
index ea88ddd..141c13e 100644
--- a/packages/SystemUI/res/values-rm/strings.xml
+++ b/packages/SystemUI/res/values-rm/strings.xml
@@ -268,4 +268,6 @@
     <skip />
     <!-- no translation found for accessibility_rotation_lock_on_portrait (5809367521644012115) -->
     <skip />
+    <!-- no translation found for jelly_bean_dream_name (5992026543636816792) -->
+    <skip />
 </resources>
diff --git a/packages/SystemUI/res/values-ro/strings.xml b/packages/SystemUI/res/values-ro/strings.xml
index c7dff3a..42991cb 100644
--- a/packages/SystemUI/res/values-ro/strings.xml
+++ b/packages/SystemUI/res/values-ro/strings.xml
@@ -149,4 +149,6 @@
     <string name="accessibility_rotation_lock_off" msgid="4062780228931590069">"Ecranul se va roti în mod automat."</string>
     <string name="accessibility_rotation_lock_on_landscape" msgid="6731197337665366273">"Ecranul este blocat în orientarea de tip peisaj."</string>
     <string name="accessibility_rotation_lock_on_portrait" msgid="5809367521644012115">"Ecranul este blocat în orientarea de tip portret."</string>
+    <!-- no translation found for jelly_bean_dream_name (5992026543636816792) -->
+    <skip />
 </resources>
diff --git a/packages/SystemUI/res/values-ru/strings.xml b/packages/SystemUI/res/values-ru/strings.xml
index d435670..78b9297 100644
--- a/packages/SystemUI/res/values-ru/strings.xml
+++ b/packages/SystemUI/res/values-ru/strings.xml
@@ -151,4 +151,6 @@
     <string name="accessibility_rotation_lock_off" msgid="4062780228931590069">"Экран будет поворачиваться автоматически."</string>
     <string name="accessibility_rotation_lock_on_landscape" msgid="6731197337665366273">"Выбрана только альбомная ориентация экрана."</string>
     <string name="accessibility_rotation_lock_on_portrait" msgid="5809367521644012115">"Выбрана только книжная ориентация экрана."</string>
+    <!-- no translation found for jelly_bean_dream_name (5992026543636816792) -->
+    <skip />
 </resources>
diff --git a/packages/SystemUI/res/values-sk/strings.xml b/packages/SystemUI/res/values-sk/strings.xml
index b57afe3..5fc943e 100644
--- a/packages/SystemUI/res/values-sk/strings.xml
+++ b/packages/SystemUI/res/values-sk/strings.xml
@@ -151,4 +151,6 @@
     <string name="accessibility_rotation_lock_off" msgid="4062780228931590069">"Obrazovka sa automaticky otočí."</string>
     <string name="accessibility_rotation_lock_on_landscape" msgid="6731197337665366273">"Obrazovka je uzamknutá v orientácii na šírku."</string>
     <string name="accessibility_rotation_lock_on_portrait" msgid="5809367521644012115">"Obrazovka je uzamknutá v orientácii na výšku."</string>
+    <!-- no translation found for jelly_bean_dream_name (5992026543636816792) -->
+    <skip />
 </resources>
diff --git a/packages/SystemUI/res/values-sl/strings.xml b/packages/SystemUI/res/values-sl/strings.xml
index 1bed89b..9953428 100644
--- a/packages/SystemUI/res/values-sl/strings.xml
+++ b/packages/SystemUI/res/values-sl/strings.xml
@@ -149,4 +149,6 @@
     <string name="accessibility_rotation_lock_off" msgid="4062780228931590069">"Zaslon se bo samodejno zasukal."</string>
     <string name="accessibility_rotation_lock_on_landscape" msgid="6731197337665366273">"Zaslon je zaklenjen v ležeči usmerjenosti."</string>
     <string name="accessibility_rotation_lock_on_portrait" msgid="5809367521644012115">"Zaslon je zaklenjen v pokončni usmerjenosti."</string>
+    <!-- no translation found for jelly_bean_dream_name (5992026543636816792) -->
+    <skip />
 </resources>
diff --git a/packages/SystemUI/res/values-sr/strings.xml b/packages/SystemUI/res/values-sr/strings.xml
index 5dbbbb4..83ada24 100644
--- a/packages/SystemUI/res/values-sr/strings.xml
+++ b/packages/SystemUI/res/values-sr/strings.xml
@@ -149,4 +149,6 @@
     <string name="accessibility_rotation_lock_off" msgid="4062780228931590069">"Екран ће се аутоматски ротирати."</string>
     <string name="accessibility_rotation_lock_on_landscape" msgid="6731197337665366273">"Екран је закључан у хоризонталном положају."</string>
     <string name="accessibility_rotation_lock_on_portrait" msgid="5809367521644012115">"Екран је закључан у вертикалном положају."</string>
+    <!-- no translation found for jelly_bean_dream_name (5992026543636816792) -->
+    <skip />
 </resources>
diff --git a/packages/SystemUI/res/values-sv/strings.xml b/packages/SystemUI/res/values-sv/strings.xml
index f09dc2a..e87a2d9 100644
--- a/packages/SystemUI/res/values-sv/strings.xml
+++ b/packages/SystemUI/res/values-sv/strings.xml
@@ -149,4 +149,6 @@
     <string name="accessibility_rotation_lock_off" msgid="4062780228931590069">"Skärmen roteras automatiskt."</string>
     <string name="accessibility_rotation_lock_on_landscape" msgid="6731197337665366273">"Bildskärmens riktning är nu låst i liggande format."</string>
     <string name="accessibility_rotation_lock_on_portrait" msgid="5809367521644012115">"Bildskärmens riktning är nu låst i stående format."</string>
+    <!-- no translation found for jelly_bean_dream_name (5992026543636816792) -->
+    <skip />
 </resources>
diff --git a/packages/SystemUI/res/values-sw/strings.xml b/packages/SystemUI/res/values-sw/strings.xml
index 768b1c8..30fea17 100644
--- a/packages/SystemUI/res/values-sw/strings.xml
+++ b/packages/SystemUI/res/values-sw/strings.xml
@@ -147,4 +147,6 @@
     <string name="accessibility_rotation_lock_off" msgid="4062780228931590069">"Skrini itazunguka kiotomatiki."</string>
     <string name="accessibility_rotation_lock_on_landscape" msgid="6731197337665366273">"Skrini imefungwa sasa katika uelekezo wa mandhari."</string>
     <string name="accessibility_rotation_lock_on_portrait" msgid="5809367521644012115">"Skrini imefungwa katika uelekeo wa picha."</string>
+    <!-- no translation found for jelly_bean_dream_name (5992026543636816792) -->
+    <skip />
 </resources>
diff --git a/packages/SystemUI/res/values-th/strings.xml b/packages/SystemUI/res/values-th/strings.xml
index fb06e1a..89c640d 100644
--- a/packages/SystemUI/res/values-th/strings.xml
+++ b/packages/SystemUI/res/values-th/strings.xml
@@ -149,4 +149,6 @@
     <string name="accessibility_rotation_lock_off" msgid="4062780228931590069">"หน้าจอจะหมุนโดยอัตโนมัติ"</string>
     <string name="accessibility_rotation_lock_on_landscape" msgid="6731197337665366273">"ขณะนี้หน้าจอถูกล็อกให้วางในแนวนอน"</string>
     <string name="accessibility_rotation_lock_on_portrait" msgid="5809367521644012115">"ขณะนี้หน้าจอถูกล็อกให้วางในแนวตั้ง"</string>
+    <!-- no translation found for jelly_bean_dream_name (5992026543636816792) -->
+    <skip />
 </resources>
diff --git a/packages/SystemUI/res/values-tl/strings.xml b/packages/SystemUI/res/values-tl/strings.xml
index ad601c9..88d3607 100644
--- a/packages/SystemUI/res/values-tl/strings.xml
+++ b/packages/SystemUI/res/values-tl/strings.xml
@@ -149,4 +149,6 @@
     <string name="accessibility_rotation_lock_off" msgid="4062780228931590069">"Awtomatikong iikot ang screen."</string>
     <string name="accessibility_rotation_lock_on_landscape" msgid="6731197337665366273">"Naka-lock ang screen sa pahigang oryentasyon."</string>
     <string name="accessibility_rotation_lock_on_portrait" msgid="5809367521644012115">"Naka-lock ang screen sa patayong oryentasyon."</string>
+    <!-- no translation found for jelly_bean_dream_name (5992026543636816792) -->
+    <skip />
 </resources>
diff --git a/packages/SystemUI/res/values-tr/strings.xml b/packages/SystemUI/res/values-tr/strings.xml
index c4c64d9..15bc353 100644
--- a/packages/SystemUI/res/values-tr/strings.xml
+++ b/packages/SystemUI/res/values-tr/strings.xml
@@ -149,4 +149,6 @@
     <string name="accessibility_rotation_lock_off" msgid="4062780228931590069">"Ekran otomatik olarak dönecektir."</string>
     <string name="accessibility_rotation_lock_on_landscape" msgid="6731197337665366273">"Ekran yatay yönde kilitlendi."</string>
     <string name="accessibility_rotation_lock_on_portrait" msgid="5809367521644012115">"Ekran dikey yönde kilitlendi."</string>
+    <!-- no translation found for jelly_bean_dream_name (5992026543636816792) -->
+    <skip />
 </resources>
diff --git a/packages/SystemUI/res/values-uk/strings.xml b/packages/SystemUI/res/values-uk/strings.xml
index 973c6bc..c731fad 100644
--- a/packages/SystemUI/res/values-uk/strings.xml
+++ b/packages/SystemUI/res/values-uk/strings.xml
@@ -149,4 +149,6 @@
     <string name="accessibility_rotation_lock_off" msgid="4062780228931590069">"Екран обертатиметься автоматично."</string>
     <string name="accessibility_rotation_lock_on_landscape" msgid="6731197337665366273">"Екран заблоковано в альбомній орієнтації."</string>
     <string name="accessibility_rotation_lock_on_portrait" msgid="5809367521644012115">"Екран заблоковано в книжковій орієнтації."</string>
+    <!-- no translation found for jelly_bean_dream_name (5992026543636816792) -->
+    <skip />
 </resources>
diff --git a/packages/SystemUI/res/values-vi/strings.xml b/packages/SystemUI/res/values-vi/strings.xml
index f9d2b3c..6a51cc1 100644
--- a/packages/SystemUI/res/values-vi/strings.xml
+++ b/packages/SystemUI/res/values-vi/strings.xml
@@ -149,4 +149,6 @@
     <string name="accessibility_rotation_lock_off" msgid="4062780228931590069">"Màn hình sẽ xoay tự động."</string>
     <string name="accessibility_rotation_lock_on_landscape" msgid="6731197337665366273">"Màn hình hiện bị khóa theo hướng ngang."</string>
     <string name="accessibility_rotation_lock_on_portrait" msgid="5809367521644012115">"Màn hình hiện bị khóa theo hướng dọc."</string>
+    <!-- no translation found for jelly_bean_dream_name (5992026543636816792) -->
+    <skip />
 </resources>
diff --git a/packages/SystemUI/res/values-zh-rCN/strings.xml b/packages/SystemUI/res/values-zh-rCN/strings.xml
index 408f861..6aa03a0 100644
--- a/packages/SystemUI/res/values-zh-rCN/strings.xml
+++ b/packages/SystemUI/res/values-zh-rCN/strings.xml
@@ -151,4 +151,6 @@
     <string name="accessibility_rotation_lock_off" msgid="4062780228931590069">"屏幕会自动旋转。"</string>
     <string name="accessibility_rotation_lock_on_landscape" msgid="6731197337665366273">"屏幕锁定为横向模式。"</string>
     <string name="accessibility_rotation_lock_on_portrait" msgid="5809367521644012115">"屏幕锁定为纵向模式。"</string>
+    <!-- no translation found for jelly_bean_dream_name (5992026543636816792) -->
+    <skip />
 </resources>
diff --git a/packages/SystemUI/res/values-zh-rTW/strings.xml b/packages/SystemUI/res/values-zh-rTW/strings.xml
index debdb1c..053b538c 100644
--- a/packages/SystemUI/res/values-zh-rTW/strings.xml
+++ b/packages/SystemUI/res/values-zh-rTW/strings.xml
@@ -151,4 +151,6 @@
     <string name="accessibility_rotation_lock_off" msgid="4062780228931590069">"螢幕會自動旋轉。"</string>
     <string name="accessibility_rotation_lock_on_landscape" msgid="6731197337665366273">"螢幕已鎖定為橫向模式。"</string>
     <string name="accessibility_rotation_lock_on_portrait" msgid="5809367521644012115">"螢幕已鎖定為垂直模式。"</string>
+    <!-- no translation found for jelly_bean_dream_name (5992026543636816792) -->
+    <skip />
 </resources>
diff --git a/packages/SystemUI/res/values-zu/strings.xml b/packages/SystemUI/res/values-zu/strings.xml
index f31a11e..c10e968 100644
--- a/packages/SystemUI/res/values-zu/strings.xml
+++ b/packages/SystemUI/res/values-zu/strings.xml
@@ -149,4 +149,6 @@
     <string name="accessibility_rotation_lock_off" msgid="4062780228931590069">"Isikrini sizophenduka ngokuzenzakalela."</string>
     <string name="accessibility_rotation_lock_on_landscape" msgid="6731197337665366273">"Isikrini sikhiyelwe ngomumo we-landscape."</string>
     <string name="accessibility_rotation_lock_on_portrait" msgid="5809367521644012115">"Isikrini sikhiyelwe ngomumo we-portrait."</string>
+    <!-- no translation found for jelly_bean_dream_name (5992026543636816792) -->
+    <skip />
 </resources>
diff --git a/packages/SystemUI/res/values/config.xml b/packages/SystemUI/res/values/config.xml
index 34e58a3..734e68c 100644
--- a/packages/SystemUI/res/values/config.xml
+++ b/packages/SystemUI/res/values/config.xml
@@ -81,5 +81,11 @@
 
     <!-- Min alpha % that recent items will fade to while being dismissed -->
     <integer name="config_recent_item_min_alpha">3</integer>
+
+    <!-- The number of columns in the QuickSettings -->
+    <integer name="quick_settings_num_columns">3</integer>
+
+    <!-- The number of columns that the top level tiles span in the QuickSettings -->
+    <integer name="quick_settings_user_time_settings_tile_span">1</integer>
 </resources>
 
diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml
index 0d7cdb1..63ce2a9 100644
--- a/packages/SystemUI/res/values/dimens.xml
+++ b/packages/SystemUI/res/values/dimens.xml
@@ -174,4 +174,14 @@
 
     <!-- The distance you can pull a notificaiton before it pops open -->
     <dimen name="one_finger_pop_limit">32dp</dimen>
+
+    <!-- The amount of padding around the QuickSettings tiles -->
+    <dimen name="quick_settings_container_padding">12dp</dimen>
+
+    <!-- The fixed height of each tile -->
+    <dimen name="quick_settings_cell_height">110dp</dimen>
+
+    <!-- The padding between each tile within the QuickSettings layout -->
+    <dimen name="quick_settings_cell_gap">5dp</dimen>
+
 </resources>
diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml
index 609d63b..2bcf951 100644
--- a/packages/SystemUI/res/values/strings.xml
+++ b/packages/SystemUI/res/values/strings.xml
@@ -372,9 +372,6 @@
     <!-- Content description of the clear button in the notification panel for accessibility (not shown on the screen). [CHAR LIMIT=NONE] -->
     <string name="accessibility_clear_all">Clear all notifications.</string>
 
-    <!-- Description of the desk dock action that invokes the Android Dreams screen saver feature -->
-    <string name="dreams_dock_launcher">Activate screen saver</string>
-
     <!-- Title shown in notification popup for inspecting the responsible
          application -->
     <string name="status_bar_notification_inspect_item_title">App info</string>
@@ -400,4 +397,58 @@
 
     <!-- Name of the Jelly Bean platlogo screensaver -->
     <string name="jelly_bean_dream_name">BeanFlinger</string>
+
+    <!-- Name of the launcher shortcut icon that allows dreams to be started immediately [CHAR LIMIT=20] -->
+    <string name="start_dreams">Start dreams</string>
+
+    <!-- QuickSettings: Airplane mode [CHAR LIMIT=NONE] -->
+    <string name="quick_settings_airplane_mode_label">Airplane mode</string>
+    <!-- QuickSettings: Battery [CHAR LIMIT=NONE] -->
+    <string name="quick_settings_battery_label">Battery</string>
+    <!-- QuickSettings: Bluetooth [CHAR LIMIT=NONE] -->
+    <string name="quick_settings_bluetooth_label">Bluetooth</string>
+    <!-- QuickSettings: Brightness [CHAR LIMIT=NONE] -->
+    <string name="quick_settings_brightness_label">Brightness</string>
+    <!-- QuickSettings: IME [CHAR LIMIT=NONE] -->
+    <string name="quick_settings_ime_label">IME</string>
+    <!-- QuickSettings: Location [CHAR LIMIT=NONE] -->
+    <string name="quick_settings_location_label">Location in use</string>
+    <!-- QuickSettings: Media device [CHAR LIMIT=NONE] -->
+    <string name="quick_settings_media_device_label">Media device</string>
+    <!-- QuickSettings: RSSI [CHAR LIMIT=NONE] -->
+    <string name="quick_settings_rssi_label">RSSI</string>
+    <!-- QuickSettings: RSSI (No network) [CHAR LIMIT=NONE] -->
+    <string name="quick_settings_rssi_emergency_only">Emergency Calls Only</string>
+    <!-- QuickSettings: Settings [CHAR LIMIT=NONE] -->
+    <string name="quick_settings_settings_label">Settings</string>
+    <!-- QuickSettings: Time [CHAR LIMIT=NONE] -->
+    <string name="quick_settings_time_label">Time</string>
+    <!-- QuickSettings: User [CHAR LIMIT=NONE] -->
+    <string name="quick_settings_user_label">Me</string>
+    <!-- QuickSettings: Wifi [CHAR LIMIT=NONE] -->
+    <string name="quick_settings_wifi_label">Wifi</string>
+    <!-- QuickSettings: Wifi (No network) [CHAR LIMIT=NONE] -->
+    <string name="quick_settings_wifi_no_network">No Network</string>
+    <!-- QuickSettings: Wifi display [CHAR LIMIT=NONE] -->
+    <string name="quick_settings_wifi_display_label">Wifi Display</string>
+    <!-- QuickSettings: Wifi display [CHAR LIMIT=NONE] -->
+    <string name="quick_settings_wifi_display_no_connection_label">No Wifi Display Connection</string>
+
+    <!-- Wifi display: Scan button text [CHAR LIMIT=15] -->
+    <string name="wifi_display_scan">Scan</string>
+
+    <!-- Wifi display: Disconnect button text [CHAR LIMIT=15] -->
+    <string name="wifi_display_disconnect">Disconnect</string>
+
+    <!-- Wifi display: Quick setting dialog title [CHAR LIMIT=30] -->
+    <string name="wifi_display_dialog_title">Wifi Display</string>
+
+    <!-- Wifi display: Subtitle text shown to indicate that a display is available [CHAR LIMIT=30] -->
+    <string name="wifi_display_state_available">Available</string>
+
+    <!-- Wifi display: Subtitle text shown to indicate that a display is connecting [CHAR LIMIT=30] -->
+    <string name="wifi_display_state_connecting">Connecting</string>
+
+    <!-- Wifi display: Subtitle text shown to indicate that a display is connected [CHAR LIMIT=30] -->
+    <string name="wifi_display_state_connected">Connected</string>
 </resources>
diff --git a/packages/SystemUI/res/values/styles.xml b/packages/SystemUI/res/values/styles.xml
index 2564003..34bd627 100644
--- a/packages/SystemUI/res/values/styles.xml
+++ b/packages/SystemUI/res/values/styles.xml
@@ -70,6 +70,28 @@
     <style name="TextAppearance.StatusBar.Expanded.Network.EmergencyOnly">
     </style>
 
+    <style name="TextAppearance" />
+    <style name="TextAppearance.QuickSettings" />
+
+    <style name="TextAppearance.QuickSettings.TileView">
+        <item name="android:padding">8dp</item>
+        <item name="android:textSize">13dp</item>
+        <item name="android:textStyle">normal</item>
+        <item name="android:textColor">#ff8d908c</item>
+        <item name="android:singleLine">true</item>
+        <item name="android:ellipsize">marquee</item>
+        <item name="android:fadingEdge">horizontal</item>
+    </style>
+
+    <style name="TextAppearance.QuickSettings.Clock" parent="@style/TextAppearance.QuickSettings.TileView">
+        <item name="android:textSize">24dp</item>
+        <item name="android:textColor">@android:color/holo_blue_light</item>
+    </style>
+
+    <style name="TextAppearance.QuickSettings.Date" parent="@style/TextAppearance.QuickSettings.TileView">
+        <item name="android:textSize">14dp</item>
+    </style>
+
     <style name="Animation" />
 
     <style name="Animation.ShirtPocketPanel">
diff --git a/packages/SystemUI/src/com/android/systemui/Somnambulator.java b/packages/SystemUI/src/com/android/systemui/Somnambulator.java
new file mode 100644
index 0000000..89d4ef7
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/Somnambulator.java
@@ -0,0 +1,61 @@
+/*);
+ * Copyright (C) 2012 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.systemui;
+
+import android.app.Activity;
+import android.content.Intent;
+import android.os.RemoteException;
+import android.os.ServiceManager;
+import android.service.dreams.IDreamManager;
+import android.util.Slog;
+
+public class Somnambulator extends Activity {
+
+    public Somnambulator() {
+    }
+    
+    @Override
+    public void onStart() {
+        super.onStart();
+        final Intent launchIntent = getIntent();
+        final String action = launchIntent.getAction();
+        if (Intent.ACTION_CREATE_SHORTCUT.equals(action)) {
+            Intent shortcutIntent = new Intent(this, Somnambulator.class);
+            shortcutIntent.setFlags(Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS
+                    | Intent.FLAG_ACTIVITY_NEW_TASK);
+            Intent resultIntent = new Intent();
+            resultIntent.putExtra(Intent.EXTRA_SHORTCUT_ICON_RESOURCE,
+                    Intent.ShortcutIconResource.fromContext(this, R.mipmap.ic_dreams));
+            resultIntent.putExtra(Intent.EXTRA_SHORTCUT_INTENT, shortcutIntent);
+            resultIntent.putExtra(Intent.EXTRA_SHORTCUT_NAME, getString(R.string.start_dreams));
+            setResult(RESULT_OK, resultIntent);
+        } else {
+            IDreamManager somnambulist = IDreamManager.Stub.asInterface(
+                    ServiceManager.checkService("dreams"));
+            if (somnambulist != null) {
+                try {
+                    Slog.v("Somnambulator", "Dreaming by user request.");
+                    somnambulist.dream();
+                } catch (RemoteException e) {
+                    // fine, stay asleep then
+                }
+            }
+        }
+        finish();
+    }
+
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java
index 2f551e1..bee63ee 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java
@@ -12,6 +12,10 @@
 import android.widget.FrameLayout;
 
 import com.android.systemui.R;
+import com.android.systemui.statusbar.policy.BatteryController;
+import com.android.systemui.statusbar.policy.BluetoothController;
+import com.android.systemui.statusbar.policy.LocationController;
+import com.android.systemui.statusbar.policy.NetworkController;
 
 public class PanelView extends FrameLayout {
     public static final boolean DEBUG = false;
@@ -356,6 +360,11 @@
         mBar = panelBar;
     }
 
+    public void setup(NetworkController network, BluetoothController bt, BatteryController batt,
+            LocationController location) {
+        // To be implemented by classes extending PanelView
+    }
+
     public void collapse() {
         // TODO: abort animation or ongoing touch
         if (mExpandedHeight > 0) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
index 5646c55..a5d4a8e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
@@ -19,11 +19,10 @@
 import android.animation.Animator;
 import android.animation.AnimatorListenerAdapter;
 import android.animation.AnimatorSet;
+import android.animation.LayoutTransition;
 import android.animation.ObjectAnimator;
 import android.app.ActivityManager;
 import android.app.ActivityManagerNative;
-import android.app.Dialog;
-import android.app.KeyguardManager;
 import android.app.Notification;
 import android.app.PendingIntent;
 import android.app.StatusBarManager;
@@ -31,7 +30,6 @@
 import android.content.Context;
 import android.content.Intent;
 import android.content.IntentFilter;
-import android.content.res.Configuration;
 import android.content.res.Resources;
 import android.graphics.Canvas;
 import android.graphics.ColorFilter;
@@ -54,13 +52,11 @@
 import android.util.Slog;
 import android.view.Display;
 import android.view.Gravity;
-import android.view.IWindowManager;
-import android.view.KeyEvent;
+import android.view.LayoutInflater;
 import android.view.MotionEvent;
 import android.view.VelocityTracker;
 import android.view.View;
 import android.view.ViewGroup;
-import android.view.WindowManagerGlobal;
 import android.view.ViewGroup.LayoutParams;
 import android.view.WindowManager;
 import android.view.animation.AccelerateInterpolator;
@@ -76,7 +72,6 @@
 import com.android.internal.statusbar.StatusBarIcon;
 import com.android.internal.statusbar.StatusBarNotification;
 import com.android.systemui.R;
-import com.android.systemui.recent.RecentTasksLoader;
 import com.android.systemui.statusbar.BaseStatusBar;
 import com.android.systemui.statusbar.CommandQueue;
 import com.android.systemui.statusbar.GestureRecorder;
@@ -86,6 +81,7 @@
 import com.android.systemui.statusbar.SignalClusterView;
 import com.android.systemui.statusbar.StatusBarIconView;
 import com.android.systemui.statusbar.policy.BatteryController;
+import com.android.systemui.statusbar.policy.BluetoothController;
 import com.android.systemui.statusbar.policy.DateView;
 import com.android.systemui.statusbar.policy.IntruderAlertView;
 import com.android.systemui.statusbar.policy.LocationController;
@@ -139,6 +135,7 @@
     PhoneStatusBarPolicy mIconPolicy;
 
     // These are no longer handled by the policy, because we need custom strategies for them
+    BluetoothController mBluetoothController;
     BatteryController mBatteryController;
     LocationController mLocationController;
     NetworkController mNetworkController;
@@ -317,9 +314,6 @@
                   View.STATUS_BAR_DISABLE_NOTIFICATION_TICKER
                 | (mNotificationPanelIsFullScreenWidth ? 0 : View.STATUS_BAR_DISABLE_SYSTEM_INFO));
 
-        // quick settings (WIP)
-        mSettingsPanel = (PanelView) mStatusBarWindow.findViewById(R.id.settings_panel);
-
         if (!ActivityManager.isHighEndGfx()) {
             mStatusBarWindow.setBackground(null);
             mNotificationPanel.setBackground(new FastColorDrawable(context.getResources().getColor(
@@ -394,9 +388,11 @@
         mBatteryController = new BatteryController(mContext);
         mBatteryController.addIconView((ImageView)mStatusBarView.findViewById(R.id.battery));
         mNetworkController = new NetworkController(mContext);
+        mBluetoothController = new BluetoothController(mContext);
         final SignalClusterView signalCluster =
                 (SignalClusterView)mStatusBarView.findViewById(R.id.signal_cluster);
 
+
         mNetworkController.addSignalCluster(signalCluster);
         signalCluster.setNetworkController(mNetworkController);
 
@@ -434,6 +430,12 @@
             });
         }
 
+        // Quick Settings (WIP)
+        mSettingsPanel = (PanelView) mStatusBarWindow.findViewById(R.id.settings_panel);
+        mSettingsPanel.setBar(mStatusBarView);
+        mSettingsPanel.setup(mNetworkController, mBluetoothController, mBatteryController,
+                mLocationController);
+
 //        final ImageView wimaxRSSI =
 //                (ImageView)sb.findViewById(R.id.wimax_signal);
 //        if (wimaxRSSI != null) {
@@ -1844,6 +1846,10 @@
         if (mClearButton instanceof TextView) {
             ((TextView)mClearButton).setText(context.getText(R.string.status_bar_clear_all_button));
         }
+
+        // Update the QuickSettings container
+        ((SettingsPanelView) mSettingsPanel).updateResources();
+
         loadDimens();
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickSettings.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickSettings.java
new file mode 100644
index 0000000..f374c11
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickSettings.java
@@ -0,0 +1,787 @@
+/*
+ * Copyright (C) 2012 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.systemui.statusbar.phone;
+
+import android.app.Dialog;
+import android.bluetooth.BluetoothAdapter;
+import android.bluetooth.BluetoothAdapter.BluetoothStateChangeCallback;
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.CursorLoader;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.content.Loader;
+import android.content.res.Resources;
+import android.database.Cursor;
+import android.graphics.drawable.ClipDrawable;
+import android.hardware.display.DisplayManager;
+import android.hardware.display.WifiDisplay;
+import android.hardware.display.WifiDisplayStatus;
+import android.net.Uri;
+import android.provider.ContactsContract;
+import android.provider.Settings;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.view.WindowManager;
+import android.widget.AdapterView;
+import android.widget.ArrayAdapter;
+import android.widget.Button;
+import android.widget.ListView;
+import android.widget.TextView;
+
+import java.util.ArrayList;
+import java.util.Comparator;
+
+import com.android.systemui.R;
+import com.android.systemui.statusbar.phone.QuickSettingsModel.State;
+import com.android.systemui.statusbar.policy.BatteryController;
+import com.android.systemui.statusbar.policy.BatteryController.BatteryStateChangeCallback;
+import com.android.systemui.statusbar.policy.BluetoothController;
+import com.android.systemui.statusbar.policy.LocationController;
+import com.android.systemui.statusbar.policy.LocationController.LocationGpsStateChangeCallback;
+import com.android.systemui.statusbar.policy.NetworkController;
+import com.android.systemui.statusbar.policy.NetworkController.NetworkSignalChangedCallback;
+
+class QuickSettingsModel implements BluetoothStateChangeCallback,
+        NetworkSignalChangedCallback,
+        BatteryStateChangeCallback,
+        LocationGpsStateChangeCallback {
+
+    /** Represents the state of a given attribute. */
+    static class State {
+        int iconId;
+        String label;
+        boolean enabled;
+    }
+    static class BatteryState extends State {
+        int batteryLevel;
+        boolean pluggedIn;
+    }
+
+    /** The callback to update a given tile. */
+    interface RefreshCallback {
+        public void refreshView(QuickSettingsTileView view, State state);
+    }
+
+    private Context mContext;
+
+    private QuickSettingsTileView mUserTile;
+    private RefreshCallback mUserCallback;
+    private State mUserState = new State();
+
+    private QuickSettingsTileView mAirplaneModeTile;
+    private RefreshCallback mAirplaneModeCallback;
+    private State mAirplaneModeState = new State();
+
+    private QuickSettingsTileView mWifiTile;
+    private RefreshCallback mWifiCallback;
+    private State mWifiState = new State();
+
+    private QuickSettingsTileView mWifiDisplayTile;
+    private RefreshCallback mWifiDisplayCallback;
+    private State mWifiDisplayState = new State();
+
+    private QuickSettingsTileView mRSSITile;
+    private RefreshCallback mRSSICallback;
+    private State mRSSIState = new State();
+
+    private QuickSettingsTileView mBluetoothTile;
+    private RefreshCallback mBluetoothCallback;
+    private State mBluetoothState = new State();
+
+    private QuickSettingsTileView mBatteryTile;
+    private RefreshCallback mBatteryCallback;
+    private BatteryState mBatteryState = new BatteryState();
+
+    private QuickSettingsTileView mLocationTile;
+    private RefreshCallback mLocationCallback;
+    private State mLocationState = new State();
+
+    public QuickSettingsModel(Context context) {
+        mContext = context;
+    }
+
+    // User
+    void addUserTile(QuickSettingsTileView view, RefreshCallback cb) {
+        mUserTile = view;
+        mUserCallback = cb;
+        mUserCallback.refreshView(mUserTile, mUserState);
+    }
+    void setUserTileInfo(String name) {
+        mUserState.label = name;
+        mUserCallback.refreshView(mUserTile, mUserState);
+    }
+
+    // Airplane Mode
+    void addAirplaneModeTile(QuickSettingsTileView view, RefreshCallback cb) {
+        mAirplaneModeTile = view;
+        mAirplaneModeTile.setOnClickListener(new View.OnClickListener() {
+            @Override
+            public void onClick(View v) {
+                if (mAirplaneModeState.enabled) {
+                    setAirplaneModeState(false);
+                } else {
+                    setAirplaneModeState(true);
+                }
+            }
+        });
+        mAirplaneModeCallback = cb;
+        mAirplaneModeCallback.refreshView(mAirplaneModeTile, mAirplaneModeState);
+    }
+    private void setAirplaneModeState(boolean enabled) {
+        // TODO: Sets the view to be "awaiting" if not already awaiting
+
+        // Change the system setting
+        Settings.System.putInt(mContext.getContentResolver(), Settings.System.AIRPLANE_MODE_ON,
+                                enabled ? 1 : 0);
+
+        // TODO: Update the UI to reflect system setting
+        // mCheckBoxPref.setChecked(enabled);
+
+        // Post the intent
+        Intent intent = new Intent(Intent.ACTION_AIRPLANE_MODE_CHANGED);
+        intent.putExtra("state", enabled);
+        mContext.sendBroadcast(intent);
+    }
+    // NetworkSignalChanged callback
+    @Override
+    public void onAirplaneModeChanged(boolean enabled) {
+        // TODO: If view is in awaiting state, disable
+        Resources r = mContext.getResources();
+        mAirplaneModeState.enabled = enabled;
+        mAirplaneModeState.iconId = (enabled ?
+                R.drawable.ic_qs_airplane_enabled :
+                R.drawable.ic_qs_airplane_normal);
+        mAirplaneModeCallback.refreshView(mAirplaneModeTile, mAirplaneModeState);
+    }
+
+    // Wifi
+    void addWifiTile(QuickSettingsTileView view, RefreshCallback cb) {
+        mWifiTile = view;
+        mWifiCallback = cb;
+        mWifiCallback.refreshView(mWifiTile, mWifiState);
+    }
+    // NetworkSignalChanged callback
+    @Override
+    public void onWifiSignalChanged(boolean enabled, String description) {
+        // TODO: If view is in awaiting state, disable
+        Resources r = mContext.getResources();
+        // TODO: Check if wifi is enabled
+        mWifiState.enabled = enabled;
+        mWifiState.iconId = (enabled ?
+                R.drawable.ic_qs_wifi_enabled :
+                R.drawable.ic_qs_wifi_normal);
+        mWifiState.label = (enabled ?
+                description :
+                r.getString(R.string.quick_settings_wifi_no_network));
+        mWifiCallback.refreshView(mWifiTile, mWifiState);
+    }
+
+    // RSSI
+    void addRSSITile(QuickSettingsTileView view, RefreshCallback cb) {
+        mRSSITile = view;
+        mRSSICallback = cb;
+        mRSSICallback.refreshView(mRSSITile, mRSSIState);
+    }
+    private void setRSSIState(boolean enabled) {
+        // TODO: Set RSSI enabled
+        // TODO: Sets the view to be "awaiting" if not already awaiting
+    }
+    // NetworkSignalChanged callback
+    @Override
+    public void onMobileDataSignalChanged(boolean enabled, String description) {
+        // TODO: If view is in awaiting state, disable
+        Resources r = mContext.getResources();
+        // TODO: Check if RSSI is enabled
+        mRSSIState.enabled = enabled;
+        mRSSIState.iconId = (enabled ?
+                R.drawable.ic_qs_rssi_enabled :
+                R.drawable.ic_qs_rssi_normal);
+        mRSSIState.label = (enabled ?
+                description :
+                r.getString(R.string.quick_settings_rssi_emergency_only));
+        mRSSICallback.refreshView(mRSSITile, mRSSIState);
+    }
+
+    // Bluetooth
+    void addBluetoothTile(QuickSettingsTileView view, RefreshCallback cb) {
+        mBluetoothTile = view;
+        mBluetoothTile.setOnClickListener(new View.OnClickListener() {
+            @Override
+            public void onClick(View v) {
+                if (mBluetoothState.enabled) {
+                    setBluetoothState(false);
+                } else {
+                    setBluetoothState(true);
+                }
+            }
+        });
+        mBluetoothCallback = cb;
+
+        final BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
+        onBluetoothStateChange(adapter.isEnabled());
+    }
+    private void setBluetoothState(boolean enabled) {
+        // TODO: Sets the view to be "awaiting" if not already awaiting
+        final BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
+        if (adapter != null) {
+            if (enabled) {
+                adapter.enable();
+            } else {
+                adapter.disable();
+            }
+        }
+    }
+    // BluetoothController callback
+    @Override
+    public void onBluetoothStateChange(boolean on) {
+        // TODO: If view is in awaiting state, disable
+        Resources r = mContext.getResources();
+        mBluetoothState.enabled = on;
+        if (on) {
+            mBluetoothState.iconId = R.drawable.ic_qs_bluetooth_enabled;
+        } else {
+            mBluetoothState.iconId = R.drawable.ic_qs_bluetooth_normal;
+        }
+        mBluetoothCallback.refreshView(mBluetoothTile, mBluetoothState);
+    }
+
+    // Battery
+    void addBatteryTile(QuickSettingsTileView view, RefreshCallback cb) {
+        mBatteryTile = view;
+        mBatteryCallback = cb;
+        mBatteryCallback.refreshView(mBatteryTile, mBatteryState);
+    }
+    // BatteryController callback
+    @Override
+    public void onBatteryLevelChanged(int level, boolean pluggedIn) {
+        mBatteryState.batteryLevel = level;
+        mBatteryState.pluggedIn = pluggedIn;
+        mBatteryCallback.refreshView(mBatteryTile, mBatteryState);
+    }
+
+    // Location
+    void addLocationTile(QuickSettingsTileView view, RefreshCallback cb) {
+        mLocationTile = view;
+        mLocationCallback = cb;
+        mLocationCallback.refreshView(mLocationTile, mLocationState);
+        disableLocationTile();
+    }
+    private void enableLocationTile() {
+        mLocationTile.setVisibility(View.VISIBLE);
+    }
+    private void disableLocationTile() {
+        mLocationTile.setVisibility(View.GONE);
+    }
+    // LocationController callback
+    @Override
+    public void onLocationGpsStateChanged(boolean inUse, String description) {
+        if (inUse) {
+            mLocationState.enabled = inUse;
+            mLocationState.label = description;
+            mLocationCallback.refreshView(mLocationTile, mLocationState);
+            enableLocationTile();
+        } else {
+            disableLocationTile();
+        }
+    }
+
+    // Wifi Display
+    void addWifiDisplayTile(QuickSettingsTileView view, RefreshCallback cb) {
+        mWifiDisplayTile = view;
+        mWifiDisplayCallback = cb;
+    }
+    private void enableWifiDisplayTile() {
+        mWifiDisplayTile.setVisibility(View.VISIBLE);
+    }
+    private void disableWifiDisplayTile() {
+        mWifiDisplayTile.setVisibility(View.GONE);
+    }
+    public void onWifiDisplayStateChanged(WifiDisplayStatus status) {
+        if (status.isEnabled()) {
+            if (status.getActiveDisplay() != null) {
+                mWifiDisplayState.label = status.getActiveDisplay().getDeviceName();
+            } else {
+                mWifiDisplayState.label = mContext.getString(
+                        R.string.quick_settings_wifi_display_no_connection_label);
+            }
+            mWifiDisplayCallback.refreshView(mWifiDisplayTile, mWifiDisplayState);
+            enableWifiDisplayTile();
+        } else {
+            disableWifiDisplayTile();
+        }
+    }
+
+}
+
+/**
+ *
+ */
+class QuickSettings {
+
+    private Context mContext;
+    private PanelBar mBar;
+    private QuickSettingsModel mModel;
+    private QuickSettingsContainerView mContainerView;
+
+    private DisplayManager mDisplayManager;
+    private WifiDisplayStatus mWifiDisplayStatus;
+    private WifiDisplayListAdapter mWifiDisplayListAdapter;
+
+    private CursorLoader mUserInfoLoader;
+
+    // The set of QuickSettingsTiles that have dynamic spans (and need to be updated on
+    // configuration change)
+    private final ArrayList<QuickSettingsTileView> mDynamicSpannedTiles =
+            new ArrayList<QuickSettingsTileView>();
+
+    public QuickSettings(Context context, QuickSettingsContainerView container) {
+        mDisplayManager = (DisplayManager) context.getSystemService(Context.DISPLAY_SERVICE);
+        mContext = context;
+        mContainerView = container;
+        mModel = new QuickSettingsModel(context);
+        mWifiDisplayStatus = new WifiDisplayStatus();
+        mWifiDisplayListAdapter = new WifiDisplayListAdapter(context);
+
+        IntentFilter filter = new IntentFilter();
+        filter.addAction(DisplayManager.ACTION_WIFI_DISPLAY_STATUS_CHANGED);
+        mContext.registerReceiver(mReceiver, filter);
+
+        setupQuickSettings();
+        updateWifiDisplayStatus();
+        updateResources();
+    }
+
+    void setBar(PanelBar bar) {
+        mBar = bar;
+    }
+
+    void setup(NetworkController networkController, BluetoothController bluetoothController,
+            BatteryController batteryController, LocationController locationController) {
+        networkController.addNetworkSignalChangedCallback(mModel);
+        bluetoothController.addStateChangedCallback(mModel);
+        batteryController.addStateChangedCallback(mModel);
+        locationController.addStateChangedCallback(mModel);
+    }
+
+    private void queryForUserInformation() {
+        Uri userContactUri = Uri.withAppendedPath(
+            ContactsContract.Profile.CONTENT_URI,
+            ContactsContract.Contacts.Data.CONTENT_DIRECTORY);
+
+        String[] selectArgs = {
+            ContactsContract.CommonDataKinds.StructuredName.DISPLAY_NAME,
+            ContactsContract.CommonDataKinds.Photo.PHOTO
+        };
+        String where = String.format("(%s = ? OR %s = ?) AND %s IS NULL",
+            ContactsContract.Contacts.Data.MIMETYPE,
+            ContactsContract.Contacts.Data.MIMETYPE,
+            ContactsContract.RawContacts.ACCOUNT_TYPE);
+        String[] whereArgs = {
+            ContactsContract.CommonDataKinds.StructuredName.CONTENT_ITEM_TYPE,
+            ContactsContract.CommonDataKinds.Photo.CONTENT_ITEM_TYPE
+        };
+
+        mUserInfoLoader = new CursorLoader(mContext, userContactUri, selectArgs, where, whereArgs,
+                null);
+        mUserInfoLoader.registerListener(0,
+                new Loader.OnLoadCompleteListener<Cursor>() {
+                    @Override
+                    public void onLoadComplete(Loader<Cursor> loader,
+                            Cursor cursor) {
+                        if (cursor != null && cursor.moveToFirst()) {
+                            String name = cursor.getString(0); // DISPLAY_NAME
+                            mModel.setUserTileInfo(name);
+                            /*
+                            byte[] photoData = cursor.getBlob(0);
+                            Bitmap b =
+                                BitmapFactory.decodeByteArray(photoData, 0, photoData.length);
+                             */
+                        }
+                        mUserInfoLoader.stopLoading();
+                    }
+                });
+        mUserInfoLoader.startLoading();
+    }
+
+    private void setupQuickSettings() {
+        // Setup the tiles that we are going to be showing (including the temporary ones)
+        LayoutInflater inflater = LayoutInflater.from(mContext);
+
+        addUserTiles(mContainerView, inflater);
+        addSystemTiles(mContainerView, inflater);
+        addTemporaryTiles(mContainerView, inflater);
+
+        queryForUserInformation();
+    }
+
+    private void addUserTiles(ViewGroup parent, LayoutInflater inflater) {
+        QuickSettingsTileView userTile = (QuickSettingsTileView)
+                inflater.inflate(R.layout.quick_settings_tile, parent, false);
+        userTile.setContent(R.layout.quick_settings_tile_user, inflater);
+        mModel.addUserTile(userTile, new QuickSettingsModel.RefreshCallback() {
+            @Override
+            public void refreshView(QuickSettingsTileView view, State state) {
+                TextView tv = (TextView) view.findViewById(R.id.user_textview);
+                tv.setText(state.label);
+            }
+        });
+        parent.addView(userTile);
+        mDynamicSpannedTiles.add(userTile);
+
+        // Time tile
+        QuickSettingsTileView timeTile = (QuickSettingsTileView)
+                inflater.inflate(R.layout.quick_settings_tile, parent, false);
+        timeTile.setContent(R.layout.quick_settings_tile_time, inflater);
+        parent.addView(timeTile);
+        mDynamicSpannedTiles.add(timeTile);
+
+        // Settings tile
+        QuickSettingsTileView settingsTile = (QuickSettingsTileView)
+                inflater.inflate(R.layout.quick_settings_tile, parent, false);
+        settingsTile.setContent(R.layout.quick_settings_tile_settings, inflater);
+        settingsTile.setOnClickListener(new View.OnClickListener() {
+            @Override
+            public void onClick(View v) {
+                Intent intent = new Intent(android.provider.Settings.ACTION_SETTINGS);
+                intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+                mContext.startActivity(intent);
+                mBar.collapseAllPanels(true);
+            }
+        });
+        parent.addView(settingsTile);
+        mDynamicSpannedTiles.add(settingsTile);
+    }
+
+    private void addSystemTiles(ViewGroup parent, LayoutInflater inflater) {
+        // Wi-fi
+        QuickSettingsTileView wifiTile = (QuickSettingsTileView)
+                inflater.inflate(R.layout.quick_settings_tile, parent, false);
+        wifiTile.setContent(R.layout.quick_settings_tile_wifi, inflater);
+        wifiTile.setOnClickListener(new View.OnClickListener() {
+            @Override
+            public void onClick(View v) {
+                Intent intent = new Intent(android.provider.Settings.ACTION_WIFI_SETTINGS);
+                intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+                mContext.startActivity(intent);
+                mBar.collapseAllPanels(true);
+            }
+        });
+        mModel.addWifiTile(wifiTile, new QuickSettingsModel.RefreshCallback() {
+            @Override
+            public void refreshView(QuickSettingsTileView view, State state) {
+                TextView tv = (TextView) view.findViewById(R.id.wifi_textview);
+                tv.setCompoundDrawablesRelativeWithIntrinsicBounds(0, state.iconId, 0, 0);
+                tv.setText(state.label);
+            }
+        });
+        parent.addView(wifiTile);
+
+        // RSSI
+        QuickSettingsTileView rssiTile = (QuickSettingsTileView)
+                inflater.inflate(R.layout.quick_settings_tile, parent, false);
+        rssiTile.setContent(R.layout.quick_settings_tile_rssi, inflater);
+        rssiTile.setOnClickListener(new View.OnClickListener() {
+            @Override
+            public void onClick(View v) {
+                Intent intent = new Intent(android.provider.Settings.ACTION_WIRELESS_SETTINGS);
+                intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+                mContext.startActivity(intent);
+                mBar.collapseAllPanels(true);
+            }
+        });
+        mModel.addRSSITile(rssiTile, new QuickSettingsModel.RefreshCallback() {
+            @Override
+            public void refreshView(QuickSettingsTileView view, State state) {
+                TextView tv = (TextView) view.findViewById(R.id.rssi_textview);
+                tv.setCompoundDrawablesRelativeWithIntrinsicBounds(0, state.iconId, 0, 0);
+                tv.setText(state.label);
+            }
+        });
+        parent.addView(rssiTile);
+
+        // Battery
+        QuickSettingsTileView batteryTile = (QuickSettingsTileView)
+                inflater.inflate(R.layout.quick_settings_tile, parent, false);
+        batteryTile.setContent(R.layout.quick_settings_tile_battery, inflater);
+        batteryTile.setOnClickListener(new View.OnClickListener() {
+            @Override
+            public void onClick(View v) {
+                Intent intent = new Intent(Intent.ACTION_POWER_USAGE_SUMMARY);
+                intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+                mContext.startActivity(intent);
+                mBar.collapseAllPanels(true);
+            }
+        });
+        mModel.addBatteryTile(batteryTile, new QuickSettingsModel.RefreshCallback() {
+            @Override
+            public void refreshView(QuickSettingsTileView view, State state) {
+                QuickSettingsModel.BatteryState batteryState =
+                        (QuickSettingsModel.BatteryState) state;
+                TextView tv = (TextView) view.findViewById(R.id.battery_textview);
+                ClipDrawable drawable = (ClipDrawable) tv.getCompoundDrawables()[1];
+                drawable.setLevel((int) (10000 * (batteryState.batteryLevel / 100.0f)));
+                // TODO: use format string
+                tv.setText(batteryState.batteryLevel + "%");
+            }
+        });
+        parent.addView(batteryTile);
+
+        // Airplane Mode
+        QuickSettingsTileView airplaneTile = (QuickSettingsTileView)
+                inflater.inflate(R.layout.quick_settings_tile, parent, false);
+        airplaneTile.setContent(R.layout.quick_settings_tile_airplane, inflater);
+        mModel.addAirplaneModeTile(airplaneTile, new QuickSettingsModel.RefreshCallback() {
+            @Override
+            public void refreshView(QuickSettingsTileView view, State state) {
+                TextView tv = (TextView) view.findViewById(R.id.airplane_mode_textview);
+                tv.setCompoundDrawablesRelativeWithIntrinsicBounds(0, state.iconId, 0, 0);
+            }
+        });
+        parent.addView(airplaneTile);
+
+        // Bluetooth
+        QuickSettingsTileView bluetoothTile = (QuickSettingsTileView)
+                inflater.inflate(R.layout.quick_settings_tile, parent, false);
+        bluetoothTile.setContent(R.layout.quick_settings_tile_bluetooth, inflater);
+        mModel.addBluetoothTile(bluetoothTile, new QuickSettingsModel.RefreshCallback() {
+            @Override
+            public void refreshView(QuickSettingsTileView view, State state) {
+                TextView tv = (TextView) view.findViewById(R.id.bluetooth_textview);
+                tv.setCompoundDrawablesRelativeWithIntrinsicBounds(0, state.iconId, 0, 0);
+            }
+        });
+        parent.addView(bluetoothTile);
+
+        // Brightness
+        QuickSettingsTileView brightnessTile = (QuickSettingsTileView)
+                inflater.inflate(R.layout.quick_settings_tile, parent, false);
+        brightnessTile.setContent(R.layout.quick_settings_tile_brightness, inflater);
+        brightnessTile.setOnClickListener(new View.OnClickListener() {
+            @Override
+            public void onClick(View v) {
+                Intent intent = new Intent(android.provider.Settings.ACTION_DISPLAY_SETTINGS);
+                intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+                mContext.startActivity(intent);
+                mBar.collapseAllPanels(true);
+            }
+        });
+        parent.addView(brightnessTile);
+    }
+
+    private void addTemporaryTiles(final ViewGroup parent, final LayoutInflater inflater) {
+        // Location
+        QuickSettingsTileView locationTile = (QuickSettingsTileView)
+                inflater.inflate(R.layout.quick_settings_tile, parent, false);
+        locationTile.setContent(R.layout.quick_settings_tile_location, inflater);
+        locationTile.setOnClickListener(new View.OnClickListener() {
+            @Override
+            public void onClick(View v) {
+                Intent intent =
+                        new Intent(android.provider.Settings.ACTION_LOCATION_SOURCE_SETTINGS);
+                intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+                mContext.startActivity(intent);
+                mBar.collapseAllPanels(true);
+            }
+        });
+        mModel.addLocationTile(locationTile, new QuickSettingsModel.RefreshCallback() {
+            @Override
+            public void refreshView(QuickSettingsTileView view, State state) {
+                TextView tv = (TextView) view.findViewById(R.id.location_textview);
+                tv.setText(state.label);
+            }
+        });
+        parent.addView(locationTile);
+
+        // Wifi Display
+        QuickSettingsTileView wifiDisplayTile = (QuickSettingsTileView)
+                inflater.inflate(R.layout.quick_settings_tile, parent, false);
+        wifiDisplayTile.setContent(R.layout.quick_settings_tile_wifi_display, inflater);
+        wifiDisplayTile.setOnClickListener(new View.OnClickListener() {
+            @Override
+            public void onClick(View v) {
+                showWifiDisplayDialog();
+                mBar.collapseAllPanels(true);
+            }
+        });
+        mModel.addWifiDisplayTile(wifiDisplayTile, new QuickSettingsModel.RefreshCallback() {
+            @Override
+            public void refreshView(QuickSettingsTileView view, State state) {
+                TextView tv = (TextView) view.findViewById(R.id.wifi_display_textview);
+                tv.setText(state.label);
+            }
+        });
+        parent.addView(wifiDisplayTile);
+
+        /*
+        QuickSettingsTileView mediaTile = (QuickSettingsTileView)
+                inflater.inflate(R.layout.quick_settings_tile, parent, false);
+        mediaTile.setContent(R.layout.quick_settings_tile_media, inflater);
+        parent.addView(mediaTile);
+        QuickSettingsTileView imeTile = (QuickSettingsTileView)
+                inflater.inflate(R.layout.quick_settings_tile, parent, false);
+        imeTile.setContent(R.layout.quick_settings_tile_ime, inflater);
+        imeTile.setOnClickListener(new View.OnClickListener() {
+            @Override
+            public void onClick(View v) {
+                parent.removeViewAt(0);
+            }
+        });
+        parent.addView(imeTile);
+        */
+    }
+
+    void updateResources() {
+        Resources r = mContext.getResources();
+
+        // Update the User, Time, and Settings tiles spans, and reset everything else
+        int span = r.getInteger(R.integer.quick_settings_user_time_settings_tile_span);
+        for (QuickSettingsTileView v : mDynamicSpannedTiles) {
+            v.setColumnSpan(span);
+        }
+        mContainerView.requestLayout();
+    }
+
+    private void showWifiDisplayDialog() {
+        mDisplayManager.scanWifiDisplays();
+        updateWifiDisplayStatus();
+
+        Dialog dialog = new Dialog(mContext);
+        dialog.setContentView(R.layout.wifi_display_dialog);
+        dialog.setCanceledOnTouchOutside(true);
+        dialog.setTitle(R.string.wifi_display_dialog_title);
+
+        Button scanButton = (Button)dialog.findViewById(R.id.scan);
+        scanButton.setOnClickListener(new View.OnClickListener() {
+            @Override
+            public void onClick(View v) {
+                mDisplayManager.scanWifiDisplays();
+            }
+        });
+
+        Button disconnectButton = (Button)dialog.findViewById(R.id.disconnect);
+        disconnectButton.setOnClickListener(new View.OnClickListener() {
+            @Override
+            public void onClick(View v) {
+                mDisplayManager.disconnectWifiDisplay();
+            }
+        });
+
+        ListView list = (ListView)dialog.findViewById(R.id.list);
+        list.setAdapter(mWifiDisplayListAdapter);
+        list.setOnItemClickListener(new AdapterView.OnItemClickListener() {
+            @Override
+            public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
+                WifiDisplay display = mWifiDisplayListAdapter.getItem(position);
+                mDisplayManager.connectWifiDisplay(display.getDeviceAddress());
+            }
+        });
+
+        dialog.getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_ALERT);
+        dialog.show();
+    }
+
+    private void updateWifiDisplayStatus() {
+        applyWifiDisplayStatus(mDisplayManager.getWifiDisplayStatus());
+    }
+
+    private void applyWifiDisplayStatus(WifiDisplayStatus status) {
+        mWifiDisplayStatus = status;
+
+        mWifiDisplayListAdapter.clear();
+        mWifiDisplayListAdapter.addAll(status.getKnownDisplays());
+        if (status.getActiveDisplay() != null
+                && !contains(status.getKnownDisplays(), status.getActiveDisplay())) {
+            mWifiDisplayListAdapter.add(status.getActiveDisplay());
+        }
+        mWifiDisplayListAdapter.sort(mWifiDisplayComparator);
+
+        mModel.onWifiDisplayStateChanged(status);
+    }
+
+    private static boolean contains(WifiDisplay[] displays, WifiDisplay display) {
+        for (WifiDisplay d : displays) {
+            if (d.equals(display)) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
+        @Override
+        public void onReceive(Context context, Intent intent) {
+            if (intent.getAction().equals(DisplayManager.ACTION_WIFI_DISPLAY_STATUS_CHANGED)) {
+                WifiDisplayStatus status = (WifiDisplayStatus)intent.getParcelableExtra(
+                        DisplayManager.EXTRA_WIFI_DISPLAY_STATUS);
+                applyWifiDisplayStatus(status);
+            }
+        }
+    };
+
+    private final class WifiDisplayListAdapter extends ArrayAdapter<WifiDisplay> {
+        private final LayoutInflater mInflater;
+
+        public WifiDisplayListAdapter(Context context) {
+            super(context, android.R.layout.simple_list_item_2);
+            mInflater = LayoutInflater.from(context);
+        }
+
+        @Override
+        public View getView(int position, View convertView, ViewGroup parent) {
+            WifiDisplay item = getItem(position);
+            View view = convertView;
+            if (view == null) {
+                view = mInflater.inflate(android.R.layout.simple_list_item_2,
+                        parent, false);
+            }
+            TextView headline = (TextView) view.findViewById(android.R.id.text1);
+            TextView subText = (TextView) view.findViewById(android.R.id.text2);
+            headline.setText(item.getDeviceName());
+
+            int state = WifiDisplayStatus.DISPLAY_STATE_NOT_CONNECTED;
+            if (item.equals(mWifiDisplayStatus.getActiveDisplay())) {
+                state = mWifiDisplayStatus.getActiveDisplayState();
+            }
+            switch (state) {
+                case WifiDisplayStatus.DISPLAY_STATE_CONNECTING:
+                    subText.setText(R.string.wifi_display_state_connecting);
+                    break;
+                case WifiDisplayStatus.DISPLAY_STATE_CONNECTED:
+                    subText.setText(R.string.wifi_display_state_connected);
+                    break;
+                case WifiDisplayStatus.DISPLAY_STATE_NOT_CONNECTED:
+                default:
+                    subText.setText(R.string.wifi_display_state_available);
+                    break;
+            }
+            return view;
+        }
+    }
+
+    private final Comparator<WifiDisplay> mWifiDisplayComparator = new Comparator<WifiDisplay>() {
+        @Override
+        public int compare(WifiDisplay lhs, WifiDisplay rhs) {
+            int c = lhs.getDeviceName().compareToIgnoreCase(rhs.getDeviceName());
+            if (c == 0) {
+                c = lhs.getDeviceAddress().compareToIgnoreCase(rhs.getDeviceAddress());
+            }
+            return c;
+        }
+    };
+}
\ No newline at end of file
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickSettingsContainerView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickSettingsContainerView.java
new file mode 100644
index 0000000..105ceb1
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickSettingsContainerView.java
@@ -0,0 +1,138 @@
+/*
+ * Copyright (C) 2012 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.systemui.statusbar.phone;
+
+import android.animation.LayoutTransition;
+import android.content.Context;
+import android.content.res.Resources;
+import android.util.AttributeSet;
+import android.view.ViewGroup;
+import android.widget.FrameLayout;
+
+import com.android.systemui.R;
+
+/**
+ *
+ */
+class QuickSettingsContainerView extends FrameLayout {
+
+    // The number of columns in the QuickSettings grid
+    private int mNumColumns;
+
+    // The gap between tiles in the QuickSettings grid
+    private float mCellGap;
+
+    public QuickSettingsContainerView(Context context, AttributeSet attrs) {
+        super(context, attrs);
+
+        updateResources();
+    }
+
+    @Override
+    protected void onFinishInflate() {
+        super.onFinishInflate();
+
+        // TODO: Setup the layout transitions
+        LayoutTransition transitions = getLayoutTransition();
+    }
+
+    void updateResources() {
+        Resources r = getContext().getResources();
+        mCellGap = r.getDimension(R.dimen.quick_settings_cell_gap);
+        mNumColumns = r.getInteger(R.integer.quick_settings_num_columns);
+        requestLayout();
+    }
+
+    @Override
+    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
+        // Calculate the cell width dynamically
+        int width = MeasureSpec.getSize(widthMeasureSpec);
+        int height = MeasureSpec.getSize(heightMeasureSpec);
+        int availableWidth = (int) (width - getPaddingLeft() - getPaddingRight() -
+                (mNumColumns - 1) * mCellGap);
+        float cellWidth = availableWidth / mNumColumns;
+
+        // Update each of the children's widths accordingly to the cell width
+        int N = getChildCount();
+        int cellHeight = 0;
+        int cursor = 0;
+        for (int i = 0; i < N; ++i) {
+            // Update the child's width
+            QuickSettingsTileView v = (QuickSettingsTileView) getChildAt(i);
+            ViewGroup.MarginLayoutParams lp = (ViewGroup.MarginLayoutParams) v.getLayoutParams();
+            int colSpan = v.getColumnSpan();
+            lp.width = (int) ((colSpan * cellWidth) + (colSpan - 1) * mCellGap);
+
+            // Measure the child
+            v.setMinimumWidth(lp.width);
+            v.setMinimumHeight(lp.height);
+            int newWidthSpec = MeasureSpec.makeMeasureSpec(lp.width, MeasureSpec.AT_MOST);
+            int newHeightSpec = MeasureSpec.makeMeasureSpec(lp.height, MeasureSpec.AT_MOST);
+            v.measure(newWidthSpec, newHeightSpec);
+
+            // Save the cell height
+            if (cellHeight <= 0) {
+                cellHeight = v.getMeasuredHeight();
+            }
+            cursor += colSpan;
+        }
+
+        // Set the measured dimensions.  We always fill the tray width, but wrap to the height of
+        // all the tiles.
+        int numRows = (int) Math.ceil((float) cursor / mNumColumns);
+        int newHeight = (int) ((numRows * cellHeight) + ((numRows - 1) * mCellGap)) +
+                getPaddingTop() + getPaddingBottom();
+        setMeasuredDimension(width, newHeight);
+    }
+
+    @Override
+    protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
+        int N = getChildCount();
+        int x = getPaddingLeft();
+        int y = getPaddingTop();
+        int cursor = 0;
+        for (int i = 0; i < N; ++i) {
+            QuickSettingsTileView v = (QuickSettingsTileView) getChildAt(i);
+            ViewGroup.LayoutParams lp = (ViewGroup.LayoutParams) v.getLayoutParams();
+            if (v.getVisibility() != GONE) {
+                int col = cursor % mNumColumns;
+                int colSpan = v.getColumnSpan();
+                int row = (int) (cursor / mNumColumns);
+
+                // Push the item to the next row if it can't fit on this one
+                if ((col + colSpan) > mNumColumns) {
+                    x = getPaddingLeft();
+                    y += lp.height + mCellGap;
+                    row++;
+                }
+
+                // Layout the container
+                v.layout(x, y, x + lp.width, y + lp.height);
+
+                // Offset the position by the cell gap or reset the position and cursor when we
+                // reach the end of the row
+                cursor += v.getColumnSpan();
+                if (cursor < (((row + 1) * mNumColumns))) {
+                    x += lp.width + mCellGap;
+                } else {
+                    x = getPaddingLeft();
+                    y += lp.height + mCellGap;
+                }
+            }
+        }
+    }
+}
\ No newline at end of file
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickSettingsTileView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickSettingsTileView.java
new file mode 100644
index 0000000..8f5cde6
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickSettingsTileView.java
@@ -0,0 +1,51 @@
+/*
+ * Copyright (C) 2012 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.systemui.statusbar.phone;
+
+import android.content.Context;
+import android.util.AttributeSet;
+import android.view.LayoutInflater;
+import android.widget.FrameLayout;
+
+/**
+ *
+ */
+class QuickSettingsTileView extends FrameLayout {
+
+    private int mColSpan;
+    private int mRowSpan;
+    private int mCellWidth;
+
+    public QuickSettingsTileView(Context context, AttributeSet attrs) {
+        super(context, attrs);
+
+        mColSpan = 1;
+        mRowSpan = 1;
+    }
+
+    void setColumnSpan(int span) {
+        mColSpan = span;
+    }
+
+    int getColumnSpan() {
+        return mColSpan;
+    }
+
+    void setContent(int layoutId, LayoutInflater inflater) {
+        inflater.inflate(layoutId, this);
+    }
+}
\ No newline at end of file
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/SettingsPanelView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/SettingsPanelView.java
index fb1528f..f896d57 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/SettingsPanelView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/SettingsPanelView.java
@@ -16,15 +16,70 @@
 
 package com.android.systemui.statusbar.phone;
 
+import android.animation.LayoutTransition;
 import android.content.Context;
+import android.content.Intent;
+import android.content.res.Resources;
 import android.util.AttributeSet;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+
+import com.android.systemui.R;
+import com.android.systemui.statusbar.BaseStatusBar;
+import com.android.systemui.statusbar.policy.BatteryController;
+import com.android.systemui.statusbar.policy.BluetoothController;
+import com.android.systemui.statusbar.policy.LocationController;
+import com.android.systemui.statusbar.policy.NetworkController;
 
 public class SettingsPanelView extends PanelView {
+
+    private QuickSettings mQS;
+    private QuickSettingsContainerView mQSContainer;
+
     public SettingsPanelView(Context context, AttributeSet attrs) {
         super(context, attrs);
     }
 
     @Override
+    protected void onFinishInflate() {
+        super.onFinishInflate();
+
+        mQSContainer = (QuickSettingsContainerView) findViewById(R.id.quick_settings_container);
+        mQS = new QuickSettings(getContext(), mQSContainer);
+    }
+
+    @Override
+    public void setBar(PanelBar panelBar) {
+        super.setBar(panelBar);
+
+        if (mQS != null) {
+            mQS.setBar(panelBar);
+        }
+    }
+
+    @Override
+    public void setup(NetworkController networkController, BluetoothController bluetoothController,
+            BatteryController batteryController, LocationController locationController) {
+        super.setup(networkController, bluetoothController, batteryController, locationController);
+
+        if (mQS != null) {
+            mQS.setup(networkController, bluetoothController, batteryController,
+                    locationController);
+        }
+    }
+
+    void updateResources() {
+        if (mQS != null) {
+            mQS.updateResources();
+        }
+        if (mQSContainer != null) {
+            mQSContainer.updateResources();
+        }
+        requestLayout();
+    }
+
+    @Override
     public void fling(float vel, boolean always) {
         ((PhoneStatusBarView) mBar).mBar.getGestureRecorder().tag(
             "fling " + ((vel > 0) ? "open" : "closed"),
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/BatteryController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/BatteryController.java
index ff418c4..7f9bcac 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/BatteryController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/BatteryController.java
@@ -18,6 +18,7 @@
 
 import java.util.ArrayList;
 
+import android.bluetooth.BluetoothAdapter.BluetoothStateChangeCallback;
 import android.content.BroadcastReceiver;
 import android.content.Context;
 import android.content.Intent;
@@ -36,6 +37,13 @@
     private ArrayList<ImageView> mIconViews = new ArrayList<ImageView>();
     private ArrayList<TextView> mLabelViews = new ArrayList<TextView>();
 
+    private ArrayList<BatteryStateChangeCallback> mChangeCallbacks =
+            new ArrayList<BatteryStateChangeCallback>();
+
+    public interface BatteryStateChangeCallback {
+        public void onBatteryLevelChanged(int level, boolean pluggedIn);
+    }
+
     public BatteryController(Context context) {
         mContext = context;
 
@@ -52,6 +60,10 @@
         mLabelViews.add(v);
     }
 
+    public void addStateChangedCallback(BatteryStateChangeCallback cb) {
+        mChangeCallbacks.add(cb);
+    }
+
     public void onReceive(Context context, Intent intent) {
         final String action = intent.getAction();
         if (action.equals(Intent.ACTION_BATTERY_CHANGED)) {
@@ -73,6 +85,10 @@
                 v.setText(mContext.getString(R.string.status_bar_settings_battery_meter_format,
                         level));
             }
+
+            for (BatteryStateChangeCallback cb : mChangeCallbacks) {
+                cb.onBatteryLevelChanged(level, plugged);
+            }
         }
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/BluetoothController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/BluetoothController.java
index 603808e..e517dde 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/BluetoothController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/BluetoothController.java
@@ -16,9 +16,8 @@
 
 package com.android.systemui.statusbar.policy;
 
-import java.util.ArrayList;
-
 import android.bluetooth.BluetoothAdapter;
+import android.bluetooth.BluetoothAdapter.BluetoothStateChangeCallback;
 import android.content.BroadcastReceiver;
 import android.content.Context;
 import android.content.Intent;
@@ -26,6 +25,8 @@
 import android.view.View;
 import android.widget.ImageView;
 
+import java.util.ArrayList;
+
 import com.android.systemui.R;
 
 public class BluetoothController extends BroadcastReceiver {
@@ -38,6 +39,9 @@
     private int mContentDescriptionId = 0;
     private boolean mEnabled = false;
 
+    private ArrayList<BluetoothStateChangeCallback> mChangeCallbacks =
+            new ArrayList<BluetoothStateChangeCallback>();
+
     public BluetoothController(Context context) {
         mContext = context;
 
@@ -58,6 +62,10 @@
         mIconViews.add(v);
     }
 
+    public void addStateChangedCallback(BluetoothStateChangeCallback cb) {
+        mChangeCallbacks.add(cb);
+    }
+
     @Override
     public void onReceive(Context context, Intent intent) {
         final String action = intent.getAction();
@@ -98,5 +106,8 @@
                     ? null
                     : mContext.getString(mContentDescriptionId));
         }
+        for (BluetoothStateChangeCallback cb : mChangeCallbacks) {
+            cb.onBluetoothStateChange(mEnabled);
+        }
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/DateView.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/DateView.java
index c19550b..640dcca 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/DateView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/DateView.java
@@ -30,7 +30,7 @@
 
 import java.util.Date;
 
-public final class DateView extends TextView {
+public class DateView extends TextView {
     private static final String TAG = "DateView";
 
     private boolean mAttachedToWindow;
@@ -86,7 +86,7 @@
         return 0;
     }
 
-    private final void updateClock() {
+    protected void updateClock() {
         final Context context = getContext();
         Date now = new Date();
         CharSequence dow = DateFormat.format("EEEE", now);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/LocationController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/LocationController.java
index bec5d72..4bf03e7 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/LocationController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/LocationController.java
@@ -37,6 +37,7 @@
 import com.android.internal.statusbar.StatusBarNotification;
 
 import com.android.systemui.R;
+import com.android.systemui.statusbar.policy.BatteryController.BatteryStateChangeCallback;
 
 public class LocationController extends BroadcastReceiver {
     private static final String TAG = "StatusBar.LocationController";
@@ -47,6 +48,13 @@
 
     private INotificationManager mNotificationService;
 
+    private ArrayList<LocationGpsStateChangeCallback> mChangeCallbacks =
+            new ArrayList<LocationGpsStateChangeCallback>();
+
+    public interface LocationGpsStateChangeCallback {
+        public void onLocationGpsStateChanged(boolean inUse, String description);
+    }
+
     public LocationController(Context context) {
         mContext = context;
 
@@ -60,6 +68,10 @@
         mNotificationService = nm.getService();
     }
 
+    public void addStateChangedCallback(LocationGpsStateChangeCallback cb) {
+        mChangeCallbacks.add(cb);
+    }
+
     @Override
     public void onReceive(Context context, Intent intent) {
         final String action = intent.getAction();
@@ -89,12 +101,14 @@
             if (visible) {
                 Intent gpsIntent = new Intent(Settings.ACTION_LOCATION_SOURCE_SETTINGS);
                 gpsIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+
                 PendingIntent pendingIntent = PendingIntent.getActivityAsUser(context, 0,
                         gpsIntent, 0, null, UserHandle.CURRENT);
+                String text = mContext.getText(textResId).toString();
 
                 Notification n = new Notification.Builder(mContext)
                     .setSmallIcon(iconId)
-                    .setContentTitle(mContext.getText(textResId))
+                    .setContentTitle(text)
                     .setOngoing(true)
                     .setContentIntent(pendingIntent)
                     .getNotification();
@@ -117,6 +131,10 @@
                 mNotificationService.cancelNotificationWithTag(
                         mContext.getPackageName(), null,
                         GPS_NOTIFICATION_ID, UserHandle.USER_CURRENT);
+
+                for (LocationGpsStateChangeCallback cb : mChangeCallbacks) {
+                    cb.onLocationGpsStateChanged(false, null);
+                }
             }
         } catch (android.os.RemoteException ex) {
             // well, it was worth a shot
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkController.java
index d94c6b2..23f27e7 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkController.java
@@ -148,6 +148,8 @@
     ArrayList<TextView> mWifiLabelViews = new ArrayList<TextView>();
     ArrayList<TextView> mEmergencyLabelViews = new ArrayList<TextView>();
     ArrayList<SignalCluster> mSignalClusters = new ArrayList<SignalCluster>();
+    ArrayList<NetworkSignalChangedCallback> mSignalsChangedCallbacks =
+            new ArrayList<NetworkSignalChangedCallback>();
     int mLastPhoneSignalIconId = -1;
     int mLastDataDirectionIconId = -1;
     int mLastDataDirectionOverlayIconId = -1;
@@ -172,6 +174,12 @@
         void setIsAirplaneMode(boolean is, int airplaneIcon);
     }
 
+    public interface NetworkSignalChangedCallback {
+        void onWifiSignalChanged(boolean enabled, String description);
+        void onMobileDataSignalChanged(boolean enabled, String description);
+        void onAirplaneModeChanged(boolean enabled);
+    }
+
     /**
      * Construct this controller object and register for updates.
      */
@@ -299,6 +307,11 @@
         refreshSignalCluster(cluster);
     }
 
+    public void addNetworkSignalChangedCallback(NetworkSignalChangedCallback cb) {
+        mSignalsChangedCallbacks.add(cb);
+        notifySignalsChangedCallbacks(cb);
+    }
+
     public void refreshSignalCluster(SignalCluster cluster) {
         cluster.setWifiIndicators(
                 // only show wifi in the cluster if connected or if wifi-only
@@ -329,6 +342,27 @@
         cluster.setIsAirplaneMode(mAirplaneMode, mAirplaneIconId);
     }
 
+    void notifySignalsChangedCallbacks(NetworkSignalChangedCallback cb) {
+        // only show wifi in the cluster if connected or if wifi-only
+        boolean wifiEnabled = mWifiEnabled && (mWifiConnected || !mHasMobileDataFeature);
+        String wifiDesc = wifiEnabled ?
+                mWifiSsid : null;
+        cb.onWifiSignalChanged(wifiEnabled, wifiDesc);
+
+        if (isEmergencyOnly()) {
+            cb.onMobileDataSignalChanged(false, null);
+        } else {
+            if (mIsWimaxEnabled && mWimaxConnected) {
+                // wimax is special
+                cb.onMobileDataSignalChanged(true, mNetworkName);
+            } else {
+                // normal mobile data
+                cb.onMobileDataSignalChanged(mHasMobileDataFeature, mNetworkName);
+            }
+        }
+        cb.onAirplaneModeChanged(mAirplaneMode);
+    }
+
     public void setStackedMode(boolean stacked) {
         mDataAndWifiStacked = true;
     }
@@ -1124,6 +1158,9 @@
             for (SignalCluster cluster : mSignalClusters) {
                 refreshSignalCluster(cluster);
             }
+            for (NetworkSignalChangedCallback cb : mSignalsChangedCallbacks) {
+                notifySignalsChangedCallbacks(cb);
+            }
         }
 
         if (mLastAirplaneMode != mAirplaneMode) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/QuickSettingsDateView.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/QuickSettingsDateView.java
new file mode 100644
index 0000000..c52f94b
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/QuickSettingsDateView.java
@@ -0,0 +1,45 @@
+/*
+ * 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.systemui.statusbar.policy;
+
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.text.format.DateFormat;
+import android.util.AttributeSet;
+import android.view.View;
+import android.view.ViewParent;
+import android.widget.TextView;
+
+import com.android.systemui.R;
+
+import java.util.Date;
+
+public final class QuickSettingsDateView extends DateView {
+
+    public QuickSettingsDateView(Context context, AttributeSet attrs) {
+        super(context, attrs);
+    }
+
+    protected void updateClock() {
+        final Context context = getContext();
+        Date now = new Date();
+        CharSequence dow = DateFormat.format("MMM d, yyyy", now);
+        setText(dow);
+    }
+}
diff --git a/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java b/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
index b07d8b8..6c62680 100755
--- a/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
+++ b/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
@@ -40,7 +40,6 @@
 import android.graphics.Rect;
 import android.media.AudioManager;
 import android.media.IAudioService;
-import android.os.BatteryManager;
 import android.os.Bundle;
 import android.os.FactoryTest;
 import android.os.Handler;
@@ -67,12 +66,12 @@
 import com.android.internal.telephony.ITelephony;
 import com.android.internal.widget.PointerLocationView;
 
-import android.service.dreams.IDreamManager;
 import android.util.DisplayMetrics;
 import android.util.EventLog;
 import android.util.Log;
 import android.util.Slog;
 import android.util.SparseArray;
+import android.util.SparseIntArray;
 import android.view.Display;
 import android.view.Gravity;
 import android.view.HapticFeedbackConstants;
@@ -116,6 +115,7 @@
 import static android.view.WindowManager.LayoutParams.TYPE_HIDDEN_NAV_CONSUMER;
 import static android.view.WindowManager.LayoutParams.TYPE_KEYGUARD;
 import static android.view.WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG;
+import static android.view.WindowManager.LayoutParams.TYPE_MAGNIFICATION_OVERLAY;
 import static android.view.WindowManager.LayoutParams.TYPE_PHONE;
 import static android.view.WindowManager.LayoutParams.TYPE_PRIORITY_PHONE;
 import static android.view.WindowManager.LayoutParams.TYPE_SEARCH_BAR;
@@ -221,16 +221,18 @@
     static final int NAVIGATION_BAR_PANEL_LAYER = 20;
     // system-level error dialogs
     static final int SYSTEM_ERROR_LAYER = 21;
+    // used to highlight the magnified portion of a display
+    static final int MAGNIFICATION_OVERLAY_LAYER = 22;
     // used to simulate secondary display devices
-    static final int DISPLAY_OVERLAY_LAYER = 22;
+    static final int DISPLAY_OVERLAY_LAYER = 23;
     // the drag layer: input for drag-and-drop is associated with this window,
     // which sits above all other focusable windows
-    static final int DRAG_LAYER = 23;
-    static final int SECURE_SYSTEM_OVERLAY_LAYER = 24;
-    static final int BOOT_PROGRESS_LAYER = 25;
+    static final int DRAG_LAYER = 24;
+    static final int SECURE_SYSTEM_OVERLAY_LAYER = 25;
+    static final int BOOT_PROGRESS_LAYER = 26;
     // the (mouse) pointer layer
-    static final int POINTER_LAYER = 26;
-    static final int HIDDEN_NAV_CONSUMER_LAYER = 27;
+    static final int POINTER_LAYER = 27;
+    static final int HIDDEN_NAV_CONSUMER_LAYER = 28;
 
     static final int APPLICATION_MEDIA_SUBLAYER = -2;
     static final int APPLICATION_MEDIA_OVERLAY_SUBLAYER = -1;
@@ -1334,6 +1336,8 @@
             return UNIVERSE_BACKGROUND_LAYER;
         case TYPE_DISPLAY_OVERLAY:
             return DISPLAY_OVERLAY_LAYER;
+        case TYPE_MAGNIFICATION_OVERLAY:
+            return MAGNIFICATION_OVERLAY_LAYER;
         }
         Log.e(TAG, "Unknown window type: " + type);
         return APPLICATION_LAYER;
@@ -2239,6 +2243,7 @@
                 & ~mForceClearedSystemUiFlags;
     }
 
+    @Override
     public void getContentInsetHintLw(WindowManager.LayoutParams attrs, Rect contentInset) {
         final int fl = attrs.flags;
         final int systemUiVisibility = (attrs.systemUiVisibility|attrs.subtreeSystemUiVisibility);
@@ -2279,7 +2284,9 @@
     }
 
     /** {@inheritDoc} */
-    public void beginLayoutLw(int displayWidth, int displayHeight, int displayRotation) {
+    @Override
+    public void beginLayoutLw(boolean isDefaultDisplay, int displayWidth, int displayHeight,
+                              int displayRotation) {
         mUnrestrictedScreenLeft = mUnrestrictedScreenTop = 0;
         mUnrestrictedScreenWidth = displayWidth;
         mUnrestrictedScreenHeight = displayHeight;
@@ -2306,136 +2313,138 @@
         pf.right = df.right = vf.right = mDockRight;
         pf.bottom = df.bottom = vf.bottom = mDockBottom;
 
-        // For purposes of putting out fake window up to steal focus, we will
-        // drive nav being hidden only by whether it is requested.
-        boolean navVisible = (mLastSystemUiFlags&View.SYSTEM_UI_FLAG_HIDE_NAVIGATION) == 0;
+        if (isDefaultDisplay) {
+            // For purposes of putting out fake window up to steal focus, we will
+            // drive nav being hidden only by whether it is requested.
+            boolean navVisible = (mLastSystemUiFlags&View.SYSTEM_UI_FLAG_HIDE_NAVIGATION) == 0;
 
-        // When the navigation bar isn't visible, we put up a fake
-        // input window to catch all touch events.  This way we can
-        // detect when the user presses anywhere to bring back the nav
-        // bar and ensure the application doesn't see the event.
-        if (navVisible) {
-            if (mHideNavFakeWindow != null) {
-                mHideNavFakeWindow.dismiss();
-                mHideNavFakeWindow = null;
+            // When the navigation bar isn't visible, we put up a fake
+            // input window to catch all touch events.  This way we can
+            // detect when the user presses anywhere to bring back the nav
+            // bar and ensure the application doesn't see the event.
+            if (navVisible) {
+                if (mHideNavFakeWindow != null) {
+                    mHideNavFakeWindow.dismiss();
+                    mHideNavFakeWindow = null;
+                }
+            } else if (mHideNavFakeWindow == null) {
+                mHideNavFakeWindow = mWindowManagerFuncs.addFakeWindow(
+                        mHandler.getLooper(), mHideNavInputEventReceiverFactory,
+                        "hidden nav", WindowManager.LayoutParams.TYPE_HIDDEN_NAV_CONSUMER,
+                        0, false, false, true);
             }
-        } else if (mHideNavFakeWindow == null) {
-            mHideNavFakeWindow = mWindowManagerFuncs.addFakeWindow(
-                    mHandler.getLooper(), mHideNavInputEventReceiverFactory,
-                    "hidden nav", WindowManager.LayoutParams.TYPE_HIDDEN_NAV_CONSUMER,
-                    0, false, false, true);
-        }
 
-        // For purposes of positioning and showing the nav bar, if we have
-        // decided that it can't be hidden (because of the screen aspect ratio),
-        // then take that into account.
-        navVisible |= !mCanHideNavigationBar;
+            // For purposes of positioning and showing the nav bar, if we have
+            // decided that it can't be hidden (because of the screen aspect ratio),
+            // then take that into account.
+            navVisible |= !mCanHideNavigationBar;
 
-        if (mNavigationBar != null) {
-            // Force the navigation bar to its appropriate place and
-            // size.  We need to do this directly, instead of relying on
-            // it to bubble up from the nav bar, because this needs to
-            // change atomically with screen rotations.
-            mNavigationBarOnBottom = (!mNavigationBarCanMove || displayWidth < displayHeight);
-            if (mNavigationBarOnBottom) {
-                // It's a system nav bar or a portrait screen; nav bar goes on bottom.
-                int top = displayHeight - mNavigationBarHeightForRotation[displayRotation];
-                mTmpNavigationFrame.set(0, top, displayWidth, displayHeight);
-                mStableBottom = mStableFullscreenBottom = mTmpNavigationFrame.top;
-                if (navVisible) {
-                    mNavigationBar.showLw(true);
-                    mDockBottom = mTmpNavigationFrame.top;
-                    mRestrictedScreenHeight = mDockBottom - mDockTop;
+            if (mNavigationBar != null) {
+                // Force the navigation bar to its appropriate place and
+                // size.  We need to do this directly, instead of relying on
+                // it to bubble up from the nav bar, because this needs to
+                // change atomically with screen rotations.
+                mNavigationBarOnBottom = (!mNavigationBarCanMove || displayWidth < displayHeight);
+                if (mNavigationBarOnBottom) {
+                    // It's a system nav bar or a portrait screen; nav bar goes on bottom.
+                    int top = displayHeight - mNavigationBarHeightForRotation[displayRotation];
+                    mTmpNavigationFrame.set(0, top, displayWidth, displayHeight);
+                    mStableBottom = mStableFullscreenBottom = mTmpNavigationFrame.top;
+                    if (navVisible) {
+                        mNavigationBar.showLw(true);
+                        mDockBottom = mTmpNavigationFrame.top;
+                        mRestrictedScreenHeight = mDockBottom - mDockTop;
+                    } else {
+                        // We currently want to hide the navigation UI.
+                        mNavigationBar.hideLw(true);
+                    }
+                    if (navVisible && !mNavigationBar.isAnimatingLw()) {
+                        // If the nav bar is currently requested to be visible,
+                        // and not in the process of animating on or off, then
+                        // we can tell the app that it is covered by it.
+                        mSystemBottom = mTmpNavigationFrame.top;
+                    }
                 } else {
-                    // We currently want to hide the navigation UI.
-                    mNavigationBar.hideLw(true);
+                    // Landscape screen; nav bar goes to the right.
+                    int left = displayWidth - mNavigationBarWidthForRotation[displayRotation];
+                    mTmpNavigationFrame.set(left, 0, displayWidth, displayHeight);
+                    mStableRight = mStableFullscreenRight = mTmpNavigationFrame.left;
+                    if (navVisible) {
+                        mNavigationBar.showLw(true);
+                        mDockRight = mTmpNavigationFrame.left;
+                        mRestrictedScreenWidth = mDockRight - mDockLeft;
+                    } else {
+                        // We currently want to hide the navigation UI.
+                        mNavigationBar.hideLw(true);
+                    }
+                    if (navVisible && !mNavigationBar.isAnimatingLw()) {
+                        // If the nav bar is currently requested to be visible,
+                        // and not in the process of animating on or off, then
+                        // we can tell the app that it is covered by it.
+                        mSystemRight = mTmpNavigationFrame.left;
+                    }
                 }
-                if (navVisible && !mNavigationBar.isAnimatingLw()) {
-                    // If the nav bar is currently requested to be visible,
-                    // and not in the process of animating on or off, then
-                    // we can tell the app that it is covered by it.
-                    mSystemBottom = mTmpNavigationFrame.top;
-                }
-            } else {
-                // Landscape screen; nav bar goes to the right.
-                int left = displayWidth - mNavigationBarWidthForRotation[displayRotation];
-                mTmpNavigationFrame.set(left, 0, displayWidth, displayHeight);
-                mStableRight = mStableFullscreenRight = mTmpNavigationFrame.left;
-                if (navVisible) {
-                    mNavigationBar.showLw(true);
-                    mDockRight = mTmpNavigationFrame.left;
-                    mRestrictedScreenWidth = mDockRight - mDockLeft;
-                } else {
-                    // We currently want to hide the navigation UI.
-                    mNavigationBar.hideLw(true);
-                }
-                if (navVisible && !mNavigationBar.isAnimatingLw()) {
-                    // If the nav bar is currently requested to be visible,
-                    // and not in the process of animating on or off, then
-                    // we can tell the app that it is covered by it.
-                    mSystemRight = mTmpNavigationFrame.left;
-                }
-            }
-            // Make sure the content and current rectangles are updated to
-            // account for the restrictions from the navigation bar.
-            mContentTop = mCurTop = mDockTop;
-            mContentBottom = mCurBottom = mDockBottom;
-            mContentLeft = mCurLeft = mDockLeft;
-            mContentRight = mCurRight = mDockRight;
-            mStatusBarLayer = mNavigationBar.getSurfaceLayer();
-            // And compute the final frame.
-            mNavigationBar.computeFrameLw(mTmpNavigationFrame, mTmpNavigationFrame,
-                    mTmpNavigationFrame, mTmpNavigationFrame);
-            if (DEBUG_LAYOUT) Log.i(TAG, "mNavigationBar frame: " + mTmpNavigationFrame);
-        }
-        if (DEBUG_LAYOUT) Log.i(TAG, String.format("mDock rect: (%d,%d - %d,%d)",
-                mDockLeft, mDockTop, mDockRight, mDockBottom));
-
-        // decide where the status bar goes ahead of time
-        if (mStatusBar != null) {
-            // apply any navigation bar insets
-            pf.left = df.left = mUnrestrictedScreenLeft;
-            pf.top = df.top = mUnrestrictedScreenTop;
-            pf.right = df.right = mUnrestrictedScreenWidth - mUnrestrictedScreenLeft;
-            pf.bottom = df.bottom = mUnrestrictedScreenHeight - mUnrestrictedScreenTop;
-            vf.left = mStableLeft;
-            vf.top = mStableTop;
-            vf.right = mStableRight;
-            vf.bottom = mStableBottom;
-
-            mStatusBarLayer = mStatusBar.getSurfaceLayer();
-
-            // Let the status bar determine its size.
-            mStatusBar.computeFrameLw(pf, df, vf, vf);
-
-            // For layout, the status bar is always at the top with our fixed height.
-            mStableTop = mUnrestrictedScreenTop + mStatusBarHeight;
-
-            // If the status bar is hidden, we don't want to cause
-            // windows behind it to scroll.
-            if (mStatusBar.isVisibleLw()) {
-                // Status bar may go away, so the screen area it occupies
-                // is available to apps but just covering them when the
-                // status bar is visible.
-                mDockTop = mUnrestrictedScreenTop + mStatusBarHeight;
-                
+                // Make sure the content and current rectangles are updated to
+                // account for the restrictions from the navigation bar.
                 mContentTop = mCurTop = mDockTop;
                 mContentBottom = mCurBottom = mDockBottom;
                 mContentLeft = mCurLeft = mDockLeft;
                 mContentRight = mCurRight = mDockRight;
-
-                if (DEBUG_LAYOUT) Log.v(TAG, "Status bar: " +
-                    String.format(
-                        "dock=[%d,%d][%d,%d] content=[%d,%d][%d,%d] cur=[%d,%d][%d,%d]",
-                        mDockLeft, mDockTop, mDockRight, mDockBottom,
-                        mContentLeft, mContentTop, mContentRight, mContentBottom,
-                        mCurLeft, mCurTop, mCurRight, mCurBottom));
+                mStatusBarLayer = mNavigationBar.getSurfaceLayer();
+                // And compute the final frame.
+                mNavigationBar.computeFrameLw(mTmpNavigationFrame, mTmpNavigationFrame,
+                        mTmpNavigationFrame, mTmpNavigationFrame);
+                if (DEBUG_LAYOUT) Log.i(TAG, "mNavigationBar frame: " + mTmpNavigationFrame);
             }
-            if (mStatusBar.isVisibleLw() && !mStatusBar.isAnimatingLw()) {
-                // If the status bar is currently requested to be visible,
-                // and not in the process of animating on or off, then
-                // we can tell the app that it is covered by it.
-                mSystemTop = mUnrestrictedScreenTop + mStatusBarHeight;
+            if (DEBUG_LAYOUT) Log.i(TAG, String.format("mDock rect: (%d,%d - %d,%d)",
+                    mDockLeft, mDockTop, mDockRight, mDockBottom));
+
+            // decide where the status bar goes ahead of time
+            if (mStatusBar != null) {
+                // apply any navigation bar insets
+                pf.left = df.left = mUnrestrictedScreenLeft;
+                pf.top = df.top = mUnrestrictedScreenTop;
+                pf.right = df.right = mUnrestrictedScreenWidth - mUnrestrictedScreenLeft;
+                pf.bottom = df.bottom = mUnrestrictedScreenHeight - mUnrestrictedScreenTop;
+                vf.left = mStableLeft;
+                vf.top = mStableTop;
+                vf.right = mStableRight;
+                vf.bottom = mStableBottom;
+
+                mStatusBarLayer = mStatusBar.getSurfaceLayer();
+
+                // Let the status bar determine its size.
+                mStatusBar.computeFrameLw(pf, df, vf, vf);
+
+                // For layout, the status bar is always at the top with our fixed height.
+                mStableTop = mUnrestrictedScreenTop + mStatusBarHeight;
+
+                // If the status bar is hidden, we don't want to cause
+                // windows behind it to scroll.
+                if (mStatusBar.isVisibleLw()) {
+                    // Status bar may go away, so the screen area it occupies
+                    // is available to apps but just covering them when the
+                    // status bar is visible.
+                    mDockTop = mUnrestrictedScreenTop + mStatusBarHeight;
+
+                    mContentTop = mCurTop = mDockTop;
+                    mContentBottom = mCurBottom = mDockBottom;
+                    mContentLeft = mCurLeft = mDockLeft;
+                    mContentRight = mCurRight = mDockRight;
+
+                    if (DEBUG_LAYOUT) Log.v(TAG, "Status bar: " +
+                        String.format(
+                            "dock=[%d,%d][%d,%d] content=[%d,%d][%d,%d] cur=[%d,%d][%d,%d]",
+                            mDockLeft, mDockTop, mDockRight, mDockBottom,
+                            mContentLeft, mContentTop, mContentRight, mContentBottom,
+                            mCurLeft, mCurTop, mCurRight, mCurBottom));
+                }
+                if (mStatusBar.isVisibleLw() && !mStatusBar.isAnimatingLw()) {
+                    // If the status bar is currently requested to be visible,
+                    // and not in the process of animating on or off, then
+                    // we can tell the app that it is covered by it.
+                    mSystemTop = mUnrestrictedScreenTop + mStatusBarHeight;
+                }
             }
         }
     }
@@ -2518,13 +2527,15 @@
     }
 
     /** {@inheritDoc} */
+    @Override
     public void layoutWindowLw(WindowState win, WindowManager.LayoutParams attrs,
             WindowState attached) {
         // we've already done the status bar
         if (win == mStatusBar || win == mNavigationBar) {
             return;
         }
-        final boolean needsToOffsetInputMethodTarget =
+        final boolean isDefaultDisplay = win.isDefaultDisplay();
+        final boolean needsToOffsetInputMethodTarget = isDefaultDisplay &&
                 (win == mLastInputMethodTargetWindow && mLastInputMethodWindow != null);
         if (needsToOffsetInputMethodTarget) {
             if (DEBUG_LAYOUT) {
@@ -2541,11 +2552,25 @@
         final Rect df = mTmpDisplayFrame;
         final Rect cf = mTmpContentFrame;
         final Rect vf = mTmpVisibleFrame;
-        
-        final boolean hasNavBar = (mHasNavigationBar 
+
+        final boolean hasNavBar = (isDefaultDisplay && mHasNavigationBar
                 && mNavigationBar != null && mNavigationBar.isVisibleLw());
 
-        if (attrs.type == TYPE_INPUT_METHOD) {
+        if (!isDefaultDisplay) {
+            if (attached != null) {
+                // If this window is attached to another, our display
+                // frame is the same as the one we are attached to.
+                setAttachedWindowFrames(win, fl, sim, attached, true, pf, df, cf, vf);
+            } else {
+                // Give the window full screen.
+                pf.left = df.left = cf.left = mUnrestrictedScreenLeft;
+                pf.top = df.top = cf.top = mUnrestrictedScreenTop;
+                pf.right = df.right = cf.right
+                        = mUnrestrictedScreenLeft + mUnrestrictedScreenWidth;
+                pf.bottom = df.bottom = cf.bottom
+                        = mUnrestrictedScreenTop + mUnrestrictedScreenHeight;
+            }
+        } else  if (attrs.type == TYPE_INPUT_METHOD) {
             pf.left = df.left = cf.left = vf.left = mDockLeft;
             pf.top = df.top = cf.top = vf.top = mDockTop;
             pf.right = df.right = cf.right = vf.right = mDockRight;
@@ -2612,6 +2637,7 @@
                         pf.right = df.right = mRestrictedScreenLeft+mRestrictedScreenWidth;
                         pf.bottom = df.bottom = mRestrictedScreenTop+mRestrictedScreenHeight;
                     }
+
                     if (adjust != SOFT_INPUT_ADJUST_RESIZE) {
                         cf.left = mDockLeft;
                         cf.top = mDockTop;
@@ -2623,6 +2649,7 @@
                         cf.right = mContentRight;
                         cf.bottom = mContentBottom;
                     }
+
                     applyStableConstraints(sysUiFl, fl, cf);
                     if (adjust != SOFT_INPUT_ADJUST_NOTHING) {
                         vf.left = mCurLeft;
@@ -2706,7 +2733,9 @@
                     pf.bottom = df.bottom = cf.bottom
                             = mRestrictedScreenTop+mRestrictedScreenHeight;
                 }
+
                 applyStableConstraints(sysUiFl, fl, cf);
+
                 if (adjust != SOFT_INPUT_ADJUST_NOTHING) {
                     vf.left = mCurLeft;
                     vf.top = mCurTop;
@@ -2763,7 +2792,7 @@
                 }
             }
         }
-        
+
         if ((fl & FLAG_LAYOUT_NO_LIMITS) != 0) {
             df.left = df.top = cf.left = cf.top = vf.left = vf.top = -10000;
             df.right = df.bottom = cf.right = cf.bottom = vf.right = vf.bottom = 10000;
@@ -2775,9 +2804,9 @@
                 + String.format(" flags=0x%08x", fl)
                 + " pf=" + pf.toShortString() + " df=" + df.toShortString()
                 + " cf=" + cf.toShortString() + " vf=" + vf.toShortString());
-        
+
         win.computeFrameLw(pf, df, cf, vf);
-        
+
         // Dock windows carve out the bottom of the screen, so normal windows
         // can't appear underneath them.
         if (attrs.type == TYPE_INPUT_METHOD && !win.getGivenInsetsPendingLw()) {
@@ -4123,7 +4152,7 @@
             } catch (ActivityNotFoundException e) {
             }
         }
-        mContext.startActivity(mHomeIntent);
+        mContext.startActivityAsUser(mHomeIntent, UserHandle.CURRENT);
     }
     
     /**
@@ -4152,22 +4181,22 @@
                     Intent dock = createHomeDockIntent();
                     if (dock != null) {
                         int result = ActivityManagerNative.getDefault()
-                                .startActivity(null, dock,
+                                .startActivityAsUser(null, dock,
                                         dock.resolveTypeIfNeeded(mContext.getContentResolver()),
                                         null, null, 0,
                                         ActivityManager.START_FLAG_ONLY_IF_NEEDED,
-                                        null, null, null);
+                                        null, null, null, UserHandle.USER_CURRENT);
                         if (result == ActivityManager.START_RETURN_INTENT_TO_CALLER) {
                             return false;
                         }
                     }
                 }
                 int result = ActivityManagerNative.getDefault()
-                        .startActivity(null, mHomeIntent,
+                        .startActivityAsUser(null, mHomeIntent,
                                 mHomeIntent.resolveTypeIfNeeded(mContext.getContentResolver()),
                                 null, null, 0,
                                 ActivityManager.START_FLAG_ONLY_IF_NEEDED,
-                                null, null, null);
+                                null, null, null, UserHandle.USER_CURRENT);
                 if (result == ActivityManager.START_RETURN_INTENT_TO_CALLER) {
                     return false;
                 }
@@ -4287,6 +4316,18 @@
         mLastInputMethodTargetWindow = target;
     }
 
+    public boolean canMagnifyWindow(WindowManager.LayoutParams attrs) {
+        switch (attrs.type) {
+            case WindowManager.LayoutParams.TYPE_INPUT_METHOD:
+            case WindowManager.LayoutParams.TYPE_INPUT_METHOD_DIALOG:
+            case WindowManager.LayoutParams.TYPE_NAVIGATION_BAR:
+            case WindowManager.LayoutParams.TYPE_MAGNIFICATION_OVERLAY: {
+                return false;
+            }
+        }
+        return true;
+    }
+
     public void dump(String prefix, PrintWriter pw, String[] args) {
         pw.print(prefix); pw.print("mSafeMode="); pw.print(mSafeMode);
                 pw.print(" mSystemReady="); pw.print(mSystemReady);
diff --git a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardHostView.java b/policy/src/com/android/internal/policy/impl/keyguard/KeyguardHostView.java
index 058bf92..e170ec1 100644
--- a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardHostView.java
+++ b/policy/src/com/android/internal/policy/impl/keyguard/KeyguardHostView.java
@@ -29,26 +29,30 @@
 import android.content.Intent;
 import android.content.IntentSender;
 import android.content.SharedPreferences;
+import android.content.pm.UserInfo;
 import android.content.res.Resources;
 import android.graphics.Canvas;
+import android.os.UserManager;
 import android.telephony.TelephonyManager;
 import android.util.AttributeSet;
 import android.util.Log;
 import android.util.Slog;
 import android.view.KeyEvent;
+import android.view.LayoutInflater;
 import android.view.View;
 import android.view.WindowManager;
 import android.view.animation.AnimationUtils;
 import android.widget.Button;
-import android.widget.ViewFlipper;
 import android.widget.RemoteViews.OnClickHandler;
+import android.widget.ViewFlipper;
 
+import com.android.internal.R;
 import com.android.internal.policy.impl.keyguard.KeyguardSecurityModel.SecurityMode;
 import com.android.internal.widget.LockPatternUtils;
-import com.android.internal.R;
 
 import java.io.File;
 import java.util.ArrayList;
+import java.util.List;
 
 public class KeyguardHostView extends KeyguardViewBase {
     // Use this to debug all of keyguard
@@ -57,43 +61,14 @@
     static final int APPWIDGET_HOST_ID = 0x4B455947;
     private static final String KEYGUARD_WIDGET_PREFS = "keyguard_widget_prefs";
 
-    // time after launching EmergencyDialer before the screen goes blank.
-    private static final int EMERGENCY_CALL_TIMEOUT = 10000;
-
-    // intent action for launching emergency dialer activity.
-    static final String ACTION_EMERGENCY_DIAL = "com.android.phone.EmergencyDialer.DIAL";
-
     private static final String TAG = "KeyguardViewHost";
-
-    private static final int SECURITY_SELECTOR_ID = R.id.keyguard_selector_view;
-    private static final int SECURITY_PATTERN_ID = R.id.keyguard_pattern_view;
-    private static final int SECURITY_PASSWORD_ID = R.id.keyguard_password_view;
-    private static final int SECURITY_BIOMETRIC_ID = R.id.keyguard_face_unlock_view;
-    private static final int SECURITY_SIM_PIN_ID = R.id.keyguard_sim_pin_view;
-    private static final int SECURITY_SIM_PUK_ID = R.id.keyguard_sim_puk_view;
-    private static final int SECURITY_ACCOUNT_ID = R.id.keyguard_account_view;
-
     private AppWidgetHost mAppWidgetHost;
     private KeyguardWidgetPager mAppWidgetContainer;
-    private ViewFlipper mViewFlipper;
-    private Button mEmergencyDialerButton;
+    private ViewFlipper mSecurityViewContainer;
     private boolean mEnableMenuKey;
     private boolean mIsVerifyUnlockOnly;
     private boolean mEnableFallback; // TODO: This should get the value from KeyguardPatternView
-    private int mCurrentSecurityId = SECURITY_SELECTOR_ID;
-
-    // KeyguardSecurityViews
-    final private int [] mViewIds = {
-        SECURITY_SELECTOR_ID,
-        SECURITY_PATTERN_ID,
-        SECURITY_PASSWORD_ID,
-        SECURITY_BIOMETRIC_ID,
-        SECURITY_SIM_PIN_ID,
-        SECURITY_SIM_PUK_ID,
-        SECURITY_ACCOUNT_ID,
-    };
-
-    private ArrayList<View> mViews = new ArrayList<View>(mViewIds.length);
+    private SecurityMode mCurrentSecuritySelection = SecurityMode.None;
 
     protected Runnable mLaunchRunnable;
 
@@ -128,41 +103,31 @@
     protected void onFinishInflate() {
         mAppWidgetContainer = (KeyguardWidgetPager) findViewById(R.id.app_widget_container);
         mAppWidgetContainer.setVisibility(VISIBLE);
+        mSecurityViewContainer = (ViewFlipper) findViewById(R.id.view_flipper);
+        updateSecurityViews();
+    }
 
-        // View Flipper
-        mViewFlipper = (ViewFlipper) findViewById(R.id.view_flipper);
-
-        // Initialize all security views
-        for (int i = 0; i < mViewIds.length; i++) {
-            View view = findViewById(mViewIds[i]);
-            mViews.add(view);
-            if (view != null) {
-                ((KeyguardSecurityView) view).setKeyguardCallback(mCallback);
-            } else {
-                Log.v("*********", "Can't find view id " + mViewIds[i]);
-            }
+    private void updateSecurityViews() {
+        int children = mSecurityViewContainer.getChildCount();
+        for (int i = 0; i < children; i++) {
+            updateSecurityView(mSecurityViewContainer.getChildAt(i));
         }
+    }
 
-        // Enable emergency dialer button
-        mEmergencyDialerButton = (Button) findViewById(R.id.emergency_call_button);
-        mEmergencyDialerButton.setOnClickListener(new OnClickListener() {
-            public void onClick(View v) {
-                takeEmergencyCallAction();
-            }
-        });
+    private void updateSecurityView(View view) {
+        if (view instanceof KeyguardSecurityView) {
+            KeyguardSecurityView ksv = (KeyguardSecurityView) view;
+            ksv.setKeyguardCallback(mCallback);
+            ksv.setLockPatternUtils(mLockPatternUtils);
+        } else {
+            Log.w(TAG, "View " + view + " is not a KeyguardSecurityView");
+        }
     }
 
     void setLockPatternUtils(LockPatternUtils utils) {
         mSecurityModel.setLockPatternUtils(utils);
         mLockPatternUtils = utils;
-        for (int i = 0; i < mViews.size(); i++) {
-            KeyguardSecurityView ksv = (KeyguardSecurityView) mViews.get(i);
-            if (ksv != null) {
-                ksv.setLockPatternUtils(utils);
-            } else {
-                Log.w(TAG, "**** ksv was null at " + i);
-            }
-        }
+        updateSecurityViews();
     }
 
     @Override
@@ -225,22 +190,6 @@
 
     };
 
-    /**
-     * Shows the emergency dialer or returns the user to the existing call.
-     */
-    public void takeEmergencyCallAction() {
-        mCallback.userActivity(EMERGENCY_CALL_TIMEOUT);
-        if (TelephonyManager.getDefault().getCallState()
-                == TelephonyManager.CALL_STATE_OFFHOOK) {
-            mLockPatternUtils.resumeCall();
-        } else {
-            Intent intent = new Intent(ACTION_EMERGENCY_DIAL);
-            intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK
-                    | Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS);
-            getContext().startActivity(intent);
-        }
-    }
-
     private void showDialog(String title, String message) {
         final AlertDialog dialog = new AlertDialog.Builder(mContext)
             .setTitle(title)
@@ -340,7 +289,7 @@
                     showTimeout = false; // don't show both dialogs
                 } else if (failedAttempts >= LockPatternUtils.FAILED_ATTEMPTS_BEFORE_RESET) {
                     mLockPatternUtils.setPermanentlyLocked(true);
-                    showSecurityScreen(SECURITY_ACCOUNT_ID);
+                    showSecurityScreen(SecurityMode.Account);
                     // don't show timeout dialog because we show account unlock screen next
                     showTimeout = false;
                 }
@@ -360,56 +309,53 @@
      */
     private void showBackupSecurity() {
         SecurityMode currentMode = mSecurityModel.getAlternateFor(mSecurityModel.getSecurityMode());
-        SecurityMode backup = mSecurityModel.getBackupFor(currentMode);
-        showSecurityScreen(getSecurityViewIdForMode(backup));
+        showSecurityScreen(mSecurityModel.getBackupFor(currentMode));
     }
 
     private void showNextSecurityScreenOrFinish(boolean authenticated) {
         boolean finish = false;
-        if (SECURITY_SELECTOR_ID == mCurrentSecurityId) {
+        if (SecurityMode.None == mCurrentSecuritySelection) {
             SecurityMode securityMode = mSecurityModel.getSecurityMode();
             // Allow an alternate, such as biometric unlock
             securityMode = mSecurityModel.getAlternateFor(securityMode);
-            int realSecurityId = getSecurityViewIdForMode(securityMode);
-            if (SECURITY_SELECTOR_ID == realSecurityId) {
+            if (SecurityMode.None == securityMode) {
                 finish = true; // no security required
             } else {
-                showSecurityScreen(realSecurityId); // switch to the "real" security view
+                showSecurityScreen(securityMode); // switch to the alternate security view
             }
         } else if (authenticated) {
-            switch (mCurrentSecurityId) {
-                case SECURITY_PATTERN_ID:
-                case SECURITY_PASSWORD_ID:
-                case SECURITY_ACCOUNT_ID:
-                case SECURITY_BIOMETRIC_ID:
+            switch (mCurrentSecuritySelection) {
+                case Pattern:
+                case Password:
+                case Account:
+                case Biometric:
                     finish = true;
                     break;
 
-                case SECURITY_SIM_PIN_ID:
-                case SECURITY_SIM_PUK_ID:
+                case SimPin:
+                case SimPuk:
                     // Shortcut for SIM PIN/PUK to go to directly to user's security screen or home
                     SecurityMode securityMode = mSecurityModel.getSecurityMode();
                     if (securityMode != SecurityMode.None) {
-                        showSecurityScreen(getSecurityViewIdForMode(securityMode));
+                        showSecurityScreen(securityMode);
                     } else {
                         finish = true;
                     }
                     break;
 
                 default:
-                    showSecurityScreen(SECURITY_SELECTOR_ID);
+                    showSecurityScreen(SecurityMode.None);
                     break;
             }
         } else {
             // Not authenticated but we were asked to dismiss so go back to selector screen.
-            showSecurityScreen(SECURITY_SELECTOR_ID);
+            showSecurityScreen(SecurityMode.None);
         }
         if (finish) {
             // If there's a pending runnable because the user interacted with a widget
             // and we're leaving keyguard, then run it.
             if (mLaunchRunnable != null) {
                 mLaunchRunnable.run();
-                mViewFlipper.setDisplayedChild(0);
                 mLaunchRunnable = null;
             }
             mViewMediatorCallback.keyguardDone(true);
@@ -465,28 +411,38 @@
         mLaunchRunnable = runnable;
     }
 
-    private KeyguardSecurityView getSecurityView(int securitySelectorId) {
-        final int children = mViewFlipper.getChildCount();
+    private KeyguardSecurityView getSecurityView(SecurityMode securityMode) {
+        final int securityViewIdForMode = getSecurityViewIdForMode(securityMode);
+        KeyguardSecurityView view = null;
+        final int children = mSecurityViewContainer.getChildCount();
         for (int child = 0; child < children; child++) {
-            if (mViewFlipper.getChildAt(child).getId() == securitySelectorId) {
-                return ((KeyguardSecurityView)mViewFlipper.getChildAt(child));
+            if (mSecurityViewContainer.getChildAt(child).getId() == securityViewIdForMode) {
+                view = ((KeyguardSecurityView)mSecurityViewContainer.getChildAt(child));
+                break;
             }
         }
-        return null;
+        if (view == null) {
+            final LayoutInflater inflater = LayoutInflater.from(mContext);
+            View v = inflater.inflate(getLayoutIdFor(securityMode), this, false);
+            mSecurityViewContainer.addView(v);
+            updateSecurityView(v);
+            view = (KeyguardSecurityView) v;
+        }
+        return view;
     }
 
     /**
      * Switches to the given security view unless it's already being shown, in which case
      * this is a no-op.
      *
-     * @param securityViewId
+     * @param securityMode
      */
-    private void showSecurityScreen(int securityViewId) {
+    private void showSecurityScreen(SecurityMode securityMode) {
 
-        if (securityViewId == mCurrentSecurityId) return;
+        if (securityMode == mCurrentSecuritySelection) return;
 
-        KeyguardSecurityView oldView = getSecurityView(mCurrentSecurityId);
-        KeyguardSecurityView newView = getSecurityView(securityViewId);
+        KeyguardSecurityView oldView = getSecurityView(mCurrentSecuritySelection);
+        KeyguardSecurityView newView = getSecurityView(securityMode);
 
         // Emulate Activity life cycle
         oldView.onPause();
@@ -495,43 +451,46 @@
         mViewMediatorCallback.setNeedsInput(newView.needsInput());
 
         // Find and show this child.
-        final int childCount = mViewFlipper.getChildCount();
+        final int childCount = mSecurityViewContainer.getChildCount();
 
         // If we're go to/from the selector view, do flip animation, otherwise use fade animation.
-        final boolean doFlip = mCurrentSecurityId == SECURITY_SELECTOR_ID
-                || securityViewId == SECURITY_SELECTOR_ID;
+        final boolean doFlip = mCurrentSecuritySelection == SecurityMode.None
+                || securityMode == SecurityMode.None;
         final int inAnimation = doFlip ? R.anim.keyguard_security_animate_in
                 : R.anim.keyguard_security_fade_in;
         final int outAnimation = doFlip ? R.anim.keyguard_security_animate_out
                 : R.anim.keyguard_security_fade_out;
 
-        mViewFlipper.setInAnimation(AnimationUtils.loadAnimation(mContext, inAnimation));
-        mViewFlipper.setOutAnimation(AnimationUtils.loadAnimation(mContext, outAnimation));
+        mSecurityViewContainer.setInAnimation(AnimationUtils.loadAnimation(mContext, inAnimation));
+        mSecurityViewContainer.setOutAnimation(AnimationUtils.loadAnimation(mContext, outAnimation));
+        final int securityViewIdForMode = getSecurityViewIdForMode(securityMode);
         for (int i = 0; i < childCount; i++) {
-            if (securityViewId == mViewFlipper.getChildAt(i).getId()) {
-                mViewFlipper.setDisplayedChild(i);
+            if (mSecurityViewContainer.getChildAt(i).getId() == securityViewIdForMode) {
+                mSecurityViewContainer.setDisplayedChild(i);
                 break;
             }
         }
 
         // Discard current runnable if we're switching back to the selector view
-        if (securityViewId == SECURITY_SELECTOR_ID) {
+        if (securityMode == SecurityMode.None) {
             setOnDismissRunnable(null);
         }
 
-        mCurrentSecurityId = securityViewId;
+        mCurrentSecuritySelection = securityMode;
     }
 
     @Override
     public void onScreenTurnedOn() {
         if (DEBUG) Log.d(TAG, "screen on");
-        showSecurityScreen(mCurrentSecurityId);
+        showSecurityScreen(mCurrentSecuritySelection);
+        getSecurityView(mCurrentSecuritySelection).onResume();
     }
 
     @Override
     public void onScreenTurnedOff() {
         if (DEBUG) Log.d(TAG, "screen off");
-        showSecurityScreen(SECURITY_SELECTOR_ID);
+        showSecurityScreen(SecurityMode.None);
+        getSecurityView(mCurrentSecuritySelection).onPause();
     }
 
     @Override
@@ -562,7 +521,7 @@
         if (DEBUG) Log.d(TAG, "onWakeKey");
         if (keyCode == KeyEvent.KEYCODE_MENU && isSecure()) {
             if (DEBUG) Log.d(TAG, "switching screens to unlock screen because wake key was MENU");
-            showSecurityScreen(SECURITY_SELECTOR_ID);
+            showSecurityScreen(SecurityMode.None);
             mViewMediatorCallback.pokeWakelock();
         } else {
             if (DEBUG) Log.d(TAG, "poking wake lock immediately");
@@ -582,23 +541,37 @@
         } else {
             // otherwise, go to the unlock screen, see if they can verify it
             mIsVerifyUnlockOnly = true;
-            showSecurityScreen(getSecurityViewIdForMode(securityMode));
+            showSecurityScreen(securityMode);
         }
     }
 
     private int getSecurityViewIdForMode(SecurityMode securityMode) {
         switch (securityMode) {
-            case None: return SECURITY_SELECTOR_ID;
-            case Pattern: return SECURITY_PATTERN_ID;
-            case Password: return SECURITY_PASSWORD_ID;
-            case Biometric: return SECURITY_BIOMETRIC_ID;
-            case Account: return SECURITY_ACCOUNT_ID;
-            case SimPin: return SECURITY_SIM_PIN_ID;
-            case SimPuk: return SECURITY_SIM_PUK_ID;
+            case None: return R.id.keyguard_selector_view;
+            case Pattern: return R.id.keyguard_pattern_view;
+            case Password: return R.id.keyguard_password_view;
+            case Biometric: return R.id.keyguard_face_unlock_view;
+            case Account: return R.id.keyguard_account_view;
+            case SimPin: return R.id.keyguard_sim_pin_view;
+            case SimPuk: return R.id.keyguard_sim_puk_view;
         }
         return 0;
     }
 
+    private int getLayoutIdFor(SecurityMode securityMode) {
+        switch (securityMode) {
+            case None: return R.layout.keyguard_selector_view;
+            case Pattern: return R.layout.keyguard_pattern_view;
+            case Password: return R.layout.keyguard_password_view;
+            case Biometric: return R.layout.keyguard_face_unlock_view;
+            case Account: return R.layout.keyguard_account_view;
+            case SimPin: return R.layout.keyguard_sim_pin_view;
+            case SimPuk: return R.layout.keyguard_sim_puk_view;
+            default:
+                throw new RuntimeException("No layout for securityMode " + securityMode);
+        }
+    }
+
     private void addWidget(int appId) {
         AppWidgetManager appWidgetManager = AppWidgetManager.getInstance(mContext);
         AppWidgetProviderInfo appWidgetInfo = appWidgetManager.getAppWidgetInfo(appId);
@@ -614,6 +587,7 @@
             Log.v(TAG, "Keyguard widgets disabled because of device policy admin");
             return;
         }
+        inflateAndAddUserSelectorWidgetIfNecessary();
         SharedPreferences prefs = mContext.getSharedPreferences(
                 KEYGUARD_WIDGET_PREFS, Context.MODE_PRIVATE);
         for (String key : prefs.getAll().keySet()) {
@@ -627,6 +601,21 @@
         }
     }
 
+    private void inflateAndAddUserSelectorWidgetIfNecessary() {
+        // if there are multiple users, we need to add the multi-user switcher widget to the
+        // keyguard.
+        UserManager mUm = (UserManager) mContext.getSystemService(Context.USER_SERVICE);
+        List<UserInfo> users = mUm.getUsers();
+
+        if (users.size() > 1) {
+            KeyguardWidgetFrame userswitcher = (KeyguardWidgetFrame)
+                LayoutInflater.from(mContext).inflate(R.layout.keyguard_multi_user_selector_widget,
+                        mAppWidgetContainer, false);
+            // add the switcher in the first position
+            mAppWidgetContainer.addView(userswitcher, 0);
+        }
+    }
+
     @Override
     public void cleanUp() {
 
diff --git a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardMultiUserAvatar.java b/policy/src/com/android/internal/policy/impl/keyguard/KeyguardMultiUserAvatar.java
new file mode 100644
index 0000000..8aef68f
--- /dev/null
+++ b/policy/src/com/android/internal/policy/impl/keyguard/KeyguardMultiUserAvatar.java
@@ -0,0 +1,89 @@
+/*
+ * Copyright (C) 2012 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.internal.policy.impl.keyguard;
+
+import android.app.ActivityManagerNative;
+import android.content.Context;
+import android.content.pm.UserInfo;
+import android.graphics.drawable.Drawable;
+import android.os.RemoteException;
+import android.util.AttributeSet;
+import android.util.Log;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.WindowManagerGlobal;
+import android.widget.FrameLayout;
+import android.widget.ImageView;
+import android.widget.TextView;
+
+import com.android.internal.R;
+
+class KeyguardMultiUserAvatar extends FrameLayout {
+    private static final String TAG = "KeyguardViewHost";
+
+    private ImageView mUserImage;
+    private TextView mUserName;
+    private UserInfo mUserInfo;
+    private KeyguardMultiUserSelectorView mUserSelector;
+
+    public static KeyguardMultiUserAvatar fromXml(int resId, Context context,
+            KeyguardMultiUserSelectorView userSelector, UserInfo info) {
+        KeyguardMultiUserAvatar icon = (KeyguardMultiUserAvatar)
+                LayoutInflater.from(context).inflate(resId, userSelector, false);
+
+        icon.setup(info, userSelector);
+        return icon;
+    }
+
+    public KeyguardMultiUserAvatar(Context context) {
+        super(context, null, 0);
+    }
+
+    public KeyguardMultiUserAvatar(Context context, AttributeSet attrs) {
+        super(context, attrs, 0);
+    }
+
+    public KeyguardMultiUserAvatar(Context context, AttributeSet attrs, int defStyle) {
+        super(context, attrs, defStyle);
+    }
+
+    public void setup(UserInfo user, KeyguardMultiUserSelectorView userSelector) {
+        mUserInfo = user;
+        mUserSelector = userSelector;
+        init();
+    }
+
+    private void init() {
+        mUserImage = (ImageView) findViewById(R.id.keyguard_user_avatar);
+        mUserName = (TextView) findViewById(R.id.keyguard_user_name);
+
+        mUserImage.setImageDrawable(Drawable.createFromPath(mUserInfo.iconPath));
+        mUserName.setText(mUserInfo.name);
+        setOnClickListener(new OnClickListener() {
+            @Override
+            public void onClick(View v) {
+                try {
+                    ActivityManagerNative.getDefault().switchUser(mUserInfo.id);
+                    WindowManagerGlobal.getWindowManagerService().lockNow();
+                    mUserSelector.init();
+                } catch (RemoteException re) {
+                    Log.e(TAG, "Couldn't switch user " + re);
+                }
+            }
+        });
+    }
+}
diff --git a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardMultiUserSelectorView.java b/policy/src/com/android/internal/policy/impl/keyguard/KeyguardMultiUserSelectorView.java
new file mode 100644
index 0000000..ba99a55
--- /dev/null
+++ b/policy/src/com/android/internal/policy/impl/keyguard/KeyguardMultiUserSelectorView.java
@@ -0,0 +1,84 @@
+/*
+ * Copyright (C) 2012 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.internal.policy.impl.keyguard;
+
+import android.app.ActivityManagerNative;
+import android.content.Context;
+import android.content.pm.UserInfo;
+import android.os.RemoteException;
+import android.os.UserManager;
+import android.util.AttributeSet;
+import android.widget.LinearLayout;
+
+import com.android.internal.R;
+
+import java.util.ArrayList;
+
+public class KeyguardMultiUserSelectorView extends LinearLayout{
+    private KeyguardMultiUserAvatar mActiveUser;
+    private LinearLayout mInactiveUsers;
+
+    public KeyguardMultiUserSelectorView(Context context) {
+        this(context, null, 0);
+    }
+
+    public KeyguardMultiUserSelectorView(Context context, AttributeSet attrs) {
+        this(context, attrs, 0);
+    }
+
+    public KeyguardMultiUserSelectorView(Context context, AttributeSet attrs, int defStyle) {
+        super(context, attrs, defStyle);
+    }
+
+    protected void onFinishInflate () {
+        init();
+    }
+
+    public void init() {
+        mActiveUser = (KeyguardMultiUserAvatar) findViewById(R.id.keyguard_active_user);
+        mInactiveUsers = (LinearLayout) findViewById(R.id.keyguard_inactive_users);
+
+        mInactiveUsers.removeAllViews();
+
+        UserInfo currentUser;
+        try {
+            currentUser = ActivityManagerNative.getDefault().getCurrentUser();
+        } catch (RemoteException re) {
+            currentUser = null;
+        }
+
+        UserManager mUm = (UserManager) mContext.getSystemService(Context.USER_SERVICE);
+        ArrayList<UserInfo> users = new ArrayList<UserInfo>(mUm.getUsers());
+        for (UserInfo user: users) {
+            if (user.id == currentUser.id) {
+                setActiveUser(user);
+            } else {
+                createAndAddInactiveUser(user);
+            }
+        }
+    }
+
+    private void setActiveUser(UserInfo user) {
+        mActiveUser.setup(user, this);
+    }
+
+    private void createAndAddInactiveUser(UserInfo user) {
+        KeyguardMultiUserAvatar uv = KeyguardMultiUserAvatar.fromXml(
+                R.layout.keyguard_multi_user_avatar, mContext, this, user);
+        mInactiveUsers.addView(uv);
+    }
+}
diff --git a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardPasswordView.java b/policy/src/com/android/internal/policy/impl/keyguard/KeyguardPasswordView.java
index b2ce73e..7e9aa43 100644
--- a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardPasswordView.java
+++ b/policy/src/com/android/internal/policy/impl/keyguard/KeyguardPasswordView.java
@@ -68,6 +68,9 @@
     // any passwords with length less than or equal to this length.
     private static final int MINIMUM_PASSWORD_LENGTH_BEFORE_REPORT = 3;
 
+    // Enable this if we want to hide the on-screen PIN keyboard when a physical one is showing
+    private static final boolean ENABLE_HIDE_KEYBOARD = false;
+
     public KeyguardPasswordView(Context context) {
         super(context);
     }
@@ -123,10 +126,13 @@
             mKeyboardHelper.setKeyboardMode(PasswordEntryKeyboardHelper.KEYBOARD_MODE_ALPHA);
             mKeyboardView.setVisibility(View.GONE);
         } else {
-            // Use lockscreen's numeric keyboard if the physical keyboard isn't showing
             mKeyboardHelper.setKeyboardMode(PasswordEntryKeyboardHelper.KEYBOARD_MODE_NUMERIC);
-            mKeyboardView.setVisibility(getResources().getConfiguration().hardKeyboardHidden
-                    == Configuration.HARDKEYBOARDHIDDEN_NO ? View.INVISIBLE : View.VISIBLE);
+
+            // Use lockscreen's numeric keyboard if the physical keyboard isn't showing
+            boolean hardKeyboardVisible = getResources().getConfiguration().hardKeyboardHidden
+                    == Configuration.HARDKEYBOARDHIDDEN_NO;
+            mKeyboardView.setVisibility(
+                    (ENABLE_HIDE_KEYBOARD && hardKeyboardVisible) ? View.INVISIBLE : View.VISIBLE);
 
             // The delete button is of the PIN keyboard itself in some (e.g. tablet) layouts,
             // not a separate view
diff --git a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardSecurityModel.java b/policy/src/com/android/internal/policy/impl/keyguard/KeyguardSecurityModel.java
index a19b35d..75c4a7c 100644
--- a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardSecurityModel.java
+++ b/policy/src/com/android/internal/policy/impl/keyguard/KeyguardSecurityModel.java
@@ -69,7 +69,8 @@
         SecurityMode mode = SecurityMode.None;
         if (simState == IccCardConstants.State.PIN_REQUIRED) {
             mode = SecurityMode.SimPin;
-        } else if (simState == IccCardConstants.State.PUK_REQUIRED) {
+        } else if (simState == IccCardConstants.State.PUK_REQUIRED
+                && mLockPatternUtils.isPukUnlockScreenEnable()) {
             mode = SecurityMode.SimPuk;
         } else {
             final int security = mLockPatternUtils.getKeyguardStoredPasswordQuality();
diff --git a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardSelectorView.java b/policy/src/com/android/internal/policy/impl/keyguard/KeyguardSelectorView.java
index 6e51707..7554236 100644
--- a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardSelectorView.java
+++ b/policy/src/com/android/internal/policy/impl/keyguard/KeyguardSelectorView.java
@@ -25,6 +25,7 @@
 import android.os.RemoteException;
 import android.os.UserHandle;
 import android.provider.MediaStore;
+import android.telephony.TelephonyManager;
 import android.util.AttributeSet;
 import android.util.Log;
 import android.util.Slog;
@@ -33,6 +34,7 @@
 import android.widget.LinearLayout;
 
 import com.android.internal.telephony.IccCardConstants;
+import com.android.internal.telephony.IccCardConstants.State;
 import com.android.internal.widget.LockPatternUtils;
 import com.android.internal.widget.multiwaveview.GlowPadView;
 import com.android.internal.widget.multiwaveview.GlowPadView.OnTriggerListener;
@@ -43,6 +45,9 @@
     private static final String TAG = "SecuritySelectorView";
     private static final String ASSIST_ICON_METADATA_NAME =
         "com.android.systemui.action_assist_icon";
+    private static final int EMERGENCY_CALL_TIMEOUT = 10000; // screen timeout after starting e.d.
+    static final String ACTION_EMERGENCY_DIAL = "com.android.phone.EmergencyDialer.DIAL";
+
     private KeyguardSecurityCallback mCallback;
     private GlowPadView mGlowPadView;
     private Button mEmergencyCallButton;
@@ -98,9 +103,19 @@
 
     };
 
-    KeyguardUpdateMonitorCallback mInfoCallback = new KeyguardUpdateMonitorCallback() {
+    private void updateEmergencyCallButton(State simState, int phoneState) {
+        if (mEmergencyCallButton != null) {
+            boolean en = mLockPatternUtils.isEmergencyCallCapable()
+                || (phoneState == TelephonyManager.CALL_STATE_OFFHOOK); // voice call in progress
+            if (en && KeyguardUpdateMonitor.isSimLocked(simState)) {
+                // Some countries can't handle emergency calls while SIM is locked.
+                en = mLockPatternUtils.isEmergencyCallEnabledWhileSimLocked();
+            }
+            mLockPatternUtils.updateEmergencyCallButtonState(mEmergencyCallButton, phoneState, en);
+        }
+    }
 
-        private boolean mEmergencyDialerDisableBecauseSimLocked;
+    KeyguardUpdateMonitorCallback mInfoCallback = new KeyguardUpdateMonitorCallback() {
 
         @Override
         public void onDevicePolicyManagerStateChanged() {
@@ -108,19 +123,15 @@
         }
 
         @Override
-        public void onSimStateChanged(IccCardConstants.State simState) {
-            // Some carriers aren't capable of handling emergency calls while the SIM is locked
-            mEmergencyDialerDisableBecauseSimLocked = KeyguardUpdateMonitor.isSimLocked(simState)
-                    && !mLockPatternUtils.isEmergencyCallEnabledWhileSimLocked();
+        public void onSimStateChanged(State simState) {
+            int phoneState = KeyguardUpdateMonitor.getInstance(mContext).getPhoneState();
+            updateEmergencyCallButton(simState, phoneState);
             updateTargets();
         }
 
         void onPhoneStateChanged(int phoneState) {
-            if (mEmergencyCallButton != null) {
-                mLockPatternUtils.isEmergencyCallEnabledWhileSimLocked();
-                mLockPatternUtils.updateEmergencyCallButtonState(mEmergencyCallButton,
-                        phoneState, !mEmergencyDialerDisableBecauseSimLocked);
-            }
+            State simState = KeyguardUpdateMonitor.getInstance(mContext).getSimState();
+            updateEmergencyCallButton(simState, phoneState);
         };
     };
 
@@ -151,9 +162,30 @@
         mGlowPadView = (GlowPadView) findViewById(R.id.glow_pad_view);
         mGlowPadView.setOnTriggerListener(mOnTriggerListener);
         mEmergencyCallButton = (Button) findViewById(R.id.emergency_call_button);
+        mEmergencyCallButton.setOnClickListener(new OnClickListener() {
+            public void onClick(View v) {
+                takeEmergencyCallAction();
+            }
+        });
         updateTargets();
     }
 
+    /**
+     * Shows the emergency dialer or returns the user to the existing call.
+     */
+    public void takeEmergencyCallAction() {
+        mCallback.userActivity(EMERGENCY_CALL_TIMEOUT);
+        if (TelephonyManager.getDefault().getCallState()
+                == TelephonyManager.CALL_STATE_OFFHOOK) {
+            mLockPatternUtils.resumeCall();
+        } else {
+            Intent intent = new Intent(ACTION_EMERGENCY_DIAL);
+            intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK
+                    | Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS);
+            getContext().startActivity(intent);
+        }
+    }
+
     public boolean isTargetPresent(int resId) {
         return mGlowPadView.getTargetPosition(resId) != -1;
     }
diff --git a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardStatusView.java b/policy/src/com/android/internal/policy/impl/keyguard/KeyguardStatusView.java
index 481e9ad..5704425 100644
--- a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardStatusView.java
+++ b/policy/src/com/android/internal/policy/impl/keyguard/KeyguardStatusView.java
@@ -21,6 +21,7 @@
 import android.widget.GridLayout;
 
 public class KeyguardStatusView extends GridLayout {
+    @SuppressWarnings("unused")
     private KeyguardStatusViewManager mStatusViewManager;
 
     public KeyguardStatusView(Context context) {
diff --git a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardStatusViewManager.java b/policy/src/com/android/internal/policy/impl/keyguard/KeyguardStatusViewManager.java
index 20fad0b..e325f94 100644
--- a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardStatusViewManager.java
+++ b/policy/src/com/android/internal/policy/impl/keyguard/KeyguardStatusViewManager.java
@@ -32,11 +32,10 @@
 import android.text.format.DateFormat;
 import android.util.Log;
 import android.view.View;
-import android.widget.Button;
 import android.widget.TextView;
 
 /***
- * Manages a number of views inside of LockScreen layouts. See below for a list of widgets
+ * Manages a number of views inside of the given layout. See below for a list of widgets.
  */
 class KeyguardStatusViewManager {
     private static final boolean DEBUG = false;
@@ -92,21 +91,12 @@
     private boolean mShowingStatus;
     private CharSequence mPlmn;
     private CharSequence mSpn;
-    protected int mPhoneState;
     private DigitalClock mDigitalClock;
     protected boolean mBatteryCharged;
     protected boolean mBatteryIsLow;
-    private boolean mEmergencyButtonEnabledBecauseSimLocked;
-    private Button mEmergencyCallButton;
-    private boolean mEmergencyCallButtonEnabledInScreen;
 
     /**
-     *
      * @param view the containing view of all widgets
-     * @param updateMonitor the update monitor to use
-     * @param lockPatternUtils lock pattern util object
-     * @param callback used to invoke emergency dialer
-     * @param emergencyButtonEnabledInScreen whether emergency button is enabled by default
      */
     public KeyguardStatusViewManager(View view) {
         if (DEBUG) Log.v(TAG, "KeyguardStatusViewManager()");
@@ -364,7 +354,6 @@
 
         CharSequence carrierText = null;
         int carrierHelpTextId = 0;
-        mEmergencyButtonEnabledBecauseSimLocked = false;
         mStatus = getStatusForIccState(simState);
         mSimState = simState;
         switch (mStatus) {
@@ -394,7 +383,6 @@
                 carrierText = getContext().getText(
                         R.string.lockscreen_permanent_disabled_sim_message_short);
                 carrierHelpTextId = R.string.lockscreen_permanent_disabled_sim_instructions;
-                mEmergencyButtonEnabledBecauseSimLocked = true;
                 break;
 
             case SimMissingLocked:
@@ -402,33 +390,25 @@
                         getContext().getText(R.string.lockscreen_missing_sim_message_short),
                         mPlmn);
                 carrierHelpTextId = R.string.lockscreen_missing_sim_instructions;
-                mEmergencyButtonEnabledBecauseSimLocked = true;
                 break;
 
             case SimLocked:
                 carrierText = makeCarrierStringOnEmergencyCapable(
                         getContext().getText(R.string.lockscreen_sim_locked_message),
                         mPlmn);
-                mEmergencyButtonEnabledBecauseSimLocked = true;
                 break;
 
             case SimPukLocked:
                 carrierText = makeCarrierStringOnEmergencyCapable(
                         getContext().getText(R.string.lockscreen_sim_puk_locked_message),
                         mPlmn);
-                if (!mLockPatternUtils.isPukUnlockScreenEnable()) {
-                    // This means we're showing the PUK unlock screen
-                    mEmergencyButtonEnabledBecauseSimLocked = true;
-                }
                 break;
         }
 
         setCarrierText(carrierText);
         setCarrierHelpText(carrierHelpTextId);
-        updateEmergencyCallButtonState(mPhoneState);
     }
 
-
     /*
      * Add emergencyCallMessage to carrier string only if phone supports emergency calls.
      */
@@ -500,17 +480,6 @@
         }
     }
 
-    private void updateEmergencyCallButtonState(int phoneState) {
-        if (mEmergencyCallButton != null) {
-            boolean enabledBecauseSimLocked =
-                    mLockPatternUtils.isEmergencyCallEnabledWhileSimLocked()
-                    && mEmergencyButtonEnabledBecauseSimLocked;
-            boolean shown = mEmergencyCallButtonEnabledInScreen || enabledBecauseSimLocked;
-            mLockPatternUtils.updateEmergencyCallButtonState(mEmergencyCallButton,
-                    phoneState, shown);
-        }
-    }
-
     private KeyguardUpdateMonitorCallback mInfoCallback = new KeyguardUpdateMonitorCallback() {
 
         @Override
@@ -537,12 +506,6 @@
         }
 
         @Override
-        public void onPhoneStateChanged(int phoneState) {
-            mPhoneState = phoneState;
-            updateEmergencyCallButtonState(phoneState);
-        }
-
-        @Override
         public void onSimStateChanged(IccCardConstants.State simState) {
             updateCarrierStateWithSimStatus(simState);
         }
diff --git a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardUpdateMonitor.java b/policy/src/com/android/internal/policy/impl/keyguard/KeyguardUpdateMonitor.java
index 281ed19..66c7c10 100644
--- a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardUpdateMonitor.java
+++ b/policy/src/com/android/internal/policy/impl/keyguard/KeyguardUpdateMonitor.java
@@ -261,12 +261,13 @@
         }
 
         /**
-         * Determine whether the device is plugged in (USB or power).
+         * Determine whether the device is plugged in (USB, power, or wireless).
          * @return true if the device is plugged in.
          */
         boolean isPluggedIn() {
             return plugged == BatteryManager.BATTERY_PLUGGED_AC
-                    || plugged == BatteryManager.BATTERY_PLUGGED_USB;
+                    || plugged == BatteryManager.BATTERY_PLUGGED_USB
+                    || plugged == BatteryManager.BATTERY_PLUGGED_WIRELESS;
         }
 
         /**
diff --git a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardWidgetFrame.java b/policy/src/com/android/internal/policy/impl/keyguard/KeyguardWidgetFrame.java
index e8078fd..f957753 100644
--- a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardWidgetFrame.java
+++ b/policy/src/com/android/internal/policy/impl/keyguard/KeyguardWidgetFrame.java
@@ -38,6 +38,7 @@
     private static Drawable sRightOverscrollDrawable;
 
     private Drawable mForegroundDrawable;
+    private float mOverScrollAmount = 0f;
     private final Rect mForegroundRect = new Rect();
     private int mForegroundAlpha = 0;
 
@@ -80,14 +81,17 @@
     }
 
     void setOverScrollAmount(float r, boolean left) {
-        if (left && mForegroundDrawable != sLeftOverscrollDrawable) {
-            mForegroundDrawable = sLeftOverscrollDrawable;
-        } else if (!left && mForegroundDrawable != sRightOverscrollDrawable) {
-            mForegroundDrawable = sRightOverscrollDrawable;
-        }
+        if (Float.compare(mOverScrollAmount, r) != 0) {
+            mOverScrollAmount = r;
+            if (left && mForegroundDrawable != sLeftOverscrollDrawable) {
+                mForegroundDrawable = sLeftOverscrollDrawable;
+            } else if (!left && mForegroundDrawable != sRightOverscrollDrawable) {
+                mForegroundDrawable = sRightOverscrollDrawable;
+            }
 
-        mForegroundAlpha = (int) Math.round((r * 255));
-        mForegroundDrawable.setAlpha(mForegroundAlpha);
-        invalidate();
+            mForegroundAlpha = (int) Math.round((r * 255));
+            mForegroundDrawable.setAlpha(mForegroundAlpha);
+            invalidate();
+        }
     }
 }
diff --git a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardWidgetPager.java b/policy/src/com/android/internal/policy/impl/keyguard/KeyguardWidgetPager.java
index 7d077e2..fd9362a 100644
--- a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardWidgetPager.java
+++ b/policy/src/com/android/internal/policy/impl/keyguard/KeyguardWidgetPager.java
@@ -146,6 +146,9 @@
                         v.setPivotY(pageHeight / 2.0f);
                         v.setPivotX(pageWidth / 2.0f);
                         v.setRotationY(0f);
+                        if (v instanceof KeyguardWidgetFrame) {
+                            ((KeyguardWidgetFrame) v).setOverScrollAmount(0, false);
+                        }
                     }
                 }
 
diff --git a/services/input/InputReader.cpp b/services/input/InputReader.cpp
index 6d63998..513dc13 100644
--- a/services/input/InputReader.cpp
+++ b/services/input/InputReader.cpp
@@ -203,34 +203,18 @@
 
 // --- InputReaderConfiguration ---
 
-bool InputReaderConfiguration::getDisplayInfo(int32_t displayId, bool external,
-        int32_t* width, int32_t* height, int32_t* orientation) const {
-    if (displayId == 0) {
-        const DisplayInfo& info = external ? mExternalDisplay : mInternalDisplay;
-        if (info.width > 0 && info.height > 0) {
-            if (width) {
-                *width = info.width;
-            }
-            if (height) {
-                *height = info.height;
-            }
-            if (orientation) {
-                *orientation = info.orientation;
-            }
-            return true;
-        }
+bool InputReaderConfiguration::getDisplayInfo(bool external, DisplayViewport* outViewport) const {
+    const DisplayViewport& viewport = external ? mExternalDisplay : mInternalDisplay;
+    if (viewport.displayId >= 0) {
+        *outViewport = viewport;
+        return true;
     }
     return false;
 }
 
-void InputReaderConfiguration::setDisplayInfo(int32_t displayId, bool external,
-        int32_t width, int32_t height, int32_t orientation) {
-    if (displayId == 0) {
-        DisplayInfo& info = external ? mExternalDisplay : mInternalDisplay;
-        info.width = width;
-        info.height = height;
-        info.orientation = orientation;
-    }
+void InputReaderConfiguration::setDisplayInfo(bool external, const DisplayViewport& viewport) {
+    DisplayViewport& v = external ? mExternalDisplay : mInternalDisplay;
+    v = viewport;
 }
 
 
@@ -2001,9 +1985,11 @@
     }
 
     if (!changes || (changes & InputReaderConfiguration::CHANGE_DISPLAY_INFO)) {
-        if (mParameters.orientationAware && mParameters.associatedDisplayId >= 0) {
-            if (!config->getDisplayInfo(mParameters.associatedDisplayId,
-                        false /*external*/, NULL, NULL, &mOrientation)) {
+        if (mParameters.orientationAware && mParameters.hasAssociatedDisplay) {
+            DisplayViewport v;
+            if (config->getDisplayInfo(false /*external*/, &v)) {
+                mOrientation = v.orientation;
+            } else {
                 mOrientation = DISPLAY_ORIENTATION_0;
             }
         } else {
@@ -2017,16 +2003,16 @@
     getDevice()->getConfiguration().tryGetProperty(String8("keyboard.orientationAware"),
             mParameters.orientationAware);
 
-    mParameters.associatedDisplayId = -1;
+    mParameters.hasAssociatedDisplay = false;
     if (mParameters.orientationAware) {
-        mParameters.associatedDisplayId = 0;
+        mParameters.hasAssociatedDisplay = true;
     }
 }
 
 void KeyboardInputMapper::dumpParameters(String8& dump) {
     dump.append(INDENT3 "Parameters:\n");
-    dump.appendFormat(INDENT4 "AssociatedDisplayId: %d\n",
-            mParameters.associatedDisplayId);
+    dump.appendFormat(INDENT4 "HasAssociatedDisplay: %s\n",
+            toString(mParameters.hasAssociatedDisplay));
     dump.appendFormat(INDENT4 "OrientationAware: %s\n",
             toString(mParameters.orientationAware));
 }
@@ -2086,7 +2072,7 @@
 
     if (down) {
         // Rotate key codes according to orientation if needed.
-        if (mParameters.orientationAware && mParameters.associatedDisplayId >= 0) {
+        if (mParameters.orientationAware && mParameters.hasAssociatedDisplay) {
             keyCode = rotateKeyCode(keyCode, mOrientation);
         }
 
@@ -2317,9 +2303,11 @@
     }
 
     if (!changes || (changes & InputReaderConfiguration::CHANGE_DISPLAY_INFO)) {
-        if (mParameters.orientationAware && mParameters.associatedDisplayId >= 0) {
-            if (!config->getDisplayInfo(mParameters.associatedDisplayId,
-                        false /*external*/, NULL, NULL, &mOrientation)) {
+        if (mParameters.orientationAware && mParameters.hasAssociatedDisplay) {
+            DisplayViewport v;
+            if (config->getDisplayInfo(false /*external*/, &v)) {
+                mOrientation = v.orientation;
+            } else {
                 mOrientation = DISPLAY_ORIENTATION_0;
             }
         } else {
@@ -2344,16 +2332,16 @@
     getDevice()->getConfiguration().tryGetProperty(String8("cursor.orientationAware"),
             mParameters.orientationAware);
 
-    mParameters.associatedDisplayId = -1;
+    mParameters.hasAssociatedDisplay = false;
     if (mParameters.mode == Parameters::MODE_POINTER || mParameters.orientationAware) {
-        mParameters.associatedDisplayId = 0;
+        mParameters.hasAssociatedDisplay = true;
     }
 }
 
 void CursorInputMapper::dumpParameters(String8& dump) {
     dump.append(INDENT3 "Parameters:\n");
-    dump.appendFormat(INDENT4 "AssociatedDisplayId: %d\n",
-            mParameters.associatedDisplayId);
+    dump.appendFormat(INDENT4 "HasAssociatedDisplay: %s\n",
+            toString(mParameters.hasAssociatedDisplay));
 
     switch (mParameters.mode) {
     case Parameters::MODE_POINTER:
@@ -2420,7 +2408,7 @@
     bool moved = deltaX != 0 || deltaY != 0;
 
     // Rotate delta according to orientation if needed.
-    if (mParameters.orientationAware && mParameters.associatedDisplayId >= 0
+    if (mParameters.orientationAware && mParameters.hasAssociatedDisplay
             && (deltaX != 0.0f || deltaY != 0.0f)) {
         rotateDelta(mOrientation, &deltaX, &deltaY);
     }
@@ -2782,15 +2770,15 @@
     getDevice()->getConfiguration().tryGetProperty(String8("touch.orientationAware"),
             mParameters.orientationAware);
 
-    mParameters.associatedDisplayId = -1;
+    mParameters.hasAssociatedDisplay = false;
     mParameters.associatedDisplayIsExternal = false;
     if (mParameters.orientationAware
             || mParameters.deviceType == Parameters::DEVICE_TYPE_TOUCH_SCREEN
             || mParameters.deviceType == Parameters::DEVICE_TYPE_POINTER) {
+        mParameters.hasAssociatedDisplay = true;
         mParameters.associatedDisplayIsExternal =
                 mParameters.deviceType == Parameters::DEVICE_TYPE_TOUCH_SCREEN
                         && getDevice()->isExternal();
-        mParameters.associatedDisplayId = 0;
     }
 }
 
@@ -2822,8 +2810,9 @@
         ALOG_ASSERT(false);
     }
 
-    dump.appendFormat(INDENT4 "AssociatedDisplay: id=%d, isExternal=%s\n",
-            mParameters.associatedDisplayId, toString(mParameters.associatedDisplayIsExternal));
+    dump.appendFormat(INDENT4 "AssociatedDisplay: present=%s, isExternal=%s\n",
+            toString(mParameters.hasAssociatedDisplay),
+            toString(mParameters.associatedDisplayIsExternal));
     dump.appendFormat(INDENT4 "OrientationAware: %s\n",
             toString(mParameters.orientationAware));
 }
@@ -2861,7 +2850,7 @@
             mSource |= AINPUT_SOURCE_STYLUS;
         }
     } else if (mParameters.deviceType == Parameters::DEVICE_TYPE_TOUCH_SCREEN
-            && mParameters.associatedDisplayId >= 0) {
+            && mParameters.hasAssociatedDisplay) {
         mSource = AINPUT_SOURCE_TOUCHSCREEN;
         mDeviceMode = DEVICE_MODE_DIRECT;
         if (hasStylus()) {
@@ -2881,15 +2870,13 @@
     }
 
     // Get associated display dimensions.
-    if (mParameters.associatedDisplayId >= 0) {
-        if (!mConfig.getDisplayInfo(mParameters.associatedDisplayId,
-                mParameters.associatedDisplayIsExternal,
-                &mAssociatedDisplayWidth, &mAssociatedDisplayHeight,
-                &mAssociatedDisplayOrientation)) {
+    if (mParameters.hasAssociatedDisplay) {
+        if (!mConfig.getDisplayInfo(mParameters.associatedDisplayIsExternal,
+                &mAssociatedDisplayViewport)) {
             ALOGI(INDENT "Touch device '%s' could not query the properties of its associated "
-                    "display %d.  The device will be inoperable until the display size "
+                    "display.  The device will be inoperable until the display size "
                     "becomes available.",
-                    getDeviceName().string(), mParameters.associatedDisplayId);
+                    getDeviceName().string());
             mDeviceMode = DEVICE_MODE_DISABLED;
             return;
         }
@@ -2898,10 +2885,16 @@
     // Configure dimensions.
     int32_t width, height, orientation;
     if (mDeviceMode == DEVICE_MODE_DIRECT || mDeviceMode == DEVICE_MODE_POINTER) {
-        width = mAssociatedDisplayWidth;
-        height = mAssociatedDisplayHeight;
+        width = mAssociatedDisplayViewport.logicalRight - mAssociatedDisplayViewport.logicalLeft;
+        height = mAssociatedDisplayViewport.logicalBottom - mAssociatedDisplayViewport.logicalTop;
+        if (mAssociatedDisplayViewport.orientation == DISPLAY_ORIENTATION_90
+                || mAssociatedDisplayViewport.orientation == DISPLAY_ORIENTATION_270) {
+            int32_t temp = height;
+            height = width;
+            width = temp;
+        }
         orientation = mParameters.orientationAware ?
-                mAssociatedDisplayOrientation : DISPLAY_ORIENTATION_0;
+                mAssociatedDisplayViewport.orientation : DISPLAY_ORIENTATION_0;
     } else {
         width = mRawPointerAxes.x.maxValue - mRawPointerAxes.x.minValue + 1;
         height = mRawPointerAxes.y.maxValue - mRawPointerAxes.y.minValue + 1;
@@ -3163,8 +3156,7 @@
             int32_t rawWidth = mRawPointerAxes.x.maxValue - mRawPointerAxes.x.minValue + 1;
             int32_t rawHeight = mRawPointerAxes.y.maxValue - mRawPointerAxes.y.minValue + 1;
             float rawDiagonal = hypotf(rawWidth, rawHeight);
-            float displayDiagonal = hypotf(mAssociatedDisplayWidth,
-                    mAssociatedDisplayHeight);
+            float displayDiagonal = hypotf(width, height);
 
             // Scale movements such that one whole swipe of the touch pad covers a
             // given area relative to the diagonal size of the display when no acceleration
diff --git a/services/input/InputReader.h b/services/input/InputReader.h
index 6c06986..e345a5fb 100644
--- a/services/input/InputReader.h
+++ b/services/input/InputReader.h
@@ -24,7 +24,6 @@
 #include <androidfw/Input.h>
 #include <androidfw/VelocityControl.h>
 #include <androidfw/VelocityTracker.h>
-#include <ui/DisplayInfo.h>
 #include <utils/KeyedVector.h>
 #include <utils/threads.h>
 #include <utils/Timers.h>
@@ -48,6 +47,45 @@
 class InputDevice;
 class InputMapper;
 
+/*
+ * Describes how coordinates are mapped on a physical display.
+ * See com.android.server.display.DisplayViewport.
+ */
+struct DisplayViewport {
+    int32_t displayId; // -1 if invalid
+    int32_t orientation;
+    int32_t logicalLeft;
+    int32_t logicalTop;
+    int32_t logicalRight;
+    int32_t logicalBottom;
+    int32_t physicalLeft;
+    int32_t physicalTop;
+    int32_t physicalRight;
+    int32_t physicalBottom;
+
+    DisplayViewport() :
+            displayId(-1), orientation(DISPLAY_ORIENTATION_0),
+            logicalLeft(0), logicalTop(0), logicalRight(0), logicalBottom(0),
+            physicalLeft(0), physicalTop(0), physicalRight(0), physicalBottom(0) {
+    }
+
+    bool operator==(const DisplayViewport& other) const {
+        return displayId == other.displayId
+                && orientation == other.orientation
+                && logicalLeft == other.logicalLeft
+                && logicalTop == other.logicalTop
+                && logicalRight == other.logicalRight
+                && logicalBottom == other.logicalBottom
+                && physicalLeft == other.physicalLeft
+                && physicalTop == other.physicalTop
+                && physicalRight == other.physicalRight
+                && physicalBottom == other.physicalBottom;
+    }
+
+    bool operator!=(const DisplayViewport& other) const {
+        return !(*this == other);
+    }
+};
 
 /*
  * Input reader configuration.
@@ -180,25 +218,12 @@
             pointerGestureZoomSpeedRatio(0.3f),
             showTouches(false) { }
 
-    bool getDisplayInfo(int32_t displayId, bool external,
-            int32_t* width, int32_t* height, int32_t* orientation) const;
-
-    void setDisplayInfo(int32_t displayId, bool external,
-            int32_t width, int32_t height, int32_t orientation);
+    bool getDisplayInfo(bool external, DisplayViewport* outViewport) const;
+    void setDisplayInfo(bool external, const DisplayViewport& viewport);
 
 private:
-    struct DisplayInfo {
-        int32_t width;
-        int32_t height;
-        int32_t orientation;
-
-        DisplayInfo() :
-            width(-1), height(-1), orientation(DISPLAY_ORIENTATION_0) {
-        }
-    };
-
-    DisplayInfo mInternalDisplay;
-    DisplayInfo mExternalDisplay;
+    DisplayViewport mInternalDisplay;
+    DisplayViewport mExternalDisplay;
 };
 
 
@@ -992,7 +1017,7 @@
 
     // Immutable configuration parameters.
     struct Parameters {
-        int32_t associatedDisplayId;
+        bool hasAssociatedDisplay;
         bool orientationAware;
     } mParameters;
 
@@ -1042,7 +1067,7 @@
         };
 
         Mode mode;
-        int32_t associatedDisplayId;
+        bool hasAssociatedDisplay;
         bool orientationAware;
     } mParameters;
 
@@ -1143,7 +1168,7 @@
         };
 
         DeviceType deviceType;
-        int32_t associatedDisplayId;
+        bool hasAssociatedDisplay;
         bool associatedDisplayIsExternal;
         bool orientationAware;
 
@@ -1277,10 +1302,8 @@
     int32_t mSurfaceWidth;
     int32_t mSurfaceHeight;
 
-    // The associated display orientation and width and height set by configureSurface().
-    int32_t mAssociatedDisplayOrientation;
-    int32_t mAssociatedDisplayWidth;
-    int32_t mAssociatedDisplayHeight;
+    // The associated display viewport set by configureSurface().
+    DisplayViewport mAssociatedDisplayViewport;
 
     // Translation and scaling factors, orientation-independent.
     float mXScale;
diff --git a/services/input/PointerController.cpp b/services/input/PointerController.cpp
index fc828a6..9af521b 100644
--- a/services/input/PointerController.cpp
+++ b/services/input/PointerController.cpp
@@ -307,9 +307,17 @@
     }
 }
 
-void PointerController::setDisplaySize(int32_t width, int32_t height) {
+void PointerController::setDisplayViewport(int32_t width, int32_t height, int32_t orientation) {
     AutoMutex _l(mLock);
 
+    // Adjust to use the display's unrotated coordinate frame.
+    if (orientation == DISPLAY_ORIENTATION_90
+            || orientation == DISPLAY_ORIENTATION_270) {
+        int32_t temp = height;
+        height = width;
+        width = temp;
+    }
+
     if (mLocked.displayWidth != width || mLocked.displayHeight != height) {
         mLocked.displayWidth = width;
         mLocked.displayHeight = height;
@@ -324,12 +332,7 @@
         }
 
         fadeOutAndReleaseAllSpotsLocked();
-        updatePointerLocked();
     }
-}
-
-void PointerController::setDisplayOrientation(int32_t orientation) {
-    AutoMutex _l(mLock);
 
     if (mLocked.displayOrientation != orientation) {
         // Apply offsets to convert from the pixel top-left corner position to the pixel center.
@@ -380,9 +383,9 @@
         mLocked.pointerX = x - 0.5f;
         mLocked.pointerY = y - 0.5f;
         mLocked.displayOrientation = orientation;
-
-        updatePointerLocked();
     }
+
+    updatePointerLocked();
 }
 
 void PointerController::setPointerIcon(const SpriteIcon& icon) {
diff --git a/services/input/PointerController.h b/services/input/PointerController.h
index 4c307c4..fd68b61 100644
--- a/services/input/PointerController.h
+++ b/services/input/PointerController.h
@@ -170,8 +170,7 @@
             const uint32_t* spotIdToIndex, BitSet32 spotIdBits);
     virtual void clearSpots();
 
-    void setDisplaySize(int32_t width, int32_t height);
-    void setDisplayOrientation(int32_t orientation);
+    void setDisplayViewport(int32_t width, int32_t height, int32_t orientation);
     void setPointerIcon(const SpriteIcon& icon);
     void setInactivityTimeout(InactivityTimeout inactivityTimeout);
 
diff --git a/services/input/tests/InputReader_test.cpp b/services/input/tests/InputReader_test.cpp
index abda10b..03516af 100644
--- a/services/input/tests/InputReader_test.cpp
+++ b/services/input/tests/InputReader_test.cpp
@@ -138,8 +138,21 @@
 
     void setDisplayInfo(int32_t displayId, int32_t width, int32_t height, int32_t orientation) {
         // Set the size of both the internal and external display at the same time.
-        mConfig.setDisplayInfo(displayId, false /*external*/, width, height, orientation);
-        mConfig.setDisplayInfo(displayId, true /*external*/, width, height, orientation);
+        bool isRotated = (orientation == DISPLAY_ORIENTATION_90
+                || orientation == DISPLAY_ORIENTATION_270);
+        DisplayViewport v;
+        v.displayId = displayId;
+        v.orientation = orientation;
+        v.logicalLeft = 0;
+        v.logicalTop = 0;
+        v.logicalRight = isRotated ? height : width;
+        v.logicalBottom = isRotated ? width : height;
+        v.physicalLeft = 0;
+        v.physicalTop = 0;
+        v.physicalRight = isRotated ? height : width;
+        v.physicalBottom = isRotated ? width : height;
+        mConfig.setDisplayInfo(false /*external*/, v);
+        mConfig.setDisplayInfo(true /*external*/, v);
     }
 
     void addExcludedDeviceName(const String8& deviceName) {
diff --git a/services/java/com/android/server/BackupManagerService.java b/services/java/com/android/server/BackupManagerService.java
index 955ea23..1d40f4f 100644
--- a/services/java/com/android/server/BackupManagerService.java
+++ b/services/java/com/android/server/BackupManagerService.java
@@ -4401,6 +4401,18 @@
                     return;
                 }
 
+                if (packageInfo.applicationInfo.backupAgentName == null
+                        || "".equals(packageInfo.applicationInfo.backupAgentName)) {
+                    if (DEBUG) {
+                        Slog.i(TAG, "Data exists for package " + packageName
+                                + " but app has no agent; skipping");
+                    }
+                    EventLog.writeEvent(EventLogTags.RESTORE_AGENT_FAILURE, packageName,
+                            "Package has no agent");
+                    executeNextState(RestoreState.RUNNING_QUEUE);
+                    return;
+                }
+
                 if (metaInfo.versionCode > packageInfo.versionCode) {
                     // Data is from a "newer" version of the app than we have currently
                     // installed.  If the app has not declared that it is prepared to
diff --git a/services/java/com/android/server/BluetoothManagerService.java b/services/java/com/android/server/BluetoothManagerService.java
index 4b43070..9404dce 100755
--- a/services/java/com/android/server/BluetoothManagerService.java
+++ b/services/java/com/android/server/BluetoothManagerService.java
@@ -40,6 +40,8 @@
     private static final String SECURE_SETTINGS_BLUETOOTH_NAME="bluetooth_name";
     private static final int TIMEOUT_BIND_MS = 3000; //Maximum msec to wait for a bind
     private static final int TIMEOUT_SAVE_MS = 500; //Maximum msec to wait for a save
+    //Maximum msec to wait for service restart
+    private static final int SERVICE_RESTART_TIME_MS = 200;
 
     private static final int MESSAGE_ENABLE = 1;
     private static final int MESSAGE_DISABLE = 2;
@@ -49,6 +51,7 @@
     private static final int MESSAGE_UNREGISTER_STATE_CHANGE_CALLBACK = 31;
     private static final int MESSAGE_BLUETOOTH_SERVICE_CONNECTED = 40;
     private static final int MESSAGE_BLUETOOTH_SERVICE_DISCONNECTED = 41;
+    private static final int MESSAGE_RESTART_BLUETOOTH_SERVICE = 42;
     private static final int MESSAGE_BLUETOOTH_STATE_CHANGE=60;
     private static final int MESSAGE_TIMEOUT_BIND =100;
     private static final int MESSAGE_TIMEOUT_UNBIND =101;
@@ -660,8 +663,36 @@
                 {
                     if (DBG) Log.d(TAG, "MESSAGE_BLUETOOTH_SERVICE_DISCONNECTED");
                     sendBluetoothServiceDownCallback();
+
+                    // Send BT state broadcast to update
+                    // the BT icon correctly
+                    Message stateChangeMsg = mHandler.obtainMessage(
+                        MESSAGE_BLUETOOTH_STATE_CHANGE);
+                    stateChangeMsg.arg1 = BluetoothAdapter.STATE_ON;
+                    stateChangeMsg.arg2 =
+                        BluetoothAdapter.STATE_TURNING_OFF;
+                    mHandler.sendMessage(stateChangeMsg);
+                    synchronized(mConnection) {
+                        mBluetooth = null;
+                    }
+                    // Send a Bluetooth Restart message
+                    Message restartMsg = mHandler.obtainMessage(
+                        MESSAGE_RESTART_BLUETOOTH_SERVICE);
+                    mHandler.sendMessageDelayed(restartMsg,
+                        SERVICE_RESTART_TIME_MS);
                     break;
                 }
+                case MESSAGE_RESTART_BLUETOOTH_SERVICE:
+                {
+                    Log.d(TAG, "MESSAGE_RESTART_BLUETOOTH_SERVICE:"
+                        +" Restart IBluetooth service");
+                    /* Enable without persisting the setting as
+                     it doesnt change when IBluetooth
+                     service restarts */
+                    handleEnable(false, mQuietEnable);
+                    break;
+                }
+
                 case MESSAGE_TIMEOUT_UNBIND:
                 {
                     Log.e(TAG, "MESSAGE_TIMEOUT_UNBIND");
diff --git a/services/java/com/android/server/ConnectivityService.java b/services/java/com/android/server/ConnectivityService.java
index cbbfda1..3a338a9 100644
--- a/services/java/com/android/server/ConnectivityService.java
+++ b/services/java/com/android/server/ConnectivityService.java
@@ -77,6 +77,7 @@
 import android.os.Message;
 import android.os.ParcelFileDescriptor;
 import android.os.PowerManager;
+import android.os.Process;
 import android.os.RemoteException;
 import android.os.ServiceManager;
 import android.os.SystemClock;
@@ -3370,7 +3371,7 @@
 
     @Override
     public boolean updateLockdownVpn() {
-        mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
+        enforceSystemUid();
 
         // Tear down existing lockdown if profile was removed
         mLockdownEnabled = LockdownVpnTracker.isEnabled();
@@ -3421,4 +3422,11 @@
             throw new IllegalStateException("Unavailable in lockdown mode");
         }
     }
+
+    private static void enforceSystemUid() {
+        final int uid = Binder.getCallingUid();
+        if (uid != Process.SYSTEM_UID) {
+            throw new SecurityException("Only available to AID_SYSTEM");
+        }
+    }
 }
diff --git a/services/java/com/android/server/DevicePolicyManagerService.java b/services/java/com/android/server/DevicePolicyManagerService.java
index 61517b1..fd6060a 100644
--- a/services/java/com/android/server/DevicePolicyManagerService.java
+++ b/services/java/com/android/server/DevicePolicyManagerService.java
@@ -1628,8 +1628,8 @@
             } else {
                 // Make sure KEEP_SCREEN_ON is disabled, since that
                 // would allow bypassing of the maximum time to lock.
-                Settings.System.putInt(mContext.getContentResolver(),
-                        Settings.System.STAY_ON_WHILE_PLUGGED_IN, 0);
+                Settings.Global.putInt(mContext.getContentResolver(),
+                        Settings.Global.STAY_ON_WHILE_PLUGGED_IN, 0);
             }
 
             mLastMaximumTimeToLock = timeMs;
diff --git a/services/java/com/android/server/EventLogTags.logtags b/services/java/com/android/server/EventLogTags.logtags
index dd50beb..39355d5 100644
--- a/services/java/com/android/server/EventLogTags.logtags
+++ b/services/java/com/android/server/EventLogTags.logtags
@@ -148,3 +148,11 @@
 # ---------------------------
 51100 netstats_mobile_sample (dev_rx_bytes|2|2),(dev_tx_bytes|2|2),(dev_rx_pkts|2|1),(dev_tx_pkts|2|1),(xt_rx_bytes|2|2),(xt_tx_bytes|2|2),(xt_rx_pkts|2|1),(xt_tx_pkts|2|1),(uid_rx_bytes|2|2),(uid_tx_bytes|2|2),(uid_rx_pkts|2|1),(uid_tx_pkts|2|1),(trusted_time|2|3)
 51101 netstats_wifi_sample (dev_rx_bytes|2|2),(dev_tx_bytes|2|2),(dev_rx_pkts|2|1),(dev_tx_pkts|2|1),(xt_rx_bytes|2|2),(xt_tx_bytes|2|2),(xt_rx_pkts|2|1),(xt_tx_pkts|2|1),(uid_rx_bytes|2|2),(uid_tx_bytes|2|2),(uid_rx_pkts|2|1),(uid_tx_pkts|2|1),(trusted_time|2|3)
+
+
+# ---------------------------
+# LockdownVpnTracker.java
+# ---------------------------
+51200 lockdown_vpn_connecting (egress_net|1)
+51201 lockdown_vpn_connected (egress_net|1)
+51202 lockdown_vpn_error (egress_net|1)
diff --git a/services/java/com/android/server/MountService.java b/services/java/com/android/server/MountService.java
index 1eccbbe..f40333d 100644
--- a/services/java/com/android/server/MountService.java
+++ b/services/java/com/android/server/MountService.java
@@ -1114,9 +1114,8 @@
                         Slog.e(TAG, "path or description is null in readStorageList");
                     } else {
                         String pathString = path.toString();
-                        StorageVolume volume = new StorageVolume(pathString,
-                                descriptionId, removable, emulated,
-                                mtpReserve, allowMassStorage, maxFileSize);
+                        StorageVolume volume = new StorageVolume(pathString, descriptionId, primary,
+                                removable, emulated, mtpReserve, allowMassStorage, maxFileSize);
                         if (primary) {
                             if (mPrimaryVolume == null) {
                                 mPrimaryVolume = volume;
diff --git a/services/java/com/android/server/NetworkManagementService.java b/services/java/com/android/server/NetworkManagementService.java
index efa16af..3ddae3e 100644
--- a/services/java/com/android/server/NetworkManagementService.java
+++ b/services/java/com/android/server/NetworkManagementService.java
@@ -45,8 +45,10 @@
 import android.net.RouteInfo;
 import android.net.wifi.WifiConfiguration;
 import android.net.wifi.WifiConfiguration.KeyMgmt;
+import android.os.Binder;
 import android.os.Handler;
 import android.os.INetworkManagementService;
+import android.os.Process;
 import android.os.RemoteCallbackList;
 import android.os.RemoteException;
 import android.os.SystemClock;
@@ -1436,7 +1438,7 @@
 
     @Override
     public void setFirewallEnabled(boolean enabled) {
-        mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
+        enforceSystemUid();
         try {
             mConnector.execute("firewall", enabled ? "enable" : "disable");
             mFirewallEnabled = enabled;
@@ -1447,13 +1449,13 @@
 
     @Override
     public boolean isFirewallEnabled() {
-        mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
+        enforceSystemUid();
         return mFirewallEnabled;
     }
 
     @Override
     public void setFirewallInterfaceRule(String iface, boolean allow) {
-        mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
+        enforceSystemUid();
         Preconditions.checkState(mFirewallEnabled);
         final String rule = allow ? ALLOW : DENY;
         try {
@@ -1465,7 +1467,7 @@
 
     @Override
     public void setFirewallEgressSourceRule(String addr, boolean allow) {
-        mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
+        enforceSystemUid();
         Preconditions.checkState(mFirewallEnabled);
         final String rule = allow ? ALLOW : DENY;
         try {
@@ -1477,7 +1479,7 @@
 
     @Override
     public void setFirewallEgressDestRule(String addr, int port, boolean allow) {
-        mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
+        enforceSystemUid();
         Preconditions.checkState(mFirewallEnabled);
         final String rule = allow ? ALLOW : DENY;
         try {
@@ -1489,7 +1491,7 @@
 
     @Override
     public void setFirewallUidRule(int uid, boolean allow) {
-        mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
+        enforceSystemUid();
         Preconditions.checkState(mFirewallEnabled);
         final String rule = allow ? ALLOW : DENY;
         try {
@@ -1499,6 +1501,13 @@
         }
     }
 
+    private static void enforceSystemUid() {
+        final int uid = Binder.getCallingUid();
+        if (uid != Process.SYSTEM_UID) {
+            throw new SecurityException("Only available to AID_SYSTEM");
+        }
+    }
+
     @Override
     public void monitor() {
         if (mConnector != null) {
diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java
index 1aad9b3..c28afb2 100644
--- a/services/java/com/android/server/SystemServer.java
+++ b/services/java/com/android/server/SystemServer.java
@@ -304,6 +304,7 @@
 
             ActivityManagerService.self().setWindowManager(wm);
             display.setWindowManager(wm);
+            display.setInputManager(inputManager);
 
             // Skip Bluetooth if we have an emulator kernel
             // TODO: Use a more reliable check to see if this product should
diff --git a/services/java/com/android/server/UiModeManagerService.java b/services/java/com/android/server/UiModeManagerService.java
index f618263..3e83baa 100644
--- a/services/java/com/android/server/UiModeManagerService.java
+++ b/services/java/com/android/server/UiModeManagerService.java
@@ -463,7 +463,7 @@
 
                 if (homeIntent != null) {
                     try {
-                        mContext.startActivity(homeIntent);
+                        mContext.startActivityAsUser(homeIntent, UserHandle.CURRENT);
                     } catch (ActivityNotFoundException e) {
                     }
                 }
diff --git a/services/java/com/android/server/accessibility/AccessibilityInputFilter.java b/services/java/com/android/server/accessibility/AccessibilityInputFilter.java
index fc774d4..f1a03de 100644
--- a/services/java/com/android/server/accessibility/AccessibilityInputFilter.java
+++ b/services/java/com/android/server/accessibility/AccessibilityInputFilter.java
@@ -26,57 +26,49 @@
 import android.view.WindowManagerPolicy;
 import android.view.accessibility.AccessibilityEvent;
 
-/**
- * Input filter for accessibility.
- *
- * Currently just a stub but will eventually implement touch exploration, etc.
- */
-public class AccessibilityInputFilter extends InputFilter {
-    private static final String TAG = "AccessibilityInputFilter";
+class AccessibilityInputFilter extends InputFilter implements EventStreamTransformation {
+
+    private static final String TAG = AccessibilityInputFilter.class.getSimpleName();
+
     private static final boolean DEBUG = false;
 
+    private static final int UNDEFINED_DEVICE_ID = -1;
+
+    /**
+     * Flag for enabling the screen magnification feature.
+     *
+     * @see #setEnabledFeatures(int)
+     */
+    static final int FLAG_FEATURE_SCREEN_MAGNIFIER = 0x00000001;
+
+    /**
+     * Flag for enabling the touch exploration feature.
+     *
+     * @see #setEnabledFeatures(int)
+     */
+    static final int FLAG_FEATURE_TOUCH_EXPLORATION = 0x00000002;
+
     private final Context mContext;
 
     private final PowerManager mPm;
 
     private final AccessibilityManagerService mAms;
 
-    /**
-     * This is an interface for explorers that take a {@link MotionEvent}
-     * stream and perform touch exploration of the screen content.
-     */
-    public interface Explorer {
-        /**
-         * Handles a {@link MotionEvent}.
-         *
-         * @param event The event to handle.
-         * @param policyFlags The policy flags associated with the event.
-         */
-        public void onMotionEvent(MotionEvent event, int policyFlags);
+    private int mCurrentDeviceId;
 
-        /**
-         * Requests that the explorer clears its internal state.
-         *
-         * @param event The last received event.
-         * @param policyFlags The policy flags associated with the event.
-         */
-        public void clear(MotionEvent event, int policyFlags);
+    private boolean mInstalled;
 
-        /**
-         * Requests that the explorer clears its internal state.
-         */
-        public void clear();
-    }
+    private int mEnabledFeatures;
 
     private TouchExplorer mTouchExplorer;
+    private ScreenMagnifier mScreenMagnifier;
+    private EventStreamTransformation mEventHandler;
 
-    private int mTouchscreenSourceDeviceId;
-
-    public AccessibilityInputFilter(Context context, AccessibilityManagerService service) {
+    AccessibilityInputFilter(Context context, AccessibilityManagerService service) {
         super(context.getMainLooper());
         mContext = context;
         mAms = service;
-        mPm = (PowerManager)context.getSystemService(Context.POWER_SERVICE);
+        mPm = (PowerManager) context.getSystemService(Context.POWER_SERVICE);
     }
 
     @Override
@@ -84,7 +76,9 @@
         if (DEBUG) {
             Slog.d(TAG, "Accessibility input filter installed.");
         }
-        mTouchExplorer = new TouchExplorer(this, mContext, mAms);
+        mInstalled = true;
+        disableFeatures();
+        enableFeatures();
         super.onInstalled();
     }
 
@@ -93,7 +87,8 @@
         if (DEBUG) {
             Slog.d(TAG, "Accessibility input filter uninstalled.");
         }
-        mTouchExplorer.clear();
+        mInstalled = false;
+        disableFeatures();
         super.onUninstalled();
     }
 
@@ -103,27 +98,104 @@
             Slog.d(TAG, "Received event: " + event + ", policyFlags=0x" 
                     + Integer.toHexString(policyFlags));
         }
-        if (event.getSource() == InputDevice.SOURCE_TOUCHSCREEN) {
-            MotionEvent motionEvent = (MotionEvent) event;
-            int deviceId = event.getDeviceId();
-            if (mTouchscreenSourceDeviceId != deviceId) {
-                mTouchscreenSourceDeviceId = deviceId;
-                mTouchExplorer.clear(motionEvent, policyFlags);
-            }
-            if ((policyFlags & WindowManagerPolicy.FLAG_PASS_TO_USER) != 0) {
-                mPm.userActivity(event.getEventTime(), false);
-                mTouchExplorer.onMotionEvent(motionEvent, policyFlags);
-            } else {
-                mTouchExplorer.clear(motionEvent, policyFlags);
-            }
-        } else {
+        if (mEventHandler == null) {
             super.onInputEvent(event, policyFlags);
+            return;
+        }
+        if (event.getSource() != InputDevice.SOURCE_TOUCHSCREEN) {
+            super.onInputEvent(event, policyFlags);
+            return;
+        }
+        if ((policyFlags & WindowManagerPolicy.FLAG_PASS_TO_USER) == 0) {
+            mEventHandler.clear();
+            super.onInputEvent(event, policyFlags);
+            return;
+        }
+        final int deviceId = event.getDeviceId();
+        if (mCurrentDeviceId != deviceId) {
+            if (mCurrentDeviceId != UNDEFINED_DEVICE_ID) {
+                mEventHandler.clear();
+            }
+            mCurrentDeviceId = deviceId;
+        }
+        mPm.userActivity(event.getEventTime(), false);
+        MotionEvent motionEvent = (MotionEvent) event;
+        mEventHandler.onMotionEvent(motionEvent, policyFlags);
+    }
+
+    @Override
+    public void onMotionEvent(MotionEvent event, int policyFlags) {
+        sendInputEvent(event, policyFlags);
+    }
+
+    @Override
+    public void onAccessibilityEvent(AccessibilityEvent event) {
+        // TODO Implement this to inject the accessibility event
+        //      into the accessibility manager service similarly
+        //      to how this is done for input events.
+    }
+
+    @Override
+    public void setNext(EventStreamTransformation sink) {
+        /* do nothing */
+    }
+
+    @Override
+    public void clear() {
+        /* do nothing */
+    }
+
+    void setEnabledFeatures(int enabledFeatures) {
+        if (mEnabledFeatures == enabledFeatures) {
+            return;
+        }
+        if (mInstalled) {
+            disableFeatures();
+        }
+        mEnabledFeatures = enabledFeatures;
+        if (mInstalled) {
+            enableFeatures();
         }
     }
 
-    public void onAccessibilityEvent(AccessibilityEvent event) {
-        if (mTouchExplorer != null) {
-            mTouchExplorer.onAccessibilityEvent(event);
+    void notifyAccessibilityEvent(AccessibilityEvent event) {
+        if (mEventHandler != null) {
+            mEventHandler.onAccessibilityEvent(event);
         }
     }
+
+    private void enableFeatures() {
+        if ((mEnabledFeatures & FLAG_FEATURE_SCREEN_MAGNIFIER) != 0) {
+            mEventHandler = mScreenMagnifier = new ScreenMagnifier(mContext);
+            mEventHandler.setNext(this);
+        }
+        if ((mEnabledFeatures & FLAG_FEATURE_TOUCH_EXPLORATION) != 0) {
+            mTouchExplorer = new TouchExplorer(mContext, mAms);
+            mTouchExplorer.setNext(this);
+            if (mEventHandler != null) {
+                mEventHandler.setNext(mTouchExplorer);
+            } else {
+                mEventHandler = mTouchExplorer;
+            }
+        }
+    }
+
+    private void disableFeatures() {
+        if (mTouchExplorer != null) {
+            mTouchExplorer.clear();
+            mTouchExplorer.onDestroy();
+            mTouchExplorer = null;
+        }
+        if (mScreenMagnifier != null) {
+            mScreenMagnifier.clear();
+            mScreenMagnifier.onDestroy();
+            mScreenMagnifier = null;
+        }
+        mEventHandler = null;
+    }
+
+    @Override
+    public void onDestroy() {
+        /* ignore */
+    }
 }
diff --git a/services/java/com/android/server/accessibility/AccessibilityManagerService.java b/services/java/com/android/server/accessibility/AccessibilityManagerService.java
index 857334e..f6354bb 100644
--- a/services/java/com/android/server/accessibility/AccessibilityManagerService.java
+++ b/services/java/com/android/server/accessibility/AccessibilityManagerService.java
@@ -48,6 +48,7 @@
 import android.os.Bundle;
 import android.os.Handler;
 import android.os.IBinder;
+import android.os.Looper;
 import android.os.Message;
 import android.os.RemoteException;
 import android.os.ServiceManager;
@@ -62,6 +63,7 @@
 import android.view.InputDevice;
 import android.view.KeyCharacterMap;
 import android.view.KeyEvent;
+import android.view.WindowInfo;
 import android.view.WindowManager;
 import android.view.accessibility.AccessibilityEvent;
 import android.view.accessibility.AccessibilityInteractionClient;
@@ -115,6 +117,8 @@
 
     private static final int MSG_SEND_ACCESSIBILITY_EVENT_TO_INPUT_FILTER = 3;
 
+    private static final int MSG_SEND_UPDATE_INPUT_FILTER = 4;
+
     private static int sIdCounter = 0;
 
     private static int sNextWindowId;
@@ -157,11 +161,13 @@
 
     private boolean mIsTouchExplorationEnabled;
 
+    private boolean mIsScreenMagnificationEnabled;
+
     private final IWindowManager mWindowManager;
 
     private final SecurityPolicy mSecurityPolicy;
 
-    private final MainHanler mMainHandler;
+    private final MainHandler mMainHandler;
 
     private Service mUiAutomationService;
 
@@ -183,7 +189,7 @@
         mPackageManager = mContext.getPackageManager();
         mWindowManager = (IWindowManager) ServiceManager.getService(Context.WINDOW_SERVICE);
         mSecurityPolicy = new SecurityPolicy();
-        mMainHandler = new MainHanler();
+        mMainHandler = new MainHandler(mContext.getMainLooper());
         registerPackageChangeAndBootCompletedBroadcastReceiver();
         registerSettingsContentObservers();
     }
@@ -201,7 +207,7 @@
                 synchronized (mLock) {
                     // We will update when the automation service dies.
                     if (mUiAutomationService == null) {
-                        populateAccessibilityServiceListLocked();
+                        populateInstalledAccessibilityServiceLocked();
                         manageServicesLocked();
                     }
                 }
@@ -262,18 +268,11 @@
                     synchronized (mLock) {
                         // We will update when the automation service dies.
                         if (mUiAutomationService == null) {
-                            populateAccessibilityServiceListLocked();
-                            populateEnabledAccessibilityServicesLocked();
-                            populateTouchExplorationGrantedAccessibilityServicesLocked();
-                            handleAccessibilityEnabledSettingChangedLocked();
-                            handleTouchExplorationEnabledSettingChangedLocked();
-                            updateInputFilterLocked();
-                            sendStateToClientsLocked();
+                            updateInternalStateLocked();
                         }
                     }
                     return;
                 }
-
                 super.onReceive(context, intent);
             }
         };
@@ -329,6 +328,24 @@
                     }
                 });
 
+        Uri accessibilityScreenMagnificationEnabledUri = Settings.Secure.getUriFor(
+                Settings.Secure.ACCESSIBILITY_DISPLAY_MAGNIFICATION_ENABLED);
+        contentResolver.registerContentObserver(accessibilityScreenMagnificationEnabledUri, false,
+            new ContentObserver(new Handler()) {
+                @Override
+                public void onChange(boolean selfChange) {
+                    super.onChange(selfChange);
+                    synchronized (mLock) {
+                        // We will update when the automation service dies.
+                        if (mUiAutomationService == null) {
+                            handleScreenMagnificationEnabledSettingChangedLocked();
+                            updateInputFilterLocked();
+                            sendStateToClientsLocked();
+                        }
+                    }
+                }
+            });
+
         Uri accessibilityServicesUri =
             Settings.Secure.getUriFor(Settings.Secure.ENABLED_ACCESSIBILITY_SERVICES);
         contentResolver.registerContentObserver(accessibilityServicesUri, false,
@@ -587,8 +604,11 @@
             final int windowId = mSecurityPolicy.mActiveWindowId;
             IBinder token = mWindowIdToWindowTokenMap.get(windowId);
             try {
-                mWindowManager.getWindowFrame(token, outBounds);
-                return true;
+                WindowInfo info = mWindowManager.getWindowInfo(token);
+                if (info != null) {
+                    outBounds.set(info.frame);
+                    return true;
+                }
             } catch (RemoteException re) {
                 /* ignore */
             }
@@ -652,7 +672,7 @@
     /**
      * Populates the cached list of installed {@link AccessibilityService}s.
      */
-    private void populateAccessibilityServiceListLocked() {
+    private void populateInstalledAccessibilityServiceLocked() {
         mInstalledServices.clear();
 
         List<ResolveInfo> installedServices = mPackageManager.queryIntentServices(
@@ -962,31 +982,26 @@
     }
 
     /**
-     * Updates the touch exploration state.
+     * Updates the state of the input filter.
      */
     private void updateInputFilterLocked() {
-        if (mIsAccessibilityEnabled && mIsTouchExplorationEnabled) {
-            if (!mHasInputFilter) {
-                mHasInputFilter = true;
-                if (mInputFilter == null) {
-                    mInputFilter = new AccessibilityInputFilter(mContext, this);
-                }
-                try {
-                    mWindowManager.setInputFilter(mInputFilter);
-                } catch (RemoteException re) {
-                    /* ignore */
-                }
-            }
-            return;
-        }
-        if (mHasInputFilter) {
-            mHasInputFilter = false;
-            try {
-                mWindowManager.setInputFilter(null);
-            } catch (RemoteException re) {
-                /* ignore */
-            }
-        }
+         mMainHandler.obtainMessage(MSG_SEND_UPDATE_INPUT_FILTER).sendToTarget();
+    }
+
+    /**
+     * Updated the internal state of this service to match the current settings.
+     */
+    private void updateInternalStateLocked() {
+        populateInstalledAccessibilityServiceLocked();
+        populateEnabledAccessibilityServicesLocked();
+        populateTouchExplorationGrantedAccessibilityServicesLocked();
+
+        handleTouchExplorationEnabledSettingChangedLocked();
+        handleScreenMagnificationEnabledSettingChangedLocked();
+        handleAccessibilityEnabledSettingChangedLocked();
+
+        updateInputFilterLocked();
+        sendStateToClientsLocked();
     }
 
     /**
@@ -1012,6 +1027,15 @@
                 Settings.Secure.TOUCH_EXPLORATION_ENABLED, 0) == 1;
     }
 
+    /**
+     * Updates the state based on the screen magnification enabled setting.
+     */
+    private void handleScreenMagnificationEnabledSettingChangedLocked() {
+        mIsScreenMagnificationEnabled = Settings.Secure.getInt(
+                mContext.getContentResolver(),
+                Settings.Secure.ACCESSIBILITY_DISPLAY_MAGNIFICATION_ENABLED, 0) == 1;
+    }
+
     private void handleTouchExplorationGrantedAccessibilityServicesChangedLocked() {
         final int serviceCount = mServices.size();
         for (int i = 0; i < serviceCount; i++) {
@@ -1083,7 +1107,12 @@
         }
     }
 
-    private class MainHanler extends Handler {
+    private class MainHandler extends Handler {
+
+        public MainHandler(Looper looper) {
+            super(looper);
+        }
+
         @Override
         public void handleMessage(Message msg) {
             final int type = msg.what;
@@ -1140,10 +1169,50 @@
                 case MSG_SEND_ACCESSIBILITY_EVENT_TO_INPUT_FILTER: {
                     AccessibilityEvent event = (AccessibilityEvent) msg.obj;
                     if (mHasInputFilter && mInputFilter != null) {
-                        mInputFilter.onAccessibilityEvent(event);
+                        mInputFilter.notifyAccessibilityEvent(event);
                     }
                     event.recycle();
                 } break;
+                case MSG_SEND_UPDATE_INPUT_FILTER: {
+                    boolean setInputFilter = false;
+                    AccessibilityInputFilter inputFilter = null;
+                    synchronized (mLock) {
+                        if ((mIsAccessibilityEnabled && mIsTouchExplorationEnabled)
+                                || mIsScreenMagnificationEnabled) {
+                            if (!mHasInputFilter) {
+                                mHasInputFilter = true;
+                                if (mInputFilter == null) {
+                                    mInputFilter = new AccessibilityInputFilter(mContext,
+                                            AccessibilityManagerService.this);
+                                }
+                                inputFilter = mInputFilter;
+                                setInputFilter = true;
+                            }
+                            int flags = 0;
+                            if (mIsScreenMagnificationEnabled) {
+                                flags |= AccessibilityInputFilter.FLAG_FEATURE_SCREEN_MAGNIFIER;
+                            }
+                            if (mIsTouchExplorationEnabled) {
+                                flags |= AccessibilityInputFilter.FLAG_FEATURE_TOUCH_EXPLORATION;
+                            }
+                            mInputFilter.setEnabledFeatures(flags);
+                        } else {
+                            if (mHasInputFilter) {
+                                mHasInputFilter = false;
+                                mInputFilter.setEnabledFeatures(0);
+                                inputFilter = null;
+                                setInputFilter = true;
+                            }
+                        }
+                    }
+                    if (setInputFilter) {
+                        try {
+                            mWindowManager.setInputFilter(inputFilter);
+                        } catch (RemoteException re) {
+                            /* ignore */
+                        }
+                    }
+                } break;
             }
         }
     }
@@ -1629,18 +1698,7 @@
                 // the state based on values in the settings database.
                 if (mIsAutomation) {
                     mUiAutomationService = null;
-
-                    populateEnabledAccessibilityServicesLocked();
-                    populateTouchExplorationGrantedAccessibilityServicesLocked();
-
-                    handleAccessibilityEnabledSettingChangedLocked();
-                    sendStateToClientsLocked();
-
-                    handleTouchExplorationEnabledSettingChangedLocked();
-                    updateInputFilterLocked();
-
-                    populateAccessibilityServiceListLocked();
-                    manageServicesLocked();
+                    updateInternalStateLocked();
                 }
             }
         }
diff --git a/services/java/com/android/server/accessibility/EventStreamTransformation.java b/services/java/com/android/server/accessibility/EventStreamTransformation.java
new file mode 100644
index 0000000..b715570
--- /dev/null
+++ b/services/java/com/android/server/accessibility/EventStreamTransformation.java
@@ -0,0 +1,90 @@
+/*
+ ** Copyright 2012, 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.accessibility;
+
+import android.view.KeyEvent;
+import android.view.MotionEvent;
+import android.view.accessibility.AccessibilityEvent;
+
+/**
+ * Interface for classes that can handle and potentially transform a stream of
+ * motion and accessibility events. Instances implementing this interface are
+ * ordered in a sequence to implement a transformation chain. An instance may
+ * consume, modify, and generate events. It is responsible to deliver the
+ * output events to the next transformation in the sequence set via
+ * {@link #setNext(EventStreamTransformation)}.
+ *
+ * Note that since instances implementing this interface are transformations
+ * of the event stream, an instance should work against the event stream
+ * potentially modified by previous ones. Hence, the order of transformations
+ * is important.
+ *
+ * It is a responsibility of each handler that decides to react to an event
+ * sequence and prevent any subsequent ones from performing an action to send
+ * the appropriate cancel event given it has delegated a part of the events
+ * that belong to the current gesture. This will ensure that subsequent
+ * transformations will not be left in an inconsistent state and the applications
+ * see a consistent event stream.
+ *
+ * For example, to cancel a {@link KeyEvent} the handler has to emit an event
+ * with action {@link KeyEvent#ACTION_UP} with the additional flag
+ * {@link KeyEvent#FLAG_CANCELED}. To cancel a {@link MotionEvent} the handler
+ * has to send an event with action {@link MotionEvent#ACTION_CANCEL}.
+ *
+ * It is a responsibility of each handler that received a cancel event to clear its
+ * internal state and to propagate the event to the next one to enable subsequent
+ * transformations to clear their internal state.
+ *
+ * It is a responsibility for each transformation to start handling events only
+ * after an event that designates the start of a well-formed event sequence.
+ * For example, if it received a down motion event followed by a cancel motion
+ * event, it should not handle subsequent move and up events until it gets a down.
+ */
+interface EventStreamTransformation {
+
+    /**
+     * Receives a motion event.
+     *
+     * @param event The motion event.
+     * @param policyFlags Policy flags for the event.
+     */
+    public void onMotionEvent(MotionEvent event, int policyFlags);
+
+    /**
+     * Receives an accessibility event.
+     *
+     * @param event The accessibility event.
+     */
+    public void onAccessibilityEvent(AccessibilityEvent event);
+
+    /**
+     * Sets the next transformation.
+     *
+     * @param next The next transformation.
+     */
+    public void setNext(EventStreamTransformation next);
+
+    /**
+     * Clears the internal state of this transformation.
+     */
+    public void clear();
+
+    /**
+     * Destroys this transformation.
+     */
+    public void onDestroy();
+}
diff --git a/services/java/com/android/server/accessibility/GestureUtils.java b/services/java/com/android/server/accessibility/GestureUtils.java
new file mode 100644
index 0000000..b68b09f
--- /dev/null
+++ b/services/java/com/android/server/accessibility/GestureUtils.java
@@ -0,0 +1,102 @@
+package com.android.server.accessibility;
+
+import android.util.MathUtils;
+import android.view.MotionEvent;
+
+/**
+ * Some helper functions for gesture detection.
+ */
+final class GestureUtils {
+
+    private GestureUtils() {
+        /* cannot be instantiated */
+    }
+
+    public static boolean isTap(MotionEvent down, MotionEvent up, int tapTimeSlop,
+            int tapDistanceSlop, int actionIndex) {
+        return eventsWithinTimeAndDistanceSlop(down, up, tapTimeSlop, tapDistanceSlop, actionIndex);
+    }
+
+    public static boolean isMultiTap(MotionEvent firstUp, MotionEvent secondUp,
+            int multiTapTimeSlop, int multiTapDistanceSlop, int actionIndex) {
+        return eventsWithinTimeAndDistanceSlop(firstUp, secondUp, multiTapTimeSlop,
+                multiTapDistanceSlop, actionIndex);
+    }
+
+    private static boolean eventsWithinTimeAndDistanceSlop(MotionEvent first, MotionEvent second,
+            int timeout, int distance, int actionIndex) {
+        if (isTimedOut(first, second, timeout)) {
+            return false;
+        }
+        final double deltaMove = computeDistance(first, second, actionIndex);
+        if (deltaMove >= distance) {
+            return false;
+        }
+        return true;
+    }
+
+    public static double computeDistance(MotionEvent first, MotionEvent second, int pointerIndex) {
+         return MathUtils.dist(first.getX(pointerIndex), first.getY(pointerIndex),
+                 second.getX(pointerIndex), second.getY(pointerIndex));
+    }
+
+    public static boolean isTimedOut(MotionEvent firstUp, MotionEvent secondUp, int timeout) {
+        final long deltaTime = secondUp.getEventTime() - firstUp.getEventTime();
+        return (deltaTime >= timeout);
+    }
+
+    public static boolean isSamePointerContext(MotionEvent first, MotionEvent second) {
+        return (first.getPointerIdBits() == second.getPointerIdBits()
+                && first.getPointerId(first.getActionIndex())
+                        == second.getPointerId(second.getActionIndex()));
+    }
+
+    /**
+     * Determines whether a two pointer gesture is a dragging one.
+     *
+     * @param event The event with the pointer data.
+     * @return True if the gesture is a dragging one.
+     */
+    public static boolean isDraggingGesture(float firstPtrDownX, float firstPtrDownY,
+            float secondPtrDownX, float secondPtrDownY, float firstPtrX, float firstPtrY,
+            float secondPtrX, float secondPtrY, float maxDraggingAngleCos) {
+
+        // Check if the pointers are moving in the same direction.
+        final float firstDeltaX = firstPtrX - firstPtrDownX;
+        final float firstDeltaY = firstPtrY - firstPtrDownY;
+
+        if (firstDeltaX == 0 && firstDeltaY == 0) {
+            return true;
+        }
+
+        final float firstMagnitude =
+            (float) Math.sqrt(firstDeltaX * firstDeltaX + firstDeltaY * firstDeltaY);
+        final float firstXNormalized =
+            (firstMagnitude > 0) ? firstDeltaX / firstMagnitude : firstDeltaX;
+        final float firstYNormalized =
+            (firstMagnitude > 0) ? firstDeltaY / firstMagnitude : firstDeltaY;
+
+        final float secondDeltaX = secondPtrX - secondPtrDownX;
+        final float secondDeltaY = secondPtrY - secondPtrDownY;
+
+        if (secondDeltaX == 0 && secondDeltaY == 0) {
+            return true;
+        }
+
+        final float secondMagnitude =
+            (float) Math.sqrt(secondDeltaX * secondDeltaX + secondDeltaY * secondDeltaY);
+        final float secondXNormalized =
+            (secondMagnitude > 0) ? secondDeltaX / secondMagnitude : secondDeltaX;
+        final float secondYNormalized =
+            (secondMagnitude > 0) ? secondDeltaY / secondMagnitude : secondDeltaY;
+
+        final float angleCos =
+            firstXNormalized * secondXNormalized + firstYNormalized * secondYNormalized;
+
+        if (angleCos < maxDraggingAngleCos) {
+            return false;
+        }
+
+        return true;
+    }
+}
diff --git a/services/java/com/android/server/accessibility/ScreenMagnifier.java b/services/java/com/android/server/accessibility/ScreenMagnifier.java
new file mode 100644
index 0000000..f33517b
--- /dev/null
+++ b/services/java/com/android/server/accessibility/ScreenMagnifier.java
@@ -0,0 +1,1766 @@
+/*
+ * Copyright (C) 2012 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.accessibility;
+
+import android.animation.Animator;
+import android.animation.Animator.AnimatorListener;
+import android.animation.ObjectAnimator;
+import android.animation.TypeEvaluator;
+import android.animation.ValueAnimator;
+import android.content.Context;
+import android.graphics.Canvas;
+import android.graphics.Color;
+import android.graphics.PixelFormat;
+import android.graphics.PointF;
+import android.graphics.PorterDuff.Mode;
+import android.graphics.Rect;
+import android.graphics.drawable.Drawable;
+import android.hardware.display.DisplayManager;
+import android.hardware.display.DisplayManager.DisplayListener;
+import android.os.AsyncTask;
+import android.os.Handler;
+import android.os.Message;
+import android.os.RemoteException;
+import android.os.ServiceManager;
+import android.provider.Settings;
+import android.util.MathUtils;
+import android.util.Property;
+import android.util.Slog;
+import android.view.Display;
+import android.view.DisplayInfo;
+import android.view.Gravity;
+import android.view.IDisplayContentChangeListener;
+import android.view.IWindowManager;
+import android.view.MotionEvent;
+import android.view.ScaleGestureDetector;
+import android.view.MotionEvent.PointerCoords;
+import android.view.MotionEvent.PointerProperties;
+import android.view.ScaleGestureDetector.OnScaleGestureListener;
+import android.view.Surface;
+import android.view.View;
+import android.view.ViewConfiguration;
+import android.view.ViewGroup;
+import android.view.WindowInfo;
+import android.view.WindowManager;
+import android.view.WindowManagerPolicy;
+import android.view.accessibility.AccessibilityEvent;
+import android.view.animation.DecelerateInterpolator;
+import android.view.animation.Interpolator;
+
+import com.android.internal.R;
+import com.android.internal.os.SomeArgs;
+
+import java.util.ArrayList;
+
+/**
+ * This class handles the screen magnification when accessibility is enabled.
+ * The behavior is as follows:
+ *
+ * 1. Triple tap toggles permanent screen magnification which is magnifying
+ *    the area around the location of the triple tap. One can think of the
+ *    location of the triple tap as the center of the magnified viewport.
+ *    For example, a triple tap when not magnified would magnify the screen
+ *    and leave it in a magnified state. A triple tapping when magnified would
+ *    clear magnification and leave the screen in a not magnified state.
+ *
+ * 2. Triple tap and hold would magnify the screen if not magnified and enable
+ *    viewport dragging mode until the finger goes up. One can think of this
+ *    mode as a way to move the magnified viewport since the area around the
+ *    moving finger will be magnified to fit the screen. For example, if the
+ *    screen was not magnified and the user triple taps and holds the screen
+ *    would magnify and the viewport will follow the user's finger. When the
+ *    finger goes up the screen will clear zoom out. If the same user interaction
+ *    is performed when the screen is magnified, the viewport movement will
+ *    be the same but when the finger goes up the screen will stay magnified.
+ *    In other words, the initial magnified state is sticky.
+ *
+ * 3. Pinching with any number of additional fingers when viewport dragging
+ *    is enabled, i.e. the user triple tapped and holds, would adjust the
+ *    magnification scale which will become the current default magnification
+ *    scale. The next time the user magnifies the same magnification scale
+ *    would be used.
+ *
+ * 4. When in a permanent magnified state the user can use two or more fingers
+ *    to pan the viewport. Note that in this mode the content is panned as
+ *    opposed to the viewport dragging mode in which the viewport is moved.
+ *
+ * 5. When in a permanent magnified state the user can use three or more
+ *    fingers to change the magnification scale which will become the current
+ *    default magnification scale. The next time the user magnifies the same
+ *    magnification scale would be used.
+ *
+ * 6. The magnification scale will be persisted in settings and in the cloud.
+ */
+public final class ScreenMagnifier implements EventStreamTransformation {
+
+    private static final boolean DEBUG_STATE_TRANSITIONS = false;
+    private static final boolean DEBUG_DETECTING = false;
+    private static final boolean DEBUG_TRANSFORMATION = false;
+    private static final boolean DEBUG_PANNING = false;
+    private static final boolean DEBUG_SCALING = false;
+    private static final boolean DEBUG_VIEWPORT_WINDOW = false;
+    private static final boolean DEBUG_WINDOW_TRANSITIONS = false;
+    private static final boolean DEBUG_ROTATION = false;
+    private static final boolean DEBUG_GESTURE_DETECTOR = false;
+    private static final boolean DEBUG_MAGNIFICATION_CONTROLLER = false;
+
+    private static final String LOG_TAG = ScreenMagnifier.class.getSimpleName();
+
+    private static final int STATE_DELEGATING = 1;
+    private static final int STATE_DETECTING = 2;
+    private static final int STATE_SCALING = 3;
+    private static final int STATE_VIEWPORT_DRAGGING = 4;
+    private static final int STATE_PANNING = 5;
+    private static final int STATE_DECIDE_PAN_OR_SCALE = 6;
+
+    private static final float DEFAULT_MAGNIFICATION_SCALE = 2.0f;
+    private static final int DEFAULT_SCREEN_MAGNIFICATION_AUTO_UPDATE = 1;
+    private static final float DEFAULT_WINDOW_ANIMATION_SCALE = 1.0f;
+
+    private final IWindowManager mWindowManagerService = IWindowManager.Stub.asInterface(
+            ServiceManager.getService("window"));
+    private final WindowManager mWindowManager;
+    private final DisplayProvider mDisplayProvider;
+
+    private final DetectingStateHandler mDetectingStateHandler = new DetectingStateHandler();
+    private final GestureDetector mGestureDetector;
+    private final StateViewportDraggingHandler mStateViewportDraggingHandler =
+            new StateViewportDraggingHandler();
+
+    private final Interpolator mInterpolator = new DecelerateInterpolator(2.5f);
+
+    private final MagnificationController mMagnificationController;
+    private final DisplayContentObserver mDisplayContentObserver;
+    private final Viewport mViewport;
+
+    private final int mTapTimeSlop = ViewConfiguration.getTapTimeout();
+    private final int mMultiTapTimeSlop = ViewConfiguration.getDoubleTapTimeout();
+    private final int mTapDistanceSlop;
+    private final int mMultiTapDistanceSlop;
+
+    private final int mShortAnimationDuration;
+    private final int mLongAnimationDuration;
+    private final float mWindowAnimationScale;
+
+    private final Context mContext;
+
+    private EventStreamTransformation mNext;
+
+    private int mCurrentState;
+    private boolean mTranslationEnabledBeforePan;
+
+    private PointerCoords[] mTempPointerCoords;
+    private PointerProperties[] mTempPointerProperties;
+
+    public ScreenMagnifier(Context context) {
+        mContext = context;
+        mWindowManager = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
+
+        mShortAnimationDuration = context.getResources().getInteger(
+                com.android.internal.R.integer.config_shortAnimTime);
+        mLongAnimationDuration = context.getResources().getInteger(
+                com.android.internal.R.integer.config_longAnimTime);
+        mTapDistanceSlop = ViewConfiguration.get(context).getScaledTouchSlop();
+        mMultiTapDistanceSlop = ViewConfiguration.get(context).getScaledDoubleTapSlop();
+        mWindowAnimationScale = Settings.System.getFloat(context.getContentResolver(),
+                Settings.System.WINDOW_ANIMATION_SCALE, DEFAULT_WINDOW_ANIMATION_SCALE);
+
+        mMagnificationController = new MagnificationController(mShortAnimationDuration);
+        mDisplayProvider = new DisplayProvider(context, mWindowManager);
+        mViewport = new Viewport(mContext, mWindowManager, mWindowManagerService,
+                mDisplayProvider, mInterpolator, mShortAnimationDuration);
+        mDisplayContentObserver = new DisplayContentObserver(mContext, mViewport,
+                mMagnificationController, mWindowManagerService, mDisplayProvider,
+                mLongAnimationDuration, mWindowAnimationScale);
+
+        mGestureDetector = new GestureDetector(context);
+
+        transitionToState(STATE_DETECTING);
+    }
+
+    @Override
+    public void onMotionEvent(MotionEvent event, int policyFlags) {
+        switch (mCurrentState) {
+            case STATE_DELEGATING: {
+                handleMotionEventStateDelegating(event, policyFlags);
+            } break;
+            case STATE_DETECTING: {
+                mDetectingStateHandler.onMotionEvent(event, policyFlags);
+            } break;
+            case STATE_VIEWPORT_DRAGGING: {
+                mStateViewportDraggingHandler.onMotionEvent(event, policyFlags);
+            } break;
+            case STATE_SCALING:
+            case STATE_PANNING:
+            case STATE_DECIDE_PAN_OR_SCALE: {
+                // Handled by the gesture detector. Since the detector
+                // needs all touch events to work properly we cannot
+                // call it only for these states.
+            } break;
+            default: {
+                throw new IllegalStateException("Unknown state: " + mCurrentState);
+            }
+        }
+        mGestureDetector.onMotionEvent(event);
+    }
+
+    @Override
+    public void onAccessibilityEvent(AccessibilityEvent event) {
+        if (mNext != null) {
+            mNext.onAccessibilityEvent(event);
+        }
+    }
+
+    @Override
+    public void setNext(EventStreamTransformation next) {
+        mNext = next;
+    }
+
+    @Override
+    public void clear() {
+        mCurrentState = STATE_DETECTING;
+        mDetectingStateHandler.clear();
+        mStateViewportDraggingHandler.clear();
+        mGestureDetector.clear();
+        if (mNext != null) {
+            mNext.clear();
+        }
+    }
+
+    @Override
+    public void onDestroy() {
+        mMagnificationController.setScaleAndMagnifiedRegionCenter(1.0f,
+                0, 0, true);
+        mViewport.setFrameShown(false, true);
+        mDisplayProvider.destroy();
+        mDisplayContentObserver.destroy();
+    }
+
+    private void handleMotionEventStateDelegating(MotionEvent event, int policyFlags) {
+        if (event.getActionMasked() == MotionEvent.ACTION_UP) {
+            if (mDetectingStateHandler.mDelayedEventQueue == null) {
+                transitionToState(STATE_DETECTING);
+            }
+        }
+        if (mNext != null) {
+            // If the event is within the magnified portion of the screen we have
+            // to change its location to be where the user thinks he is poking the
+            // UI which may have been magnified and panned.
+            final float eventX = event.getX();
+            final float eventY = event.getY();
+            if (mMagnificationController.isMagnifying()
+                    && mViewport.getBounds().contains((int) eventX, (int) eventY)) {
+                final float scale = mMagnificationController.getScale();
+                final float scaledOffsetX = mMagnificationController.getScaledOffsetX();
+                final float scaledOffsetY = mMagnificationController.getScaledOffsetY();
+                final int pointerCount = event.getPointerCount();
+                PointerCoords[] coords = getTempPointerCoordsWithMinSize(pointerCount);
+                PointerProperties[] properties = getTempPointerPropertiesWithMinSize(pointerCount);
+                for (int i = 0; i < pointerCount; i++) {
+                    event.getPointerCoords(i, coords[i]);
+                    coords[i].x = (coords[i].x - scaledOffsetX) / scale;
+                    coords[i].y = (coords[i].y - scaledOffsetY) / scale;
+                    event.getPointerProperties(i, properties[i]);
+                }
+                event = MotionEvent.obtain(event.getDownTime(),
+                        event.getEventTime(), event.getAction(), pointerCount, properties,
+                        coords, 0, 0, 1.0f, 1.0f, event.getDeviceId(), 0, event.getSource(),
+                        event.getFlags());
+            }
+            mNext.onMotionEvent(event, policyFlags);
+        }
+    }
+
+    private PointerCoords[] getTempPointerCoordsWithMinSize(int size) {
+        final int oldSize = (mTempPointerCoords != null) ? mTempPointerCoords.length : 0;
+        if (oldSize < size) {
+            PointerCoords[] oldTempPointerCoords = mTempPointerCoords;
+            mTempPointerCoords = new PointerCoords[size];
+            if (oldTempPointerCoords != null) {
+                System.arraycopy(oldTempPointerCoords, 0, mTempPointerCoords, 0, oldSize);
+            }
+        }
+        for (int i = oldSize; i < size; i++) {
+            mTempPointerCoords[i] = new PointerCoords();
+        }
+        return mTempPointerCoords;
+    }
+
+    private PointerProperties[] getTempPointerPropertiesWithMinSize(int size) {
+        final int oldSize = (mTempPointerProperties != null) ? mTempPointerProperties.length : 0;
+        if (oldSize < size) {
+            PointerProperties[] oldTempPointerProperties = mTempPointerProperties;
+            mTempPointerProperties = new PointerProperties[size];
+            if (oldTempPointerProperties != null) {
+                System.arraycopy(oldTempPointerProperties, 0, mTempPointerProperties, 0, oldSize);
+            }
+        }
+        for (int i = oldSize; i < size; i++) {
+            mTempPointerProperties[i] = new PointerProperties();
+        }
+        return mTempPointerProperties;
+    }
+    
+    private void transitionToState(int state) {
+        if (DEBUG_STATE_TRANSITIONS) {
+            switch (state) {
+                case STATE_DELEGATING: {
+                    Slog.i(LOG_TAG, "mCurrentState: STATE_DELEGATING");
+                } break;
+                case STATE_DETECTING: {
+                    Slog.i(LOG_TAG, "mCurrentState: STATE_DETECTING");
+                } break;
+                case STATE_VIEWPORT_DRAGGING: {
+                    Slog.i(LOG_TAG, "mCurrentState: STATE_VIEWPORT_DRAGGING");
+                } break;
+                case STATE_SCALING: {
+                    Slog.i(LOG_TAG, "mCurrentState: STATE_SCALING");
+                } break;
+                case STATE_PANNING: {
+                    Slog.i(LOG_TAG, "mCurrentState: STATE_PANNING");
+                } break;
+                case STATE_DECIDE_PAN_OR_SCALE: {
+                    Slog.i(LOG_TAG, "mCurrentState: STATE_DECIDE_PAN_OR_SCALE");
+                } break;
+                default: {
+                    throw new IllegalArgumentException("Unknown state: " + state);
+                }
+            }
+        }
+        mCurrentState = state;
+    }
+
+    private final class GestureDetector implements OnScaleGestureListener {
+        private static final float MIN_SCALE = 1.3f;
+        private static final float MAX_SCALE = 5.0f;
+
+        private static final float DETECT_SCALING_THRESHOLD = 0.25f;
+        private static final int DETECT_PANNING_THRESHOLD_DIP = 30;
+
+        private final float mScaledDetectPanningThreshold;
+
+        private final ScaleGestureDetector mScaleGestureDetector;
+
+        private final PointF mPrevFocus = new PointF(Float.NaN, Float.NaN);
+        private final PointF mInitialFocus = new PointF(Float.NaN, Float.NaN);
+
+        private float mCurrScale = Float.NaN;
+        private float mCurrScaleFactor = 1.0f;
+        private float mPrevScaleFactor = 1.0f;
+        private float mCurrPan;
+        private float mPrevPan;
+
+        private float mScaleFocusX = Float.NaN;
+        private float mScaleFocusY = Float.NaN;
+
+        public GestureDetector(Context context) {
+            final float density = context.getResources().getDisplayMetrics().density;
+            mScaledDetectPanningThreshold = DETECT_PANNING_THRESHOLD_DIP * density;
+            mScaleGestureDetector = new ScaleGestureDetector(context, this);
+        }
+
+        public void onMotionEvent(MotionEvent event) {
+            mScaleGestureDetector.onTouchEvent(event);
+            switch (mCurrentState) {
+                case STATE_DETECTING:
+                case STATE_DELEGATING:
+                case STATE_VIEWPORT_DRAGGING: {
+                    return;
+                }
+            }
+            if (event.getActionMasked() == MotionEvent.ACTION_UP) {
+                clear();
+                if (mCurrentState == STATE_SCALING) {
+                    persistScale(mMagnificationController.getScale());
+                }
+                transitionToState(STATE_DETECTING);
+            }
+        }
+
+        @Override
+        public boolean onScale(ScaleGestureDetector detector) {
+            switch (mCurrentState) {
+                case STATE_DETECTING:
+                case STATE_DELEGATING:
+                case STATE_VIEWPORT_DRAGGING: {
+                    return true;
+                }
+                case STATE_DECIDE_PAN_OR_SCALE: {
+                    mCurrScaleFactor = mScaleGestureDetector.getScaleFactor();
+                    final float scaleDelta = Math.abs(1.0f - mCurrScaleFactor * mPrevScaleFactor);
+                    if (DEBUG_GESTURE_DETECTOR) {
+                        Slog.i(LOG_TAG, "scaleDelta: " + scaleDelta);
+                    }
+                    if (scaleDelta > DETECT_SCALING_THRESHOLD) {
+                        performScale(detector, true);
+                        clear();
+                        transitionToState(STATE_SCALING);
+                        return false;
+                    }
+                    mCurrPan = (float) MathUtils.dist(
+                            mScaleGestureDetector.getFocusX(),
+                            mScaleGestureDetector.getFocusY(),
+                            mInitialFocus.x, mInitialFocus.y);
+                    final float panDelta = mCurrPan + mPrevPan;
+                    if (DEBUG_GESTURE_DETECTOR) {
+                        Slog.i(LOG_TAG, "panDelta: " + panDelta);
+                    }
+                    if (panDelta > mScaledDetectPanningThreshold) {
+                        performPan(detector, true);
+                        clear();
+                        transitionToState(STATE_PANNING);
+                        return false;
+                    }
+                } break;
+                case STATE_SCALING: {
+                    performScale(detector, false);
+                } break;
+                case STATE_PANNING: {
+                    performPan(detector, false);
+                } break;
+            }
+            return false;
+        }
+
+        @Override
+        public boolean onScaleBegin(ScaleGestureDetector detector) {
+            switch (mCurrentState) {
+                case STATE_DECIDE_PAN_OR_SCALE: {
+                    mPrevScaleFactor *= mCurrScaleFactor;
+                    mPrevPan += mCurrPan;
+                    mPrevFocus.x = mInitialFocus.x = detector.getFocusX();
+                    mPrevFocus.y = mInitialFocus.y = detector.getFocusY();
+                } break;
+                case STATE_SCALING: {
+                    mPrevScaleFactor = 1.0f;
+                    mCurrScale = Float.NaN;
+                } break;
+                case STATE_PANNING: {
+                    mPrevPan += mCurrPan;
+                    mPrevFocus.x = mInitialFocus.x = detector.getFocusX();
+                    mPrevFocus.y = mInitialFocus.y = detector.getFocusY();
+                } break;
+            }
+            return true;
+        }
+
+        @Override
+        public void onScaleEnd(ScaleGestureDetector detector) {
+            /* do nothing */
+        }
+
+        public void clear() {
+            mCurrScaleFactor = 1.0f;
+            mPrevScaleFactor = 1.0f;
+            mPrevPan = 0;
+            mCurrPan = 0;
+            mInitialFocus.set(Float.NaN, Float.NaN);
+            mPrevFocus.set(Float.NaN, Float.NaN);
+            mCurrScale = Float.NaN;
+            mScaleFocusX = Float.NaN;
+            mScaleFocusY = Float.NaN;
+        }
+
+        private void performPan(ScaleGestureDetector detector, boolean animate) {
+            if (Float.compare(mPrevFocus.x, Float.NaN) == 0
+                    && Float.compare(mPrevFocus.y, Float.NaN) == 0) {
+                mPrevFocus.set(detector.getFocusX(), detector.getFocusY());
+                return;
+            }
+            final float scale = mMagnificationController.getScale();
+            final float scrollX = (detector.getFocusX() - mPrevFocus.x) / scale;
+            final float scrollY = (detector.getFocusY() - mPrevFocus.y) / scale;
+            final float centerX = mMagnificationController.getMagnifiedRegionCenterX()
+                    - scrollX;
+            final float centerY = mMagnificationController.getMagnifiedRegionCenterY()
+                    - scrollY;
+            if (DEBUG_PANNING) {
+                Slog.i(LOG_TAG, "Panned content by scrollX: " + scrollX
+                        + " scrollY: " + scrollY);
+            }
+            mMagnificationController.setMagnifiedRegionCenter(centerX, centerY, animate);
+            mPrevFocus.set(detector.getFocusX(), detector.getFocusY());
+        }
+
+        private void performScale(ScaleGestureDetector detector, boolean animate) {
+            if (Float.compare(mCurrScale, Float.NaN) == 0) {
+                mCurrScale = mMagnificationController.getScale();
+                return;
+            }
+            final float totalScaleFactor = mPrevScaleFactor * detector.getScaleFactor();
+            final float newScale = mCurrScale * totalScaleFactor;
+            final float normalizedNewScale = Math.min(Math.max(newScale, MIN_SCALE),
+                    MAX_SCALE);
+            if (DEBUG_SCALING) {
+                Slog.i(LOG_TAG, "normalizedNewScale: " + normalizedNewScale);
+            }
+            if (Float.compare(mScaleFocusX, Float.NaN) == 0
+                    && Float.compare(mScaleFocusY, Float.NaN) == 0) {
+                mScaleFocusX = detector.getFocusX();
+                mScaleFocusY = detector.getFocusY();
+            }
+            mMagnificationController.setScale(normalizedNewScale, mScaleFocusX,
+                    mScaleFocusY, animate);
+        }
+    }
+
+    private final class StateViewportDraggingHandler {
+        private boolean mLastMoveOutsideMagnifiedRegion;
+
+        private void onMotionEvent(MotionEvent event, int policyFlags) {
+            final int action = event.getActionMasked();
+            switch (action) {
+                case MotionEvent.ACTION_DOWN: {
+                    throw new IllegalArgumentException("Unexpected event type: ACTION_DOWN");
+                }
+                case MotionEvent.ACTION_POINTER_DOWN: {
+                    clear();
+                    transitionToState(STATE_SCALING);
+                } break;
+                case MotionEvent.ACTION_MOVE: {
+                    if (event.getPointerCount() != 1) {
+                        throw new IllegalStateException("Should have one pointer down.");
+                    }
+                    final float eventX = event.getX();
+                    final float eventY = event.getY();
+                    if (mViewport.getBounds().contains((int) eventX, (int) eventY)) {
+                        if (mLastMoveOutsideMagnifiedRegion) {
+                            mLastMoveOutsideMagnifiedRegion = false;
+                            mMagnificationController.setMagnifiedRegionCenter(eventX,
+                                    eventY, true);
+                        } else {
+                            mMagnificationController.setMagnifiedRegionCenter(eventX,
+                                    eventY, false);
+                        }
+                    } else {
+                        mLastMoveOutsideMagnifiedRegion = true;
+                    }
+                } break;
+                case MotionEvent.ACTION_UP: {
+                    if (!mTranslationEnabledBeforePan) {
+                        mMagnificationController.reset(true);
+                        mViewport.setFrameShown(false, true);
+                    }
+                    clear();
+                    transitionToState(STATE_DETECTING);
+                } break;
+                case MotionEvent.ACTION_POINTER_UP: {
+                    throw new IllegalArgumentException("Unexpected event type: ACTION_POINTER_UP");
+                }
+            }
+        }
+
+        public void clear() {
+            mLastMoveOutsideMagnifiedRegion = false;
+        }
+    }
+
+    private final class DetectingStateHandler {
+
+        private static final int MESSAGE_ON_ACTION_TAP_AND_HOLD = 1;
+
+        private static final int MESSAGE_TRANSITION_TO_DELEGATING_STATE = 2;
+
+        private static final int ACTION_TAP_COUNT = 3;
+
+        private MotionEventInfo mDelayedEventQueue;
+
+        private MotionEvent mLastDownEvent;
+        private MotionEvent mLastTapUpEvent;
+        private int mTapCount;
+
+        private final Handler mHandler = new Handler() {
+            @Override
+            public void handleMessage(Message message) {
+                final int type = message.what;
+                switch (type) {
+                    case MESSAGE_ON_ACTION_TAP_AND_HOLD: {
+                        MotionEvent event = (MotionEvent) message.obj;
+                        final int policyFlags = message.arg1;
+                        onActionTapAndHold(event, policyFlags);
+                    } break;
+                    case MESSAGE_TRANSITION_TO_DELEGATING_STATE: {
+                        transitionToState(STATE_DELEGATING);
+                        sendDelayedMotionEvents();
+                        clear();
+                    } break;
+                    default: {
+                        throw new IllegalArgumentException("Unknown message type: " + type);
+                    }
+                }
+            }
+        };
+
+        public void onMotionEvent(MotionEvent event, int policyFlags) {
+            cacheDelayedMotionEvent(event, policyFlags);
+            final int action = event.getActionMasked();
+            switch (action) {
+                case MotionEvent.ACTION_DOWN: {
+                    mHandler.removeMessages(MESSAGE_TRANSITION_TO_DELEGATING_STATE);
+                    if (!mViewport.getBounds().contains((int) event.getX(),
+                            (int) event.getY())) {
+                        transitionToDelegatingStateAndClear();
+                        return;
+                    }
+                    if (mTapCount == ACTION_TAP_COUNT - 1 && mLastDownEvent != null
+                            && GestureUtils.isMultiTap(mLastDownEvent, event,
+                                    mMultiTapTimeSlop, mMultiTapDistanceSlop, 0)) {
+                        Message message = mHandler.obtainMessage(MESSAGE_ON_ACTION_TAP_AND_HOLD,
+                                policyFlags, 0, event);
+                        mHandler.sendMessageDelayed(message,
+                                ViewConfiguration.getLongPressTimeout());
+                    } else if (mTapCount < ACTION_TAP_COUNT) {
+                        Message message = mHandler.obtainMessage(
+                                MESSAGE_TRANSITION_TO_DELEGATING_STATE);
+                        mHandler.sendMessageDelayed(message, mTapTimeSlop + mMultiTapDistanceSlop);
+                    }
+                    clearLastDownEvent();
+                    mLastDownEvent = MotionEvent.obtain(event);
+                } break;
+                case MotionEvent.ACTION_POINTER_DOWN: {
+                    if (mMagnificationController.isMagnifying()) {
+                        transitionToState(STATE_DECIDE_PAN_OR_SCALE);
+                        clear();
+                    } else {
+                        transitionToDelegatingStateAndClear();
+                    }
+                } break;
+                case MotionEvent.ACTION_MOVE: {
+                    if (mLastDownEvent != null && mTapCount < ACTION_TAP_COUNT - 1) {
+                        final double distance = GestureUtils.computeDistance(mLastDownEvent,
+                                event, 0);
+                        if (Math.abs(distance) > mTapDistanceSlop) {
+                            transitionToDelegatingStateAndClear();
+                        }
+                    }
+                } break;
+                case MotionEvent.ACTION_UP: {
+                    if (mLastDownEvent == null) {
+                        return;
+                    }
+                    mHandler.removeMessages(MESSAGE_ON_ACTION_TAP_AND_HOLD);
+                    if (!mViewport.getBounds().contains((int) event.getX(), (int) event.getY())) {
+                         transitionToDelegatingStateAndClear();
+                         return;
+                    }
+                    if (!GestureUtils.isTap(mLastDownEvent, event, mTapTimeSlop,
+                            mTapDistanceSlop, 0)) {
+                        transitionToDelegatingStateAndClear();
+                        return;
+                    }
+                    if (mLastTapUpEvent != null && !GestureUtils.isMultiTap(mLastTapUpEvent,
+                            event, mMultiTapTimeSlop, mMultiTapDistanceSlop, 0)) {
+                        transitionToDelegatingStateAndClear();
+                        return;
+                    }
+                    mTapCount++;
+                    if (DEBUG_DETECTING) {
+                        Slog.i(LOG_TAG, "Tap count:" + mTapCount);
+                    }
+                    if (mTapCount == ACTION_TAP_COUNT) {
+                        clear();
+                        onActionTap(event, policyFlags);
+                        return;
+                    }
+                    clearLastTapUpEvent();
+                    mLastTapUpEvent = MotionEvent.obtain(event);
+                } break;
+                case MotionEvent.ACTION_POINTER_UP: {
+                    /* do nothing */
+                } break;
+            }
+        }
+
+        public void clear() {
+            mHandler.removeMessages(MESSAGE_ON_ACTION_TAP_AND_HOLD);
+            mHandler.removeMessages(MESSAGE_TRANSITION_TO_DELEGATING_STATE);
+            clearTapDetectionState();
+            clearDelayedMotionEvents();
+        }
+
+        private void clearTapDetectionState() {
+            mTapCount = 0;
+            clearLastTapUpEvent();
+            clearLastDownEvent();
+        }
+
+        private void clearLastTapUpEvent() {
+            if (mLastTapUpEvent != null) {
+                mLastTapUpEvent.recycle();
+                mLastTapUpEvent = null;
+            }
+        }
+
+        private void clearLastDownEvent() {
+            if (mLastDownEvent != null) {
+                mLastDownEvent.recycle();
+                mLastDownEvent = null;
+            }
+        }
+
+        private void cacheDelayedMotionEvent(MotionEvent event, int policyFlags) {
+            MotionEventInfo info = MotionEventInfo.obtain(event, policyFlags);
+            if (mDelayedEventQueue == null) {
+                mDelayedEventQueue = info;
+            } else {
+                MotionEventInfo tail = mDelayedEventQueue;
+                while (tail.mNext != null) {
+                    tail = tail.mNext;
+                }
+                tail.mNext = info;
+            }
+        }
+
+        private void sendDelayedMotionEvents() {
+            while (mDelayedEventQueue != null) {
+                MotionEventInfo info = mDelayedEventQueue;
+                mDelayedEventQueue = info.mNext;
+                ScreenMagnifier.this.onMotionEvent(info.mEvent, info.mPolicyFlags);
+                info.recycle();
+            }
+        }
+
+        private void clearDelayedMotionEvents() {
+            while (mDelayedEventQueue != null) {
+                MotionEventInfo info = mDelayedEventQueue;
+                mDelayedEventQueue = info.mNext;
+                info.recycle();
+            }
+        }
+
+        private void transitionToDelegatingStateAndClear() {
+            transitionToState(STATE_DELEGATING);
+            sendDelayedMotionEvents();
+            clear();
+        }
+
+        private void onActionTap(MotionEvent up, int policyFlags) {
+            if (DEBUG_DETECTING) {
+                Slog.i(LOG_TAG, "onActionTap()");
+            }
+            if (!mMagnificationController.isMagnifying()) {
+                mMagnificationController.setScaleAndMagnifiedRegionCenter(getPersistedScale(),
+                        up.getX(), up.getY(), true);
+                mViewport.setFrameShown(true, true);
+            } else {
+                mMagnificationController.reset(true);
+                mViewport.setFrameShown(false, true);
+            }
+        }
+
+        private void onActionTapAndHold(MotionEvent down, int policyFlags) {
+            if (DEBUG_DETECTING) {
+                Slog.i(LOG_TAG, "onActionTapAndHold()");
+            }
+            clear();
+            mTranslationEnabledBeforePan = mMagnificationController.isMagnifying();
+            mMagnificationController.setScaleAndMagnifiedRegionCenter(getPersistedScale(),
+                    down.getX(), down.getY(), true);
+            mViewport.setFrameShown(true, true);
+            transitionToState(STATE_VIEWPORT_DRAGGING);
+        }
+    }
+
+    private void persistScale(final float scale) {
+        new AsyncTask<Void, Void, Void>() {
+            @Override
+            protected Void doInBackground(Void... params) {
+                Settings.Secure.putFloat(mContext.getContentResolver(),
+                        Settings.Secure.ACCESSIBILITY_DISPLAY_MAGNIFICATION_SCALE, scale);
+                return null;
+            }
+        }.execute();
+    }
+
+    private float getPersistedScale() {
+        return Settings.Secure.getFloat(mContext.getContentResolver(),
+                Settings.Secure.ACCESSIBILITY_DISPLAY_MAGNIFICATION_SCALE,
+                DEFAULT_MAGNIFICATION_SCALE);
+    }
+
+    private static final class MotionEventInfo {
+
+        private static final int MAX_POOL_SIZE = 10;
+
+        private static final Object sLock = new Object();
+        private static MotionEventInfo sPool;
+        private static int sPoolSize;
+
+        private MotionEventInfo mNext;
+        private boolean mInPool;
+
+        public MotionEvent mEvent;
+        public int mPolicyFlags;
+
+        public static MotionEventInfo obtain(MotionEvent event, int policyFlags) {
+            synchronized (sLock) {
+                MotionEventInfo info;
+                if (sPoolSize > 0) {
+                    sPoolSize--;
+                    info = sPool;
+                    sPool = info.mNext;
+                    info.mNext = null;
+                    info.mInPool = false;
+                } else {
+                    info = new MotionEventInfo();
+                }
+                info.initialize(event, policyFlags);
+                return info;
+            }
+        }
+
+        private void initialize(MotionEvent event, int policyFlags) {
+            mEvent = MotionEvent.obtain(event);
+            mPolicyFlags = policyFlags;
+        }
+
+        public void recycle() {
+            synchronized (sLock) {
+                if (mInPool) {
+                    throw new IllegalStateException("Already recycled.");
+                }
+                clear();
+                if (sPoolSize < MAX_POOL_SIZE) {
+                    sPoolSize++;
+                    mNext = sPool;
+                    sPool = this;
+                    mInPool = true;
+                }
+            }
+        }
+
+        private void clear() {
+            mEvent.recycle();
+            mEvent = null;
+            mPolicyFlags = 0;
+        }
+    }
+
+    private static final class DisplayContentObserver {
+
+        private static final int MESSAGE_SHOW_VIEWPORT_FRAME = 1;
+        private static final int MESSAGE_RECOMPUTE_VIEWPORT_BOUNDS = 2;
+        private static final int MESSAGE_ON_RECTANGLE_ON_SCREEN_REQUESTED = 3;
+        private static final int MESSAGE_ON_WINDOW_TRANSITION = 4;
+        private static final int MESSAGE_ON_ROTATION_CHANGED = 5;
+
+        private final Handler mHandler = new MyHandler();
+
+        private final Rect mTempRect = new Rect();
+
+        private final IDisplayContentChangeListener mDisplayContentChangeListener;
+
+        private final Context mContext;
+        private final Viewport mViewport;
+        private final MagnificationController mMagnificationController;
+        private final IWindowManager mWindowManagerService;
+        private final DisplayProvider mDisplayProvider;
+        private final long mLongAnimationDuration;
+        private final float mWindowAnimationScale;
+
+        public DisplayContentObserver(Context context, Viewport viewport,
+                MagnificationController magnificationController,
+                IWindowManager windowManagerService, DisplayProvider displayProvider,
+                long longAnimationDuration, float windowAnimationScale) {
+            mContext = context;
+            mViewport = viewport;
+            mMagnificationController = magnificationController;
+            mWindowManagerService = windowManagerService;
+            mDisplayProvider = displayProvider;
+            mLongAnimationDuration = longAnimationDuration;
+            mWindowAnimationScale = windowAnimationScale;
+
+            mDisplayContentChangeListener = new IDisplayContentChangeListener.Stub() {
+                @Override
+                public void onWindowTransition(int displayId, int transition, WindowInfo info) {
+                    mHandler.obtainMessage(MESSAGE_ON_WINDOW_TRANSITION, transition, 0,
+                            WindowInfo.obtain(info)).sendToTarget();
+                }
+
+                @Override
+                public void onRectangleOnScreenRequested(int dsiplayId, Rect rectangle,
+                        boolean immediate) {
+                    SomeArgs args = SomeArgs.obtain();
+                    args.argi1 = rectangle.left;
+                    args.argi2 = rectangle.top;
+                    args.argi3 = rectangle.right;
+                    args.argi4 = rectangle.bottom;
+                    mHandler.obtainMessage(MESSAGE_ON_RECTANGLE_ON_SCREEN_REQUESTED, 0,
+                            immediate ? 1 : 0, args).sendToTarget();
+                }
+
+                @Override
+                public void onRotationChanged(int rotation) throws RemoteException {
+                    mHandler.obtainMessage(MESSAGE_ON_ROTATION_CHANGED, rotation, 0)
+                            .sendToTarget();
+                }
+            };
+
+            try {
+                mWindowManagerService.addDisplayContentChangeListener(
+                        mDisplayProvider.getDisplay().getDisplayId(),
+                        mDisplayContentChangeListener);
+            } catch (RemoteException re) {
+                /* ignore */
+            }
+        }
+
+        public void destroy() {
+            try {
+                mWindowManagerService.removeDisplayContentChangeListener(
+                        mDisplayProvider.getDisplay().getDisplayId(),
+                        mDisplayContentChangeListener);
+            } catch (RemoteException re) {
+                /* ignore*/
+            }
+        }
+
+        private void handleOnRotationChanged(int rotation) {
+            if (DEBUG_ROTATION) {
+                Slog.i(LOG_TAG, "Rotation: " + rotationToString(rotation));
+            }
+            resetMagnificationIfNeeded();
+            mViewport.setFrameShown(false, false);
+            mViewport.rotationChanged();
+            mViewport.recomputeBounds(false);
+            if (mMagnificationController.isMagnifying()) {
+                final long delay = (long) (2 * mLongAnimationDuration * mWindowAnimationScale);
+                Message message = mHandler.obtainMessage(MESSAGE_SHOW_VIEWPORT_FRAME);
+                mHandler.sendMessageDelayed(message, delay);
+            }
+        }
+
+        private void handleOnWindowTransition(int transition, WindowInfo info) {
+            if (DEBUG_WINDOW_TRANSITIONS) {
+                Slog.i(LOG_TAG, "Window transitioning: "
+                        + windowTransitionToString(transition));
+            }
+            try {
+                final boolean magnifying = mMagnificationController.isMagnifying();
+                if (magnifying) {
+                    switch (transition) {
+                        case WindowManagerPolicy.TRANSIT_ACTIVITY_OPEN:
+                        case WindowManagerPolicy.TRANSIT_TASK_OPEN:
+                        case WindowManagerPolicy.TRANSIT_TASK_TO_FRONT:
+                        case WindowManagerPolicy.TRANSIT_WALLPAPER_OPEN:
+                        case WindowManagerPolicy.TRANSIT_WALLPAPER_CLOSE:
+                        case WindowManagerPolicy.TRANSIT_WALLPAPER_INTRA_OPEN: {
+                            resetMagnificationIfNeeded();
+                        }
+                    }
+                }
+                if (info.type == WindowManager.LayoutParams.TYPE_NAVIGATION_BAR
+                        || info.type == WindowManager.LayoutParams.TYPE_INPUT_METHOD
+                        || info.type == WindowManager.LayoutParams.TYPE_INPUT_METHOD_DIALOG) {
+                    switch (transition) {
+                        case WindowManagerPolicy.TRANSIT_ENTER:
+                        case WindowManagerPolicy.TRANSIT_SHOW:
+                        case WindowManagerPolicy.TRANSIT_EXIT:
+                        case WindowManagerPolicy.TRANSIT_HIDE: {
+                            mViewport.recomputeBounds(mMagnificationController.isMagnifying());
+                        } break;
+                    }
+                } else {
+                    switch (transition) {
+                        case WindowManagerPolicy.TRANSIT_ENTER:
+                        case WindowManagerPolicy.TRANSIT_SHOW: {
+                            if (!magnifying || !screenMagnificationAutoUpdateEnabled(mContext)) {
+                                break;
+                            }
+                            final int type = info.type;
+                            switch (type) {
+                                // TODO: Are these all the windows we want to make
+                                //       visible when they appear on the screen?
+                                //       Do we need to take some of them out?
+                                case WindowManager.LayoutParams.TYPE_APPLICATION_PANEL:
+                                case WindowManager.LayoutParams.TYPE_APPLICATION_MEDIA:
+                                case WindowManager.LayoutParams.TYPE_APPLICATION_SUB_PANEL:
+                                case WindowManager.LayoutParams.TYPE_APPLICATION_ATTACHED_DIALOG:
+                                case WindowManager.LayoutParams.TYPE_SEARCH_BAR:
+                                case WindowManager.LayoutParams.TYPE_PHONE:
+                                case WindowManager.LayoutParams.TYPE_SYSTEM_ALERT:
+                                case WindowManager.LayoutParams.TYPE_TOAST:
+                                case WindowManager.LayoutParams.TYPE_SYSTEM_OVERLAY:
+                                case WindowManager.LayoutParams.TYPE_PRIORITY_PHONE:
+                                case WindowManager.LayoutParams.TYPE_SYSTEM_DIALOG:
+                                case WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG:
+                                case WindowManager.LayoutParams.TYPE_SYSTEM_ERROR:
+                                case WindowManager.LayoutParams.TYPE_VOLUME_OVERLAY:
+                                case WindowManager.LayoutParams.TYPE_NAVIGATION_BAR_PANEL: {
+                                    Rect magnifiedRegionBounds = mMagnificationController
+                                            .getMagnifiedRegionBounds();
+                                    Rect touchableRegion = info.touchableRegion;
+                                    if (!magnifiedRegionBounds.intersect(touchableRegion)) {
+                                        ensureRectangleInMagnifiedRegionBounds(
+                                                magnifiedRegionBounds, touchableRegion);
+                                    }
+                                } break;
+                            } break;
+                        }
+                    }
+                }
+            } finally {
+                if (info != null) {
+                    info.recycle();
+                }
+            }
+        }
+
+        private void handleOnRectangleOnScreenRequested(Rect rectangle, boolean immediate) {
+            if (!mMagnificationController.isMagnifying()) {
+                return;
+            }
+            Rect magnifiedRegionBounds = mMagnificationController.getMagnifiedRegionBounds();
+            if (magnifiedRegionBounds.contains(rectangle)) {
+                return;
+            }
+            ensureRectangleInMagnifiedRegionBounds(magnifiedRegionBounds, rectangle);
+        }
+
+        private void ensureRectangleInMagnifiedRegionBounds(Rect magnifiedRegionBounds,
+                Rect rectangle) {
+            if (!Rect.intersects(rectangle, mViewport.getBounds())) {
+                return;
+            }
+            final float scrollX;
+            final float scrollY;
+            if (rectangle.width() > magnifiedRegionBounds.width()) {
+                scrollX = rectangle.left - magnifiedRegionBounds.left;
+            } else if (rectangle.left < magnifiedRegionBounds.left) {
+                scrollX = rectangle.left - magnifiedRegionBounds.left;
+            } else if (rectangle.right > magnifiedRegionBounds.right) {
+                scrollX = rectangle.right - magnifiedRegionBounds.right;
+            } else {
+                scrollX = 0;
+            }
+            if (rectangle.height() > magnifiedRegionBounds.height()) {
+                scrollY = rectangle.top - magnifiedRegionBounds.top;
+            } else if (rectangle.top < magnifiedRegionBounds.top) {
+                scrollY = rectangle.top - magnifiedRegionBounds.top;
+            } else if (rectangle.bottom > magnifiedRegionBounds.bottom) {
+                scrollY = rectangle.bottom - magnifiedRegionBounds.bottom;
+            } else {
+                scrollY = 0;
+            }
+            final float viewportCenterX = mMagnificationController.getMagnifiedRegionCenterX()
+                    + scrollX;
+            final float viewportCenterY = mMagnificationController.getMagnifiedRegionCenterY()
+                    + scrollY;
+            mMagnificationController.setMagnifiedRegionCenter(viewportCenterX, viewportCenterY,
+                    true);
+        }
+
+        private void resetMagnificationIfNeeded() {
+            if (mMagnificationController.isMagnifying()
+                    && screenMagnificationAutoUpdateEnabled(mContext)) {
+                mMagnificationController.reset(true);
+                mViewport.setFrameShown(false, true);
+            }
+        }
+
+        private boolean screenMagnificationAutoUpdateEnabled(Context context) {
+            return (Settings.Secure.getInt(context.getContentResolver(),
+                    Settings.Secure.ACCESSIBILITY_DISPLAY_MAGNIFICATION_AUTO_UPDATE,
+                    DEFAULT_SCREEN_MAGNIFICATION_AUTO_UPDATE) == 1);
+        }
+
+        private String windowTransitionToString(int transition) {
+            switch (transition) {
+                case WindowManagerPolicy.TRANSIT_UNSET: {
+                    return "TRANSIT_UNSET";
+                }
+                case WindowManagerPolicy.TRANSIT_NONE: {
+                    return "TRANSIT_NONE";
+                }
+                case WindowManagerPolicy.TRANSIT_ENTER: {
+                    return "TRANSIT_ENTER";
+                }
+                case WindowManagerPolicy.TRANSIT_EXIT: {
+                    return "TRANSIT_EXIT";
+                }
+                case WindowManagerPolicy.TRANSIT_SHOW: {
+                    return "TRANSIT_SHOW";
+                }
+                case WindowManagerPolicy.TRANSIT_EXIT_MASK: {
+                    return "TRANSIT_EXIT_MASK";
+                }
+                case WindowManagerPolicy.TRANSIT_PREVIEW_DONE: {
+                    return "TRANSIT_PREVIEW_DONE";
+                }
+                case WindowManagerPolicy.TRANSIT_ACTIVITY_OPEN: {
+                    return "TRANSIT_ACTIVITY_OPEN";
+                }
+                case WindowManagerPolicy.TRANSIT_ACTIVITY_CLOSE: {
+                    return "TRANSIT_ACTIVITY_CLOSE";
+                }
+                case WindowManagerPolicy.TRANSIT_TASK_OPEN: {
+                    return "TRANSIT_TASK_OPEN";
+                }
+                case WindowManagerPolicy.TRANSIT_TASK_CLOSE: {
+                    return "TRANSIT_TASK_CLOSE";
+                }
+                case WindowManagerPolicy.TRANSIT_TASK_TO_FRONT: {
+                    return "TRANSIT_TASK_TO_FRONT";
+                }
+                case WindowManagerPolicy.TRANSIT_TASK_TO_BACK: {
+                    return "TRANSIT_TASK_TO_BACK";
+                }
+                case WindowManagerPolicy.TRANSIT_WALLPAPER_CLOSE: {
+                    return "TRANSIT_WALLPAPER_CLOSE";
+                }
+                case WindowManagerPolicy.TRANSIT_WALLPAPER_OPEN: {
+                    return "TRANSIT_WALLPAPER_OPEN";
+                }
+                case WindowManagerPolicy.TRANSIT_WALLPAPER_INTRA_OPEN: {
+                    return "TRANSIT_WALLPAPER_INTRA_OPEN";
+                }
+                case WindowManagerPolicy.TRANSIT_WALLPAPER_INTRA_CLOSE: {
+                    return "TRANSIT_WALLPAPER_INTRA_CLOSE";
+                }
+                default: {
+                    return "<UNKNOWN>";
+                }
+            }
+        }
+
+        private String rotationToString(int rotation) {
+            switch (rotation) {
+                case Surface.ROTATION_0: {
+                    return "ROTATION_0";
+                }
+                case Surface.ROTATION_90: {
+                    return "ROATATION_90";
+                }
+                case Surface.ROTATION_180: {
+                    return "ROATATION_180";
+                }
+                case Surface.ROTATION_270: {
+                    return "ROATATION_270";
+                }
+                default: {
+                    throw new IllegalArgumentException("Invalid rotation: "
+                        + rotation);
+                }
+            }
+        }
+
+        private final class MyHandler extends Handler {
+            @Override
+            public void handleMessage(Message message) {
+                final int action = message.what;
+                switch (action) {
+                    case MESSAGE_SHOW_VIEWPORT_FRAME: {
+                        mViewport.setFrameShown(true, true);
+                    } break;
+                    case MESSAGE_RECOMPUTE_VIEWPORT_BOUNDS: {
+                        final boolean animate = message.arg1 == 1;
+                        mViewport.recomputeBounds(animate);
+                    } break;
+                    case MESSAGE_ON_RECTANGLE_ON_SCREEN_REQUESTED: {
+                        SomeArgs args = (SomeArgs) message.obj;
+                        try {
+                            mTempRect.set(args.argi1, args.argi2, args.argi3, args.argi4);
+                            final boolean immediate = (message.arg1 == 1);
+                            handleOnRectangleOnScreenRequested(mTempRect, immediate);
+                        } finally {
+                            args.recycle();
+                        }
+                    } break;
+                    case MESSAGE_ON_WINDOW_TRANSITION: {
+                        final int transition = message.arg1;
+                        WindowInfo info = (WindowInfo) message.obj;
+                        handleOnWindowTransition(transition, info);
+                    } break;
+                    case MESSAGE_ON_ROTATION_CHANGED: {
+                        final int rotation = message.arg1;
+                        handleOnRotationChanged(rotation);
+                    } break;
+                    default: {
+                        throw new IllegalArgumentException("Unknown message: " + action);
+                    }
+                }
+            }
+        }
+    }
+
+    private final class MagnificationController {
+
+        private static final String PROPERTY_NAME_ACCESSIBILITY_TRANSFORMATION =
+                "accessibilityTransformation";
+
+        private final MagnificationSpec mSentMagnificationSpec = new MagnificationSpec();
+
+        private final MagnificationSpec mCurrentMagnificationSpec = new MagnificationSpec();
+
+        private final Rect mTempRect = new Rect();
+
+        private final ValueAnimator mTransformationAnimator;
+
+        public MagnificationController(int animationDuration) {
+            Property<MagnificationController, MagnificationSpec> property =
+                    Property.of(MagnificationController.class, MagnificationSpec.class,
+                    PROPERTY_NAME_ACCESSIBILITY_TRANSFORMATION);
+            TypeEvaluator<MagnificationSpec> evaluator = new TypeEvaluator<MagnificationSpec>() {
+                private final MagnificationSpec mTempTransformationSpec = new MagnificationSpec();
+                @Override
+                public MagnificationSpec evaluate(float fraction, MagnificationSpec fromSpec,
+                        MagnificationSpec toSpec) {
+                    MagnificationSpec result = mTempTransformationSpec;
+                    result.mScale = fromSpec.mScale
+                            + (toSpec.mScale - fromSpec.mScale) * fraction;
+                    result.mMagnifiedRegionCenterX = fromSpec.mMagnifiedRegionCenterX
+                            + (toSpec.mMagnifiedRegionCenterX - fromSpec.mMagnifiedRegionCenterX)
+                            * fraction;
+                    result.mMagnifiedRegionCenterY = fromSpec.mMagnifiedRegionCenterY
+                            + (toSpec.mMagnifiedRegionCenterY - fromSpec.mMagnifiedRegionCenterY)
+                            * fraction;
+                    result.mScaledOffsetX = fromSpec.mScaledOffsetX
+                            + (toSpec.mScaledOffsetX - fromSpec.mScaledOffsetX)
+                            * fraction;
+                    result.mScaledOffsetY = fromSpec.mScaledOffsetY
+                            + (toSpec.mScaledOffsetY - fromSpec.mScaledOffsetY)
+                            * fraction;
+                    return result;
+                }
+            };
+            mTransformationAnimator = ObjectAnimator.ofObject(this, property,
+                    evaluator, mSentMagnificationSpec, mCurrentMagnificationSpec);
+            mTransformationAnimator.setDuration((long) (animationDuration));
+            mTransformationAnimator.setInterpolator(mInterpolator);
+        }
+
+        public boolean isMagnifying() {
+            return mCurrentMagnificationSpec.mScale > 1.0f;
+        }
+
+        public void reset(boolean animate) {
+            if (mTransformationAnimator.isRunning()) {
+                mTransformationAnimator.cancel();
+            }
+            mCurrentMagnificationSpec.reset();
+            if (animate) {
+                animateAccessibilityTranformation(mSentMagnificationSpec,
+                        mCurrentMagnificationSpec);
+            } else {
+                setAccessibilityTransformation(mCurrentMagnificationSpec);
+            }
+        }
+
+        public Rect getMagnifiedRegionBounds() {
+            mTempRect.set(mViewport.getBounds());
+            mTempRect.offset((int) -mCurrentMagnificationSpec.mScaledOffsetX,
+                    (int) -mCurrentMagnificationSpec.mScaledOffsetY);
+            mTempRect.scale(1.0f / mCurrentMagnificationSpec.mScale);
+            return mTempRect;
+        }
+
+        public float getScale() {
+            return mCurrentMagnificationSpec.mScale;
+        }
+
+        public float getMagnifiedRegionCenterX() {
+            return mCurrentMagnificationSpec.mMagnifiedRegionCenterX;
+        }
+
+        public float getMagnifiedRegionCenterY() {
+            return mCurrentMagnificationSpec.mMagnifiedRegionCenterY;
+        }
+
+        public float getScaledOffsetX() {
+            return mCurrentMagnificationSpec.mScaledOffsetX;
+        }
+
+        public float getScaledOffsetY() {
+            return mCurrentMagnificationSpec.mScaledOffsetY;
+        }
+
+        public void setScale(float scale, float pivotX, float pivotY, boolean animate) {
+            MagnificationSpec spec = mCurrentMagnificationSpec;
+            final float oldScale = spec.mScale;
+            final float oldCenterX = spec.mMagnifiedRegionCenterX;
+            final float oldCenterY = spec.mMagnifiedRegionCenterY;
+            final float normPivotX = (-spec.mScaledOffsetX + pivotX) / oldScale;
+            final float normPivotY = (-spec.mScaledOffsetY + pivotY) / oldScale;
+            final float offsetX = (oldCenterX - normPivotX) * (oldScale / scale);
+            final float offsetY = (oldCenterY - normPivotY) * (oldScale / scale);
+            final float centerX = normPivotX + offsetX;
+            final float centerY = normPivotY + offsetY;
+            setScaleAndMagnifiedRegionCenter(scale, centerX, centerY, animate);
+        }
+
+        public void setMagnifiedRegionCenter(float centerX, float centerY, boolean animate) {
+            setScaleAndMagnifiedRegionCenter(mCurrentMagnificationSpec.mScale, centerX, centerY,
+                    animate);
+        }
+
+        public void setScaleAndMagnifiedRegionCenter(float scale, float centerX, float centerY,
+                boolean animate) {
+            if (Float.compare(mCurrentMagnificationSpec.mScale, scale) == 0
+                    && Float.compare(mCurrentMagnificationSpec.mMagnifiedRegionCenterX,
+                            centerX) == 0
+                    && Float.compare(mCurrentMagnificationSpec.mMagnifiedRegionCenterY,
+                            centerY) == 0) {
+                return;
+            }
+            if (mTransformationAnimator.isRunning()) {
+                mTransformationAnimator.cancel();
+            }
+            if (DEBUG_MAGNIFICATION_CONTROLLER) {
+                Slog.i(LOG_TAG, "scale: " + scale + " centerX: " + centerX
+                        + " centerY: " + centerY);
+            }
+            mCurrentMagnificationSpec.initialize(scale, centerX, centerY);
+            if (animate) {
+                animateAccessibilityTranformation(mSentMagnificationSpec,
+                        mCurrentMagnificationSpec);
+            } else {
+                setAccessibilityTransformation(mCurrentMagnificationSpec);
+            }
+        }
+
+        private void animateAccessibilityTranformation(MagnificationSpec fromSpec,
+                MagnificationSpec toSpec) {
+            mTransformationAnimator.setObjectValues(fromSpec, toSpec);
+            mTransformationAnimator.start();
+        }
+
+        @SuppressWarnings("unused")
+        // Called from an animator.
+        public MagnificationSpec getAccessibilityTransformation() {
+            return mSentMagnificationSpec;
+        }
+
+        public void setAccessibilityTransformation(MagnificationSpec transformation) {
+            if (DEBUG_TRANSFORMATION) {
+                Slog.i(LOG_TAG, "Transformation scale: " + transformation.mScale
+                        + " offsetX: " + transformation.mScaledOffsetX
+                        + " offsetY: " + transformation.mScaledOffsetY);
+            }
+            try {
+                mSentMagnificationSpec.updateFrom(transformation);
+                mWindowManagerService.magnifyDisplay(mDisplayProvider.getDisplay().getDisplayId(),
+                        transformation.mScale, transformation.mScaledOffsetX,
+                        transformation.mScaledOffsetY);
+            } catch (RemoteException re) {
+                /* ignore */
+            }
+        }
+
+        private class MagnificationSpec {
+
+            private static final float DEFAULT_SCALE = 1.0f;
+
+            public float mScale = DEFAULT_SCALE;
+
+            public float mMagnifiedRegionCenterX;
+
+            public float mMagnifiedRegionCenterY;
+
+            public float mScaledOffsetX;
+
+            public float mScaledOffsetY;
+
+            public void initialize(float scale, float magnifiedRegionCenterX,
+                    float magnifiedRegionCenterY) {
+                mScale = scale;
+
+                final int viewportWidth = mViewport.getBounds().width();
+                final int viewportHeight = mViewport.getBounds().height();
+                final float minMagnifiedRegionCenterX = (viewportWidth / 2) / scale;
+                final float minMagnifiedRegionCenterY = (viewportHeight / 2) / scale;
+                final float maxMagnifiedRegionCenterX = viewportWidth - minMagnifiedRegionCenterX;
+                final float maxMagnifiedRegionCenterY = viewportHeight - minMagnifiedRegionCenterY;
+
+                mMagnifiedRegionCenterX = Math.min(Math.max(magnifiedRegionCenterX,
+                        minMagnifiedRegionCenterX), maxMagnifiedRegionCenterX);
+                mMagnifiedRegionCenterY = Math.min(Math.max(magnifiedRegionCenterY,
+                        minMagnifiedRegionCenterY), maxMagnifiedRegionCenterY);
+
+                mScaledOffsetX = -(mMagnifiedRegionCenterX * scale - viewportWidth / 2);
+                mScaledOffsetY = -(mMagnifiedRegionCenterY * scale - viewportHeight / 2);
+            }
+
+            public void updateFrom(MagnificationSpec other) {
+                mScale = other.mScale;
+                mMagnifiedRegionCenterX = other.mMagnifiedRegionCenterX;
+                mMagnifiedRegionCenterY = other.mMagnifiedRegionCenterY;
+                mScaledOffsetX = other.mScaledOffsetX;
+                mScaledOffsetY = other.mScaledOffsetY;
+            }
+
+            public void reset() {
+                mScale = DEFAULT_SCALE;
+                mMagnifiedRegionCenterX = 0;
+                mMagnifiedRegionCenterY = 0;
+                mScaledOffsetX = 0;
+                mScaledOffsetY = 0;
+            }
+        }
+    }
+
+    private static final class Viewport {
+
+        private static final String PROPERTY_NAME_ALPHA = "alpha";
+
+        private static final String PROPERTY_NAME_BOUNDS = "bounds";
+
+        private static final int MIN_ALPHA = 0;
+
+        private static final int MAX_ALPHA = 255;
+
+        private final ArrayList<WindowInfo> mTempWindowInfoList = new ArrayList<WindowInfo>();
+
+        private final Rect mTempRect = new Rect();
+
+        private final IWindowManager mWindowManagerService;
+        private final DisplayProvider mDisplayProvider;
+
+        private final ViewportWindow mViewportFrame;
+
+        private final ValueAnimator mResizeFrameAnimator;
+
+        private final ValueAnimator mShowHideFrameAnimator;
+
+        public Viewport(Context context, WindowManager windowManager,
+                IWindowManager windowManagerService, DisplayProvider displayInfoProvider,
+                Interpolator animationInterpolator, long animationDuration) {
+            mWindowManagerService = windowManagerService;
+            mDisplayProvider = displayInfoProvider;
+            mViewportFrame = new ViewportWindow(context, windowManager, displayInfoProvider);
+
+            mShowHideFrameAnimator = ObjectAnimator.ofInt(mViewportFrame, PROPERTY_NAME_ALPHA,
+                  MIN_ALPHA, MAX_ALPHA);
+            mShowHideFrameAnimator.setInterpolator(animationInterpolator);
+            mShowHideFrameAnimator.setDuration(animationDuration);
+            mShowHideFrameAnimator.addListener(new AnimatorListener() {
+                @Override
+                public void onAnimationEnd(Animator animation) {
+                    if (mShowHideFrameAnimator.getAnimatedValue().equals(MIN_ALPHA)) {
+                        mViewportFrame.hide();
+                    }
+                }
+                @Override
+                public void onAnimationStart(Animator animation) {
+                    /* do nothing - stub */
+                }
+                @Override
+                public void onAnimationCancel(Animator animation) {
+                    /* do nothing - stub */
+                }
+                @Override
+                public void onAnimationRepeat(Animator animation) {
+                    /* do nothing - stub */
+                }
+            });
+
+            Property<ViewportWindow, Rect> property = Property.of(ViewportWindow.class,
+                    Rect.class, PROPERTY_NAME_BOUNDS);
+            TypeEvaluator<Rect> evaluator = new TypeEvaluator<Rect>() {
+                private final Rect mReusableResultRect = new Rect();
+                @Override
+                public Rect evaluate(float fraction, Rect fromFrame, Rect toFrame) {
+                    Rect result = mReusableResultRect;
+                    result.left = (int) (fromFrame.left
+                            + (toFrame.left - fromFrame.left) * fraction);
+                    result.top = (int) (fromFrame.top
+                            + (toFrame.top - fromFrame.top) * fraction);
+                    result.right = (int) (fromFrame.right
+                            + (toFrame.right - fromFrame.right) * fraction);
+                    result.bottom = (int) (fromFrame.bottom
+                            + (toFrame.bottom - fromFrame.bottom) * fraction);
+                    return result;
+                }
+            };
+            mResizeFrameAnimator = ObjectAnimator.ofObject(mViewportFrame, property,
+                    evaluator, mViewportFrame.mBounds, mViewportFrame.mBounds);
+            mResizeFrameAnimator.setDuration((long) (animationDuration));
+            mResizeFrameAnimator.setInterpolator(animationInterpolator);
+
+            recomputeBounds(false);
+        }
+
+        public void recomputeBounds(boolean animate) {
+            Rect frame = mTempRect;
+            frame.set(0, 0, mDisplayProvider.getDisplayInfo().logicalWidth,
+                    mDisplayProvider.getDisplayInfo().logicalHeight);
+            ArrayList<WindowInfo> infos = mTempWindowInfoList;
+            infos.clear();
+            try {
+                mWindowManagerService.getVisibleWindowsForDisplay(
+                        mDisplayProvider.getDisplay().getDisplayId(), infos);
+                final int windowCount = infos.size();
+                for (int i = 0; i < windowCount; i++) {
+                    WindowInfo info = infos.get(i);
+                    if (info.type == WindowManager.LayoutParams.TYPE_NAVIGATION_BAR
+                            || info.type == WindowManager.LayoutParams.TYPE_INPUT_METHOD
+                            || info.type == WindowManager.LayoutParams.TYPE_INPUT_METHOD_DIALOG) {
+                        subtract(frame, info.touchableRegion);
+                    }
+                    info.recycle();
+                }
+            } catch (RemoteException re) {
+                /* ignore */
+            } finally {
+                infos.clear();
+            }
+            resize(frame, animate);
+        }
+
+        public void rotationChanged() {
+            mViewportFrame.rotationChanged();
+        }
+
+        public Rect getBounds() {
+            return mViewportFrame.getBounds();
+        }
+
+        public void setFrameShown(boolean shown, boolean animate) {
+            if (mViewportFrame.isShown() == shown) {
+                return;
+            }
+            if (animate) {
+                if (mShowHideFrameAnimator.isRunning()) {
+                    mShowHideFrameAnimator.reverse();
+                } else {
+                    if (shown) {
+                        mViewportFrame.show();
+                        mShowHideFrameAnimator.start();
+                    } else {
+                        mShowHideFrameAnimator.reverse();
+                    }
+                }
+            } else {
+                mShowHideFrameAnimator.cancel();
+                if (shown) {
+                    mViewportFrame.show();
+                } else {
+                    mViewportFrame.hide();
+                }
+            }
+        }
+
+        private void resize(Rect bounds, boolean animate) {
+            if (mViewportFrame.getBounds().equals(bounds)) {
+                return;
+            }
+            if (animate) {
+                if (mResizeFrameAnimator.isRunning()) {
+                    mResizeFrameAnimator.cancel();
+                }
+                mResizeFrameAnimator.setObjectValues(mViewportFrame.mBounds, bounds);
+                mResizeFrameAnimator.start();
+            } else {
+                mViewportFrame.setBounds(bounds);
+            }
+        }
+
+        private boolean subtract(Rect lhs, Rect rhs) {
+            if (lhs.right < rhs.left || lhs.left  > rhs.right
+                    || lhs.bottom < rhs.top || lhs.top > rhs.bottom) {
+                return false;
+            }
+            if (lhs.left < rhs.left) {
+                lhs.right = rhs.left;
+            }
+            if (lhs.top < rhs.top) {
+                lhs.bottom = rhs.top;
+            }
+            if (lhs.right > rhs.right) {
+                lhs.left = rhs.right;
+            }
+            if (lhs.bottom > rhs.bottom) {
+                lhs.top = rhs.bottom;
+            }
+            return true;
+        }
+
+        private static final class ViewportWindow {
+            private static final String WINDOW_TITLE = "Magnification Overlay";
+
+            private final WindowManager mWindowManager;
+            private final DisplayProvider mDisplayProvider;
+
+            private final ContentView mWindowContent;
+            private final WindowManager.LayoutParams mWindowParams;
+
+            private final Rect mBounds = new Rect();
+            private boolean mShown;
+            private int mAlpha;
+
+            public ViewportWindow(Context context, WindowManager windowManager,
+                    DisplayProvider displayProvider) {
+                mWindowManager = windowManager;
+                mDisplayProvider = displayProvider;
+
+                ViewGroup.LayoutParams contentParams = new ViewGroup.LayoutParams(
+                        ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT);
+                mWindowContent = new ContentView(context);
+                mWindowContent.setLayoutParams(contentParams);
+                mWindowContent.setBackgroundColor(R.color.transparent);
+
+                mWindowParams = new WindowManager.LayoutParams(
+                        WindowManager.LayoutParams.TYPE_MAGNIFICATION_OVERLAY);
+                mWindowParams.flags |= WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN
+                        | WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
+                        | WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE;
+                mWindowParams.setTitle(WINDOW_TITLE);
+                mWindowParams.gravity = Gravity.CENTER;
+                mWindowParams.width = displayProvider.getDisplayInfo().logicalWidth;
+                mWindowParams.height = displayProvider.getDisplayInfo().logicalHeight;
+                mWindowParams.format = PixelFormat.TRANSLUCENT;
+            }
+
+            public boolean isShown() {
+                return mShown;
+            }
+
+            public void show() {
+                if (mShown) {
+                    return;
+                }
+                mShown = true;
+                mWindowManager.addView(mWindowContent, mWindowParams);
+                if (DEBUG_VIEWPORT_WINDOW) {
+                    Slog.i(LOG_TAG, "ViewportWindow shown.");
+                }
+            }
+
+            public void hide() {
+                if (!mShown) {
+                    return;
+                }
+                mShown = false;
+                mWindowManager.removeView(mWindowContent);
+                if (DEBUG_VIEWPORT_WINDOW) {
+                    Slog.i(LOG_TAG, "ViewportWindow hidden.");
+                }
+            }
+
+            @SuppressWarnings("unused")
+            // Called reflectively from an animator.
+            public int getAlpha() {
+                return mAlpha;
+            }
+
+            @SuppressWarnings("unused")
+            // Called reflectively from an animator.
+            public void setAlpha(int alpha) {
+                if (mAlpha == alpha) {
+                    return;
+                }
+                mAlpha = alpha;
+                if (mShown) {
+                    mWindowContent.invalidate();
+                }
+                if (DEBUG_VIEWPORT_WINDOW) {
+                    Slog.i(LOG_TAG, "ViewportFrame set alpha: " + alpha);
+                }
+            }
+
+            public Rect getBounds() {
+                return mBounds;
+            }
+
+            public void rotationChanged() {
+                mWindowParams.width = mDisplayProvider.getDisplayInfo().logicalWidth;
+                mWindowParams.height = mDisplayProvider.getDisplayInfo().logicalHeight;
+                if (mShown) {
+                    mWindowManager.updateViewLayout(mWindowContent, mWindowParams);
+                }
+            }
+
+            public void setBounds(Rect bounds) {
+                if (mBounds.equals(bounds)) {
+                    return;
+                }
+                mBounds.set(bounds);
+                if (mShown) {
+                    mWindowContent.invalidate();
+                }
+                if (DEBUG_VIEWPORT_WINDOW) {
+                    Slog.i(LOG_TAG, "ViewportFrame set bounds: " + bounds);
+                }
+            }
+
+            private final class ContentView extends View {
+                private final Drawable mHighlightFrame;
+
+                public ContentView(Context context) {
+                    super(context);
+                    mHighlightFrame = context.getResources().getDrawable(
+                            R.drawable.magnified_region_frame);
+                }
+
+                @Override
+                public void onDraw(Canvas canvas) {
+                    canvas.drawColor(Color.TRANSPARENT, Mode.CLEAR);
+                    mHighlightFrame.setBounds(mBounds);
+                    mHighlightFrame.setAlpha(mAlpha);
+                    mHighlightFrame.draw(canvas);
+                }
+            }
+        }
+    }
+
+    private static class DisplayProvider implements DisplayListener {
+        private final WindowManager mWindowManager;
+        private final DisplayManager mDisplayManager;
+        private final Display mDefaultDisplay;
+        private final DisplayInfo mDefaultDisplayInfo = new DisplayInfo();
+
+        public DisplayProvider(Context context, WindowManager windowManager) {
+            mWindowManager = windowManager;
+            mDisplayManager = (DisplayManager) context.getSystemService(Context.DISPLAY_SERVICE);
+            mDefaultDisplay = mWindowManager.getDefaultDisplay();
+            mDisplayManager.registerDisplayListener(this, null);
+            updateDisplayInfo();
+        }
+
+        public DisplayInfo getDisplayInfo() {
+            return mDefaultDisplayInfo;
+        }
+
+        public Display getDisplay() {
+            return mDefaultDisplay;
+        }
+
+        private void updateDisplayInfo() {
+            if (!mDefaultDisplay.getDisplayInfo(mDefaultDisplayInfo)) {
+                Slog.e(LOG_TAG, "Default display is not valid.");
+            }
+        }
+
+        public void destroy() {
+            mDisplayManager.unregisterDisplayListener(this);
+        }
+
+        @Override
+        public void onDisplayAdded(int displayId) {
+            /* do noting */
+        }
+
+        @Override
+        public void onDisplayRemoved(int displayId) {
+            // Having no default display
+        }
+
+        @Override
+        public void onDisplayChanged(int displayId) {
+            updateDisplayInfo();
+        }
+    }
+}
diff --git a/services/java/com/android/server/accessibility/TouchExplorer.java b/services/java/com/android/server/accessibility/TouchExplorer.java
index ba9f2cd..9e4f33e 100644
--- a/services/java/com/android/server/accessibility/TouchExplorer.java
+++ b/services/java/com/android/server/accessibility/TouchExplorer.java
@@ -28,7 +28,6 @@
 import android.os.Handler;
 import android.os.SystemClock;
 import android.util.Slog;
-import android.view.InputFilter;
 import android.view.MotionEvent;
 import android.view.MotionEvent.PointerCoords;
 import android.view.MotionEvent.PointerProperties;
@@ -64,7 +63,7 @@
  *
  * @hide
  */
-public class TouchExplorer {
+class TouchExplorer implements EventStreamTransformation {
 
     private static final boolean DEBUG = false;
 
@@ -120,10 +119,6 @@
     // Slop between the first and second tap to be a double tap.
     private final int mDoubleTapSlop;
 
-    // The InputFilter this tracker is associated with i.e. the filter
-    // which delegates event processing to this touch explorer.
-    private final InputFilter mInputFilter;
-
     // The current state of the touch explorer.
     private int mCurrentState = STATE_TOUCH_EXPLORING;
 
@@ -155,6 +150,9 @@
     // The scaled velocity above which we detect gestures.
     private final int mScaledGestureDetectionVelocity;
 
+    // The handler to which to delegate events.
+    private EventStreamTransformation mNext;
+
     // Helper to track gesture velocity.
     private VelocityTracker mVelocityTracker;
 
@@ -206,12 +204,10 @@
      * @param inputFilter The input filter associated with this explorer.
      * @param context A context handle for accessing resources.
      */
-    public TouchExplorer(InputFilter inputFilter, Context context,
-            AccessibilityManagerService service) {
+    public TouchExplorer(Context context, AccessibilityManagerService service) {
         mAms = service;
         mReceivedPointerTracker = new ReceivedPointerTracker(context);
         mInjectedPointerTracker = new InjectedPointerTracker();
-        mInputFilter = inputFilter;
         mTapTimeout = ViewConfiguration.getTapTimeout();
         mDetermineUserIntentTimeout = (int) (mTapTimeout * 1.5f);
         mDoubleTapTimeout = ViewConfiguration.getDoubleTapTimeout();
@@ -242,7 +238,11 @@
         }
     }
 
-    public void clear(MotionEvent event, int policyFlags) {
+    public void onDestroy() {
+        // TODO: Implement
+    }
+
+    private void clear(MotionEvent event, int policyFlags) {
         switch (mCurrentState) {
             case STATE_TOUCH_EXPLORING: {
                 // If a touch exploration gesture is in progress send events for its end.
@@ -278,8 +278,17 @@
         mLongPressingPointerDeltaX = 0;
         mLongPressingPointerDeltaY = 0;
         mCurrentState = STATE_TOUCH_EXPLORING;
+        if (mNext != null) {
+            mNext.clear();
+        }
     }
 
+    @Override
+    public void setNext(EventStreamTransformation next) {
+        mNext = next;
+    }
+
+    @Override
     public void onMotionEvent(MotionEvent event, int policyFlags) {
         if (DEBUG) {
             Slog.d(LOG_TAG, "Received event: " + event + ", policyFlags=0x"
@@ -325,6 +334,9 @@
                 mLastTouchedWindowId = event.getWindowId();
             } break;
         }
+        if (mNext != null) {
+            mNext.onAccessibilityEvent(event);
+        }
     }
 
     /**
@@ -958,7 +970,9 @@
 
         // Make sure that the user will see the event.
         policyFlags |= WindowManagerPolicy.FLAG_PASS_TO_USER;
-        mInputFilter.sendInputEvent(event, policyFlags);
+        if (mNext != null) {
+            mNext.onMotionEvent(event, policyFlags);
+        }
 
         mInjectedPointerTracker.onMotionEvent(event);
 
@@ -1008,11 +1022,13 @@
         private MotionEvent mFirstTapEvent;
 
         public void onMotionEvent(MotionEvent event, int policyFlags) {
+            final int actionIndex = event.getActionIndex();
             final int action = event.getActionMasked();
             switch (action) {
                 case MotionEvent.ACTION_DOWN:
                 case MotionEvent.ACTION_POINTER_DOWN: {
-                    if (mFirstTapEvent != null && !isSamePointerContext(mFirstTapEvent, event)) {
+                    if (mFirstTapEvent != null
+                            && !GestureUtils.isSamePointerContext(mFirstTapEvent, event)) {
                         clear();
                     }
                     mDownEvent = MotionEvent.obtain(event);
@@ -1022,19 +1038,21 @@
                     if (mDownEvent == null) {
                         return;
                     }
-                    if (!isSamePointerContext(mDownEvent, event)) {
+                    if (!GestureUtils.isSamePointerContext(mDownEvent, event)) {
                         clear();
                         return;
                     }
-                    if (isTap(mDownEvent, event)) {
-                        if (mFirstTapEvent == null || isTimedOut(mFirstTapEvent, event,
-                                mDoubleTapTimeout)) {
+                    if (GestureUtils.isTap(mDownEvent, event, mTapTimeout, mTouchSlop,
+                            actionIndex)) {
+                        if (mFirstTapEvent == null || GestureUtils.isTimedOut(mFirstTapEvent,
+                                event, mDoubleTapTimeout)) {
                             mFirstTapEvent = MotionEvent.obtain(event);
                             mDownEvent.recycle();
                             mDownEvent = null;
                             return;
                         }
-                        if (isDoubleTap(mFirstTapEvent, event)) {
+                        if (GestureUtils.isMultiTap(mFirstTapEvent, event, mDoubleTapTimeout,
+                                mDoubleTapSlop, actionIndex)) {
                             onDoubleTap(event, policyFlags);
                             mFirstTapEvent.recycle();
                             mFirstTapEvent = null;
@@ -1140,42 +1158,6 @@
             }
         }
 
-        public boolean isTap(MotionEvent down, MotionEvent up) {
-            return eventsWithinTimeoutAndDistance(down, up, mTapTimeout, mTouchSlop);
-        }
-
-        private boolean isDoubleTap(MotionEvent firstUp, MotionEvent secondUp) {
-            return eventsWithinTimeoutAndDistance(firstUp, secondUp, mDoubleTapTimeout,
-                    mDoubleTapSlop);
-        }
-
-        private boolean eventsWithinTimeoutAndDistance(MotionEvent first, MotionEvent second,
-                int timeout, int distance) {
-            if (isTimedOut(first, second, timeout)) {
-                return false;
-            }
-            final int downPtrIndex = first.getActionIndex();
-            final int upPtrIndex = second.getActionIndex();
-            final float deltaX = second.getX(upPtrIndex) - first.getX(downPtrIndex);
-            final float deltaY = second.getY(upPtrIndex) - first.getY(downPtrIndex);
-            final double deltaMove = Math.hypot(deltaX, deltaY);
-            if (deltaMove >= distance) {
-                return false;
-            }
-            return true;
-        }
-
-        private boolean isTimedOut(MotionEvent firstUp, MotionEvent secondUp, int timeout) {
-            final long deltaTime = secondUp.getEventTime() - firstUp.getEventTime();
-            return (deltaTime >= timeout);
-        }
-
-        private boolean isSamePointerContext(MotionEvent first, MotionEvent second) {
-            return (first.getPointerIdBits() == second.getPointerIdBits()
-                    && first.getPointerId(first.getActionIndex())
-                            == second.getPointerId(second.getActionIndex()));
-        }
-
         public boolean firstTapDetected() {
             return mFirstTapEvent != null
                 && SystemClock.uptimeMillis() - mFirstTapEvent.getEventTime() < mDoubleTapTimeout;
@@ -1201,47 +1183,14 @@
         final float secondPtrX = event.getX(secondPtrIndex);
         final float secondPtrY = event.getY(secondPtrIndex);
 
-        // Check if the pointers are moving in the same direction.
-        final float firstDeltaX =
-            firstPtrX - receivedTracker.getReceivedPointerDownX(firstPtrIndex);
-        final float firstDeltaY =
-            firstPtrY - receivedTracker.getReceivedPointerDownY(firstPtrIndex);
+        final float firstPtrDownX = receivedTracker.getReceivedPointerDownX(firstPtrIndex);
+        final float firstPtrDownY = receivedTracker.getReceivedPointerDownY(firstPtrIndex);
+        final float secondPtrDownX = receivedTracker.getReceivedPointerDownX(secondPtrIndex);
+        final float secondPtrDownY = receivedTracker.getReceivedPointerDownY(secondPtrIndex);
 
-        if (firstDeltaX == 0 && firstDeltaY == 0) {
-            return true;
-        }
-
-        final float firstMagnitude =
-            (float) Math.sqrt(firstDeltaX * firstDeltaX + firstDeltaY * firstDeltaY);
-        final float firstXNormalized =
-            (firstMagnitude > 0) ? firstDeltaX / firstMagnitude : firstDeltaX;
-        final float firstYNormalized =
-            (firstMagnitude > 0) ? firstDeltaY / firstMagnitude : firstDeltaY;
-
-        final float secondDeltaX =
-            secondPtrX - receivedTracker.getReceivedPointerDownX(secondPtrIndex);
-        final float secondDeltaY =
-            secondPtrY - receivedTracker.getReceivedPointerDownY(secondPtrIndex);
-
-        if (secondDeltaX == 0 && secondDeltaY == 0) {
-            return true;
-        }
-
-        final float secondMagnitude =
-            (float) Math.sqrt(secondDeltaX * secondDeltaX + secondDeltaY * secondDeltaY);
-        final float secondXNormalized =
-            (secondMagnitude > 0) ? secondDeltaX / secondMagnitude : secondDeltaX;
-        final float secondYNormalized =
-            (secondMagnitude > 0) ? secondDeltaY / secondMagnitude : secondDeltaY;
-
-        final float angleCos =
-            firstXNormalized * secondXNormalized + firstYNormalized * secondYNormalized;
-
-        if (angleCos < MAX_DRAGGING_ANGLE_COS) {
-            return false;
-        }
-
-        return true;
+        return GestureUtils.isDraggingGesture(firstPtrDownX, firstPtrDownY, secondPtrDownX,
+                secondPtrDownY, firstPtrX, firstPtrY, secondPtrX, secondPtrY,
+                MAX_DRAGGING_ANGLE_COS);
     }
 
     /**
diff --git a/services/java/com/android/server/am/ActiveServices.java b/services/java/com/android/server/am/ActiveServices.java
index 6a3010b..2975880 100644
--- a/services/java/com/android/server/am/ActiveServices.java
+++ b/services/java/com/android/server/am/ActiveServices.java
@@ -185,7 +185,7 @@
         }
 
         private HashMap<ComponentName, ServiceRecord> getServices(int callingUser) {
-            HashMap map = mServicesByNamePerUser.get(callingUser);
+            HashMap<ComponentName, ServiceRecord> map = mServicesByNamePerUser.get(callingUser);
             if (map == null) {
                 map = new HashMap<ComponentName, ServiceRecord>();
                 mServicesByNamePerUser.put(callingUser, map);
@@ -195,7 +195,8 @@
 
         private HashMap<Intent.FilterComparison, ServiceRecord> getServicesByIntent(
                 int callingUser) {
-            HashMap map = mServicesByIntentPerUser.get(callingUser);
+            HashMap<Intent.FilterComparison, ServiceRecord> map
+                    = mServicesByIntentPerUser.get(callingUser);
             if (map == null) {
                 map = new HashMap<Intent.FilterComparison, ServiceRecord>();
                 mServicesByIntentPerUser.put(callingUser, map);
@@ -1514,10 +1515,12 @@
         }
     }
 
-    boolean forceStopLocked(String name, int userId, boolean evenPersistent, boolean doit) {
+    private boolean collectForceStopServicesLocked(String name, int userId,
+            boolean evenPersistent, boolean doit,
+            HashMap<ComponentName, ServiceRecord> services,
+            ArrayList<ServiceRecord> result) {
         boolean didSomething = false;
-        ArrayList<ServiceRecord> services = new ArrayList<ServiceRecord>();
-        for (ServiceRecord service : mServiceMap.getAllServices(userId)) {
+        for (ServiceRecord service : services.values()) {
             if ((name == null || service.packageName.equals(name))
                     && (service.app == null || evenPersistent || !service.app.persistent)) {
                 if (!doit) {
@@ -1530,7 +1533,29 @@
                 }
                 service.app = null;
                 service.isolatedProc = null;
-                services.add(service);
+                result.add(service);
+            }
+        }
+        return didSomething;
+    }
+
+    boolean forceStopLocked(String name, int userId, boolean evenPersistent, boolean doit) {
+        boolean didSomething = false;
+        ArrayList<ServiceRecord> services = new ArrayList<ServiceRecord>();
+        if (userId == UserHandle.USER_ALL) {
+            for (int i=0; i<mServiceMap.mServicesByNamePerUser.size(); i++) {
+                didSomething |= collectForceStopServicesLocked(name, userId, evenPersistent,
+                        doit, mServiceMap.mServicesByNamePerUser.valueAt(i), services);
+                if (!doit && didSomething) {
+                    return true;
+                }
+            }
+        } else {
+            HashMap<ComponentName, ServiceRecord> items
+                    = mServiceMap.mServicesByNamePerUser.get(userId);
+            if (items != null) {
+                didSomething = collectForceStopServicesLocked(name, userId, evenPersistent,
+                        doit, items, services);
             }
         }
 
diff --git a/services/java/com/android/server/am/ActivityManagerService.java b/services/java/com/android/server/am/ActivityManagerService.java
index 614b93a..0b2d769 100644
--- a/services/java/com/android/server/am/ActivityManagerService.java
+++ b/services/java/com/android/server/am/ActivityManagerService.java
@@ -116,13 +116,11 @@
 import android.provider.Settings;
 import android.text.format.Time;
 import android.util.EventLog;
-import android.util.LocaleUtil;
 import android.util.Log;
 import android.util.Pair;
 import android.util.PrintWriterPrinter;
 import android.util.Slog;
 import android.util.SparseArray;
-import android.util.SparseIntArray;
 import android.util.TimeUtils;
 import android.view.Gravity;
 import android.view.LayoutInflater;
@@ -434,6 +432,11 @@
     final SparseArray<UserStartedState> mStartedUsers = new SparseArray<UserStartedState>();
 
     /**
+     * LRU list of history of current users.  Most recently current is at the end.
+     */
+    final ArrayList<Integer> mUserLru = new ArrayList<Integer>();
+
+    /**
      * Packages that the user has asked to have run in screen size
      * compatibility mode instead of filling the screen.
      */
@@ -543,7 +546,7 @@
      */
     final ArrayList mCancelledThumbnails = new ArrayList();
 
-    final ProviderMap mProviderMap = new ProviderMap();
+    final ProviderMap mProviderMap;
 
     /**
      * List of content providers who have clients waiting for them.  The
@@ -1094,11 +1097,11 @@
             } break;
             case KILL_APPLICATION_MSG: {
                 synchronized (ActivityManagerService.this) {
-                    int uid = msg.arg1;
+                    int appid = msg.arg1;
                     boolean restart = (msg.arg2 == 1);
                     String pkg = (String) msg.obj;
-                    forceStopPackageLocked(pkg, uid, restart, false, true, false,
-                            UserHandle.getUserId(uid));
+                    forceStopPackageLocked(pkg, appid, restart, false, true, false,
+                            UserHandle.USER_ALL);
                 }
             } break;
             case FINALIZE_PENDING_INTENT_MSG: {
@@ -1508,6 +1511,7 @@
         mBroadcastQueues[1] = mBgBroadcastQueue;
 
         mServices = new ActiveServices(this);
+        mProviderMap = new ProviderMap(this);
 
         File dataDir = Environment.getDataDirectory();
         File systemDir = new File(dataDir, "system");
@@ -1526,6 +1530,7 @@
 
         // User 0 is the first and only user that runs at boot.
         mStartedUsers.put(0, new UserStartedState(new UserHandle(0), true));
+        mUserLru.add(Integer.valueOf(0));
 
         GL_ES_VERSION = SystemProperties.getInt("ro.opengles.version",
             ConfigurationInfo.GL_ES_VERSION_UNDEFINED);
@@ -1788,7 +1793,7 @@
             // Also don't let it kick out the first few "real" hidden processes.
             skipTop = ProcessList.MIN_HIDDEN_APPS;
         }
-        
+
         while (i >= 0) {
             ProcessRecord p = mLruProcesses.get(i);
             // If this app shouldn't be in front of the first N background
@@ -2146,8 +2151,7 @@
             intent.addCategory(Intent.CATEGORY_HOME);
         }
         ActivityInfo aInfo =
-            intent.resolveActivityInfo(mContext.getPackageManager(),
-                    STOCK_PM_FLAGS);
+            resolveActivityInfo(intent, STOCK_PM_FLAGS, userId);
         if (aInfo != null) {
             intent.setComponent(new ComponentName(
                     aInfo.applicationInfo.packageName, aInfo.name));
@@ -2170,6 +2174,29 @@
         return true;
     }
 
+    private ActivityInfo resolveActivityInfo(Intent intent, int flags, int userId) {
+        ActivityInfo ai = null;
+        ComponentName comp = intent.getComponent();
+        try {
+            if (comp != null) {
+                ai = AppGlobals.getPackageManager().getActivityInfo(comp, flags, userId);
+            } else {
+                ResolveInfo info = AppGlobals.getPackageManager().resolveIntent(
+                        intent,
+                        intent.resolveTypeIfNeeded(mContext.getContentResolver()),
+                            flags, userId);
+    
+                if (info != null) {
+                    ai = info.activityInfo;
+                }
+            }
+        } catch (RemoteException e) {
+            // ignore
+        }
+
+        return ai;
+    }
+
     /**
      * Starts the "new version setup screen" if appropriate.
      */
@@ -2366,17 +2393,8 @@
             String resultWho, int requestCode, int startFlags,
             String profileFile, ParcelFileDescriptor profileFd, Bundle options, int userId) {
         enforceNotIsolatedCaller("startActivity");
-        if (userId != UserHandle.getCallingUserId()) {
-            userId = handleIncomingUserLocked(Binder.getCallingPid(), Binder.getCallingUid(), userId,
-                    false, true, "startActivity", null);
-        } else {
-            if (intent.getCategories() != null
-                    && intent.getCategories().contains(Intent.CATEGORY_HOME)) {
-                // Requesting home, set the identity to the current user
-                // HACK!
-                userId = mCurrentUserId;
-            }
-        }
+        userId = handleIncomingUserLocked(Binder.getCallingPid(), Binder.getCallingUid(), userId,
+                false, true, "startActivity", null);
         return mMainStack.startActivityMayWait(caller, -1, intent, resolvedType,
                 resultTo, resultWho, requestCode, startFlags, profileFile, profileFd,
                 null, null, options, userId);
@@ -2385,8 +2403,10 @@
     public final WaitResult startActivityAndWait(IApplicationThread caller,
             Intent intent, String resolvedType, IBinder resultTo,
             String resultWho, int requestCode, int startFlags, String profileFile,
-            ParcelFileDescriptor profileFd, Bundle options) {
+            ParcelFileDescriptor profileFd, Bundle options, int userId) {
         enforceNotIsolatedCaller("startActivityAndWait");
+        userId = handleIncomingUserLocked(Binder.getCallingPid(), Binder.getCallingUid(), userId,
+                false, true, "startActivityAndWait", null);
         WaitResult res = new WaitResult();
         mMainStack.startActivityMayWait(caller, -1, intent, resolvedType,
                 resultTo, resultWho, requestCode, startFlags, profileFile, profileFd,
@@ -2661,7 +2681,7 @@
             }
             final long origId = Binder.clearCallingIdentity();
             boolean res = mMainStack.requestFinishActivityLocked(token, resultCode,
-                    resultData, "app-request");
+                    resultData, "app-request", true);
             Binder.restoreCallingIdentity(origId);
             return res;
         }
@@ -2691,7 +2711,7 @@
                     int index = mMainStack.indexOfTokenLocked(r.appToken);
                     if (index >= 0) {
                         mMainStack.finishActivityLocked(r, index, Activity.RESULT_CANCELED,
-                                null, "finish-heavy");
+                                null, "finish-heavy", true);
                     }
                 }
             }
@@ -3542,16 +3562,15 @@
     }
 
     /*
-     * The pkg name and uid have to be specified.
-     * @see android.app.IActivityManager#killApplicationWithUid(java.lang.String, int)
+     * The pkg name and app id have to be specified.
      */
-    public void killApplicationWithUid(String pkg, int uid) {
+    public void killApplicationWithAppId(String pkg, int appid) {
         if (pkg == null) {
             return;
         }
         // Make sure the uid is valid.
-        if (uid < 0) {
-            Slog.w(TAG, "Invalid uid specified for pkg : " + pkg);
+        if (appid < 0) {
+            Slog.w(TAG, "Invalid appid specified for pkg : " + pkg);
             return;
         }
         int callerUid = Binder.getCallingUid();
@@ -3559,7 +3578,7 @@
         if (callerUid == Process.SYSTEM_UID) {
             // Post an aysnc message to kill the application
             Message msg = mHandler.obtainMessage(KILL_APPLICATION_MSG);
-            msg.arg1 = uid;
+            msg.arg1 = appid;
             msg.arg2 = 0;
             msg.obj = pkg;
             mHandler.sendMessage(msg);
@@ -3609,7 +3628,7 @@
             ActivityRecord r = (ActivityRecord)mMainStack.mHistory.get(i);
             if ((r.info.flags&ActivityInfo.FLAG_FINISH_ON_CLOSE_SYSTEM_DIALOGS) != 0) {
                 r.stack.finishActivityLocked(r, i,
-                        Activity.RESULT_CANCELED, null, "close-sys");
+                        Activity.RESULT_CANCELED, null, "close-sys", true);
             }
         }
 
@@ -3691,7 +3710,7 @@
                 MY_PID, Process.SYSTEM_UID, userId);
     }
 
-    private final boolean killPackageProcessesLocked(String packageName, int uid,
+    private final boolean killPackageProcessesLocked(String packageName, int appId,
             int userId, int minOomAdj, boolean callerWillRestart, boolean allowRestart,
             boolean doit, boolean evenPersistent, String reason) {
         ArrayList<ProcessRecord> procs = new ArrayList<ProcessRecord>();
@@ -3712,32 +3731,41 @@
                     if (doit) {
                         procs.add(app);
                     }
+                    continue;
+                }
+
+                // Skip process if it doesn't meet our oom adj requirement.
+                if (app.setAdj < minOomAdj) {
+                    continue;
+                }
+
                 // If no package is specified, we call all processes under the
                 // give user id.
-                } else if (packageName == null) {
-                    if (app.userId == userId) {
-                        if (app.setAdj >= minOomAdj) {
-                            if (!doit) {
-                                return true;
-                            }
-                            app.removed = true;
-                            procs.add(app);
-                        }
+                if (packageName == null) {
+                    if (app.userId != userId) {
+                        continue;
                     }
-                // If uid is specified and the uid and process name match
-                // Or, the uid is not specified and the process name matches
-                } else if (((uid > 0 && uid != Process.SYSTEM_UID && app.info.uid == uid)
-                            || ((app.processName.equals(packageName)
-                                 || app.processName.startsWith(procNamePrefix))
-                                && uid < 0))) {
-                    if (app.setAdj >= minOomAdj) {
-                        if (!doit) {
-                            return true;
-                        }
-                        app.removed = true;
-                        procs.add(app);
+                // Package has been specified, we want to hit all processes
+                // that match it.  We need to qualify this by the processes
+                // that are running under the specified app and user ID.
+                } else {
+                    if (UserHandle.getAppId(app.uid) != appId) {
+                        continue;
+                    }
+                    if (userId != UserHandle.USER_ALL && app.userId != userId) {
+                        continue;
+                    }
+                    if (!app.pkgList.contains(packageName)) {
+                        continue;
                     }
                 }
+
+                // Process has passed all conditions, kill it!
+                if (!doit) {
+                    return true;
+                }
+                app.removed = true;
+                procs.add(app);
             }
         }
         
@@ -3748,22 +3776,28 @@
         return N > 0;
     }
 
-    private final boolean forceStopPackageLocked(String name, int uid,
+    private final boolean forceStopPackageLocked(String name, int appId,
             boolean callerWillRestart, boolean purgeCache, boolean doit,
             boolean evenPersistent, int userId) {
         int i;
         int N;
 
-        if (uid < 0 && name != null) {
+        if (userId == UserHandle.USER_ALL && name == null) {
+            Slog.w(TAG, "Can't force stop all processes of all users, that is insane!");
+        }
+
+        if (appId < 0 && name != null) {
             try {
-                uid = AppGlobals.getPackageManager().getPackageUid(name, userId);
+                appId = UserHandle.getAppId(
+                        AppGlobals.getPackageManager().getPackageUid(name, 0));
             } catch (RemoteException e) {
             }
         }
 
         if (doit) {
             if (name != null) {
-                Slog.i(TAG, "Force stopping package " + name + " uid=" + uid);
+                Slog.i(TAG, "Force stopping package " + name + " appid=" + appId
+                        + " user=" + userId);
             } else {
                 Slog.i(TAG, "Force stopping user " + userId);
             }
@@ -3775,8 +3809,14 @@
                     boolean remove = false;
                     final int entUid = ba.keyAt(i);
                     if (name != null) {
-                        if (entUid == uid) {
-                            remove = true;
+                        if (userId == UserHandle.USER_ALL) {
+                            if (UserHandle.getAppId(entUid) == appId) {
+                                remove = true;
+                            }
+                        } else {
+                            if (entUid == UserHandle.getUid(userId, appId)) {
+                                remove = true;
+                            }
                         }
                     } else if (UserHandle.getUserId(entUid) == userId) {
                         remove = true;
@@ -3791,9 +3831,8 @@
             }
         }
 
-        boolean didSomething = killPackageProcessesLocked(name, uid,
-                name == null ? userId : -1 , -100, callerWillRestart, false,
-                doit, evenPersistent,
+        boolean didSomething = killPackageProcessesLocked(name, appId, userId,
+                -100, callerWillRestart, false, doit, evenPersistent,
                 name == null ? ("force stop user " + userId) : ("force stop " + name));
         
         TaskRecord lastTask = null;
@@ -3801,7 +3840,7 @@
             ActivityRecord r = (ActivityRecord)mMainStack.mHistory.get(i);
             final boolean samePackage = r.packageName.equals(name)
                     || (name == null && r.userId == userId);
-            if (r.userId == userId
+            if ((userId == UserHandle.USER_ALL || r.userId == userId)
                     && (samePackage || r.task == lastTask)
                     && (r.app == null || evenPersistent || !r.app.persistent)) {
                 if (!doit) {
@@ -3841,22 +3880,64 @@
         }
 
         ArrayList<ContentProviderRecord> providers = new ArrayList<ContentProviderRecord>();
-        for (ContentProviderRecord provider : mProviderMap.getProvidersByClass(userId).values()) {
-            if ((name == null || provider.info.packageName.equals(name))
-                    && (provider.proc == null || evenPersistent || !provider.proc.persistent)) {
+        if (mProviderMap.collectForceStopProviders(name, appId, doit, evenPersistent,
+                userId, providers)) {
+            if (!doit) {
+                return true;
+            }
+            didSomething = true;
+        }
+        N = providers.size();
+        for (i=0; i<N; i++) {
+            removeDyingProviderLocked(null, providers.get(i), true);
+        }
+
+        if (mIntentSenderRecords.size() > 0) {
+            Iterator<WeakReference<PendingIntentRecord>> it
+                    = mIntentSenderRecords.values().iterator();
+            while (it.hasNext()) {
+                WeakReference<PendingIntentRecord> wpir = it.next();
+                if (wpir == null) {
+                    it.remove();
+                    continue;
+                }
+                PendingIntentRecord pir = wpir.get();
+                if (pir == null) {
+                    it.remove();
+                    continue;
+                }
+                if (name == null) {
+                    // Stopping user, remove all objects for the user.
+                    if (pir.key.userId != userId) {
+                        // Not the same user, skip it.
+                        continue;
+                    }
+                } else {
+                    if (UserHandle.getAppId(pir.uid) != appId) {
+                        // Different app id, skip it.
+                        continue;
+                    }
+                    if (userId != UserHandle.USER_ALL && pir.key.userId != userId) {
+                        // Different user, skip it.
+                        continue;
+                    }
+                    if (!pir.key.packageName.equals(name)) {
+                        // Different package, skip it.
+                        continue;
+                    }
+                }
                 if (!doit) {
                     return true;
                 }
                 didSomething = true;
-                providers.add(provider);
+                it.remove();
+                pir.canceled = true;
+                if (pir.key.activity != null) {
+                    pir.key.activity.pendingResults.remove(pir.ref);
+                }
             }
         }
 
-        N = providers.size();
-        for (i=0; i<N; i++) {
-            removeDyingProviderLocked(null, providers.get(i), true);
-        }
-
         if (doit) {
             if (purgeCache && name != null) {
                 AttributeCache ac = AttributeCache.instance();
@@ -6778,10 +6859,11 @@
      * Test cases are at cts/tests/appsecurity-tests/test-apps/UsePermissionDiffCert/
      *     src/com/android/cts/usespermissiondiffcertapp/AccessPermissionWithDiffSigTest.java
      */
-    public String getProviderMimeType(Uri uri) {
+    public String getProviderMimeType(Uri uri, int userId) {
         enforceNotIsolatedCaller("getProviderMimeType");
+        userId = handleIncomingUserLocked(Binder.getCallingPid(), Binder.getCallingUid(),
+                userId, false, true, "getProviderMimeType", null);
         final String name = uri.getAuthority();
-        final int userId = UserHandle.getCallingUserId();
         final long ident = Binder.clearCallingIdentity();
         ContentProviderHolder holder = null;
 
@@ -6891,7 +6973,7 @@
             if (count > 1) {
                 final long origId = Binder.clearCallingIdentity();
                 mMainStack.finishActivityLocked((ActivityRecord)mMainStack.mHistory.get(count-1),
-                        count-1, Activity.RESULT_CANCELED, null, "unhandled-back");
+                        count-1, Activity.RESULT_CANCELED, null, "unhandled-back", true);
                 Binder.restoreCallingIdentity(origId);
             }
         }
@@ -7134,7 +7216,8 @@
             mDebugTransient = !persistent;
             if (packageName != null) {
                 final long origId = Binder.clearCallingIdentity();
-                forceStopPackageLocked(packageName, -1, false, false, true, true, 0);
+                forceStopPackageLocked(packageName, -1, false, false, true, true,
+                        UserHandle.USER_ALL);
                 Binder.restoreCallingIdentity(origId);
             }
         }
@@ -7809,7 +7892,8 @@
                 if (r.app == app) {
                     Slog.w(TAG, "  Force finishing activity "
                         + r.intent.getComponent().flattenToShortString());
-                    r.stack.finishActivityLocked(r, i, Activity.RESULT_CANCELED, null, "crashed");
+                    r.stack.finishActivityLocked(r, i, Activity.RESULT_CANCELED,
+                            null, "crashed", false);
                 }
             }
             if (!app.persistent) {
@@ -7844,7 +7928,7 @@
                         + r.intent.getComponent().flattenToShortString());
                 int index = mMainStack.indexOfActivityLocked(r);
                 r.stack.finishActivityLocked(r, index,
-                        Activity.RESULT_CANCELED, null, "crashed");
+                        Activity.RESULT_CANCELED, null, "crashed", false);
                 // Also terminate any activities below it that aren't yet
                 // stopped, to avoid a situation where one will get
                 // re-start our crashing activity once it gets resumed again.
@@ -7858,7 +7942,7 @@
                             Slog.w(TAG, "  Force finishing activity "
                                     + r.intent.getComponent().flattenToShortString());
                             r.stack.finishActivityLocked(r, index,
-                                    Activity.RESULT_CANCELED, null, "crashed");
+                                    Activity.RESULT_CANCELED, null, "crashed", false);
                         }
                     }
                 }
@@ -9129,9 +9213,14 @@
         for (int i=0; i<mStartedUsers.size(); i++) {
             UserStartedState uss = mStartedUsers.valueAt(i);
             pw.print("    User #"); pw.print(uss.mHandle.getIdentifier());
-                    pw.println(":");
-            uss.dump("      ", pw);
+                    pw.print(": "); uss.dump("", pw);
         }
+        pw.print("  mUserLru: [");
+        for (int i=0; i<mUserLru.size(); i++) {
+            if (i > 0) pw.print(", ");
+            pw.print(mUserLru.get(i));
+        }
+        pw.println("]");
         pw.println("  mHomeProcess: " + mHomeProcess);
         pw.println("  mPreviousProcess: " + mPreviousProcess);
         if (dumpAll) {
@@ -10764,7 +10853,7 @@
                         builder.append("; this requires ");
                         builder.append(android.Manifest.permission.INTERACT_ACROSS_USERS_FULL);
                         if (!requireFull) {
-                            builder.append("or");
+                            builder.append(" or ");
                             builder.append(android.Manifest.permission.INTERACT_ACROSS_USERS);
                         }
                         String msg = builder.toString();
@@ -11815,8 +11904,10 @@
 
     public boolean startInstrumentation(ComponentName className,
             String profileFile, int flags, Bundle arguments,
-            IInstrumentationWatcher watcher) {
+            IInstrumentationWatcher watcher, int userId) {
         enforceNotIsolatedCaller("startInstrumentation");
+        userId = handleIncomingUserLocked(Binder.getCallingPid(), Binder.getCallingUid(),
+                userId, false, true, "startInstrumentation", null);
         // Refuse possible leaked file descriptors
         if (arguments != null && arguments.hasFileDescriptors()) {
             throw new IllegalArgumentException("File descriptors passed in Bundle");
@@ -11828,9 +11919,10 @@
             try {
                 ii = mContext.getPackageManager().getInstrumentationInfo(
                     className, STOCK_PM_FLAGS);
-                ai = mContext.getPackageManager().getApplicationInfo(
-                        ii.targetPackage, STOCK_PM_FLAGS);
+                ai = AppGlobals.getPackageManager().getApplicationInfo(
+                        ii.targetPackage, STOCK_PM_FLAGS, userId);
             } catch (PackageManager.NameNotFoundException e) {
+            } catch (RemoteException e) {
             }
             if (ii == null) {
                 reportStartInstrumentationFailure(watcher, className,
@@ -11857,7 +11949,6 @@
                 throw new SecurityException(msg);
             }
 
-            int userId = UserHandle.getCallingUserId();
             final long origId = Binder.clearCallingIdentity();
             // Instrumentation can kill and relaunch even persistent processes
             forceStopPackageLocked(ii.targetPackage, -1, true, false, true, true, userId);
@@ -12216,7 +12307,7 @@
             for (int i = start; i > finishTo; i--) {
                 ActivityRecord r = history.get(i);
                 mMainStack.requestFinishActivityLocked(r.appToken, resultCode, resultData,
-                        "navigate-up");
+                        "navigate-up", true);
                 // Only return the supplied result for the first activity finished
                 resultCode = Activity.RESULT_CANCELED;
                 resultData = null;
@@ -12242,7 +12333,7 @@
                         foundParentInTask = false;
                     }
                     mMainStack.requestFinishActivityLocked(parent.appToken, resultCode,
-                            resultData, "navigate-up");
+                            resultData, "navigate-up", true);
                 }
             }
             Binder.restoreCallingIdentity(origId);
@@ -13780,6 +13871,9 @@
             }
 
             mCurrentUserId = userId;
+            Integer userIdInt = Integer.valueOf(userId);
+            mUserLru.remove(userIdInt);
+            mUserLru.add(userIdInt);
             boolean haveActivities = mMainStack.switchUser(userId);
             if (!haveActivities) {
                 startHomeActivityLocked(userId, mStartedUsers.get(userId));
@@ -13928,6 +14022,23 @@
         }
     }
 
+    @Override
+    public boolean isUserRunning(int userId) {
+        if (checkCallingPermission(android.Manifest.permission.INTERACT_ACROSS_USERS)
+                != PackageManager.PERMISSION_GRANTED) {
+            String msg = "Permission Denial: isUserRunning() from pid="
+                    + Binder.getCallingPid()
+                    + ", uid=" + Binder.getCallingUid()
+                    + " requires " + android.Manifest.permission.INTERACT_ACROSS_USERS;
+            Slog.w(TAG, msg);
+            throw new SecurityException(msg);
+        }
+        synchronized (this) {
+            UserStartedState state = mStartedUsers.get(userId);
+            return state != null && state.mState != UserStartedState.STATE_STOPPING;
+        }
+    }
+
     private boolean userExists(int userId) {
         UserInfo user = getUserManager().getUserInfo(userId);
         return user != null;
diff --git a/services/java/com/android/server/am/ActivityRecord.java b/services/java/com/android/server/am/ActivityRecord.java
index c70650d..009fb5d 100644
--- a/services/java/com/android/server/am/ActivityRecord.java
+++ b/services/java/com/android/server/am/ActivityRecord.java
@@ -333,7 +333,6 @@
         state = ActivityState.INITIALIZING;
         frontOfTask = false;
         launchFailed = false;
-        haveState = false;
         stopped = false;
         delayedResume = false;
         finishing = false;
@@ -347,6 +346,11 @@
         idle = false;
         hasBeenLaunched = false;
 
+        // This starts out true, since the initial state of an activity
+        // is that we have everything, and we shouldn't never consider it
+        // lacking in state to be removed if it dies.
+        haveState = true;
+
         if (aInfo != null) {
             if (aInfo.targetActivity == null
                     || aInfo.launchMode == ActivityInfo.LAUNCH_MULTIPLE
diff --git a/services/java/com/android/server/am/ActivityStack.java b/services/java/com/android/server/am/ActivityStack.java
index 399ea59..bc835b6 100755
--- a/services/java/com/android/server/am/ActivityStack.java
+++ b/services/java/com/android/server/am/ActivityStack.java
@@ -422,11 +422,10 @@
     }
     
     final ActivityRecord topRunningActivityLocked(ActivityRecord notTop) {
-        // TODO: Don't look for any tasks from other users
         int i = mHistory.size()-1;
         while (i >= 0) {
             ActivityRecord r = mHistory.get(i);
-            if (!r.finishing && r != notTop) {
+            if (!r.finishing && r != notTop && r.userId == mCurrentUser) {
                 return r;
             }
             i--;
@@ -435,11 +434,10 @@
     }
 
     final ActivityRecord topRunningNonDelayedActivityLocked(ActivityRecord notTop) {
-        // TODO: Don't look for any tasks from other users
         int i = mHistory.size()-1;
         while (i >= 0) {
             ActivityRecord r = mHistory.get(i);
-            if (!r.finishing && !r.delayedResume && r != notTop) {
+            if (!r.finishing && !r.delayedResume && r != notTop && r.userId == mCurrentUser) {
                 return r;
             }
             i--;
@@ -457,12 +455,12 @@
      * @return Returns the HistoryRecord of the next activity on the stack.
      */
     final ActivityRecord topRunningActivityLocked(IBinder token, int taskId) {
-        // TODO: Don't look for any tasks from other users
         int i = mHistory.size()-1;
         while (i >= 0) {
             ActivityRecord r = mHistory.get(i);
             // Note: the taskId check depends on real taskId fields being non-zero
-            if (!r.finishing && (token != r.appToken) && (taskId != r.task.taskId)) {
+            if (!r.finishing && (token != r.appToken) && (taskId != r.task.taskId)
+                    && r.userId == mCurrentUser) {
                 return r;
             }
             i--;
@@ -727,7 +725,7 @@
                       + ", giving up", e);
                 mService.appDiedLocked(app, app.pid, app.thread);
                 requestFinishActivityLocked(r.appToken, Activity.RESULT_CANCELED, null,
-                        "2nd-crash");
+                        "2nd-crash", false);
                 return false;
             }
 
@@ -1094,7 +1092,7 @@
         if (prev != null) {
             if (prev.finishing) {
                 if (DEBUG_PAUSE) Slog.v(TAG, "Executing finish of activity: " + prev);
-                prev = finishCurrentActivityLocked(prev, FINISH_AFTER_VISIBLE);
+                prev = finishCurrentActivityLocked(prev, FINISH_AFTER_VISIBLE, false);
             } else if (prev.app != null) {
                 if (DEBUG_PAUSE) Slog.v(TAG, "Enqueueing pending stop: " + prev);
                 if (prev.waitingVisible) {
@@ -1400,7 +1398,7 @@
             // Launcher...
             if (mMainStack) {
                 ActivityOptions.abort(options);
-                return mService.startHomeActivityLocked(0, null);
+                return mService.startHomeActivityLocked(mCurrentUser, null);
             }
         }
 
@@ -1506,7 +1504,7 @@
                     Slog.d(TAG, "no-history finish of " + last + " on new resume");
                 }
                 requestFinishActivityLocked(last.appToken, Activity.RESULT_CANCELED, null,
-                        "no-history");
+                        "no-history", false);
             }
         }
 
@@ -1728,7 +1726,7 @@
                 // activity and try the next one.
                 Slog.w(TAG, "Exception thrown during resume of " + next, e);
                 requestFinishActivityLocked(next.appToken, Activity.RESULT_CANCELED, null,
-                        "resume-exception");
+                        "resume-exception", true);
                 return true;
             }
 
@@ -2082,7 +2080,7 @@
                                 continue;
                             }
                             if (finishActivityLocked(p, srcPos,
-                                    Activity.RESULT_CANCELED, null, "reset")) {
+                                    Activity.RESULT_CANCELED, null, "reset", false)) {
                                 replyChainEnd--;
                                 srcPos--;
                             }
@@ -2145,7 +2143,7 @@
                             continue;
                         }
                         if (finishActivityLocked(p, srcPos,
-                                Activity.RESULT_CANCELED, null, "reset")) {
+                                Activity.RESULT_CANCELED, null, "reset", false)) {
                             taskTopI--;
                             lastReparentPos--;
                             replyChainEnd--;
@@ -2202,7 +2200,7 @@
                             }
                             if (p.intent.getComponent().equals(target.intent.getComponent())) {
                                 if (finishActivityLocked(p, j,
-                                        Activity.RESULT_CANCELED, null, "replace")) {
+                                        Activity.RESULT_CANCELED, null, "replace", false)) {
                                     taskTopI--;
                                     lastReparentPos--;
                                 }
@@ -2272,7 +2270,7 @@
                         continue;
                     }
                     if (finishActivityLocked(r, i, Activity.RESULT_CANCELED,
-                            null, "clear")) {
+                            null, "clear", false)) {
                         i--;
                     }
                 }
@@ -2286,7 +2284,7 @@
                         int index = indexOfTokenLocked(ret.appToken);
                         if (index >= 0) {
                             finishActivityLocked(ret, index, Activity.RESULT_CANCELED,
-                                    null, "clear");
+                                    null, "clear", false);
                         }
                         return null;
                     }
@@ -2315,7 +2313,7 @@
                 continue;
             }
             if (!finishActivityLocked(r, i, Activity.RESULT_CANCELED,
-                    null, "clear")) {
+                    null, "clear", false)) {
                 i++;
             }
         }
@@ -2581,6 +2579,7 @@
             mDismissKeyguardOnNextActivity = false;
             mService.mWindowManager.dismissKeyguard();
         }
+        Slog.i(TAG, "DONE STARTING!");
         return err;
     }
   
@@ -3321,7 +3320,7 @@
                         Slog.d(TAG, "no-history finish of " + r);
                     }
                     requestFinishActivityLocked(r.appToken, Activity.RESULT_CANCELED, null,
-                            "no-history");
+                            "no-history", false);
                 } else {
                     if (DEBUG_STATES) Slog.d(TAG, "Not finishing noHistory " + r
                             + " on stop because we're just sleeping");
@@ -3533,7 +3532,7 @@
             ActivityRecord r = (ActivityRecord)stops.get(i);
             synchronized (mService) {
                 if (r.finishing) {
-                    finishCurrentActivityLocked(r, FINISH_IMMEDIATELY);
+                    finishCurrentActivityLocked(r, FINISH_IMMEDIATELY, false);
                 } else {
                     stopActivityLocked(r);
                 }
@@ -3587,7 +3586,7 @@
      * some reason it is being left as-is.
      */
     final boolean requestFinishActivityLocked(IBinder token, int resultCode,
-            Intent resultData, String reason) {
+            Intent resultData, String reason, boolean oomAdj) {
         int index = indexOfTokenLocked(token);
         if (DEBUG_RESULTS || DEBUG_STATES) Slog.v(
                 TAG, "Finishing activity @" + index + ": token=" + token
@@ -3598,7 +3597,7 @@
         }
         ActivityRecord r = mHistory.get(index);
 
-        finishActivityLocked(r, index, resultCode, resultData, reason);
+        finishActivityLocked(r, index, resultCode, resultData, reason, oomAdj);
         return true;
     }
 
@@ -3615,10 +3614,11 @@
                 if ((r.resultWho == null && resultWho == null) ||
                     (r.resultWho != null && r.resultWho.equals(resultWho))) {
                     finishActivityLocked(r, i,
-                            Activity.RESULT_CANCELED, null, "request-sub");
+                            Activity.RESULT_CANCELED, null, "request-sub", false);
                 }
             }
         }
+        mService.updateOomAdjLocked();
     }
 
     final boolean finishActivityAffinityLocked(IBinder token) {
@@ -3641,7 +3641,8 @@
             if (cur.taskAffinity != null && !cur.taskAffinity.equals(r.taskAffinity)) {
                 break;
             }
-            finishActivityLocked(cur, index, Activity.RESULT_CANCELED, null, "request-affinity");
+            finishActivityLocked(cur, index, Activity.RESULT_CANCELED, null,
+                    "request-affinity", true);
             index--;
         }
         return true;
@@ -3679,16 +3680,16 @@
      * list, or false if it is still in the list and will be removed later.
      */
     final boolean finishActivityLocked(ActivityRecord r, int index,
-            int resultCode, Intent resultData, String reason) {
-        return finishActivityLocked(r, index, resultCode, resultData, reason, false);
+            int resultCode, Intent resultData, String reason, boolean oomAdj) {
+        return finishActivityLocked(r, index, resultCode, resultData, reason, false, oomAdj);
     }
 
     /**
      * @return Returns true if this activity has been removed from the history
      * list, or false if it is still in the list and will be removed later.
      */
-    final boolean finishActivityLocked(ActivityRecord r, int index,
-            int resultCode, Intent resultData, String reason, boolean immediate) {
+    final boolean finishActivityLocked(ActivityRecord r, int index, int resultCode,
+            Intent resultData, String reason, boolean immediate, boolean oomAdj) {
         if (r.finishing) {
             Slog.w(TAG, "Duplicate finish request for " + r);
             return false;
@@ -3732,7 +3733,7 @@
 
         if (immediate) {
             return finishCurrentActivityLocked(r, index,
-                    FINISH_IMMEDIATELY) == null;
+                    FINISH_IMMEDIATELY, oomAdj) == null;
         } else if (mResumedActivity == r) {
             boolean endTask = index <= 0
                     || (mHistory.get(index-1)).task != r.task;
@@ -3756,7 +3757,7 @@
             // it is done pausing; else we can just directly finish it here.
             if (DEBUG_PAUSE) Slog.v(TAG, "Finish not pausing: " + r);
             return finishCurrentActivityLocked(r, index,
-                    FINISH_AFTER_PAUSE) == null;
+                    FINISH_AFTER_PAUSE, oomAdj) == null;
         } else {
             if (DEBUG_PAUSE) Slog.v(TAG, "Finish waiting for pause of: " + r);
         }
@@ -3769,17 +3770,17 @@
     private static final int FINISH_AFTER_VISIBLE = 2;
 
     private final ActivityRecord finishCurrentActivityLocked(ActivityRecord r,
-            int mode) {
+            int mode, boolean oomAdj) {
         final int index = indexOfActivityLocked(r);
         if (index < 0) {
             return null;
         }
 
-        return finishCurrentActivityLocked(r, index, mode);
+        return finishCurrentActivityLocked(r, index, mode, oomAdj);
     }
 
     private final ActivityRecord finishCurrentActivityLocked(ActivityRecord r,
-            int index, int mode) {
+            int index, int mode, boolean oomAdj) {
         // First things first: if this activity is currently visible,
         // and the resumed activity is not yet visible, then hold off on
         // finishing until the resumed one becomes visible.
@@ -3798,7 +3799,9 @@
             if (DEBUG_STATES) Slog.v(TAG, "Moving to STOPPING: " + r
                     + " (finish requested)");
             r.state = ActivityState.STOPPING;
-            mService.updateOomAdjLocked();
+            if (oomAdj) {
+                mService.updateOomAdjLocked();
+            }
             return r;
         }
 
@@ -3818,7 +3821,8 @@
                 || prevState == ActivityState.INITIALIZING) {
             // If this activity is already stopped, we can just finish
             // it right now.
-            boolean activityRemoved = destroyActivityLocked(r, true, true, "finish-imm");
+            boolean activityRemoved = destroyActivityLocked(r, true,
+                    oomAdj, "finish-imm");
             if (activityRemoved) {
                 resumeTopActivityLocked(null);
             }
@@ -4010,9 +4014,8 @@
                             ActivityManagerService.CANCEL_HEAVY_NOTIFICATION_MSG);
                 }
                 if (r.app.activities.size() == 0) {
-                    // No longer have activities, so update location in
-                    // LRU list.
-                    mService.updateLruProcessLocked(r.app, oomAdj, false);
+                    // No longer have activities, so update oom adj.
+                    mService.updateOomAdjLocked();
                 }
             }
 
diff --git a/services/java/com/android/server/am/ContentProviderRecord.java b/services/java/com/android/server/am/ContentProviderRecord.java
index c80d63a..de306b5 100644
--- a/services/java/com/android/server/am/ContentProviderRecord.java
+++ b/services/java/com/android/server/am/ContentProviderRecord.java
@@ -85,7 +85,7 @@
 
     public boolean canRunHere(ProcessRecord app) {
         return (info.multiprocess || info.processName.equals(app.processName))
-                && (uid == Process.SYSTEM_UID || uid == app.info.uid);
+                && uid == app.info.uid;
     }
 
     public void addExternalProcessHandleLocked(IBinder token) {
diff --git a/services/java/com/android/server/am/PendingIntentRecord.java b/services/java/com/android/server/am/PendingIntentRecord.java
index 0f72409..c61f13c 100644
--- a/services/java/com/android/server/am/PendingIntentRecord.java
+++ b/services/java/com/android/server/am/PendingIntentRecord.java
@@ -25,7 +25,6 @@
 import android.os.Bundle;
 import android.os.IBinder;
 import android.os.RemoteException;
-import android.os.UserHandle;
 import android.util.Slog;
 
 import java.io.PrintWriter;
diff --git a/services/java/com/android/server/am/ProviderMap.java b/services/java/com/android/server/am/ProviderMap.java
index 7a4fef6..9dbf5f5 100644
--- a/services/java/com/android/server/am/ProviderMap.java
+++ b/services/java/com/android/server/am/ProviderMap.java
@@ -18,7 +18,6 @@
 
 import android.content.ComponentName;
 import android.os.Binder;
-import android.os.Process;
 import android.os.RemoteException;
 import android.os.UserHandle;
 import android.util.Slog;
@@ -31,8 +30,6 @@
 import java.util.HashMap;
 import java.util.Iterator;
 import java.util.Map;
-import java.util.Map.Entry;
-import java.util.Set;
 
 /**
  * Keeps track of content providers by authority (name) and class. It separates the mapping by
@@ -44,6 +41,8 @@
 
     private static final boolean DBG = false;
 
+    private final ActivityManagerService mAm;
+
     private final HashMap<String, ContentProviderRecord> mSingletonByName
             = new HashMap<String, ContentProviderRecord>();
     private final HashMap<ComponentName, ContentProviderRecord> mSingletonByClass
@@ -54,6 +53,10 @@
     private final SparseArray<HashMap<ComponentName, ContentProviderRecord>> mProvidersByClassPerUser
             = new SparseArray<HashMap<ComponentName, ContentProviderRecord>>();
 
+    ProviderMap(ActivityManagerService am) {
+        mAm = am;
+    }
+
     ContentProviderRecord getProviderByName(String name) {
         return getProviderByName(name, -1);
     }
@@ -180,6 +183,53 @@
         }
     }
 
+    private boolean collectForceStopProvidersLocked(String name, int appId,
+            boolean doit, boolean evenPersistent, int userId,
+            HashMap<ComponentName, ContentProviderRecord> providers,
+            ArrayList<ContentProviderRecord> result) {
+        boolean didSomething = false;
+        for (ContentProviderRecord provider : providers.values()) {
+            if ((name == null || provider.info.packageName.equals(name))
+                    && (provider.proc == null || evenPersistent || !provider.proc.persistent)) {
+                if (!doit) {
+                    return true;
+                }
+                didSomething = true;
+                result.add(provider);
+            }
+        }
+        return didSomething;
+    }
+
+    boolean collectForceStopProviders(String name, int appId,
+            boolean doit, boolean evenPersistent, int userId,
+            ArrayList<ContentProviderRecord> result) {
+        boolean didSomething = collectForceStopProvidersLocked(name, appId, doit,
+                evenPersistent, userId, mSingletonByClass, result);
+        if (!doit && didSomething) {
+            return true;
+        }
+        if (userId == UserHandle.USER_ALL) {
+            for (int i=0; i<mProvidersByClassPerUser.size(); i++) {
+                if (collectForceStopProvidersLocked(name, appId, doit, evenPersistent,
+                        userId, mProvidersByClassPerUser.valueAt(i), result)) {
+                    if (!doit) {
+                        return true;
+                    }
+                    didSomething = true;
+                }
+            }
+        } else {
+            HashMap<ComponentName, ContentProviderRecord> items
+                    = getProvidersByClass(userId);
+            if (items != null) {
+                didSomething |= collectForceStopProvidersLocked(name, appId, doit,
+                        evenPersistent, userId, items, result);
+            }
+        }
+        return didSomething;
+    }
+
     private void dumpProvidersByClassLocked(PrintWriter pw, boolean dumpAll,
             HashMap<ComponentName, ContentProviderRecord> map) {
         Iterator<Map.Entry<ComponentName, ContentProviderRecord>> it = map.entrySet().iterator();
@@ -236,30 +286,33 @@
 
     protected boolean dumpProvider(FileDescriptor fd, PrintWriter pw, String name, String[] args,
             int opti, boolean dumpAll) {
+        ArrayList<ContentProviderRecord> allProviders = new ArrayList<ContentProviderRecord>();
         ArrayList<ContentProviderRecord> providers = new ArrayList<ContentProviderRecord>();
 
-        if ("all".equals(name)) {
-            synchronized (this) {
-                for (ContentProviderRecord r1 : getProvidersByClass(-1).values()) {
-                    providers.add(r1);
-                }
-            }
-        } else {
-            ComponentName componentName = name != null
-                    ? ComponentName.unflattenFromString(name) : null;
-            int objectId = 0;
-            if (componentName == null) {
-                // Not a '/' separated full component name; maybe an object ID?
-                try {
-                    objectId = Integer.parseInt(name, 16);
-                    name = null;
-                    componentName = null;
-                } catch (RuntimeException e) {
-                }
+        synchronized (mAm) {
+            allProviders.addAll(mSingletonByClass.values());
+            for (int i=0; i<mProvidersByClassPerUser.size(); i++) {
+                allProviders.addAll(mProvidersByClassPerUser.valueAt(i).values());
             }
 
-            synchronized (this) {
-                for (ContentProviderRecord r1 : getProvidersByClass(-1).values()) {
+            if ("all".equals(name)) {
+                providers.addAll(allProviders);
+            } else {
+                ComponentName componentName = name != null
+                        ? ComponentName.unflattenFromString(name) : null;
+                int objectId = 0;
+                if (componentName == null) {
+                    // Not a '/' separated full component name; maybe an object ID?
+                    try {
+                        objectId = Integer.parseInt(name, 16);
+                        name = null;
+                        componentName = null;
+                    } catch (RuntimeException e) {
+                    }
+                }
+
+                for (int i=0; i<allProviders.size(); i++) {
+                    ContentProviderRecord r1 = allProviders.get(i);
                     if (componentName != null) {
                         if (r1.name.equals(componentName)) {
                             providers.add(r1);
@@ -297,7 +350,7 @@
     private void dumpProvider(String prefix, FileDescriptor fd, PrintWriter pw,
             final ContentProviderRecord r, String[] args, boolean dumpAll) {
         String innerPrefix = prefix + "  ";
-        synchronized (this) {
+        synchronized (mAm) {
             pw.print(prefix); pw.print("PROVIDER ");
                     pw.print(r);
                     pw.print(" pid=");
diff --git a/services/java/com/android/server/display/DisplayDevice.java b/services/java/com/android/server/display/DisplayDevice.java
index bdc87f9..8eeefb4 100644
--- a/services/java/com/android/server/display/DisplayDevice.java
+++ b/services/java/com/android/server/display/DisplayDevice.java
@@ -17,7 +17,6 @@
 package com.android.server.display;
 
 import android.graphics.Rect;
-import android.graphics.SurfaceTexture;
 import android.os.IBinder;
 import android.view.Surface;
 
@@ -41,9 +40,9 @@
     private Rect mCurrentLayerStackRect;
     private Rect mCurrentDisplayRect;
 
-    // The display device does own its surface texture, but it should only set it
+    // The display device owns its surface, but it should only set it
     // within a transaction from performTraversalInTransactionLocked.
-    private SurfaceTexture mCurrentSurfaceTexture;
+    private Surface mCurrentSurface;
 
     public DisplayDevice(DisplayAdapter displayAdapter, IBinder displayToken) {
         mDisplayAdapter = displayAdapter;
@@ -109,11 +108,10 @@
      * Sets the display layer stack while in a transaction.
      */
     public final void setLayerStackInTransactionLocked(int layerStack) {
-        if (mCurrentLayerStack == layerStack) {
-            return;
+        if (mCurrentLayerStack != layerStack) {
+            mCurrentLayerStack = layerStack;
+            Surface.setDisplayLayerStack(mDisplayToken, layerStack);
         }
-        mCurrentLayerStack = layerStack;
-        Surface.setDisplayLayerStack(mDisplayToken, layerStack);
     }
 
     /**
@@ -126,28 +124,58 @@
      *            mapped to. displayRect is specified post-orientation, that is
      *            it uses the orientation seen by the end-user
      */
-    public final void setProjectionInTransactionLocked(int orientation, Rect layerStackRect, Rect displayRect) {
-        mCurrentOrientation = orientation;
-        if (mCurrentLayerStackRect == null) {
-            mCurrentLayerStackRect = new Rect();
+    public final void setProjectionInTransactionLocked(int orientation,
+            Rect layerStackRect, Rect displayRect) {
+        if (mCurrentOrientation != orientation
+                || mCurrentLayerStackRect == null
+                || !mCurrentLayerStackRect.equals(layerStackRect)
+                || mCurrentDisplayRect == null
+                || !mCurrentDisplayRect.equals(displayRect)) {
+            mCurrentOrientation = orientation;
+
+            if (mCurrentLayerStackRect == null) {
+                mCurrentLayerStackRect = new Rect();
+            }
+            mCurrentLayerStackRect.set(layerStackRect);
+
+            if (mCurrentDisplayRect == null) {
+                mCurrentDisplayRect = new Rect();
+            }
+            mCurrentDisplayRect.set(displayRect);
+
+            Surface.setDisplayProjection(mDisplayToken,
+                    orientation, layerStackRect, displayRect);
         }
-        mCurrentLayerStackRect.set(layerStackRect);
-        if (mCurrentDisplayRect == null) {
-            mCurrentDisplayRect = new Rect();
-        }
-        mCurrentDisplayRect.set(displayRect);
-        Surface.setDisplayProjection(mDisplayToken, orientation, layerStackRect, displayRect);
     }
 
     /**
-     * Sets the surface texture while in a transaction.
+     * Sets the display surface while in a transaction.
      */
-    public final void setSurfaceTextureInTransactionLocked(SurfaceTexture surfaceTexture) {
-        if (mCurrentSurfaceTexture == surfaceTexture) {
-            return;
+    public final void setSurfaceInTransactionLocked(Surface surface) {
+        if (mCurrentSurface != surface) {
+            mCurrentSurface = surface;
+            Surface.setDisplaySurface(mDisplayToken, surface);
         }
-        mCurrentSurfaceTexture = surfaceTexture;
-        Surface.setDisplaySurface(mDisplayToken, surfaceTexture);
+    }
+
+    /**
+     * Populates the specified viewport object with orientation,
+     * physical and logical rects based on the display's current projection.
+     */
+    public final void populateViewportLocked(DisplayViewport viewport) {
+        viewport.orientation = mCurrentOrientation;
+
+        if (mCurrentLayerStackRect != null) {
+            viewport.logicalFrame.set(mCurrentLayerStackRect);
+        } else {
+            viewport.logicalFrame.setEmpty();
+        }
+
+        if (mCurrentDisplayRect != null) {
+            viewport.physicalFrame.set(mCurrentDisplayRect);
+        } else {
+            viewport.physicalFrame.setEmpty();
+        }
     }
 
     /**
@@ -156,10 +184,11 @@
      */
     public void dumpLocked(PrintWriter pw) {
         pw.println("mAdapter=" + mDisplayAdapter.getName());
+        pw.println("mDisplayToken=" + mDisplayToken);
         pw.println("mCurrentLayerStack=" + mCurrentLayerStack);
         pw.println("mCurrentOrientation=" + mCurrentOrientation);
-        pw.println("mCurrentViewport=" + mCurrentLayerStackRect);
-        pw.println("mCurrentFrame=" + mCurrentDisplayRect);
-        pw.println("mCurrentSurfaceTexture=" + mCurrentSurfaceTexture);
+        pw.println("mCurrentLayerStackRect=" + mCurrentLayerStackRect);
+        pw.println("mCurrentDisplayRect=" + mCurrentDisplayRect);
+        pw.println("mCurrentSurface=" + mCurrentSurface);
     }
 }
diff --git a/services/java/com/android/server/display/DisplayDeviceInfo.java b/services/java/com/android/server/display/DisplayDeviceInfo.java
index 6f82119..7c57694 100644
--- a/services/java/com/android/server/display/DisplayDeviceInfo.java
+++ b/services/java/com/android/server/display/DisplayDeviceInfo.java
@@ -16,6 +16,8 @@
 
 package com.android.server.display;
 
+import android.util.DisplayMetrics;
+
 import libcore.util.Objects;
 
 /**
@@ -41,6 +43,21 @@
     public static final int FLAG_SUPPORTS_ROTATION = 1 << 2;
 
     /**
+     * Touch attachment: Display does not receive touch.
+     */
+    public static final int TOUCH_NONE = 0;
+
+    /**
+     * Touch attachment: Touch input is via the internal interface.
+     */
+    public static final int TOUCH_INTERNAL = 1;
+
+    /**
+     * Touch attachment: Touch input is via an external interface, such as USB.
+     */
+    public static final int TOUCH_EXTERNAL = 2;
+
+    /**
      * Gets the name of the display device, which may be derived from
      * EDID or other sources.  The name may be displayed to the user.
      */
@@ -58,13 +75,49 @@
      */
     public int height;
 
+    /**
+     * The refresh rate of the display.
+     */
     public float refreshRate;
+
+    /**
+     * The nominal apparent density of the display in DPI used for layout calculations.
+     * This density is sensitive to the viewing distance.  A big TV and a tablet may have
+     * the same apparent density even though the pixels on the TV are much bigger than
+     * those on the tablet.
+     */
     public int densityDpi;
+
+    /**
+     * The physical density of the display in DPI in the X direction.
+     * This density should specify the physical size of each pixel.
+     */
     public float xDpi;
+
+    /**
+     * The physical density of the display in DPI in the X direction.
+     * This density should specify the physical size of each pixel.
+     */
     public float yDpi;
 
+    /**
+     * Display flags.
+     */
     public int flags;
 
+    /**
+     * The touch attachment, per {@link DisplayViewport#touch}.
+     */
+    public int touch;
+
+    public void setAssumedDensityForExternalDisplay(int width, int height) {
+        densityDpi = Math.min(width, height) * DisplayMetrics.DENSITY_XHIGH / 1080;
+        // Technically, these values should be smaller than the apparent density
+        // but we don't know the physical size of the display.
+        xDpi = densityDpi;
+        yDpi = densityDpi;
+    }
+
     @Override
     public boolean equals(Object o) {
         return o instanceof DisplayDeviceInfo && equals((DisplayDeviceInfo)o);
@@ -79,7 +132,8 @@
                 && densityDpi == other.densityDpi
                 && xDpi == other.xDpi
                 && yDpi == other.yDpi
-                && flags == other.flags;
+                && flags == other.flags
+                && touch == other.touch;
     }
 
     @Override
@@ -96,6 +150,7 @@
         xDpi = other.xDpi;
         yDpi = other.yDpi;
         flags = other.flags;
+        touch = other.touch;
     }
 
     // For debugging purposes
@@ -103,7 +158,20 @@
     public String toString() {
         return "DisplayDeviceInfo{\"" + name + "\": " + width + " x " + height + ", " + refreshRate + " fps, "
                 + "density " + densityDpi + ", " + xDpi + " x " + yDpi + " dpi"
-                + flagsToString(flags) + "}";
+                + ", touch " + touchToString(touch) + flagsToString(flags) + "}";
+    }
+
+    private static String touchToString(int touch) {
+        switch (touch) {
+            case TOUCH_NONE:
+                return "NONE";
+            case TOUCH_INTERNAL:
+                return "INTERNAL";
+            case TOUCH_EXTERNAL:
+                return "EXTERNAL";
+            default:
+                return Integer.toString(touch);
+        }
     }
 
     private static String flagsToString(int flags) {
diff --git a/services/java/com/android/server/display/DisplayManagerService.java b/services/java/com/android/server/display/DisplayManagerService.java
index 706007a..39f2418 100644
--- a/services/java/com/android/server/display/DisplayManagerService.java
+++ b/services/java/com/android/server/display/DisplayManagerService.java
@@ -24,6 +24,7 @@
 import android.hardware.display.DisplayManagerGlobal;
 import android.hardware.display.IDisplayManager;
 import android.hardware.display.IDisplayManagerCallback;
+import android.hardware.display.WifiDisplayStatus;
 import android.os.Binder;
 import android.os.Handler;
 import android.os.IBinder;
@@ -58,7 +59,7 @@
  * </p><p>
  * Display adapters are only weakly coupled to the display manager service.
  * Display adapters communicate changes in display device state to the display manager
- * service asynchronously via a {@link DisplayAdapter.DisplayAdapterListener} registered
+ * service asynchronously via a {@link DisplayAdapter.Listener} registered
  * by the display manager service.  This separation of concerns is important for
  * two main reasons.  First, it neatly encapsulates the responsibilities of these
  * two classes: display adapters handle individual display devices whereas
@@ -95,6 +96,7 @@
     private static final int MSG_REGISTER_ADDITIONAL_DISPLAY_ADAPTERS = 2;
     private static final int MSG_DELIVER_DISPLAY_EVENT = 3;
     private static final int MSG_REQUEST_TRAVERSAL = 4;
+    private static final int MSG_UPDATE_VIEWPORT = 5;
 
     private final Context mContext;
     private final boolean mHeadless;
@@ -102,6 +104,7 @@
     private final Handler mUiHandler;
     private final DisplayAdapterListener mDisplayAdapterListener;
     private WindowManagerFuncs mWindowManagerFuncs;
+    private InputManagerFuncs mInputManagerFuncs;
 
     // The synchronization root for the display manager.
     // This lock guards most of the display manager's state.
@@ -137,6 +140,14 @@
     // to the surface flinger state.
     private boolean mPendingTraversal;
 
+    // The Wifi display adapter, or null if not registered.
+    private WifiDisplayAdapter mWifiDisplayAdapter;
+
+    // Viewports of the default display and the display that should receive touch
+    // input from an external source.  Used by the input system.
+    private final DisplayViewport mDefaultViewport = new DisplayViewport();
+    private final DisplayViewport mExternalTouchViewport = new DisplayViewport();
+
     // Temporary callback list, used when sending display events to applications.
     // May be used outside of the lock but only on the handler thread.
     private final ArrayList<CallbackRecord> mTempCallbacks = new ArrayList<CallbackRecord>();
@@ -144,6 +155,11 @@
     // Temporary display info, used for comparing display configurations.
     private final DisplayInfo mTempDisplayInfo = new DisplayInfo();
 
+    // Temporary viewports, used when sending new viewport information to the
+    // input system.  May be used outside of the lock but only on the handler thread.
+    private final DisplayViewport mTempDefaultViewport = new DisplayViewport();
+    private final DisplayViewport mTempExternalTouchViewport = new DisplayViewport();
+
     public DisplayManagerService(Context context, Handler mainHandler, Handler uiHandler) {
         mContext = context;
         mHeadless = SystemProperties.get(SYSTEM_HEADLESS).equals("1");
@@ -179,7 +195,7 @@
     }
 
     /**
-     * Called during initialization to associated the display manager with the
+     * Called during initialization to associate the display manager with the
      * window manager.
      */
     public void setWindowManager(WindowManagerFuncs windowManagerFuncs) {
@@ -190,6 +206,17 @@
     }
 
     /**
+     * Called during initialization to associate the display manager with the
+     * input manager.
+     */
+    public void setInputManager(InputManagerFuncs inputManagerFuncs) {
+        synchronized (mSyncRoot) {
+            mInputManagerFuncs = inputManagerFuncs;
+            scheduleTraversalLocked();
+        }
+    }
+
+    /**
      * Called when the system is ready to go.
      */
     public void systemReady(boolean safeMode, boolean onlyCore) {
@@ -254,8 +281,8 @@
      * Returns information about the specified logical display.
      *
      * @param displayId The logical display id.
-     * @param The logical display info, or null if the display does not exist.
-     * This object must be treated as immutable.
+     * @return The logical display info, or null if the display does not exist.  The
+     * returned object must be treated as immutable.
      */
     @Override // Binder call
     public DisplayInfo getDisplayInfo(int displayId) {
@@ -315,6 +342,87 @@
         }
     }
 
+    @Override // Binder call
+    public void scanWifiDisplays() {
+        if (mContext.checkCallingPermission(android.Manifest.permission.CONFIGURE_WIFI_DISPLAY)
+                != PackageManager.PERMISSION_GRANTED) {
+            throw new SecurityException("Requires CONFIGURE_WIFI_DISPLAY permission");
+        }
+
+        final long token = Binder.clearCallingIdentity();
+        try {
+            synchronized (mSyncRoot) {
+                if (mWifiDisplayAdapter != null) {
+                    mWifiDisplayAdapter.requestScanLocked();
+                }
+            }
+        } finally {
+            Binder.restoreCallingIdentity(token);
+        }
+    }
+
+    @Override // Binder call
+    public void connectWifiDisplay(String address) {
+        if (mContext.checkCallingPermission(android.Manifest.permission.CONFIGURE_WIFI_DISPLAY)
+                != PackageManager.PERMISSION_GRANTED) {
+            throw new SecurityException("Requires CONFIGURE_WIFI_DISPLAY permission");
+        }
+        if (address == null) {
+            throw new IllegalArgumentException("address must not be null");
+        }
+
+        final long token = Binder.clearCallingIdentity();
+        try {
+            synchronized (mSyncRoot) {
+                if (mWifiDisplayAdapter != null) {
+                    mWifiDisplayAdapter.requestConnectLocked(address);
+                }
+            }
+        } finally {
+            Binder.restoreCallingIdentity(token);
+        }
+    }
+
+    @Override // Binder call
+    public void disconnectWifiDisplay() {
+        if (mContext.checkCallingPermission(android.Manifest.permission.CONFIGURE_WIFI_DISPLAY)
+                != PackageManager.PERMISSION_GRANTED) {
+            throw new SecurityException("Requires CONFIGURE_WIFI_DISPLAY permission");
+        }
+
+        final long token = Binder.clearCallingIdentity();
+        try {
+            synchronized (mSyncRoot) {
+                if (mWifiDisplayAdapter != null) {
+                    mWifiDisplayAdapter.requestDisconnectLocked();
+                }
+            }
+        } finally {
+            Binder.restoreCallingIdentity(token);
+        }
+    }
+
+    @Override // Binder call
+    public WifiDisplayStatus getWifiDisplayStatus() {
+        if (mContext.checkCallingPermission(android.Manifest.permission.CONFIGURE_WIFI_DISPLAY)
+                != PackageManager.PERMISSION_GRANTED) {
+            throw new SecurityException("Requires CONFIGURE_WIFI_DISPLAY permission");
+        }
+
+        final long token = Binder.clearCallingIdentity();
+        try {
+            synchronized (mSyncRoot) {
+                if (mWifiDisplayAdapter != null) {
+                    return mWifiDisplayAdapter.getWifiDisplayStatusLocked();
+                } else {
+                    return new WifiDisplayStatus();
+                }
+            }
+        } finally {
+            Binder.restoreCallingIdentity(token);
+        }
+    }
+
     private void registerDefaultDisplayAdapter() {
         // Register default display adapter.
         synchronized (mSyncRoot) {
@@ -333,6 +441,9 @@
             if (shouldRegisterNonEssentialDisplayAdaptersLocked()) {
                 registerDisplayAdapterLocked(new OverlayDisplayAdapter(
                         mSyncRoot, mContext, mHandler, mDisplayAdapterListener, mUiHandler));
+                mWifiDisplayAdapter = new WifiDisplayAdapter(
+                        mSyncRoot, mContext, mHandler, mDisplayAdapterListener);
+                registerDisplayAdapterLocked(mWifiDisplayAdapter);
             }
         }
     }
@@ -409,7 +520,7 @@
         final int displayId = assignDisplayIdLocked(isDefault);
         final int layerStack = assignLayerStackLocked(displayId);
 
-        LogicalDisplay display = new LogicalDisplay(layerStack, device);
+        LogicalDisplay display = new LogicalDisplay(displayId, layerStack, device);
         display.updateLocked(mDisplayDevices);
         if (!display.isValidLocked()) {
             // This should never happen currently.
@@ -470,6 +581,10 @@
         }
         mRemovedDisplayDevices.clear();
 
+        // Clear all viewports before configuring displays so that we can keep
+        // track of which ones we have configured.
+        clearViewportsLocked();
+
         // Configure each display device.
         final int count = mDisplayDevices.size();
         for (int i = 0; i < count; i++) {
@@ -477,16 +592,45 @@
             configureDisplayInTransactionLocked(device);
             device.performTraversalInTransactionLocked();
         }
+
+        // Tell the input system about these new viewports.
+        if (mInputManagerFuncs != null) {
+            mHandler.sendEmptyMessage(MSG_UPDATE_VIEWPORT);
+        }
+    }
+
+    /**
+     * Tells the display manager whether there is interesting unique content on the
+     * specified logical display.  This is used to control automatic mirroring.
+     * <p>
+     * If the display has unique content, then the display manager arranges for it
+     * to be presented on a physical display if appropriate.  Otherwise, the display manager
+     * may choose to make the physical display mirror some other logical display.
+     * </p>
+     *
+     * @param displayId The logical display id to update.
+     * @param hasContent True if the logical display has content.
+     */
+    public void setDisplayHasContent(int displayId, boolean hasContent) {
+        synchronized (mSyncRoot) {
+            LogicalDisplay display = mLogicalDisplays.get(displayId);
+            if (display != null && display.hasContentLocked() != hasContent) {
+                display.setHasContentLocked(hasContent);
+                scheduleTraversalLocked();
+            }
+        }
+    }
+
+    private void clearViewportsLocked() {
+        mDefaultViewport.valid = false;
+        mExternalTouchViewport.valid = false;
     }
 
     private void configureDisplayInTransactionLocked(DisplayDevice device) {
-        // TODO: add a proper per-display mirroring control
-        boolean isMirroring = SystemProperties.getBoolean("debug.display.mirror", true);
-
         // Find the logical display that the display device is showing.
-        LogicalDisplay display = null;
-        if (!isMirroring) {
-            display = findLogicalDisplayForDeviceLocked(device);
+        LogicalDisplay display = findLogicalDisplayForDeviceLocked(device);
+        if (display != null && !display.hasContentLocked()) {
+            display = null;
         }
         if (display == null) {
             display = mLogicalDisplays.get(Display.DEFAULT_DISPLAY);
@@ -495,11 +639,30 @@
         // Apply the logical display configuration to the display device.
         if (display == null) {
             // TODO: no logical display for the device, blank it
-            Slog.d(TAG, "Missing logical display to use for physical display device: "
+            Slog.w(TAG, "Missing logical display to use for physical display device: "
                     + device.getDisplayDeviceInfoLocked());
+            return;
         } else {
             display.configureDisplayInTransactionLocked(device);
         }
+
+        // Update the viewports if needed.
+        DisplayDeviceInfo info = device.getDisplayDeviceInfoLocked();
+        if (!mDefaultViewport.valid
+                && (info.flags & DisplayDeviceInfo.FLAG_DEFAULT_DISPLAY) != 0) {
+            setViewportLocked(mDefaultViewport, display, device);
+        }
+        if (!mExternalTouchViewport.valid
+                && info.touch == DisplayDeviceInfo.TOUCH_EXTERNAL) {
+            setViewportLocked(mExternalTouchViewport, display, device);
+        }
+    }
+
+    private static void setViewportLocked(DisplayViewport viewport,
+            LogicalDisplay display, DisplayDevice device) {
+        viewport.valid = true;
+        viewport.displayId = display.getDisplayIdLocked();
+        device.populateViewportLocked(viewport);
     }
 
     private LogicalDisplay findLogicalDisplayForDeviceLocked(DisplayDevice device) {
@@ -592,6 +755,10 @@
                 pw.println("  Display " + displayId + ":");
                 display.dumpLocked(ipw);
             }
+
+            pw.println();
+            pw.println("Default viewport: " + mDefaultViewport);
+            pw.println("External touch viewport: " + mExternalTouchViewport);
         }
     }
 
@@ -609,12 +776,25 @@
      */
     public interface WindowManagerFuncs {
         /**
-         * Request that the window manager call {@link #performTraversalInTransaction}
-         * within a surface transaction at a later time.
+         * Request that the window manager call
+         * {@link #performTraversalInTransactionFromWindowManager} within a surface
+         * transaction at a later time.
          */
         void requestTraversal();
     }
 
+    /**
+     * Private interface to the input manager.
+     */
+    public interface InputManagerFuncs {
+        /**
+         * Sets information about the displays as needed by the input system.
+         * The input system should copy this information if required.
+         */
+        void setDisplayViewports(DisplayViewport defaultViewport,
+                DisplayViewport externalTouchViewport);
+    }
+
     private final class DisplayManagerHandler extends Handler {
         public DisplayManagerHandler(Looper looper) {
             super(looper, null, true /*async*/);
@@ -638,6 +818,16 @@
                 case MSG_REQUEST_TRAVERSAL:
                     mWindowManagerFuncs.requestTraversal();
                     break;
+
+                case MSG_UPDATE_VIEWPORT: {
+                    synchronized (mSyncRoot) {
+                        mTempDefaultViewport.copyFrom(mDefaultViewport);
+                        mTempExternalTouchViewport.copyFrom(mExternalTouchViewport);
+                    }
+                    mInputManagerFuncs.setDisplayViewports(
+                            mTempDefaultViewport, mTempExternalTouchViewport);
+                    break;
+                }
             }
         }
     }
diff --git a/services/java/com/android/server/display/DisplayViewport.java b/services/java/com/android/server/display/DisplayViewport.java
new file mode 100644
index 0000000..ed4016d
--- /dev/null
+++ b/services/java/com/android/server/display/DisplayViewport.java
@@ -0,0 +1,65 @@
+/*
+ * Copyright (C) 2012 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.display;
+
+import android.graphics.Rect;
+
+/**
+ * Describes how the pixels of physical display device reflects the content of
+ * a logical display.
+ * <p>
+ * This information is used by the input system to translate touch input from
+ * physical display coordinates into logical display coordinates.
+ * </p>
+ */
+public final class DisplayViewport {
+    // True if this viewport is valid.
+    public boolean valid;
+
+    // The logical display id.
+    public int displayId;
+
+    // The rotation applied to the physical coordinate system.
+    public int orientation;
+
+    // The portion of the logical display that are presented on this physical display.
+    public final Rect logicalFrame = new Rect();
+
+    // The portion of the (rotated) physical display that shows the logical display contents.
+    // The relation between logical and physical frame defines how the coordinate system
+    // should be scaled or translated after rotation.
+    public final Rect physicalFrame = new Rect();
+
+    public void copyFrom(DisplayViewport viewport) {
+        valid = viewport.valid;
+        displayId = viewport.displayId;
+        orientation = viewport.orientation;
+        logicalFrame.set(viewport.logicalFrame);
+        physicalFrame.set(viewport.physicalFrame);
+    }
+
+    // For debugging purposes.
+    @Override
+    public String toString() {
+        return "DisplayViewport{valid=" + valid
+                + ", displayId=" + displayId
+                + ", orientation=" + orientation
+                + ", logicalFrame=" + logicalFrame
+                + ", physicalFrame=" + physicalFrame
+                + "}";
+    }
+}
diff --git a/services/java/com/android/server/display/HeadlessDisplayAdapter.java b/services/java/com/android/server/display/HeadlessDisplayAdapter.java
index 3aaacf1..7629db6 100644
--- a/services/java/com/android/server/display/HeadlessDisplayAdapter.java
+++ b/services/java/com/android/server/display/HeadlessDisplayAdapter.java
@@ -61,6 +61,7 @@
                 mInfo.yDpi = 160;
                 mInfo.flags = DisplayDeviceInfo.FLAG_DEFAULT_DISPLAY
                         | DisplayDeviceInfo.FLAG_SECURE;
+                mInfo.touch = DisplayDeviceInfo.TOUCH_NONE;
             }
             return mInfo;
         }
diff --git a/services/java/com/android/server/display/LocalDisplayAdapter.java b/services/java/com/android/server/display/LocalDisplayAdapter.java
index 4a8829a..80c860b 100644
--- a/services/java/com/android/server/display/LocalDisplayAdapter.java
+++ b/services/java/com/android/server/display/LocalDisplayAdapter.java
@@ -120,19 +120,22 @@
                 mInfo.width = mPhys.width;
                 mInfo.height = mPhys.height;
                 mInfo.refreshRate = mPhys.refreshRate;
-                mInfo.densityDpi = (int)(mPhys.density * 160 + 0.5f);
-                mInfo.xDpi = mPhys.xDpi;
-                mInfo.yDpi = mPhys.yDpi;
                 if (mBuiltInDisplayId == Surface.BUILT_IN_DISPLAY_ID_MAIN) {
                     mInfo.name = getContext().getResources().getString(
                             com.android.internal.R.string.display_manager_built_in_display_name);
                     mInfo.flags = DisplayDeviceInfo.FLAG_DEFAULT_DISPLAY
                             | DisplayDeviceInfo.FLAG_SECURE
                             | DisplayDeviceInfo.FLAG_SUPPORTS_ROTATION;
+                    mInfo.densityDpi = (int)(mPhys.density * 160 + 0.5f);
+                    mInfo.xDpi = mPhys.xDpi;
+                    mInfo.yDpi = mPhys.yDpi;
+                    mInfo.touch = DisplayDeviceInfo.TOUCH_INTERNAL;
                 } else {
                     mInfo.name = getContext().getResources().getString(
                             com.android.internal.R.string.display_manager_hdmi_display_name);
                     mInfo.flags = DisplayDeviceInfo.FLAG_SECURE;
+                    mInfo.touch = DisplayDeviceInfo.TOUCH_EXTERNAL;
+                    mInfo.setAssumedDensityForExternalDisplay(mPhys.width, mPhys.height);
                 }
             }
             return mInfo;
diff --git a/services/java/com/android/server/display/LogicalDisplay.java b/services/java/com/android/server/display/LogicalDisplay.java
index c864189..2e75260 100644
--- a/services/java/com/android/server/display/LogicalDisplay.java
+++ b/services/java/com/android/server/display/LogicalDisplay.java
@@ -54,6 +54,7 @@
 final class LogicalDisplay {
     private final DisplayInfo mBaseDisplayInfo = new DisplayInfo();
 
+    private final int mDisplayId;
     private final int mLayerStack;
     private DisplayInfo mOverrideDisplayInfo; // set by the window manager
     private DisplayInfo mInfo;
@@ -63,16 +64,29 @@
     private DisplayDevice mPrimaryDisplayDevice;
     private DisplayDeviceInfo mPrimaryDisplayDeviceInfo;
 
+    // True if the logical display has unique content.
+    private boolean mHasContent;
+
     // Temporary rectangle used when needed.
     private final Rect mTempLayerStackRect = new Rect();
     private final Rect mTempDisplayRect = new Rect();
 
-    public LogicalDisplay(int layerStack, DisplayDevice primaryDisplayDevice) {
+    public LogicalDisplay(int displayId, int layerStack, DisplayDevice primaryDisplayDevice) {
+        mDisplayId = displayId;
         mLayerStack = layerStack;
         mPrimaryDisplayDevice = primaryDisplayDevice;
     }
 
     /**
+     * Gets the logical display id of this logical display.
+     *
+     * @return The logical display id.
+     */
+    public int getDisplayIdLocked() {
+        return mDisplayId;
+    }
+
+    /**
      * Gets the primary display device associated with this logical display.
      *
      * @return The primary display device.
@@ -126,7 +140,7 @@
 
     /**
      * Returns true if the logical display is in a valid state.
-     * This method should be checked after calling {@link #update} to handle the
+     * This method should be checked after calling {@link #updateLocked} to handle the
      * case where a logical display should be removed because all of its associated
      * display devices are gone or if it is otherwise no longer needed.
      *
@@ -256,6 +270,29 @@
         device.setProjectionInTransactionLocked(orientation, mTempLayerStackRect, mTempDisplayRect);
     }
 
+    /**
+     * Returns true if the logical display has unique content.
+     * <p>
+     * If the display has unique content then we will try to ensure that it is
+     * visible on at least its primary display device.  Otherwise we will ignore the
+     * logical display and perhaps show mirrored content on the primary display device.
+     * </p>
+     *
+     * @return True if the display has unique content.
+     */
+    public boolean hasContentLocked() {
+        return mHasContent;
+    }
+
+    /**
+     * Sets whether the logical display has unique content.
+     *
+     * @param hasContent True if the display has unique content.
+     */
+    public void setHasContentLocked(boolean hasContent) {
+        mHasContent = hasContent;
+    }
+
     public void dumpLocked(PrintWriter pw) {
         pw.println("mLayerStack=" + mLayerStack);
         pw.println("mPrimaryDisplayDevice=" + (mPrimaryDisplayDevice != null ?
diff --git a/services/java/com/android/server/display/OverlayDisplayAdapter.java b/services/java/com/android/server/display/OverlayDisplayAdapter.java
index ea7e88de..9b0e534 100644
--- a/services/java/com/android/server/display/OverlayDisplayAdapter.java
+++ b/services/java/com/android/server/display/OverlayDisplayAdapter.java
@@ -16,9 +16,11 @@
 
 package com.android.server.display;
 
+import com.android.internal.util.DumpUtils;
+import com.android.internal.util.IndentingPrintWriter;
+
 import android.content.Context;
 import android.database.ContentObserver;
-import android.graphics.SurfaceTexture;
 import android.os.Handler;
 import android.os.IBinder;
 import android.provider.Settings;
@@ -28,7 +30,6 @@
 import android.view.Surface;
 
 import java.io.PrintWriter;
-import java.io.StringWriter;
 import java.util.ArrayList;
 import java.util.regex.Matcher;
 import java.util.regex.Pattern;
@@ -71,6 +72,7 @@
     @Override
     public void dumpLocked(PrintWriter pw) {
         super.dumpLocked(pw);
+
         pw.println("mCurrentOverlaySetting=" + mCurrentOverlaySetting);
         pw.println("mOverlays: size=" + mOverlays.size());
         for (OverlayDisplayHandle overlay : mOverlays) {
@@ -81,17 +83,19 @@
     @Override
     public void registerLocked() {
         super.registerLocked();
-        getContext().getContentResolver().registerContentObserver(
-                Settings.System.getUriFor(Settings.Secure.OVERLAY_DISPLAY_DEVICES), true,
-                new ContentObserver(getHandler()) {
-                    @Override
-                    public void onChange(boolean selfChange) {
-                        synchronized (getSyncRoot()) {
-                            updateOverlayDisplayDevicesLocked();
-                        }
-                    }
-                });
-        updateOverlayDisplayDevicesLocked();
+
+        getHandler().post(new Runnable() {
+            @Override
+            public void run() {
+                getContext().getContentResolver().registerContentObserver(
+                        Settings.System.getUriFor(Settings.Secure.OVERLAY_DISPLAY_DEVICES),
+                        true, new SettingsObserver(getHandler()));
+
+                synchronized (getSyncRoot()) {
+                    updateOverlayDisplayDevicesLocked();
+                }
+            }
+        });
     }
 
     private void updateOverlayDisplayDevicesLocked() {
@@ -167,6 +171,19 @@
         }
     }
 
+    private final class SettingsObserver extends ContentObserver {
+        public SettingsObserver(Handler handler) {
+            super(handler);
+        }
+
+        @Override
+        public void onChange(boolean selfChange) {
+            synchronized (getSyncRoot()) {
+                updateOverlayDisplayDevicesLocked();
+            }
+        }
+    }
+
     private final class OverlayDisplayDevice extends DisplayDevice {
         private final String mName;
         private final int mWidth;
@@ -174,35 +191,29 @@
         private final float mRefreshRate;
         private final int mDensityDpi;
 
-        private SurfaceTexture mSurfaceTexture;
-        private boolean mSurfaceTextureChanged;
-
+        private Surface mSurface;
         private DisplayDeviceInfo mInfo;
 
         public OverlayDisplayDevice(IBinder displayToken, String name,
-                int width, int height, float refreshRate, int densityDpi) {
+                int width, int height, float refreshRate, int densityDpi,
+                Surface surface) {
             super(OverlayDisplayAdapter.this, displayToken);
             mName = name;
             mWidth = width;
             mHeight = height;
             mRefreshRate = refreshRate;
             mDensityDpi = densityDpi;
+            mSurface = surface;
         }
 
-        public void setSurfaceTextureLocked(SurfaceTexture surfaceTexture) {
-            if (surfaceTexture != mSurfaceTexture) {
-                mSurfaceTexture = surfaceTexture;
-                mSurfaceTextureChanged = true;
-                sendTraversalRequestLocked();
-            }
+        public void clearSurfaceLocked() {
+            mSurface = null;
+            sendTraversalRequestLocked();
         }
 
         @Override
         public void performTraversalInTransactionLocked() {
-            if (mSurfaceTextureChanged) {
-                setSurfaceTextureInTransactionLocked(mSurfaceTexture);
-                mSurfaceTextureChanged = false;
-            }
+            setSurfaceInTransactionLocked(mSurface);
         }
 
         @Override
@@ -217,6 +228,7 @@
                 mInfo.xDpi = mDensityDpi;
                 mInfo.yDpi = mDensityDpi;
                 mInfo.flags = DisplayDeviceInfo.FLAG_SECURE;
+                mInfo.touch = DisplayDeviceInfo.TOUCH_NONE;
             }
             return mInfo;
         }
@@ -256,12 +268,11 @@
 
         // Called on the UI thread.
         @Override
-        public void onWindowCreated(SurfaceTexture surfaceTexture, float refreshRate) {
+        public void onWindowCreated(Surface surface, float refreshRate) {
             synchronized (getSyncRoot()) {
                 IBinder displayToken = Surface.createDisplay(mName);
                 mDevice = new OverlayDisplayDevice(displayToken, mName,
-                        mWidth, mHeight, refreshRate, mDensityDpi);
-                mDevice.setSurfaceTextureLocked(surfaceTexture);
+                        mWidth, mHeight, refreshRate, mDensityDpi, surface);
 
                 sendDisplayDeviceEventLocked(mDevice, DISPLAY_DEVICE_EVENT_ADDED);
             }
@@ -272,40 +283,24 @@
         public void onWindowDestroyed() {
             synchronized (getSyncRoot()) {
                 if (mDevice != null) {
-                    mDevice.setSurfaceTextureLocked(null);
-
+                    mDevice.clearSurfaceLocked();
                     sendDisplayDeviceEventLocked(mDevice, DISPLAY_DEVICE_EVENT_REMOVED);
                 }
             }
         }
 
         public void dumpLocked(PrintWriter pw) {
-            pw.println("  " + mName + ": ");
+            pw.println("  " + mName + ":");
             pw.println("    mWidth=" + mWidth);
             pw.println("    mHeight=" + mHeight);
             pw.println("    mDensityDpi=" + mDensityDpi);
             pw.println("    mGravity=" + mGravity);
 
             // Try to dump the window state.
-            // This call may hang if the UI thread is waiting to acquire our lock so
-            // we use a short timeout to recover just in case.
             if (mWindow != null) {
-                final StringWriter sw = new StringWriter();
-                final OverlayDisplayWindow window = mWindow;
-                if (mUiHandler.runWithScissors(new Runnable() {
-                    @Override
-                    public void run() {
-                        PrintWriter lpw = new PrintWriter(sw);
-                        window.dump(lpw);
-                        lpw.close();
-                    }
-                }, 200)) {
-                    for (String line : sw.toString().split("\n")) {
-                        pw.println(line);
-                    }
-                } else {
-                    pw.println("    ... timed out while attempting to dump window state");
-                }
+                final IndentingPrintWriter ipw = new IndentingPrintWriter(pw, "    ");
+                ipw.increaseIndent();
+                DumpUtils.dumpAsync(mUiHandler, mWindow, ipw, 200);
             }
         }
 
diff --git a/services/java/com/android/server/display/OverlayDisplayWindow.java b/services/java/com/android/server/display/OverlayDisplayWindow.java
index 6adfa0f..d08f65f 100644
--- a/services/java/com/android/server/display/OverlayDisplayWindow.java
+++ b/services/java/com/android/server/display/OverlayDisplayWindow.java
@@ -16,6 +16,8 @@
 
 package com.android.server.display;
 
+import com.android.internal.util.DumpUtils;
+
 import android.content.Context;
 import android.graphics.SurfaceTexture;
 import android.hardware.display.DisplayManager;
@@ -27,6 +29,7 @@
 import android.view.LayoutInflater;
 import android.view.MotionEvent;
 import android.view.ScaleGestureDetector;
+import android.view.Surface;
 import android.view.TextureView;
 import android.view.View;
 import android.view.WindowManager;
@@ -42,7 +45,7 @@
  * No locks are held by this object and locks must not be held while making called into it.
  * </p>
  */
-final class OverlayDisplayWindow {
+final class OverlayDisplayWindow implements DumpUtils.Dump {
     private static final String TAG = "OverlayDisplayWindow";
     private static final boolean DEBUG = false;
 
@@ -144,18 +147,18 @@
     }
 
     public void dump(PrintWriter pw) {
-        pw.println("    mWindowVisible=" + mWindowVisible);
-        pw.println("    mWindowX=" + mWindowX);
-        pw.println("    mWindowY=" + mWindowY);
-        pw.println("    mWindowScale=" + mWindowScale);
-        pw.println("    mWindowParams=" + mWindowParams);
+        pw.println("mWindowVisible=" + mWindowVisible);
+        pw.println("mWindowX=" + mWindowX);
+        pw.println("mWindowY=" + mWindowY);
+        pw.println("mWindowScale=" + mWindowScale);
+        pw.println("mWindowParams=" + mWindowParams);
         if (mTextureView != null) {
-            pw.println("    mTextureView.getScaleX()=" + mTextureView.getScaleX());
-            pw.println("    mTextureView.getScaleY()=" + mTextureView.getScaleY());
+            pw.println("mTextureView.getScaleX()=" + mTextureView.getScaleX());
+            pw.println("mTextureView.getScaleY()=" + mTextureView.getScaleY());
         }
-        pw.println("    mLiveTranslationX=" + mLiveTranslationX);
-        pw.println("    mLiveTranslationY=" + mLiveTranslationY);
-        pw.println("    mLiveScale=" + mLiveScale);
+        pw.println("mLiveTranslationX=" + mLiveTranslationX);
+        pw.println("mLiveTranslationY=" + mLiveTranslationY);
+        pw.println("mLiveScale=" + mLiveScale);
     }
 
     private boolean updateDefaultDisplayInfo() {
@@ -286,22 +289,25 @@
     private final SurfaceTextureListener mSurfaceTextureListener =
             new SurfaceTextureListener() {
         @Override
-        public void onSurfaceTextureAvailable(SurfaceTexture surface, int width, int height) {
-            mListener.onWindowCreated(surface, mDefaultDisplayInfo.refreshRate);
+        public void onSurfaceTextureAvailable(SurfaceTexture surfaceTexture,
+                int width, int height) {
+            mListener.onWindowCreated(new Surface(surfaceTexture),
+                    mDefaultDisplayInfo.refreshRate);
         }
 
         @Override
-        public boolean onSurfaceTextureDestroyed(SurfaceTexture surface) {
+        public boolean onSurfaceTextureDestroyed(SurfaceTexture surfaceTexture) {
             mListener.onWindowDestroyed();
             return true;
         }
 
         @Override
-        public void onSurfaceTextureSizeChanged(SurfaceTexture surface, int width, int height) {
+        public void onSurfaceTextureSizeChanged(SurfaceTexture surfaceTexture,
+                int width, int height) {
         }
 
         @Override
-        public void onSurfaceTextureUpdated(SurfaceTexture surface) {
+        public void onSurfaceTextureUpdated(SurfaceTexture surfaceTexture) {
         }
     };
 
@@ -355,7 +361,7 @@
      * Watches for significant changes in the overlay display window lifecycle.
      */
     public interface Listener {
-        public void onWindowCreated(SurfaceTexture surfaceTexture, float refreshRate);
+        public void onWindowCreated(Surface surface, float refreshRate);
         public void onWindowDestroyed();
     }
 }
\ No newline at end of file
diff --git a/services/java/com/android/server/display/WifiDisplayAdapter.java b/services/java/com/android/server/display/WifiDisplayAdapter.java
new file mode 100644
index 0000000..ee82050
--- /dev/null
+++ b/services/java/com/android/server/display/WifiDisplayAdapter.java
@@ -0,0 +1,428 @@
+/*
+ * Copyright (C) 2012 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.display;
+
+import com.android.internal.util.DumpUtils;
+import com.android.internal.util.IndentingPrintWriter;
+
+import android.content.Context;
+import android.content.Intent;
+import android.hardware.display.DisplayManager;
+import android.hardware.display.WifiDisplay;
+import android.hardware.display.WifiDisplayStatus;
+import android.media.RemoteDisplay;
+import android.os.Handler;
+import android.os.IBinder;
+import android.util.Slog;
+import android.view.Surface;
+
+import java.io.PrintWriter;
+import java.util.Arrays;
+
+/**
+ * Connects to Wifi displays that implement the Miracast protocol.
+ * <p>
+ * The Wifi display protocol relies on Wifi direct for discovering and pairing
+ * with the display.  Once connected, the Media Server opens an RTSP socket and accepts
+ * a connection from the display.  After session negotiation, the Media Server
+ * streams encoded buffers to the display.
+ * </p><p>
+ * This class is responsible for connecting to Wifi displays and mediating
+ * the interactions between Media Server, Surface Flinger and the Display Manager Service.
+ * </p><p>
+ * Display adapters are guarded by the {@link DisplayManagerService.SyncRoot} lock.
+ * </p>
+ */
+final class WifiDisplayAdapter extends DisplayAdapter {
+    private static final String TAG = "WifiDisplayAdapter";
+
+    private WifiDisplayHandle mDisplayHandle;
+    private WifiDisplayController mDisplayController;
+
+    private WifiDisplayStatus mCurrentStatus;
+    private boolean mEnabled;
+    private int mScanState;
+    private int mActiveDisplayState;
+    private WifiDisplay mActiveDisplay;
+    private WifiDisplay[] mKnownDisplays = WifiDisplay.EMPTY_ARRAY;
+
+    private boolean mPendingStatusChangeBroadcast;
+
+    public WifiDisplayAdapter(DisplayManagerService.SyncRoot syncRoot,
+            Context context, Handler handler, Listener listener) {
+        super(syncRoot, context, handler, listener, TAG);
+    }
+
+    @Override
+    public void dumpLocked(PrintWriter pw) {
+        super.dumpLocked(pw);
+
+        if (mDisplayHandle == null) {
+            pw.println("mDisplayHandle=null");
+        } else {
+            pw.println("mDisplayHandle:");
+            mDisplayHandle.dumpLocked(pw);
+        }
+
+        pw.println("mCurrentStatus=" + getWifiDisplayStatusLocked());
+        pw.println("mEnabled=" + mEnabled);
+        pw.println("mScanState=" + mScanState);
+        pw.println("mActiveDisplayState=" + mActiveDisplayState);
+        pw.println("mActiveDisplay=" + mActiveDisplay);
+        pw.println("mKnownDisplays=" + Arrays.toString(mKnownDisplays));
+        pw.println("mPendingStatusChangeBroadcast=" + mPendingStatusChangeBroadcast);
+
+        // Try to dump the controller state.
+        if (mDisplayController == null) {
+            pw.println("mDisplayController=null");
+        } else {
+            pw.println("mDisplayController:");
+            final IndentingPrintWriter ipw = new IndentingPrintWriter(pw, "  ");
+            ipw.increaseIndent();
+            DumpUtils.dumpAsync(getHandler(), mDisplayController, ipw, 200);
+        }
+    }
+
+    @Override
+    public void registerLocked() {
+        super.registerLocked();
+
+        getHandler().post(new Runnable() {
+            @Override
+            public void run() {
+                mDisplayController = new WifiDisplayController(
+                        getContext(), getHandler(), mWifiDisplayListener);
+            }
+        });
+    }
+
+    public void requestScanLocked() {
+        getHandler().post(new Runnable() {
+            @Override
+            public void run() {
+                if (mDisplayController != null) {
+                    mDisplayController.requestScan();
+                }
+            }
+        });
+    }
+
+    public void requestConnectLocked(final String address) {
+        getHandler().post(new Runnable() {
+            @Override
+            public void run() {
+                if (mDisplayController != null) {
+                    mDisplayController.requestConnect(address);
+                }
+            }
+        });
+    }
+
+    public void requestDisconnectLocked() {
+        getHandler().post(new Runnable() {
+            @Override
+            public void run() {
+                if (mDisplayController != null) {
+                    mDisplayController.requestDisconnect();
+                }
+            }
+        });
+    }
+
+    public WifiDisplayStatus getWifiDisplayStatusLocked() {
+        if (mCurrentStatus == null) {
+            mCurrentStatus = new WifiDisplayStatus(mEnabled, mScanState, mActiveDisplayState,
+                    mActiveDisplay, mKnownDisplays);
+        }
+        return mCurrentStatus;
+    }
+
+    private void handleConnectLocked(WifiDisplay display, String iface) {
+        handleDisconnectLocked();
+
+        mDisplayHandle = new WifiDisplayHandle(display.getDeviceName(), iface);
+    }
+
+    private void handleDisconnectLocked() {
+        if (mDisplayHandle != null) {
+            mDisplayHandle.disposeLocked();
+            mDisplayHandle = null;
+        }
+    }
+
+    private void scheduleStatusChangedBroadcastLocked() {
+        if (!mPendingStatusChangeBroadcast) {
+            mPendingStatusChangeBroadcast = true;
+            getHandler().post(mStatusChangeBroadcast);
+        }
+    }
+
+    private final Runnable mStatusChangeBroadcast = new Runnable() {
+        @Override
+        public void run() {
+            final Intent intent;
+            synchronized (getSyncRoot()) {
+                if (!mPendingStatusChangeBroadcast) {
+                    return;
+                }
+
+                mPendingStatusChangeBroadcast = false;
+                intent = new Intent(DisplayManager.ACTION_WIFI_DISPLAY_STATUS_CHANGED);
+                intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
+                intent.putExtra(DisplayManager.EXTRA_WIFI_DISPLAY_STATUS,
+                        getWifiDisplayStatusLocked());
+            }
+
+            // Send protected broadcast about wifi display status to receivers that
+            // have the required permission.
+            getContext().sendBroadcast(intent,
+                    android.Manifest.permission.CONFIGURE_WIFI_DISPLAY);
+        }
+    };
+
+    private final WifiDisplayController.Listener mWifiDisplayListener =
+            new WifiDisplayController.Listener() {
+        @Override
+        public void onEnablementChanged(boolean enabled) {
+            synchronized (getSyncRoot()) {
+                if (mEnabled != enabled) {
+                    mCurrentStatus = null;
+                    mEnabled = enabled;
+                    scheduleStatusChangedBroadcastLocked();
+                }
+            }
+        }
+
+        @Override
+        public void onScanStarted() {
+            synchronized (getSyncRoot()) {
+                if (mScanState != WifiDisplayStatus.SCAN_STATE_SCANNING) {
+                    mCurrentStatus = null;
+                    mScanState = WifiDisplayStatus.SCAN_STATE_SCANNING;
+                    scheduleStatusChangedBroadcastLocked();
+                }
+            }
+        }
+
+        public void onScanFinished(WifiDisplay[] knownDisplays) {
+            synchronized (getSyncRoot()) {
+                if (mScanState != WifiDisplayStatus.SCAN_STATE_NOT_SCANNING
+                        || !Arrays.equals(mKnownDisplays, knownDisplays)) {
+                    mCurrentStatus = null;
+                    mScanState = WifiDisplayStatus.SCAN_STATE_NOT_SCANNING;
+                    mKnownDisplays = knownDisplays;
+                    scheduleStatusChangedBroadcastLocked();
+                }
+            }
+        }
+
+        @Override
+        public void onDisplayConnecting(WifiDisplay display) {
+            synchronized (getSyncRoot()) {
+                if (mActiveDisplayState != WifiDisplayStatus.DISPLAY_STATE_CONNECTING
+                        || mActiveDisplay == null
+                        || !mActiveDisplay.equals(display)) {
+                    mCurrentStatus = null;
+                    mActiveDisplayState = WifiDisplayStatus.DISPLAY_STATE_CONNECTING;
+                    mActiveDisplay = display;
+                    scheduleStatusChangedBroadcastLocked();
+                }
+            }
+        }
+
+        @Override
+        public void onDisplayConnectionFailed() {
+            synchronized (getSyncRoot()) {
+                if (mActiveDisplayState != WifiDisplayStatus.DISPLAY_STATE_NOT_CONNECTED
+                        || mActiveDisplay != null) {
+                    mCurrentStatus = null;
+                    mActiveDisplayState = WifiDisplayStatus.DISPLAY_STATE_NOT_CONNECTED;
+                    mActiveDisplay = null;
+                    scheduleStatusChangedBroadcastLocked();
+                }
+            }
+        }
+
+        @Override
+        public void onDisplayConnected(WifiDisplay display, String iface) {
+            synchronized (getSyncRoot()) {
+                handleConnectLocked(display, iface);
+
+                if (mActiveDisplayState != WifiDisplayStatus.DISPLAY_STATE_CONNECTED
+                        || mActiveDisplay == null
+                        || !mActiveDisplay.equals(display)) {
+                    mCurrentStatus = null;
+                    mActiveDisplayState = WifiDisplayStatus.DISPLAY_STATE_CONNECTED;
+                    mActiveDisplay = display;
+                    scheduleStatusChangedBroadcastLocked();
+                }
+            }
+        }
+
+        @Override
+        public void onDisplayDisconnected() {
+            // Stop listening.
+            synchronized (getSyncRoot()) {
+                handleDisconnectLocked();
+
+                if (mActiveDisplayState != WifiDisplayStatus.DISPLAY_STATE_NOT_CONNECTED
+                        || mActiveDisplay != null) {
+                    mCurrentStatus = null;
+                    mActiveDisplayState = WifiDisplayStatus.DISPLAY_STATE_NOT_CONNECTED;
+                    mActiveDisplay = null;
+                    scheduleStatusChangedBroadcastLocked();
+                }
+            }
+        }
+    };
+
+    private final class WifiDisplayDevice extends DisplayDevice {
+        private final String mName;
+        private final int mWidth;
+        private final int mHeight;
+        private final float mRefreshRate;
+        private final int mFlags;
+
+        private Surface mSurface;
+        private DisplayDeviceInfo mInfo;
+
+        public WifiDisplayDevice(IBinder displayToken, String name,
+                int width, int height, float refreshRate, int flags,
+                Surface surface) {
+            super(WifiDisplayAdapter.this, displayToken);
+            mName = name;
+            mWidth = width;
+            mHeight = height;
+            mRefreshRate = refreshRate;
+            mFlags = flags;
+            mSurface = surface;
+        }
+
+        public void clearSurfaceLocked() {
+            mSurface = null;
+            sendTraversalRequestLocked();
+        }
+
+        @Override
+        public void performTraversalInTransactionLocked() {
+            setSurfaceInTransactionLocked(mSurface);
+        }
+
+        @Override
+        public DisplayDeviceInfo getDisplayDeviceInfoLocked() {
+            if (mInfo == null) {
+                mInfo = new DisplayDeviceInfo();
+                mInfo.name = mName;
+                mInfo.width = mWidth;
+                mInfo.height = mHeight;
+                mInfo.refreshRate = mRefreshRate;
+                mInfo.flags = mFlags;
+                mInfo.touch = DisplayDeviceInfo.TOUCH_EXTERNAL;
+                mInfo.setAssumedDensityForExternalDisplay(mWidth, mHeight);
+            }
+            return mInfo;
+        }
+    }
+
+    private final class WifiDisplayHandle implements RemoteDisplay.Listener {
+        private final String mName;
+        private final String mIface;
+        private final RemoteDisplay mRemoteDisplay;
+
+        private WifiDisplayDevice mDevice;
+        private int mLastError;
+
+        public WifiDisplayHandle(String name, String iface) {
+            mName = name;
+            mIface = iface;
+            mRemoteDisplay = RemoteDisplay.listen(iface, this, getHandler());
+
+            Slog.i(TAG, "Listening for Wifi display connections on " + iface
+                    + " from " + mName);
+        }
+
+        public void disposeLocked() {
+            Slog.i(TAG, "Stopped listening for Wifi display connections on " + mIface
+                    + " from " + mName);
+
+            removeDisplayLocked();
+            mRemoteDisplay.dispose();
+        }
+
+        public void dumpLocked(PrintWriter pw) {
+            pw.println("  " + mName + ": " + (mDevice != null ? "connected" : "disconnected"));
+            pw.println("    mIface=" + mIface);
+            pw.println("    mLastError=" + mLastError);
+        }
+
+        // Called on the handler thread.
+        @Override
+        public void onDisplayConnected(Surface surface, int width, int height, int flags) {
+            synchronized (getSyncRoot()) {
+                mLastError = 0;
+                removeDisplayLocked();
+                addDisplayLocked(surface, width, height, flags);
+
+                Slog.i(TAG, "Wifi display connected: " + mName);
+            }
+        }
+
+        // Called on the handler thread.
+        @Override
+        public void onDisplayDisconnected() {
+            synchronized (getSyncRoot()) {
+                mLastError = 0;
+                removeDisplayLocked();
+
+                Slog.i(TAG, "Wifi display disconnected: " + mName);
+            }
+        }
+
+        // Called on the handler thread.
+        @Override
+        public void onDisplayError(int error) {
+            synchronized (getSyncRoot()) {
+                mLastError = error;
+                removeDisplayLocked();
+
+                Slog.i(TAG, "Wifi display disconnected due to error " + error + ": " + mName);
+            }
+        }
+
+        private void addDisplayLocked(Surface surface, int width, int height, int flags) {
+            int deviceFlags = 0;
+            if ((flags & RemoteDisplay.DISPLAY_FLAG_SECURE) != 0) {
+                deviceFlags |= DisplayDeviceInfo.FLAG_SECURE;
+            }
+
+            float refreshRate = 60.0f; // TODO: get this for real
+
+            IBinder displayToken = Surface.createDisplay(mName);
+            mDevice = new WifiDisplayDevice(displayToken, mName, width, height,
+                    refreshRate, deviceFlags, surface);
+            sendDisplayDeviceEventLocked(mDevice, DISPLAY_DEVICE_EVENT_ADDED);
+        }
+
+        private void removeDisplayLocked() {
+            if (mDevice != null) {
+                mDevice.clearSurfaceLocked();
+                sendDisplayDeviceEventLocked(mDevice, DISPLAY_DEVICE_EVENT_REMOVED);
+                mDevice = null;
+            }
+        }
+    }
+}
diff --git a/services/java/com/android/server/display/WifiDisplayController.java b/services/java/com/android/server/display/WifiDisplayController.java
new file mode 100644
index 0000000..b617d00
--- /dev/null
+++ b/services/java/com/android/server/display/WifiDisplayController.java
@@ -0,0 +1,712 @@
+/*
+ * Copyright (C) 2012 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.display;
+
+import com.android.internal.util.DumpUtils;
+
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.hardware.display.WifiDisplay;
+import android.net.NetworkInfo;
+import android.net.wifi.p2p.WifiP2pConfig;
+import android.net.wifi.p2p.WifiP2pDevice;
+import android.net.wifi.p2p.WifiP2pDeviceList;
+import android.net.wifi.p2p.WifiP2pGroup;
+import android.net.wifi.p2p.WifiP2pManager;
+import android.net.wifi.p2p.WifiP2pWfdInfo;
+import android.net.wifi.p2p.WifiP2pManager.ActionListener;
+import android.net.wifi.p2p.WifiP2pManager.Channel;
+import android.net.wifi.p2p.WifiP2pManager.GroupInfoListener;
+import android.net.wifi.p2p.WifiP2pManager.PeerListListener;
+import android.os.Handler;
+import android.util.Slog;
+
+import java.io.PrintWriter;
+import java.net.Inet4Address;
+import java.net.InetAddress;
+import java.net.NetworkInterface;
+import java.net.SocketException;
+import java.util.ArrayList;
+import java.util.Enumeration;
+
+/**
+ * Manages all of the various asynchronous interactions with the {@link WifiP2pManager}
+ * on behalf of {@link WifiDisplayAdapter}.
+ * <p>
+ * This code is isolated from {@link WifiDisplayAdapter} so that we can avoid
+ * accidentally introducing any deadlocks due to the display manager calling
+ * outside of itself while holding its lock.  It's also way easier to write this
+ * asynchronous code if we can assume that it is single-threaded.
+ * </p><p>
+ * The controller must be instantiated on the handler thread.
+ * </p>
+ */
+final class WifiDisplayController implements DumpUtils.Dump {
+    private static final String TAG = "WifiDisplayController";
+    private static final boolean DEBUG = true;
+
+    private static final int DEFAULT_CONTROL_PORT = 7236;
+    private static final int MAX_THROUGHPUT = 50;
+    private static final int CONNECTION_TIMEOUT_SECONDS = 30;
+
+    private static final int DISCOVER_PEERS_MAX_RETRIES = 10;
+    private static final int DISCOVER_PEERS_RETRY_DELAY_MILLIS = 500;
+
+    private static final int CONNECT_MAX_RETRIES = 3;
+    private static final int CONNECT_RETRY_DELAY_MILLIS = 500;
+
+    private final Context mContext;
+    private final Handler mHandler;
+    private final Listener mListener;
+    private final WifiP2pManager mWifiP2pManager;
+    private final Channel mWifiP2pChannel;
+
+    private boolean mWifiP2pEnabled;
+    private boolean mWfdEnabled;
+    private boolean mWfdEnabling;
+    private NetworkInfo mNetworkInfo;
+
+    private final ArrayList<WifiP2pDevice> mKnownWifiDisplayPeers =
+            new ArrayList<WifiP2pDevice>();
+
+    // True if there is a call to discoverPeers in progress.
+    private boolean mDiscoverPeersInProgress;
+
+    // Number of discover peers retries remaining.
+    private int mDiscoverPeersRetriesLeft;
+
+    // The device to which we want to connect, or null if we want to be disconnected.
+    private WifiP2pDevice mDesiredDevice;
+
+    // The device to which we are currently connecting, or null if we have already connected
+    // or are not trying to connect.
+    private WifiP2pDevice mConnectingDevice;
+
+    // The device to which we are currently connected, which means we have an active P2P group.
+    private WifiP2pDevice mConnectedDevice;
+
+    // The group info obtained after connecting.
+    private WifiP2pGroup mConnectedDeviceGroupInfo;
+
+    // The device that we announced to the rest of the system.
+    private WifiP2pDevice mPublishedDevice;
+
+    // Number of connection retries remaining.
+    private int mConnectionRetriesLeft;
+
+    public WifiDisplayController(Context context, Handler handler, Listener listener) {
+        mContext = context;
+        mHandler = handler;
+        mListener = listener;
+
+        mWifiP2pManager = (WifiP2pManager)context.getSystemService(Context.WIFI_P2P_SERVICE);
+        mWifiP2pChannel = mWifiP2pManager.initialize(context, handler.getLooper(), null);
+
+        IntentFilter intentFilter = new IntentFilter();
+        intentFilter.addAction(WifiP2pManager.WIFI_P2P_STATE_CHANGED_ACTION);
+        intentFilter.addAction(WifiP2pManager.WIFI_P2P_PEERS_CHANGED_ACTION);
+        intentFilter.addAction(WifiP2pManager.WIFI_P2P_CONNECTION_CHANGED_ACTION);
+        context.registerReceiver(mWifiP2pReceiver, intentFilter);
+    }
+
+    public void dump(PrintWriter pw) {
+        pw.println("mWifiP2pEnabled=" + mWifiP2pEnabled);
+        pw.println("mWfdEnabled=" + mWfdEnabled);
+        pw.println("mWfdEnabling=" + mWfdEnabling);
+        pw.println("mNetworkInfo=" + mNetworkInfo);
+        pw.println("mDiscoverPeersInProgress=" + mDiscoverPeersInProgress);
+        pw.println("mDiscoverPeersRetriesLeft=" + mDiscoverPeersRetriesLeft);
+        pw.println("mDesiredDevice=" + describeWifiP2pDevice(mDesiredDevice));
+        pw.println("mConnectingDisplay=" + describeWifiP2pDevice(mConnectingDevice));
+        pw.println("mConnectedDevice=" + describeWifiP2pDevice(mConnectedDevice));
+        pw.println("mPublishedDevice=" + describeWifiP2pDevice(mPublishedDevice));
+        pw.println("mConnectionRetriesLeft=" + mConnectionRetriesLeft);
+
+        pw.println("mKnownWifiDisplayPeers: size=" + mKnownWifiDisplayPeers.size());
+        for (WifiP2pDevice device : mKnownWifiDisplayPeers) {
+            pw.println("  " + describeWifiP2pDevice(device));
+        }
+    }
+
+    public void requestScan() {
+        discoverPeers();
+    }
+
+    public void requestConnect(String address) {
+        for (WifiP2pDevice device : mKnownWifiDisplayPeers) {
+            if (device.deviceAddress.equals(address)) {
+                connect(device);
+            }
+        }
+    }
+
+    public void requestDisconnect() {
+        disconnect();
+    }
+
+    private void enableWfd() {
+        if (!mWfdEnabled && !mWfdEnabling) {
+            mWfdEnabling = true;
+
+            WifiP2pWfdInfo wfdInfo = new WifiP2pWfdInfo();
+            wfdInfo.setWfdEnabled(true);
+            wfdInfo.setDeviceType(WifiP2pWfdInfo.WFD_SOURCE);
+            wfdInfo.setSessionAvailable(true);
+            wfdInfo.setControlPort(DEFAULT_CONTROL_PORT);
+            wfdInfo.setMaxThroughput(MAX_THROUGHPUT);
+            mWifiP2pManager.setWFDInfo(mWifiP2pChannel, wfdInfo, new ActionListener() {
+                @Override
+                public void onSuccess() {
+                    if (DEBUG) {
+                        Slog.d(TAG, "Successfully set WFD info.");
+                    }
+                    if (mWfdEnabling) {
+                        mWfdEnabling = false;
+                        setWfdEnabled(true);
+                        discoverPeers();
+                    }
+                }
+
+                @Override
+                public void onFailure(int reason) {
+                    if (DEBUG) {
+                        Slog.d(TAG, "Failed to set WFD info with reason " + reason + ".");
+                    }
+                    mWfdEnabling = false;
+                }
+            });
+        }
+    }
+
+    private void setWfdEnabled(final boolean enabled) {
+        if (mWfdEnabled != enabled) {
+            mWfdEnabled = enabled;
+            mHandler.post(new Runnable() {
+                @Override
+                public void run() {
+                    mListener.onEnablementChanged(enabled);
+                }
+            });
+        }
+    }
+
+    private void discoverPeers() {
+        if (!mDiscoverPeersInProgress) {
+            mDiscoverPeersInProgress = true;
+            mDiscoverPeersRetriesLeft = DISCOVER_PEERS_MAX_RETRIES;
+            handleScanStarted();
+            tryDiscoverPeers();
+        }
+    }
+
+    private void tryDiscoverPeers() {
+        mWifiP2pManager.discoverPeers(mWifiP2pChannel, new ActionListener() {
+            @Override
+            public void onSuccess() {
+                if (DEBUG) {
+                    Slog.d(TAG, "Discover peers succeeded.  Requesting peers now.");
+                }
+
+                mDiscoverPeersInProgress = false;
+                requestPeers();
+            }
+
+            @Override
+            public void onFailure(int reason) {
+                if (DEBUG) {
+                    Slog.d(TAG, "Discover peers failed with reason " + reason + ".");
+                }
+
+                if (mDiscoverPeersInProgress) {
+                    if (reason == 0 && mDiscoverPeersRetriesLeft > 0 && mWfdEnabled) {
+                        mHandler.postDelayed(new Runnable() {
+                            @Override
+                            public void run() {
+                                if (mDiscoverPeersInProgress) {
+                                    if (mDiscoverPeersRetriesLeft > 0 && mWfdEnabled) {
+                                        mDiscoverPeersRetriesLeft -= 1;
+                                        if (DEBUG) {
+                                            Slog.d(TAG, "Retrying discovery.  Retries left: "
+                                                    + mDiscoverPeersRetriesLeft);
+                                        }
+                                        tryDiscoverPeers();
+                                    } else {
+                                        handleScanFinished();
+                                        mDiscoverPeersInProgress = false;
+                                    }
+                                }
+                            }
+                        }, DISCOVER_PEERS_RETRY_DELAY_MILLIS);
+                    } else {
+                        handleScanFinished();
+                        mDiscoverPeersInProgress = false;
+                    }
+                }
+            }
+        });
+    }
+
+    private void requestPeers() {
+        mWifiP2pManager.requestPeers(mWifiP2pChannel, new PeerListListener() {
+            @Override
+            public void onPeersAvailable(WifiP2pDeviceList peers) {
+                if (DEBUG) {
+                    Slog.d(TAG, "Received list of peers.");
+                }
+
+                mKnownWifiDisplayPeers.clear();
+                for (WifiP2pDevice device : peers.getDeviceList()) {
+                    if (DEBUG) {
+                        Slog.d(TAG, "  " + describeWifiP2pDevice(device));
+                    }
+
+                    if (isWifiDisplay(device)) {
+                        mKnownWifiDisplayPeers.add(device);
+                    }
+                }
+
+                handleScanFinished();
+            }
+        });
+    }
+
+    private void handleScanStarted() {
+        mHandler.post(new Runnable() {
+            @Override
+            public void run() {
+                mListener.onScanStarted();
+            }
+        });
+    }
+
+    private void handleScanFinished() {
+        final int count = mKnownWifiDisplayPeers.size();
+        final WifiDisplay[] displays = WifiDisplay.CREATOR.newArray(count);
+        for (int i = 0; i < count; i++) {
+            displays[i] = createWifiDisplay(mKnownWifiDisplayPeers.get(i));
+        }
+
+        mHandler.post(new Runnable() {
+            @Override
+            public void run() {
+                mListener.onScanFinished(displays);
+            }
+        });
+    }
+
+    private void connect(final WifiP2pDevice device) {
+        if (mDesiredDevice != null
+                && !mDesiredDevice.deviceAddress.equals(device.deviceAddress)) {
+            if (DEBUG) {
+                Slog.d(TAG, "connect: nothing to do, already connecting to "
+                        + describeWifiP2pDevice(device));
+            }
+            return;
+        }
+
+        if (mConnectedDevice != null
+                && !mConnectedDevice.deviceAddress.equals(device.deviceAddress)
+                && mDesiredDevice == null) {
+            if (DEBUG) {
+                Slog.d(TAG, "connect: nothing to do, already connected to "
+                        + describeWifiP2pDevice(device) + " and not part way through "
+                        + "connecting to a different device.");
+            }
+            return;
+        }
+
+        mDesiredDevice = device;
+        mConnectionRetriesLeft = CONNECT_MAX_RETRIES;
+        updateConnection();
+    }
+
+    private void disconnect() {
+        mDesiredDevice = null;
+        updateConnection();
+    }
+
+    private void retryConnection() {
+        if (mDesiredDevice != null && mPublishedDevice != mDesiredDevice
+                && mConnectionRetriesLeft > 0) {
+            mConnectionRetriesLeft -= 1;
+            Slog.i(TAG, "Retrying Wifi display connection.  Retries left: "
+                    + mConnectionRetriesLeft);
+
+            // Cheap hack.  Make a new instance of the device object so that we
+            // can distinguish it from the previous connection attempt.
+            // This will cause us to tear everything down before we try again.
+            mDesiredDevice = new WifiP2pDevice(mDesiredDevice);
+            updateConnection();
+        }
+    }
+
+    /**
+     * This function is called repeatedly after each asynchronous operation
+     * until all preconditions for the connection have been satisfied and the
+     * connection is established (or not).
+     */
+    private void updateConnection() {
+        // Step 1. Before we try to connect to a new device, tell the system we
+        // have disconnected from the old one.
+        if (mPublishedDevice != null && mPublishedDevice != mDesiredDevice) {
+            mHandler.post(new Runnable() {
+                @Override
+                public void run() {
+                    mListener.onDisplayDisconnected();
+                }
+            });
+            mPublishedDevice = null;
+
+            // continue to next step
+        }
+
+        // Step 2. Before we try to connect to a new device, disconnect from the old one.
+        if (mConnectedDevice != null && mConnectedDevice != mDesiredDevice) {
+            Slog.i(TAG, "Disconnecting from Wifi display: " + mConnectedDevice.deviceName);
+
+            final WifiP2pDevice oldDevice = mConnectedDevice;
+            mWifiP2pManager.removeGroup(mWifiP2pChannel, new ActionListener() {
+                @Override
+                public void onSuccess() {
+                    Slog.i(TAG, "Disconnected from Wifi display: " + oldDevice.deviceName);
+                    next();
+                }
+
+                @Override
+                public void onFailure(int reason) {
+                    Slog.i(TAG, "Failed to disconnect from Wifi display: "
+                            + oldDevice.deviceName + ", reason=" + reason);
+                    next();
+                }
+
+                private void next() {
+                    if (mConnectedDevice == oldDevice) {
+                        mConnectedDevice = null;
+                        updateConnection();
+                    }
+                }
+            });
+            return; // wait for asynchronous callback
+        }
+
+        // Step 3. Before we try to connect to a new device, stop trying to connect
+        // to the old one.
+        if (mConnectingDevice != null && mConnectingDevice != mDesiredDevice) {
+            Slog.i(TAG, "Canceling connection to Wifi display: " + mConnectingDevice.deviceName);
+
+            mHandler.removeCallbacks(mConnectionTimeout);
+
+            final WifiP2pDevice oldDevice = mConnectingDevice;
+            mWifiP2pManager.cancelConnect(mWifiP2pChannel, new ActionListener() {
+                @Override
+                public void onSuccess() {
+                    Slog.i(TAG, "Canceled connection to Wifi display: " + oldDevice.deviceName);
+                    next();
+                }
+
+                @Override
+                public void onFailure(int reason) {
+                    Slog.i(TAG, "Failed to cancel connection to Wifi display: "
+                            + oldDevice.deviceName + ", reason=" + reason);
+                    next();
+                }
+
+                private void next() {
+                    if (mConnectingDevice == oldDevice) {
+                        mConnectingDevice = null;
+                        updateConnection();
+                    }
+                }
+            });
+            return; // wait for asynchronous callback
+        }
+
+        // Step 4. If we wanted to disconnect, then mission accomplished.
+        if (mDesiredDevice == null) {
+            return; // done
+        }
+
+        // Step 5. Try to connect.
+        if (mConnectedDevice == null && mConnectingDevice == null) {
+            Slog.i(TAG, "Connecting to Wifi display: " + mDesiredDevice.deviceName);
+
+            mConnectingDevice = mDesiredDevice;
+            WifiP2pConfig config = new WifiP2pConfig();
+            config.deviceAddress = mConnectingDevice.deviceAddress;
+
+            final WifiDisplay display = createWifiDisplay(mConnectingDevice);
+            mHandler.post(new Runnable() {
+                @Override
+                public void run() {
+                    mListener.onDisplayConnecting(display);
+                }
+            });
+
+            final WifiP2pDevice newDevice = mDesiredDevice;
+            mWifiP2pManager.connect(mWifiP2pChannel, config, new ActionListener() {
+                @Override
+                public void onSuccess() {
+                    // The connection may not yet be established.  We still need to wait
+                    // for WIFI_P2P_CONNECTION_CHANGED_ACTION.  However, we might never
+                    // get that broadcast, so we register a timeout.
+                    Slog.i(TAG, "Initiated connection to Wifi display: " + newDevice.deviceName);
+
+                    mHandler.postDelayed(mConnectionTimeout, CONNECTION_TIMEOUT_SECONDS * 1000);
+                }
+
+                @Override
+                public void onFailure(int reason) {
+                    Slog.i(TAG, "Failed to initiate connection to Wifi display: "
+                            + newDevice.deviceName + ", reason=" + reason);
+                    if (mConnectingDevice == newDevice) {
+                        mConnectingDevice = null;
+                        handleConnectionFailure(false);
+                    }
+                }
+            });
+            return; // wait for asynchronous callback
+        }
+
+        // Step 6. Publish the new connection.
+        if (mConnectedDevice != null && mPublishedDevice == null) {
+            Inet4Address addr = getInterfaceAddress(mConnectedDeviceGroupInfo);
+            if (addr == null) {
+                Slog.i(TAG, "Failed to get local interface address for communicating "
+                        + "with Wifi display: " + mConnectedDevice.deviceName);
+                handleConnectionFailure(false);
+                return; // done
+            }
+
+            WifiP2pWfdInfo wfdInfo = mConnectedDevice.wfdInfo;
+            int port = (wfdInfo != null ? wfdInfo.getControlPort() : DEFAULT_CONTROL_PORT);
+            final WifiDisplay display = createWifiDisplay(mConnectedDevice);
+            final String iface = addr.getHostAddress() + ":" + port;
+
+            mPublishedDevice = mConnectedDevice;
+            mHandler.post(new Runnable() {
+                @Override
+                public void run() {
+                    mListener.onDisplayConnected(display, iface);
+                }
+            });
+        }
+    }
+
+    private void handleStateChanged(boolean enabled) {
+        if (mWifiP2pEnabled != enabled) {
+            mWifiP2pEnabled = enabled;
+            if (enabled) {
+                if (mWfdEnabled) {
+                    discoverPeers();
+                } else {
+                    enableWfd();
+                }
+            } else {
+                setWfdEnabled(false);
+                disconnect();
+            }
+        }
+    }
+
+    private void handlePeersChanged() {
+        if (mWifiP2pEnabled) {
+            if (mWfdEnabled) {
+                requestPeers();
+            } else {
+                enableWfd();
+            }
+        }
+    }
+
+    private void handleConnectionChanged(NetworkInfo networkInfo) {
+        mNetworkInfo = networkInfo;
+        if (mWfdEnabled && networkInfo.isConnected()) {
+            if (mDesiredDevice != null) {
+                mWifiP2pManager.requestGroupInfo(mWifiP2pChannel, new GroupInfoListener() {
+                    @Override
+                    public void onGroupInfoAvailable(WifiP2pGroup info) {
+                        if (DEBUG) {
+                            Slog.d(TAG, "Received group info: " + describeWifiP2pGroup(info));
+                        }
+
+                        if (mConnectingDevice != null && !info.contains(mConnectingDevice)) {
+                            Slog.i(TAG, "Aborting connection to Wifi display because "
+                                    + "the current P2P group does not contain the device "
+                                    + "we expected to find: " + mConnectingDevice.deviceName);
+                            handleConnectionFailure(false);
+                            return;
+                        }
+
+                        if (mDesiredDevice != null && !info.contains(mDesiredDevice)) {
+                            disconnect();
+                            return;
+                        }
+
+                        if (mConnectingDevice != null && mConnectingDevice == mDesiredDevice) {
+                            Slog.i(TAG, "Connected to Wifi display: "
+                                    + mConnectingDevice.deviceName);
+
+                            mHandler.removeCallbacks(mConnectionTimeout);
+                            mConnectedDeviceGroupInfo = info;
+                            mConnectedDevice = mConnectingDevice;
+                            mConnectingDevice = null;
+                            updateConnection();
+                        }
+                    }
+                });
+            }
+        } else {
+            disconnect();
+
+            // After disconnection for a group, for some reason we have a tendency
+            // to get a peer change notification with an empty list of peers.
+            // Perform a fresh scan.
+            if (mWfdEnabled) {
+                requestPeers();
+            }
+        }
+    }
+
+    private final Runnable mConnectionTimeout = new Runnable() {
+        @Override
+        public void run() {
+            if (mConnectingDevice != null && mConnectingDevice == mDesiredDevice) {
+                Slog.i(TAG, "Timed out waiting for Wifi display connection after "
+                        + CONNECTION_TIMEOUT_SECONDS + " seconds: "
+                        + mConnectingDevice.deviceName);
+                handleConnectionFailure(true);
+            }
+        }
+    };
+
+    private void handleConnectionFailure(boolean timeoutOccurred) {
+        if (mDesiredDevice != null) {
+            Slog.i(TAG, "Wifi display connection failed!");
+
+            mHandler.post(new Runnable() {
+                @Override
+                public void run() {
+                    mListener.onDisplayConnectionFailed();
+                }
+            });
+
+            if (mConnectionRetriesLeft > 0) {
+                mHandler.postDelayed(new Runnable() {
+                    @Override
+                    public void run() {
+                        retryConnection();
+                    }
+                }, timeoutOccurred ? 0 : CONNECT_RETRY_DELAY_MILLIS);
+            } else {
+                disconnect();
+            }
+        }
+    }
+
+    private static Inet4Address getInterfaceAddress(WifiP2pGroup info) {
+        NetworkInterface iface;
+        try {
+            iface = NetworkInterface.getByName(info.getInterface());
+        } catch (SocketException ex) {
+            Slog.w(TAG, "Could not obtain address of network interface "
+                    + info.getInterface(), ex);
+            return null;
+        }
+
+        Enumeration<InetAddress> addrs = iface.getInetAddresses();
+        while (addrs.hasMoreElements()) {
+            InetAddress addr = addrs.nextElement();
+            if (addr instanceof Inet4Address) {
+                return (Inet4Address)addr;
+            }
+        }
+
+        Slog.w(TAG, "Could not obtain address of network interface "
+                + info.getInterface() + " because it had no IPv4 addresses.");
+        return null;
+    }
+
+    private static boolean isWifiDisplay(WifiP2pDevice device) {
+        // FIXME: the wfdInfo API doesn't work yet
+        return device.deviceName.startsWith("DWD-")
+                || device.deviceName.startsWith("DIRECT-")
+                || device.deviceName.startsWith("CAVM-");
+        //device.wfdInfo != null && device.wfdInfo.isWfdEnabled();
+    }
+
+    private static String describeWifiP2pDevice(WifiP2pDevice device) {
+        return device != null ? device.toString().replace('\n', ',') : "null";
+    }
+
+    private static String describeWifiP2pGroup(WifiP2pGroup group) {
+        return group != null ? group.toString().replace('\n', ',') : "null";
+    }
+
+    private static WifiDisplay createWifiDisplay(WifiP2pDevice device) {
+        return new WifiDisplay(device.deviceAddress, device.deviceName);
+    }
+
+    private final BroadcastReceiver mWifiP2pReceiver = new BroadcastReceiver() {
+        @Override
+        public void onReceive(Context context, Intent intent) {
+            final String action = intent.getAction();
+            if (action.equals(WifiP2pManager.WIFI_P2P_STATE_CHANGED_ACTION)) {
+                boolean enabled = (intent.getIntExtra(WifiP2pManager.EXTRA_WIFI_STATE,
+                        WifiP2pManager.WIFI_P2P_STATE_DISABLED)) ==
+                        WifiP2pManager.WIFI_P2P_STATE_ENABLED;
+                if (DEBUG) {
+                    Slog.d(TAG, "Received WIFI_P2P_STATE_CHANGED_ACTION: enabled="
+                            + enabled);
+                }
+
+                handleStateChanged(enabled);
+            } else if (action.equals(WifiP2pManager.WIFI_P2P_PEERS_CHANGED_ACTION)) {
+                if (DEBUG) {
+                    Slog.d(TAG, "Received WIFI_P2P_PEERS_CHANGED_ACTION.");
+                }
+
+                handlePeersChanged();
+            } else if (action.equals(WifiP2pManager.WIFI_P2P_CONNECTION_CHANGED_ACTION)) {
+                NetworkInfo networkInfo = (NetworkInfo)intent.getParcelableExtra(
+                        WifiP2pManager.EXTRA_NETWORK_INFO);
+                if (DEBUG) {
+                    Slog.d(TAG, "Received WIFI_P2P_CONNECTION_CHANGED_ACTION: networkInfo="
+                            + networkInfo);
+                }
+
+                handleConnectionChanged(networkInfo);
+            }
+        }
+    };
+
+    /**
+     * Called on the handler thread when displays are connected or disconnected.
+     */
+    public interface Listener {
+        void onEnablementChanged(boolean enabled);
+
+        void onScanStarted();
+        void onScanFinished(WifiDisplay[] knownDisplays);
+
+        void onDisplayConnecting(WifiDisplay display);
+        void onDisplayConnectionFailed();
+        void onDisplayConnected(WifiDisplay display, String iface);
+        void onDisplayDisconnected();
+    }
+}
diff --git a/services/java/com/android/server/input/InputManagerService.java b/services/java/com/android/server/input/InputManagerService.java
index fd4f5fc..95655a5 100644
--- a/services/java/com/android/server/input/InputManagerService.java
+++ b/services/java/com/android/server/input/InputManagerService.java
@@ -19,6 +19,8 @@
 import com.android.internal.R;
 import com.android.internal.util.XmlUtils;
 import com.android.server.Watchdog;
+import com.android.server.display.DisplayManagerService;
+import com.android.server.display.DisplayViewport;
 
 import org.xmlpull.v1.XmlPullParser;
 
@@ -90,7 +92,8 @@
 /*
  * Wraps the C++ InputManager and provides its callbacks.
  */
-public class InputManagerService extends IInputManager.Stub implements Watchdog.Monitor {
+public class InputManagerService extends IInputManager.Stub
+        implements Watchdog.Monitor, DisplayManagerService.InputManagerFuncs {
     static final String TAG = "InputManager";
     static final boolean DEBUG = false;
 
@@ -143,11 +146,11 @@
     private static native int nativeInit(InputManagerService service,
             Context context, MessageQueue messageQueue);
     private static native void nativeStart(int ptr);
-    private static native void nativeSetDisplaySize(int ptr, int displayId,
-            int width, int height, int externalWidth, int externalHeight);
-    private static native void nativeSetDisplayOrientation(int ptr, int displayId,
-            int rotation, int externalRotation);
-    
+    private static native void nativeSetDisplayViewport(int ptr, boolean external,
+            int displayId, int rotation,
+            int logicalLeft, int logicalTop, int logicalRight, int logicalBottom,
+            int physicalLeft, int physicalTop, int physicalRight, int physicalBottom);
+
     private static native int nativeGetScanCodeState(int ptr,
             int deviceId, int sourceMask, int scanCode);
     private static native int nativeGetKeyCodeState(int ptr,
@@ -282,28 +285,27 @@
         nativeReloadDeviceAliases(mPtr);
     }
 
-    public void setDisplaySize(int displayId, int width, int height) {
-        if (width <= 0 || height <= 0) {
-            throw new IllegalArgumentException("Invalid display id or dimensions.");
+    @Override
+    public void setDisplayViewports(DisplayViewport defaultViewport,
+            DisplayViewport externalTouchViewport) {
+        if (defaultViewport.valid) {
+            setDisplayViewport(false, defaultViewport);
         }
-        
-        if (DEBUG) {
-            Slog.d(TAG, "Setting display #" + displayId + " size to " + width + "x" + height);
+
+        if (externalTouchViewport.valid) {
+            setDisplayViewport(true, externalTouchViewport);
+        } else if (defaultViewport.valid) {
+            setDisplayViewport(true, defaultViewport);
         }
-        // FIXME: external size is deprecated
-        nativeSetDisplaySize(mPtr, displayId, width, height, 1280, 720);
     }
 
-    public void setDisplayOrientation(int displayId, int rotation) {
-        if (rotation < Surface.ROTATION_0 || rotation > Surface.ROTATION_270) {
-            throw new IllegalArgumentException("Invalid rotation.");
-        }
-        
-        if (DEBUG) {
-            Slog.d(TAG, "Setting display #" + displayId + " orientation to rotation " + rotation);
-        }
-        // FIXME: external rotation is deprecated
-        nativeSetDisplayOrientation(mPtr, displayId, rotation, Surface.ROTATION_0);
+    private void setDisplayViewport(boolean external, DisplayViewport viewport) {
+        nativeSetDisplayViewport(mPtr, external,
+                viewport.displayId, viewport.orientation,
+                viewport.logicalFrame.left, viewport.logicalFrame.top,
+                viewport.logicalFrame.right, viewport.logicalFrame.bottom,
+                viewport.physicalFrame.left, viewport.physicalFrame.top,
+                viewport.physicalFrame.right, viewport.physicalFrame.bottom);
     }
 
     /**
diff --git a/services/java/com/android/server/net/LockdownVpnTracker.java b/services/java/com/android/server/net/LockdownVpnTracker.java
index dabcf2f..f2d6745 100644
--- a/services/java/com/android/server/net/LockdownVpnTracker.java
+++ b/services/java/com/android/server/net/LockdownVpnTracker.java
@@ -41,6 +41,7 @@
 import com.android.internal.net.VpnProfile;
 import com.android.internal.util.Preconditions;
 import com.android.server.ConnectivityService;
+import com.android.server.EventLogTags;
 import com.android.server.connectivity.Vpn;
 
 /**
@@ -122,12 +123,18 @@
         }
         if (egressDisconnected) return;
 
+        final int egressType = egressInfo.getType();
+        if (vpnInfo.getDetailedState() == DetailedState.FAILED) {
+            EventLogTags.writeLockdownVpnError(egressType);
+        }
+
         if (mErrorCount > MAX_ERROR_COUNT) {
             showNotification(R.string.vpn_lockdown_error, R.drawable.vpn_disconnected);
 
         } else if (egressInfo.isConnected() && !vpnInfo.isConnectedOrConnecting()) {
             if (mProfile.isValidLockdownProfile()) {
                 Slog.d(TAG, "Active network connected; starting VPN");
+                EventLogTags.writeLockdownVpnConnecting(egressType);
                 showNotification(R.string.vpn_lockdown_connecting, R.drawable.vpn_disconnected);
 
                 mAcceptedEgressIface = egressProp.getInterfaceName();
@@ -148,6 +155,7 @@
             }
 
             Slog.d(TAG, "VPN connected using iface=" + iface + ", sourceAddr=" + sourceAddr);
+            EventLogTags.writeLockdownVpnConnected(egressType);
             showNotification(R.string.vpn_lockdown_connected, R.drawable.vpn_connected);
 
             try {
diff --git a/services/java/com/android/server/pm/Installer.java b/services/java/com/android/server/pm/Installer.java
index d4fe3fb..3329acb 100644
--- a/services/java/com/android/server/pm/Installer.java
+++ b/services/java/com/android/server/pm/Installer.java
@@ -324,20 +324,6 @@
         return execute(builder.toString());
     }
 
-    /*
-     * @param packagePathSuffix The name of the path relative to install
-     * directory. Say if the path name is /data/app/com.test-1.apk, the package
-     * suffix path will be com.test-1
-     */
-    public int setForwardLockPerm(String packagePathSuffix, int gid) {
-        StringBuilder builder = new StringBuilder("protect");
-        builder.append(' ');
-        builder.append(packagePathSuffix);
-        builder.append(' ');
-        builder.append(gid);
-        return execute(builder.toString());
-    }
-
     public int getSizeInfo(String pkgName, int persona, String apkPath, String fwdLockApkPath,
             String asecPath, PackageStats pStats) {
         StringBuilder builder = new StringBuilder("getsize");
diff --git a/services/java/com/android/server/pm/PackageManagerService.java b/services/java/com/android/server/pm/PackageManagerService.java
index 55da11f..4bb6e38 100644
--- a/services/java/com/android/server/pm/PackageManagerService.java
+++ b/services/java/com/android/server/pm/PackageManagerService.java
@@ -1193,7 +1193,7 @@
                         if (mSettings.isDisabledSystemPackageLPr(ps.name)) {
                             Slog.i(TAG, "Expecting better updatd system app for " + ps.name
                                     + "; removing system app");
-                            removePackageLI(scannedPkg, true);
+                            removePackageLI(ps, true);
                         }
 
                         continue;
@@ -1822,7 +1822,7 @@
                 }
                 pkg = new PackageParser.Package(packageName);
                 pkg.applicationInfo.packageName = packageName;
-                pkg.applicationInfo.flags = ps.pkgFlags;
+                pkg.applicationInfo.flags = ps.pkgFlags | ApplicationInfo.FLAG_IS_DATA_ONLY;
                 pkg.applicationInfo.publicSourceDir = ps.resourcePathString;
                 pkg.applicationInfo.sourceDir = ps.codePathString;
                 pkg.applicationInfo.dataDir =
@@ -2891,11 +2891,14 @@
         return index;
     }
 
-    public ParceledListSlice<PackageInfo> getInstalledPackages(int flags, String lastRead) {
+    @Override
+    public ParceledListSlice<PackageInfo> getInstalledPackages(int flags, String lastRead,
+            int userId) {
         final ParceledListSlice<PackageInfo> list = new ParceledListSlice<PackageInfo>();
         final boolean listUninstalled = (flags & PackageManager.GET_UNINSTALLED_PACKAGES) != 0;
         final String[] keys;
-        int userId = UserHandle.getCallingUserId();
+
+        enforceCrossUserPermission(Binder.getCallingUid(), userId, true, "get installed packages");
 
         // writer
         synchronized (mPackages) {
@@ -4110,8 +4113,13 @@
                     NativeLibraryHelper.copyNativeBinariesIfNeededLI(scanFile, nativeLibraryDir);
                 } else {
                     Slog.i(TAG, "Linking native library dir for " + path);
-                    mInstaller.linkNativeLibraryDirectory(dataPathString,
+                    int ret = mInstaller.linkNativeLibraryDirectory(dataPathString,
                             pkg.applicationInfo.nativeLibraryDir);
+                    if (ret < 0) {
+                        Slog.w(TAG, "Failed linking native library dir for " + path);
+                        mLastScanError = PackageManager.MOVE_FAILED_INSUFFICIENT_STORAGE;
+                        return null;
+                    }
                 }
             } catch (IOException ioe) {
                 Log.e(TAG, "Unable to get canonical file " + ioe.toString());
@@ -4429,20 +4437,40 @@
         return pkg;
     }
 
-    private void killApplication(String pkgName, int uid) {
+    private void killApplication(String pkgName, int appId) {
         // Request the ActivityManager to kill the process(only for existing packages)
         // so that we do not end up in a confused state while the user is still using the older
         // version of the application while the new one gets installed.
         IActivityManager am = ActivityManagerNative.getDefault();
         if (am != null) {
             try {
-                am.killApplicationWithUid(pkgName, uid);
+                am.killApplicationWithAppId(pkgName, appId);
             } catch (RemoteException e) {
             }
         }
     }
 
-    void removePackageLI(PackageParser.Package pkg, boolean chatty) {
+    void removePackageLI(PackageSetting ps, boolean chatty) {
+        if (DEBUG_INSTALL) {
+            if (chatty)
+                Log.d(TAG, "Removing package " + ps.name);
+        }
+
+        // writer
+        synchronized (mPackages) {
+            mPackages.remove(ps.name);
+            if (ps.codePathString != null) {
+                mAppDirs.remove(ps.codePathString);
+            }
+
+            final PackageParser.Package pkg = ps.pkg;
+            if (pkg != null) {
+                cleanPackageDataStructuresLILPw(pkg, chatty);
+            }
+        }
+    }
+
+    void removeInstalledPackageLI(PackageParser.Package pkg, boolean chatty) {
         if (DEBUG_INSTALL) {
             if (chatty)
                 Log.d(TAG, "Removing package " + pkg.applicationInfo.packageName);
@@ -4454,34 +4482,115 @@
             if (pkg.mPath != null) {
                 mAppDirs.remove(pkg.mPath);
             }
+            cleanPackageDataStructuresLILPw(pkg, chatty);
+        }
+    }
 
-            int N = pkg.providers.size();
-            StringBuilder r = null;
-            int i;
-            for (i=0; i<N; i++) {
-                PackageParser.Provider p = pkg.providers.get(i);
-                mProvidersByComponent.remove(new ComponentName(p.info.packageName,
-                        p.info.name));
-                if (p.info.authority == null) {
+    void cleanPackageDataStructuresLILPw(PackageParser.Package pkg, boolean chatty) {
+        int N = pkg.providers.size();
+        StringBuilder r = null;
+        int i;
+        for (i=0; i<N; i++) {
+            PackageParser.Provider p = pkg.providers.get(i);
+            mProvidersByComponent.remove(new ComponentName(p.info.packageName,
+                    p.info.name));
+            if (p.info.authority == null) {
 
-                    /* The is another ContentProvider with this authority when
-                     * this app was installed so this authority is null,
-                     * Ignore it as we don't have to unregister the provider.
-                     */
-                    continue;
-                }
-                String names[] = p.info.authority.split(";");
-                for (int j = 0; j < names.length; j++) {
-                    if (mProviders.get(names[j]) == p) {
-                        mProviders.remove(names[j]);
-                        if (DEBUG_REMOVE) {
-                            if (chatty)
-                                Log.d(TAG, "Unregistered content provider: " + names[j]
-                                        + ", className = " + p.info.name + ", isSyncable = "
-                                        + p.info.isSyncable);
-                        }
+                /* There was another ContentProvider with this authority when
+                 * this app was installed so this authority is null,
+                 * Ignore it as we don't have to unregister the provider.
+                 */
+                continue;
+            }
+            String names[] = p.info.authority.split(";");
+            for (int j = 0; j < names.length; j++) {
+                if (mProviders.get(names[j]) == p) {
+                    mProviders.remove(names[j]);
+                    if (DEBUG_REMOVE) {
+                        if (chatty)
+                            Log.d(TAG, "Unregistered content provider: " + names[j]
+                                    + ", className = " + p.info.name + ", isSyncable = "
+                                    + p.info.isSyncable);
                     }
                 }
+            }
+            if (chatty) {
+                if (r == null) {
+                    r = new StringBuilder(256);
+                } else {
+                    r.append(' ');
+                }
+                r.append(p.info.name);
+            }
+        }
+        if (r != null) {
+            if (DEBUG_REMOVE) Log.d(TAG, "  Providers: " + r);
+        }
+
+        N = pkg.services.size();
+        r = null;
+        for (i=0; i<N; i++) {
+            PackageParser.Service s = pkg.services.get(i);
+            mServices.removeService(s);
+            if (chatty) {
+                if (r == null) {
+                    r = new StringBuilder(256);
+                } else {
+                    r.append(' ');
+                }
+                r.append(s.info.name);
+            }
+        }
+        if (r != null) {
+            if (DEBUG_REMOVE) Log.d(TAG, "  Services: " + r);
+        }
+
+        N = pkg.receivers.size();
+        r = null;
+        for (i=0; i<N; i++) {
+            PackageParser.Activity a = pkg.receivers.get(i);
+            mReceivers.removeActivity(a, "receiver");
+            if (chatty) {
+                if (r == null) {
+                    r = new StringBuilder(256);
+                } else {
+                    r.append(' ');
+                }
+                r.append(a.info.name);
+            }
+        }
+        if (r != null) {
+            if (DEBUG_REMOVE) Log.d(TAG, "  Receivers: " + r);
+        }
+
+        N = pkg.activities.size();
+        r = null;
+        for (i=0; i<N; i++) {
+            PackageParser.Activity a = pkg.activities.get(i);
+            mActivities.removeActivity(a, "activity");
+            if (chatty) {
+                if (r == null) {
+                    r = new StringBuilder(256);
+                } else {
+                    r.append(' ');
+                }
+                r.append(a.info.name);
+            }
+        }
+        if (r != null) {
+            if (DEBUG_REMOVE) Log.d(TAG, "  Activities: " + r);
+        }
+
+        N = pkg.permissions.size();
+        r = null;
+        for (i=0; i<N; i++) {
+            PackageParser.Permission p = pkg.permissions.get(i);
+            BasePermission bp = mSettings.mPermissions.get(p.info.name);
+            if (bp == null) {
+                bp = mSettings.mPermissionTrees.get(p.info.name);
+            }
+            if (bp != null && bp.perm == p) {
+                bp.perm = null;
                 if (chatty) {
                     if (r == null) {
                         r = new StringBuilder(256);
@@ -4491,105 +4600,27 @@
                     r.append(p.info.name);
                 }
             }
-            if (r != null) {
-                if (DEBUG_REMOVE) Log.d(TAG, "  Providers: " + r);
-            }
+        }
+        if (r != null) {
+            if (DEBUG_REMOVE) Log.d(TAG, "  Permissions: " + r);
+        }
 
-            N = pkg.services.size();
-            r = null;
-            for (i=0; i<N; i++) {
-                PackageParser.Service s = pkg.services.get(i);
-                mServices.removeService(s);
-                if (chatty) {
-                    if (r == null) {
-                        r = new StringBuilder(256);
-                    } else {
-                        r.append(' ');
-                    }
-                    r.append(s.info.name);
+        N = pkg.instrumentation.size();
+        r = null;
+        for (i=0; i<N; i++) {
+            PackageParser.Instrumentation a = pkg.instrumentation.get(i);
+            mInstrumentation.remove(a.getComponentName());
+            if (chatty) {
+                if (r == null) {
+                    r = new StringBuilder(256);
+                } else {
+                    r.append(' ');
                 }
+                r.append(a.info.name);
             }
-            if (r != null) {
-                if (DEBUG_REMOVE) Log.d(TAG, "  Services: " + r);
-            }
-
-            N = pkg.receivers.size();
-            r = null;
-            for (i=0; i<N; i++) {
-                PackageParser.Activity a = pkg.receivers.get(i);
-                mReceivers.removeActivity(a, "receiver");
-                if (chatty) {
-                    if (r == null) {
-                        r = new StringBuilder(256);
-                    } else {
-                        r.append(' ');
-                    }
-                    r.append(a.info.name);
-                }
-            }
-            if (r != null) {
-                if (DEBUG_REMOVE) Log.d(TAG, "  Receivers: " + r);
-            }
-
-            N = pkg.activities.size();
-            r = null;
-            for (i=0; i<N; i++) {
-                PackageParser.Activity a = pkg.activities.get(i);
-                mActivities.removeActivity(a, "activity");
-                if (chatty) {
-                    if (r == null) {
-                        r = new StringBuilder(256);
-                    } else {
-                        r.append(' ');
-                    }
-                    r.append(a.info.name);
-                }
-            }
-            if (r != null) {
-                if (DEBUG_REMOVE) Log.d(TAG, "  Activities: " + r);
-            }
-
-            N = pkg.permissions.size();
-            r = null;
-            for (i=0; i<N; i++) {
-                PackageParser.Permission p = pkg.permissions.get(i);
-                BasePermission bp = mSettings.mPermissions.get(p.info.name);
-                if (bp == null) {
-                    bp = mSettings.mPermissionTrees.get(p.info.name);
-                }
-                if (bp != null && bp.perm == p) {
-                    bp.perm = null;
-                    if (chatty) {
-                        if (r == null) {
-                            r = new StringBuilder(256);
-                        } else {
-                            r.append(' ');
-                        }
-                        r.append(p.info.name);
-                    }
-                }
-            }
-            if (r != null) {
-                if (DEBUG_REMOVE) Log.d(TAG, "  Permissions: " + r);
-            }
-
-            N = pkg.instrumentation.size();
-            r = null;
-            for (i=0; i<N; i++) {
-                PackageParser.Instrumentation a = pkg.instrumentation.get(i);
-                mInstrumentation.remove(a.getComponentName());
-                if (chatty) {
-                    if (r == null) {
-                        r = new StringBuilder(256);
-                    } else {
-                        r.append(' ');
-                    }
-                    r.append(a.info.name);
-                }
-            }
-            if (r != null) {
-                if (DEBUG_REMOVE) Log.d(TAG, "  Instrumentation: " + r);
-            }
+        }
+        if (r != null) {
+            if (DEBUG_REMOVE) Log.d(TAG, "  Instrumentation: " + r);
         }
     }
 
@@ -5424,10 +5455,10 @@
 
         public void onEvent(int event, String path) {
             String removedPackage = null;
-            int removedUid = -1;
+            int removedAppId = -1;
             int[] removedUsers = null;
             String addedPackage = null;
-            int addedUid = -1;
+            int addedAppId = -1;
             int[] addedUsers = null;
 
             // TODO post a message to the handler to obtain serial ordering
@@ -5454,11 +5485,12 @@
                     return;
                 }
                 PackageParser.Package p = null;
+                PackageSetting ps = null;
                 // reader
                 synchronized (mPackages) {
                     p = mAppDirs.get(fullPathStr);
                     if (p != null) {
-                        PackageSetting ps = mSettings.mPackages.get(p.applicationInfo.packageName);
+                        ps = mSettings.mPackages.get(p.applicationInfo.packageName);
                         if (ps != null) {
                             removedUsers = ps.queryInstalledUsers(sUserManager.getUserIds(), true);
                         } else {
@@ -5468,10 +5500,10 @@
                     addedUsers = sUserManager.getUserIds();
                 }
                 if ((event&REMOVE_EVENTS) != 0) {
-                    if (p != null) {
-                        removePackageLI(p, true);
-                        removedPackage = p.applicationInfo.packageName;
-                        removedUid = p.applicationInfo.uid;
+                    if (ps != null) {
+                        removePackageLI(ps, true);
+                        removedPackage = ps.name;
+                        removedAppId = ps.appId;
                     }
                 }
 
@@ -5496,7 +5528,7 @@
                                         p.permissions.size() > 0 ? UPDATE_PERMISSIONS_ALL : 0);
                             }
                             addedPackage = p.applicationInfo.packageName;
-                            addedUid = p.applicationInfo.uid;
+                            addedAppId = UserHandle.getAppId(p.applicationInfo.uid);
                         }
                     }
                 }
@@ -5509,14 +5541,14 @@
 
             if (removedPackage != null) {
                 Bundle extras = new Bundle(1);
-                extras.putInt(Intent.EXTRA_UID, removedUid);
+                extras.putInt(Intent.EXTRA_UID, removedAppId);
                 extras.putBoolean(Intent.EXTRA_DATA_REMOVED, false);
                 sendPackageBroadcast(Intent.ACTION_PACKAGE_REMOVED, removedPackage,
                         extras, null, null, removedUsers);
             }
             if (addedPackage != null) {
                 Bundle extras = new Bundle(1);
-                extras.putInt(Intent.EXTRA_UID, addedUid);
+                extras.putInt(Intent.EXTRA_UID, addedAppId);
                 sendPackageBroadcast(Intent.ACTION_PACKAGE_ADDED, addedPackage,
                         extras, null, null, addedUsers);
             }
@@ -5791,8 +5823,8 @@
      * @return verification timeout in milliseconds
      */
     private long getVerificationTimeout() {
-        return android.provider.Settings.Secure.getLong(mContext.getContentResolver(),
-                android.provider.Settings.Secure.PACKAGE_VERIFIER_TIMEOUT,
+        return android.provider.Settings.Global.getLong(mContext.getContentResolver(),
+                android.provider.Settings.Global.PACKAGE_VERIFIER_TIMEOUT,
                 DEFAULT_VERIFICATION_TIMEOUT);
     }
 
@@ -5802,8 +5834,8 @@
      * @return default verification response code
      */
     private int getDefaultVerificationResponse() {
-        return android.provider.Settings.Secure.getInt(mContext.getContentResolver(),
-                android.provider.Settings.Secure.PACKAGE_VERIFIER_DEFAULT_RESPONSE,
+        return android.provider.Settings.Global.getInt(mContext.getContentResolver(),
+                android.provider.Settings.Global.PACKAGE_VERIFIER_DEFAULT_RESPONSE,
                 DEFAULT_VERIFICATION_RESPONSE);
     }
 
@@ -5813,8 +5845,8 @@
      * @return true if verification should be performed
      */
     private boolean isVerificationEnabled() {
-        return android.provider.Settings.Secure.getInt(mContext.getContentResolver(),
-                android.provider.Settings.Secure.PACKAGE_VERIFIER_ENABLE,
+        return android.provider.Settings.Global.getInt(mContext.getContentResolver(),
+                android.provider.Settings.Global.PACKAGE_VERIFIER_ENABLE,
                 DEFAULT_VERIFY_ENABLE ? 1 : 0) == 1 ? true : false;
     }
 
@@ -7527,7 +7559,7 @@
         res.removedInfo.uid = oldPkg.applicationInfo.uid;
         res.removedInfo.removedPackage = packageName;
         // Remove existing system package
-        removePackageLI(oldPkg, true);
+        removePackageLI(oldPkgSetting, true);
         // writer
         synchronized (mPackages) {
             if (!mSettings.disableSystemPackageLPw(packageName) && deletedPackage != null) {
@@ -7566,7 +7598,7 @@
             // Re installation failed. Restore old information
             // Remove new pkg information
             if (newPackage != null) {
-                removePackageLI(newPackage, true);
+                removeInstalledPackageLI(newPackage, true);
             }
             // Add back the old system package
             scanPackageLI(oldPkg, parseFlags, SCAN_MONITOR | SCAN_UPDATE_SIGNATURE, 0, user);
@@ -7967,10 +7999,10 @@
      * make sure this flag is set for partially installed apps. If not its meaningless to
      * delete a partially installed application.
      */
-    private void removePackageDataLI(PackageParser.Package p, PackageRemovedInfo outInfo,
+    private void removePackageDataLI(PackageSetting ps, PackageRemovedInfo outInfo,
             int flags, boolean writeSettings) {
-        String packageName = p.packageName;
-        removePackageLI(p, (flags&REMOVE_CHATTY) != 0);
+        String packageName = ps.name;
+        removePackageLI(ps, (flags&REMOVE_CHATTY) != 0);
         // Retrieve object to delete permissions for shared user later on
         final PackageSetting deletedPs;
         // reader
@@ -8015,38 +8047,32 @@
     /*
      * Tries to delete system package.
      */
-    private boolean deleteSystemPackageLI(PackageParser.Package p,
+    private boolean deleteSystemPackageLI(PackageSetting newPs,
             int flags, PackageRemovedInfo outInfo, boolean writeSettings) {
-        ApplicationInfo applicationInfo = p.applicationInfo;
-        //applicable for non-partially installed applications only
-        if (applicationInfo == null) {
-            Slog.w(TAG, "Package " + p.packageName + " has no applicationInfo.");
-            return false;
-        }
-        PackageSetting ps = null;
+        PackageSetting disabledPs = null;
         // Confirm if the system package has been updated
         // An updated system app can be deleted. This will also have to restore
         // the system pkg from system partition
         // reader
         synchronized (mPackages) {
-            ps = mSettings.getDisabledSystemPkgLPr(p.packageName);
+            disabledPs = mSettings.getDisabledSystemPkgLPr(newPs.name);
         }
-        if (ps == null) {
-            Slog.w(TAG, "Attempt to delete unknown system package "+ p.packageName);
+        if (disabledPs == null) {
+            Slog.w(TAG, "Attempt to delete unknown system package "+ newPs.name);
             return false;
         } else {
             Log.i(TAG, "Deleting system pkg from data partition");
         }
         // Delete the updated package
         outInfo.isRemovedPackageSystemUpdate = true;
-        if (ps.versionCode < p.mVersionCode) {
+        if (disabledPs.versionCode < newPs.versionCode) {
             // Delete data for downgrades
             flags &= ~PackageManager.DELETE_KEEP_DATA;
         } else {
             // Preserve data by setting flag
             flags |= PackageManager.DELETE_KEEP_DATA;
         }
-        boolean ret = deleteInstalledPackageLI(p, true, flags, outInfo,
+        boolean ret = deleteInstalledPackageLI(newPs, true, flags, outInfo,
                 writeSettings);
         if (!ret) {
             return false;
@@ -8054,17 +8080,18 @@
         // writer
         synchronized (mPackages) {
             // Reinstate the old system package
-            mSettings.enableSystemPackageLPw(p.packageName);
+            mSettings.enableSystemPackageLPw(newPs.name);
             // Remove any native libraries from the upgraded package.
-            NativeLibraryHelper.removeNativeBinariesLI(p.applicationInfo.nativeLibraryDir);
+            NativeLibraryHelper.removeNativeBinariesLI(newPs.nativeLibraryPathString);
         }
         // Install the system package
-        PackageParser.Package newPkg = scanPackageLI(ps.codePath,
+        PackageParser.Package newPkg = scanPackageLI(disabledPs.codePath,
                 PackageParser.PARSE_MUST_BE_APK | PackageParser.PARSE_IS_SYSTEM,
                 SCAN_MONITOR | SCAN_NO_PATHS, 0, null);
 
         if (newPkg == null) {
-            Slog.w(TAG, "Failed to restore system package:"+p.packageName+" with error:" + mLastScanError);
+            Slog.w(TAG, "Failed to restore system package:" + newPs.name
+                    + " with error:" + mLastScanError);
             return false;
         }
         // writer
@@ -8079,28 +8106,20 @@
         return true;
     }
 
-    private boolean deleteInstalledPackageLI(PackageParser.Package p,
+    private boolean deleteInstalledPackageLI(PackageSetting ps,
             boolean deleteCodeAndResources, int flags, PackageRemovedInfo outInfo,
             boolean writeSettings) {
-        ApplicationInfo applicationInfo = p.applicationInfo;
-        if (applicationInfo == null) {
-            Slog.w(TAG, "Package " + p.packageName + " has no applicationInfo.");
-            return false;
-        }
         if (outInfo != null) {
-            outInfo.uid = applicationInfo.uid;
+            outInfo.uid = ps.appId;
         }
 
         // Delete package data from internal structures and also remove data if flag is set
-        removePackageDataLI(p, outInfo, flags, writeSettings);
+        removePackageDataLI(ps, outInfo, flags, writeSettings);
 
         // Delete application code and resources
         if (deleteCodeAndResources) {
-            // TODO can pick up from PackageSettings as well
-            int installFlags = isExternal(p) ? PackageManager.INSTALL_EXTERNAL : 0;
-            installFlags |= isForwardLocked(p) ? PackageManager.INSTALL_FORWARD_LOCK : 0;
-            outInfo.args = createInstallArgs(installFlags, applicationInfo.sourceDir,
-                    applicationInfo.publicSourceDir, applicationInfo.nativeLibraryDir);
+            outInfo.args = createInstallArgs(packageFlagsToInstallFlags(ps), ps.codePathString,
+                    ps.resourcePathString, ps.nativeLibraryPathString);
         }
         return true;
     }
@@ -8115,28 +8134,17 @@
             Slog.w(TAG, "Attempt to delete null packageName.");
             return false;
         }
-        PackageParser.Package p;
+        PackageSetting ps;
         boolean dataOnly = false;
         int removeUser = -1;
         int appId = -1;
         synchronized (mPackages) {
-            p = mPackages.get(packageName);
-            if (p == null) {
-                //this retrieves partially installed apps
-                dataOnly = true;
-                PackageSetting ps = mSettings.mPackages.get(packageName);
-                if (ps == null) {
-                    Slog.w(TAG, "Package named '" + packageName + "' doesn't exist.");
-                    return false;
-                }
-                p = ps.pkg;
-            }
-            if (p == null) {
+            ps = mSettings.mPackages.get(packageName);
+            if (ps == null) {
                 Slog.w(TAG, "Package named '" + packageName + "' doesn't exist.");
                 return false;
             }
-            final PackageSetting ps = (PackageSetting)p.mExtras;
-            if (!isSystemApp(p) && ps != null && user != null
+            if (!isSystemApp(ps) && user != null
                     && user.getIdentifier() != UserHandle.USER_ALL) {
                 // The caller is asking that the package only be deleted for a single
                 // user.  To do this, we just mark its uninstalled state and delete
@@ -8177,25 +8185,20 @@
 
         if (dataOnly) {
             // Delete application data first
-            removePackageDataLI(p, outInfo, flags, writeSettings);
+            removePackageDataLI(ps, outInfo, flags, writeSettings);
             return true;
         }
-        // At this point the package should have ApplicationInfo associated with it
-        if (p.applicationInfo == null) {
-            Slog.w(TAG, "Package " + p.packageName + " has no applicationInfo.");
-            return false;
-        }
         boolean ret = false;
-        if (isSystemApp(p)) {
-            Log.i(TAG, "Removing system package:"+p.packageName);
+        if (isSystemApp(ps)) {
+            Log.i(TAG, "Removing system package:" + ps.name);
             // When an updated system application is deleted we delete the existing resources as well and
             // fall back to existing code in system partition
-            ret = deleteSystemPackageLI(p, flags, outInfo, writeSettings);
+            ret = deleteSystemPackageLI(ps, flags, outInfo, writeSettings);
         } else {
-            Log.i(TAG, "Removing non-system package:"+p.packageName);
+            Log.i(TAG, "Removing non-system package:" + ps.name);
             // Kill application pre-emptively especially for apps on sd.
-            killApplication(packageName, p.applicationInfo.uid);
-            ret = deleteInstalledPackageLI(p, deleteCodeAndResources, flags, outInfo,
+            killApplication(packageName, ps.appId);
+            ret = deleteInstalledPackageLI(ps, deleteCodeAndResources, flags, outInfo,
                     writeSettings);
         }
         return ret;
diff --git a/services/java/com/android/server/pm/Settings.java b/services/java/com/android/server/pm/Settings.java
index 5f10d44..b075da3 100644
--- a/services/java/com/android/server/pm/Settings.java
+++ b/services/java/com/android/server/pm/Settings.java
@@ -32,7 +32,6 @@
 import org.xmlpull.v1.XmlPullParserException;
 import org.xmlpull.v1.XmlSerializer;
 
-import android.app.AppGlobals;
 import android.content.ComponentName;
 import android.content.Context;
 import android.content.Intent;
@@ -50,7 +49,6 @@
 import android.os.Environment;
 import android.os.FileUtils;
 import android.os.Process;
-import android.os.RemoteException;
 import android.os.UserHandle;
 import android.util.Log;
 import android.util.Slog;
@@ -568,6 +566,10 @@
         if (p.signatures.mSignatures == null) {
             p.signatures.assignSignatures(pkg.mSignatures);
         }
+        // Update flags if needed.
+        if (pkg.applicationInfo.flags != p.pkgFlags) {
+            p.pkgFlags = pkg.applicationInfo.flags;
+        }
         // If this app defines a shared user id initialize
         // the shared user signatures as well.
         if (p.sharedUser != null && p.sharedUser.signatures.mSignatures == null) {
@@ -1261,7 +1263,7 @@
                     final ArrayList<PackageCleanItem> pkgs = mPackagesToBeCleaned.valueAt(i);
                     for (int j=0; j<pkgs.size(); j++) {
                         serializer.startTag(null, "cleaning-package");
-                        PackageCleanItem item = pkgs.get(i);
+                        PackageCleanItem item = pkgs.get(j);
                         serializer.attribute(null, ATTR_NAME, item.packageName);
                         serializer.attribute(null, ATTR_CODE, item.andCode ? "true" : "false");
                         serializer.attribute(null, ATTR_USER, userStr);
@@ -2603,8 +2605,8 @@
                     first = false;
                     pw.print("anyDensity");
                 }
+                pw.println("]");
             }
-            pw.println("]");
             pw.print("    timeStamp=");
                 date.setTime(ps.timeStamp);
                 pw.println(sdf.format(date));
@@ -2618,10 +2620,10 @@
                 pw.print("    installerPackageName="); pw.println(ps.installerPackageName);
             }
             pw.print("    signatures="); pw.println(ps.signatures);
-            pw.print("    permissionsFixed="); pw.print(ps.permissionsFixed);
-            pw.print(" haveGids="); pw.println(ps.haveGids);
-            pw.print("    pkgFlags=0x"); pw.print(Integer.toHexString(ps.pkgFlags));
-            pw.print(" installStatus="); pw.println(ps.installStatus);
+            pw.print("    permissionsFixed="); pw.println(ps.permissionsFixed);
+            pw.print("    haveGids="); pw.println(ps.haveGids);
+            pw.print("    pkgFlags="); printFlags(pw, ps.pkgFlags, FLAG_DUMP_SPEC);
+            pw.print("    installStatus="); pw.println(ps.installStatus);
             for (UserInfo user : users) {
                 pw.print("    User "); pw.print(user.id); pw.print(": ");
                 pw.print(" installed=");
diff --git a/services/java/com/android/server/power/DisplayPowerController.java b/services/java/com/android/server/power/DisplayPowerController.java
index 4f5561a..5f4a786 100644
--- a/services/java/com/android/server/power/DisplayPowerController.java
+++ b/services/java/com/android/server/power/DisplayPowerController.java
@@ -83,7 +83,8 @@
     private static final boolean USE_ELECTRON_BEAM_ON_ANIMATION = false;
 
     // If true, enables the use of the screen auto-brightness adjustment setting.
-    private static final boolean USE_SCREEN_AUTO_BRIGHTNESS_ADJUSTMENT = false;
+    private static final boolean USE_SCREEN_AUTO_BRIGHTNESS_ADJUSTMENT =
+            PowerManager.useScreenAutoBrightnessAdjustmentFeature();
 
     // The maximum range of gamma adjustment possible using the screen
     // auto-brightness adjustment setting.
diff --git a/services/java/com/android/server/power/PowerManagerService.java b/services/java/com/android/server/power/PowerManagerService.java
index 59d0954..fda619c 100644
--- a/services/java/com/android/server/power/PowerManagerService.java
+++ b/services/java/com/android/server/power/PowerManagerService.java
@@ -372,8 +372,8 @@
                     Settings.Secure.SCREENSAVER_ACTIVATE_ON_SLEEP), false, mSettingsObserver);
             resolver.registerContentObserver(Settings.System.getUriFor(
                     Settings.System.SCREEN_OFF_TIMEOUT), false, mSettingsObserver);
-            resolver.registerContentObserver(Settings.System.getUriFor(
-                    Settings.System.STAY_ON_WHILE_PLUGGED_IN), false, mSettingsObserver);
+            resolver.registerContentObserver(Settings.Global.getUriFor(
+                    Settings.Global.STAY_ON_WHILE_PLUGGED_IN), false, mSettingsObserver);
             resolver.registerContentObserver(Settings.System.getUriFor(
                     Settings.System.SCREEN_BRIGHTNESS), false, mSettingsObserver);
             resolver.registerContentObserver(Settings.System.getUriFor(
@@ -405,8 +405,8 @@
                 Settings.Secure.SCREENSAVER_ACTIVATE_ON_SLEEP, 0) != 0);
         mScreenOffTimeoutSetting = Settings.System.getInt(resolver,
                 Settings.System.SCREEN_OFF_TIMEOUT, DEFAULT_SCREEN_OFF_TIMEOUT);
-        mStayOnWhilePluggedInSetting = Settings.System.getInt(resolver,
-                Settings.System.STAY_ON_WHILE_PLUGGED_IN,
+        mStayOnWhilePluggedInSetting = Settings.Global.getInt(resolver,
+                Settings.Global.STAY_ON_WHILE_PLUGGED_IN,
                 BatteryManager.BATTERY_PLUGGED_AC);
 
         final int oldScreenBrightnessSetting = mScreenBrightnessSetting;
@@ -1585,8 +1585,8 @@
     }
 
     private void setStayOnSettingInternal(int val) {
-        Settings.System.putInt(mContext.getContentResolver(),
-                Settings.System.STAY_ON_WHILE_PLUGGED_IN, val);
+        Settings.Global.putInt(mContext.getContentResolver(),
+                Settings.Global.STAY_ON_WHILE_PLUGGED_IN, val);
     }
 
     /**
diff --git a/services/java/com/android/server/wm/DisplayContent.java b/services/java/com/android/server/wm/DisplayContent.java
index f4964cf..4df692b 100644
--- a/services/java/com/android/server/wm/DisplayContent.java
+++ b/services/java/com/android/server/wm/DisplayContent.java
@@ -16,8 +16,10 @@
 
 package com.android.server.wm;
 
+import android.os.RemoteCallbackList;
 import android.view.Display;
 import android.view.DisplayInfo;
+import android.view.IDisplayContentChangeListener;
 
 import java.io.PrintWriter;
 import java.util.ArrayList;
@@ -41,6 +43,11 @@
      * from mDisplayWindows; */
     private WindowList mWindows = new WindowList();
 
+    // Specification for magnifying the display content.
+    MagnificationSpec mMagnificationSpec;
+
+    // Callback for observing content changes on a display.
+    RemoteCallbackList<IDisplayContentChangeListener> mDisplayContentChangeListeners;
 
     // This protects the following display size properties, so that
     // getDisplaySize() doesn't need to acquire the global lock.  This is
@@ -65,11 +72,13 @@
     // Accessed directly by all users.
     boolean layoutNeeded;
     int pendingLayoutChanges;
+    final boolean isDefaultDisplay;
 
     DisplayContent(Display display) {
         mDisplay = display;
         mDisplayId = display.getDisplayId();
         display.getDisplayInfo(mDisplayInfo);
+        isDefaultDisplay = mDisplayId == Display.DEFAULT_DISPLAY;
     }
 
     int getDisplayId() {
@@ -85,10 +94,13 @@
     }
 
     DisplayInfo getDisplayInfo() {
-        mDisplay.getDisplayInfo(mDisplayInfo);
         return mDisplayInfo;
     }
 
+    public void updateDisplayInfo() {
+        mDisplay.getDisplayInfo(mDisplayInfo);
+    }
+
     public void dump(PrintWriter pw) {
         pw.print("  Display: mDisplayId="); pw.println(mDisplayId);
         pw.print("  init="); pw.print(mInitialDisplayWidth); pw.print("x");
@@ -111,7 +123,8 @@
         pw.print("x"); pw.print(mDisplayInfo.smallestNominalAppHeight);
         pw.print("-"); pw.print(mDisplayInfo.largestNominalAppWidth);
         pw.print("x"); pw.println(mDisplayInfo.largestNominalAppHeight);
-        pw.print("layoutNeeded="); pw.println(layoutNeeded);
+        pw.print("  layoutNeeded="); pw.println(layoutNeeded);
+        pw.print("magnificationSpec="); pw.println(mMagnificationSpec);
         pw.println();
     }
 }
diff --git a/services/java/com/android/server/wm/MagnificationSpec.java b/services/java/com/android/server/wm/MagnificationSpec.java
new file mode 100644
index 0000000..31aae66
--- /dev/null
+++ b/services/java/com/android/server/wm/MagnificationSpec.java
@@ -0,0 +1,46 @@
+/*
+ * Copyright (C) 2012 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.wm;
+
+public class MagnificationSpec {
+    public float mScale = 1.0f;
+    public float mOffsetX;
+    public float mOffsetY;
+
+    public void initialize(float scale, float offsetX, float offsetY) {
+        mScale = scale;
+        mOffsetX = offsetX;
+        mOffsetY = offsetY;
+    }
+
+    public boolean isNop() {
+        return mScale == 1.0f && mOffsetX == 0 && mOffsetY == 0;
+    }
+
+    @Override
+    public String toString() {
+        StringBuilder builder = new StringBuilder();
+        builder.append("<scale:");
+        builder.append(mScale);
+        builder.append(",offsetX:");
+        builder.append(mOffsetX);
+        builder.append(",offsetY:");
+        builder.append(mOffsetY);
+        builder.append(">");
+        return builder.toString();
+    }
+}
diff --git a/services/java/com/android/server/wm/Session.java b/services/java/com/android/server/wm/Session.java
index 4038b70..16beeab 100644
--- a/services/java/com/android/server/wm/Session.java
+++ b/services/java/com/android/server/wm/Session.java
@@ -422,6 +422,17 @@
         }
     }
 
+    public void onRectangleOnScreenRequested(IBinder token, Rect rectangle, boolean immediate) {
+        synchronized(mService.mWindowMap) {
+            final long identity = Binder.clearCallingIdentity();
+            try {
+                mService.onRectangleOnScreenRequested(token, rectangle, immediate);
+            } finally {
+                Binder.restoreCallingIdentity(identity);
+            }
+        }
+    }
+
     void windowAddedLocked() {
         if (mSurfaceSession == null) {
             if (WindowManagerService.localLOGV) Slog.v(
diff --git a/services/java/com/android/server/wm/WindowAnimator.java b/services/java/com/android/server/wm/WindowAnimator.java
index f0b514c..72c6a51 100644
--- a/services/java/com/android/server/wm/WindowAnimator.java
+++ b/services/java/com/android/server/wm/WindowAnimator.java
@@ -50,6 +50,7 @@
     // Layout changes for individual Displays. Indexed by displayId.
     SparseIntArray mPendingLayoutChanges = new SparseIntArray();
 
+    // TODO: Assign these from each iteration through DisplayContent. Only valid between loops.
     /** Overall window dimensions */
     int mDw, mDh;
 
@@ -698,20 +699,6 @@
         }
     }
 
-    static class SetAnimationParams {
-        final WindowStateAnimator mWinAnimator;
-        final Animation mAnimation;
-        final int mAnimDw;
-        final int mAnimDh;
-        public SetAnimationParams(final WindowStateAnimator winAnimator,
-                                  final Animation animation, final int animDw, final int animDh) {
-            mWinAnimator = winAnimator;
-            mAnimation = animation;
-            mAnimDw = animDw;
-            mAnimDh = animDh;
-        }
-    }
-
     void clearPendingActions() {
         synchronized (this) {
             mPendingActions = 0;
diff --git a/services/java/com/android/server/wm/WindowManagerService.java b/services/java/com/android/server/wm/WindowManagerService.java
index c82fa55..cdca8bc 100755
--- a/services/java/com/android/server/wm/WindowManagerService.java
+++ b/services/java/com/android/server/wm/WindowManagerService.java
@@ -86,6 +86,7 @@
 import android.os.ParcelFileDescriptor;
 import android.os.PowerManager;
 import android.os.Process;
+import android.os.RemoteCallbackList;
 import android.os.RemoteException;
 import android.os.ServiceManager;
 import android.os.StrictMode;
@@ -108,6 +109,7 @@
 import android.view.DisplayInfo;
 import android.view.Gravity;
 import android.view.IApplicationToken;
+import android.view.IDisplayContentChangeListener;
 import android.view.IInputFilter;
 import android.view.IOnKeyguardExitResult;
 import android.view.IRotationWatcher;
@@ -124,6 +126,7 @@
 import android.view.SurfaceSession;
 import android.view.View;
 import android.view.ViewTreeObserver;
+import android.view.WindowInfo;
 import android.view.WindowManager;
 import android.view.WindowManagerGlobal;
 import android.view.WindowManagerPolicy;
@@ -162,7 +165,7 @@
 /** {@hide} */
 public class WindowManagerService extends IWindowManager.Stub
         implements Watchdog.Monitor, WindowManagerPolicy.WindowManagerFuncs,
-                DisplayManagerService.WindowManagerFuncs {
+                DisplayManagerService.WindowManagerFuncs, DisplayManager.DisplayListener {
     static final String TAG = "WindowManager";
     static final boolean DEBUG = false;
     static final boolean DEBUG_ADD_REMOVE = false;
@@ -716,6 +719,9 @@
      */
     boolean mInTouchMode = true;
 
+    // Temp regions for intermediary calculations.
+    private final Region mTempRegion = new Region();
+
     private ViewServer mViewServer;
     private ArrayList<WindowChangeListener> mWindowChangeListeners =
         new ArrayList<WindowChangeListener>();
@@ -776,9 +782,15 @@
         mLimitedAlphaCompositing = context.getResources().getBoolean(
                 com.android.internal.R.bool.config_sf_limitedAlpha);
         mDisplayManagerService = displayManager;
-        mDisplayManager = (DisplayManager)context.getSystemService(Context.DISPLAY_SERVICE);
         mHeadless = displayManager.isHeadless();
 
+        mDisplayManager = (DisplayManager)context.getSystemService(Context.DISPLAY_SERVICE);
+        mDisplayManager.registerDisplayListener(this, null);
+        Display[] displays = mDisplayManager.getDisplays();
+        for (Display display : displays) {
+            createDisplayContent(display);
+        }
+
         mKeyguardDisableHandler = new KeyguardDisableHandler(mContext, mPolicy);
 
         mPowerManager = pm;
@@ -881,49 +893,76 @@
         return -1;
     }
 
+    /**
+     * Return the list of Windows from the passed token on the given Display.
+     * @param token The token with all the windows.
+     * @param displayContent The display we are interested in.
+     * @return List of windows from token that are on displayContent.
+     */
+    WindowList getTokenWindowsOnDisplay(WindowToken token, DisplayContent displayContent) {
+        final WindowList windowList = new WindowList();
+        final int count = token.windows.size();
+        for (int i = 0; i < count; i++) {
+            final WindowState win = token.windows.get(i);
+            if (win.mDisplayContent == displayContent) {
+                windowList.add(win);
+            }
+        }
+        return windowList;
+    }
+
     private void addWindowToListInOrderLocked(WindowState win, boolean addToToken) {
         final IWindow client = win.mClient;
         final WindowToken token = win.mToken;
+        final DisplayContent displayContent = win.mDisplayContent;
 
         final WindowList windows = win.getWindowList();
         final int N = windows.size();
         final WindowState attached = win.mAttachedWindow;
         int i;
+        WindowList tokenWindowList = getTokenWindowsOnDisplay(token, displayContent);
         if (attached == null) {
-            int tokenWindowsPos = token.windows.size();
+            int tokenWindowsPos = 0;
+            int windowListPos = tokenWindowList.size();
             if (token.appWindowToken != null) {
-                int index = tokenWindowsPos-1;
+                int index = windowListPos - 1;
                 if (index >= 0) {
                     // If this application has existing windows, we
                     // simply place the new window on top of them... but
                     // keep the starting window on top.
                     if (win.mAttrs.type == TYPE_BASE_APPLICATION) {
                         // Base windows go behind everything else.
-                        placeWindowBefore(token.windows.get(0), win);
-                        tokenWindowsPos = 0;
+                        WindowState lowestWindow = tokenWindowList.get(0);
+                        placeWindowBefore(lowestWindow, win);
+                        tokenWindowsPos = token.windows.indexOf(lowestWindow);
                     } else {
                         AppWindowToken atoken = win.mAppToken;
-                        if (atoken != null &&
-                                token.windows.get(index) == atoken.startingWindow) {
-                            placeWindowBefore(token.windows.get(index), win);
-                            tokenWindowsPos--;
+                        WindowState lastWindow = tokenWindowList.get(index);
+                        if (atoken != null && lastWindow == atoken.startingWindow) {
+                            placeWindowBefore(lastWindow, win);
+                            tokenWindowsPos = token.windows.indexOf(lastWindow);
                         } else {
-                            int newIdx =  findIdxBasedOnAppTokens(win);
-                            if(newIdx != -1) {
-                                //there is a window above this one associated with the same
-                                //apptoken note that the window could be a floating window
-                                //that was created later or a window at the top of the list of
-                                //windows associated with this token.
-                                if (DEBUG_FOCUS || DEBUG_WINDOW_MOVEMENT || DEBUG_ADD_REMOVE) {
-                                    Slog.v(TAG, "Adding window " + win + " at "
-                                            + (newIdx+1) + " of " + N);
-                                }
-                                windows.add(newIdx+1, win);
-                                mWindowsChanged = true;
+                            int newIdx = findIdxBasedOnAppTokens(win);
+                            //there is a window above this one associated with the same
+                            //apptoken note that the window could be a floating window
+                            //that was created later or a window at the top of the list of
+                            //windows associated with this token.
+                            if (DEBUG_FOCUS || DEBUG_WINDOW_MOVEMENT || DEBUG_ADD_REMOVE) {
+                                Slog.v(TAG, "Adding window " + win + " at "
+                                        + (newIdx + 1) + " of " + N);
                             }
+                            windows.add(newIdx + 1, win);
+                            if (newIdx < 0) {
+                                // No window from token found on win's display.
+                                tokenWindowsPos = 0;
+                            } else {
+                                tokenWindowsPos = token.windows.indexOf(windows.get(newIdx)) + 1;
+                            }
+                            mWindowsChanged = true;
                         }
                     }
                 } else {
+                    // No windows from this token on this display
                     if (localLOGV) Slog.v(
                         TAG, "Figuring out where to add app window "
                         + client.asBinder() + " (token=" + token + ")");
@@ -939,10 +978,11 @@
                         }
 
                         // We haven't reached the token yet; if this token
-                        // is not going to the bottom and has windows, we can
+                        // is not going to the bottom and has windows on this display, we can
                         // use it as an anchor for when we do reach the token.
-                        if (!t.sendingToBottom && t.windows.size() > 0) {
-                            pos = t.windows.get(0);
+                        tokenWindowList = getTokenWindowsOnDisplay(t, win.mDisplayContent);
+                        if (!t.sendingToBottom && tokenWindowList.size() > 0) {
+                            pos = tokenWindowList.get(0);
                         }
                     }
                     // We now know the index into the apps.  If we found
@@ -952,9 +992,11 @@
                         // Move behind any windows attached to this one.
                         WindowToken atoken = mTokenMap.get(pos.mClient.asBinder());
                         if (atoken != null) {
-                            final int NC = atoken.windows.size();
+                            tokenWindowList =
+                                    getTokenWindowsOnDisplay(atoken, win.mDisplayContent);
+                            final int NC = tokenWindowList.size();
                             if (NC > 0) {
-                                WindowState bottom = atoken.windows.get(0);
+                                WindowState bottom = tokenWindowList.get(0);
                                 if (bottom.mSubLayer < 0) {
                                     pos = bottom;
                                 }
@@ -963,12 +1005,13 @@
                         placeWindowBefore(pos, win);
                     } else {
                         // Continue looking down until we find the first
-                        // token that has windows.
+                        // token that has windows on this display.
                         while (i >= 0) {
                             AppWindowToken t = mAnimatingAppTokens.get(i);
-                            final int NW = t.windows.size();
+                            tokenWindowList = getTokenWindowsOnDisplay(t, win.mDisplayContent);
+                            final int NW = tokenWindowList.size();
                             if (NW > 0) {
-                                pos = t.windows.get(NW-1);
+                                pos = tokenWindowList.get(NW-1);
                                 break;
                             }
                             i--;
@@ -1010,11 +1053,10 @@
                 final int myLayer = win.mBaseLayer;
                 for (i=N-1; i>=0; i--) {
                     if (windows.get(i).mBaseLayer <= myLayer) {
-                        i++;
                         break;
                     }
                 }
-                if (i < 0) i = 0;
+                i++;
                 if (DEBUG_FOCUS || DEBUG_WINDOW_MOVEMENT || DEBUG_ADD_REMOVE) Slog.v(
                         TAG, "Adding window " + win + " at "
                         + i + " of " + N);
@@ -1030,12 +1072,12 @@
         } else {
             // Figure out this window's ordering relative to the window
             // it is attached to.
-            final int NA = token.windows.size();
+            final int NA = tokenWindowList.size();
             final int sublayer = win.mSubLayer;
             int largestSublayer = Integer.MIN_VALUE;
             WindowState windowWithLargestSublayer = null;
             for (i=0; i<NA; i++) {
-                WindowState w = token.windows.get(i);
+                WindowState w = tokenWindowList.get(i);
                 final int wSublayer = w.mSubLayer;
                 if (wSublayer >= largestSublayer) {
                     largestSublayer = wSublayer;
@@ -1084,6 +1126,10 @@
         if (win.mAppToken != null && addToToken) {
             win.mAppToken.allAppWindows.add(win);
         }
+
+        if (windows.size() == 1) {
+            mDisplayManagerService.setDisplayHasContent(win.getDisplayId(), true);
+        }
     }
 
     /** TODO(cmautner): Is this the same as {@link WindowState#canReceiveKeys()} */
@@ -2198,7 +2244,11 @@
 
             win.mWinAnimator.mEnterAnimationPending = true;
 
-            mPolicy.getContentInsetHintLw(attrs, outContentInsets);
+            if (displayContent.isDefaultDisplay) {
+                mPolicy.getContentInsetHintLw(attrs, outContentInsets);
+            } else {
+                outContentInsets.setEmpty();
+            }
 
             if (mInTouchMode) {
                 res |= WindowManagerGlobal.ADD_FLAG_IN_TOUCH_MODE;
@@ -2302,6 +2352,7 @@
                 if (win.mWinAnimator.applyAnimationLocked(transit, false)) {
                     win.mExiting = true;
                 }
+                scheduleNotifyWindowTranstionIfNeededLocked(win, transit);
             }
             if (win.mExiting || win.mWinAnimator.isAnimating()) {
                 // The exit animation is running... wait for it!
@@ -2367,6 +2418,9 @@
 
         final WindowList windows = win.getWindowList();
         windows.remove(win);
+        if (windows.isEmpty()) {
+            mDisplayManagerService.setDisplayHasContent(win.getDisplayId(), false);
+        }
         mPendingRemove.remove(win);
         mWindowsChanged = true;
         if (DEBUG_WINDOW_MOVEMENT) Slog.v(TAG, "Final remove of window: " + win);
@@ -2590,6 +2644,54 @@
         performLayoutAndPlaceSurfacesLocked();
     }
 
+    public void onRectangleOnScreenRequested(IBinder token, Rect rectangle, boolean immediate) {
+        synchronized (mWindowMap) {
+            WindowState window = mWindowMap.get(token);
+            if (window != null) {
+                scheduleNotifyRectangleOnScreenRequestedIfNeededLocked(window, rectangle,
+                        immediate);
+            }
+        }
+    }
+
+    private void scheduleNotifyRectangleOnScreenRequestedIfNeededLocked(WindowState window,
+            Rect rectangle, boolean immediate) {
+        DisplayContent displayContent = window.mDisplayContent;
+        if (displayContent.mDisplayContentChangeListeners != null
+                && displayContent.mDisplayContentChangeListeners.getRegisteredCallbackCount() > 0) {
+            mH.obtainMessage(H.NOTIFY_RECTANGLE_ON_SCREEN_REQUESTED, displayContent.getDisplayId(),
+                    immediate? 1 : 0, new Rect(rectangle)).sendToTarget();
+        }
+    }
+
+    private void handleNotifyRectangleOnScreenRequested(int displayId, Rect rectangle,
+            boolean immediate) {
+        RemoteCallbackList<IDisplayContentChangeListener> callbacks = null;
+        synchronized (mWindowMap) {
+            DisplayContent displayContent = getDisplayContent(displayId);
+            if (displayContent == null) {
+                return;
+            }
+            callbacks = displayContent.mDisplayContentChangeListeners;
+            if (callbacks == null) {
+                return;
+            }
+        }
+        final int callbackCount = callbacks.beginBroadcast();
+        try {
+            for (int i = 0; i < callbackCount; i++) {
+                try {
+                    callbacks.getBroadcastItem(i).onRectangleOnScreenRequested(displayId,
+                            rectangle, immediate);
+                } catch (RemoteException re) {
+                    /* ignore */
+                }
+            }
+        } finally {
+            callbacks.finishBroadcast();
+        }
+    }
+
     public int relayoutWindow(Session session, IWindow client, int seq,
             WindowManager.LayoutParams attrs, int requestedWidth,
             int requestedHeight, int viewVisibility, int flags,
@@ -2679,9 +2781,10 @@
                     WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM |
                     WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE)) != 0;
 
-            boolean focusMayChange = win.mViewVisibility != viewVisibility
+            final boolean isDefaultDisplay = win.isDefaultDisplay();
+            boolean focusMayChange = isDefaultDisplay && (win.mViewVisibility != viewVisibility
                     || ((flagChanges&WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE) != 0)
-                    || (!win.mRelayoutCalled);
+                    || (!win.mRelayoutCalled));
 
             boolean wallpaperMayMove = win.mViewVisibility != viewVisibility
                     && (win.mAttrs.flags & FLAG_SHOW_WALLPAPER) != 0;
@@ -2763,7 +2866,7 @@
                     return 0;
                 }
                 if (toBeDisplayed) {
-                    focusMayChange = true;
+                    focusMayChange = isDefaultDisplay;
                 }
                 if (win.mAttrs.type == TYPE_INPUT_METHOD
                         && mInputMethodWindow == null) {
@@ -2800,7 +2903,7 @@
                         }
                         if (win.isWinVisibleLw() &&
                                 winAnimator.applyAnimationLocked(transit, false)) {
-                            focusMayChange = true;
+                            focusMayChange = isDefaultDisplay;
                             win.mExiting = true;
                         } else if (win.mWinAnimator.isAnimating()) {
                             // Currently in a hide animation... turn this into
@@ -2818,6 +2921,7 @@
                             }
                             winAnimator.destroySurfaceLocked();
                         }
+                        scheduleNotifyWindowTranstionIfNeededLocked(win, transit);
                     }
                 }
 
@@ -2963,6 +3067,97 @@
         }
     }
 
+    @Override
+    public WindowInfo getWindowInfo(IBinder token) {
+        if (!checkCallingPermission(android.Manifest.permission.RETRIEVE_WINDOW_INFO,
+                "getWindowInfo()")) {
+            throw new SecurityException("Requires RETRIEVE_WINDOW_INFO permission.");
+        }
+        synchronized (mWindowMap) {
+            WindowState window = mWindowMap.get(token);
+            if (window != null) {
+                return getWindowInfoForWindowStateLocked(window);
+            }
+            return null;
+        }
+    }
+
+    @Override
+    public void getVisibleWindowsForDisplay(int displayId, List<WindowInfo> outInfos) {
+        if (!checkCallingPermission(android.Manifest.permission.RETRIEVE_WINDOW_INFO,
+                "getWindowInfos()")) {
+            throw new SecurityException("Requires RETRIEVE_WINDOW_INFO permission.");
+        }
+        synchronized (mWindowMap) {
+            DisplayContent displayContent = getDisplayContent(displayId);
+            if (displayContent == null) {
+                return;
+            }
+            WindowList windows = displayContent.getWindowList();
+            final int windowCount = windows.size();
+            for (int i = 0; i < windowCount; i++) {
+                WindowState window = windows.get(i);
+                if (window.isVisibleLw() ||
+                        window.mAttrs.type == WindowManager.LayoutParams.TYPE_UNIVERSE_BACKGROUND) {
+                    WindowInfo info = getWindowInfoForWindowStateLocked(window);
+                    outInfos.add(info);
+                }
+            }
+        }
+    }
+
+    public void magnifyDisplay(int displayId, float scale, float offsetX, float offsetY) {
+        if (!checkCallingPermission(
+                android.Manifest.permission.MAGNIFY_DISPLAY, "magnifyDisplay()")) {
+            throw new SecurityException("Requires MAGNIFY_DISPLAY permission");
+        }
+        synchronized (mWindowMap) {
+            MagnificationSpec spec = getDisplayMagnificationSpecLocked(displayId);
+            if (spec != null) {
+                final boolean scaleChanged = spec.mScale != scale;
+                final boolean offsetChanged = spec.mOffsetX != offsetX || spec.mOffsetY != offsetY;
+                if (!scaleChanged && !offsetChanged) {
+                    return;
+                }
+                spec.initialize(scale, offsetX, offsetY);
+                // If the offset has changed we need to re-add the input windows
+                // since the offsets have to be propagated to the input system.
+                if (offsetChanged) {
+                    // TODO(multidisplay): Input only occurs on the default display.
+                    if (displayId == Display.DEFAULT_DISPLAY) {
+                        mInputMonitor.updateInputWindowsLw(true);
+                    }
+                }
+                scheduleAnimationLocked();
+            }
+        }
+    }
+
+    MagnificationSpec getDisplayMagnificationSpecLocked(int displayId) {
+        DisplayContent displayContent = getDisplayContent(displayId);
+        if (displayContent != null) {
+            if (displayContent.mMagnificationSpec == null) {
+                displayContent.mMagnificationSpec = new MagnificationSpec();
+            }
+            return displayContent.mMagnificationSpec;
+        }
+        return null;
+    }
+
+    private WindowInfo getWindowInfoForWindowStateLocked(WindowState window) {
+        WindowInfo info = WindowInfo.obtain();
+        info.token = window.mToken.token;
+        info.frame.set(window.mFrame);
+        info.type = window.mAttrs.type;
+        info.displayId = window.getDisplayId();
+        info.compatibilityScale = window.mGlobalScale;
+        info.visible = window.isVisibleLw()
+                || info.type == WindowManager.LayoutParams.TYPE_UNIVERSE_BACKGROUND;
+        window.getTouchableRegion(mTempRegion);
+        mTempRegion.getBounds(info.touchableRegion);
+        return info;
+    }
+
     private AttributeCache.Entry getCachedAnimations(WindowManager.LayoutParams lp) {
         if (DEBUG_ANIM) Slog.v(TAG, "Loading animations: layout params pkg="
                 + (lp != null ? lp.packageName : null)
@@ -3457,6 +3652,8 @@
                         if (win.isVisibleNow()) {
                             win.mWinAnimator.applyAnimationLocked(WindowManagerPolicy.TRANSIT_EXIT,
                                     false);
+                            scheduleNotifyWindowTranstionIfNeededLocked(win,
+                                    WindowManagerPolicy.TRANSIT_EXIT);
                             changed = true;
                             win.mDisplayContent.layoutNeeded = true;
                         }
@@ -4230,6 +4427,10 @@
                 if (applyAnimationLocked(wtoken, lp, transit, visible)) {
                     delayed = runningAppAnimation = true;
                 }
+                WindowState window = wtoken.findMainWindow();
+                if (window != null) {
+                    scheduleNotifyWindowTranstionIfNeededLocked(window, transit);
+                }
                 changed = true;
             }
 
@@ -4247,6 +4448,8 @@
                         if (!runningAppAnimation) {
                             win.mWinAnimator.applyAnimationLocked(
                                     WindowManagerPolicy.TRANSIT_ENTER, true);
+                            scheduleNotifyWindowTranstionIfNeededLocked(win,
+                                    WindowManagerPolicy.TRANSIT_ENTER);
                         }
                         changed = true;
                         win.mDisplayContent.layoutNeeded = true;
@@ -4255,6 +4458,8 @@
                     if (!runningAppAnimation) {
                         win.mWinAnimator.applyAnimationLocked(
                                 WindowManagerPolicy.TRANSIT_EXIT, false);
+                        scheduleNotifyWindowTranstionIfNeededLocked(win,
+                                WindowManagerPolicy.TRANSIT_EXIT);
                     }
                     changed = true;
                     win.mDisplayContent.layoutNeeded = true;
@@ -4708,7 +4913,7 @@
         for (int i=0; i<NW; i++) {
             final WindowState win = token.windows.get(i);
             if (win.mDisplayContent == displayContent) {
-                index = reAddWindowLocked(index, token.windows.get(i));
+                index = reAddWindowLocked(index, win);
             }
         }
         return index;
@@ -5742,7 +5947,6 @@
         mWaitingForConfig = true;
         getDefaultDisplayContent().layoutNeeded = true;
         startFreezingDisplayLocked(inTransaction);
-        mInputManager.setDisplayOrientation(0, rotation);
 
         // We need to update our screen size information to match the new
         // rotation.  Note that this is redundant with the later call to
@@ -5794,12 +5998,16 @@
                 mInnerFields.mOrientationChangeComplete = false;
             }
         }
+
         for (int i=mRotationWatchers.size()-1; i>=0; i--) {
             try {
                 mRotationWatchers.get(i).onRotationChanged(rotation);
             } catch (RemoteException e) {
             }
         }
+
+        scheduleNotifyRotationChangedIfNeededLocked(displayContent, rotation);
+
         return true;
     }
 
@@ -6180,6 +6388,110 @@
         return success;
     }
 
+    public void addDisplayContentChangeListener(int displayId,
+            IDisplayContentChangeListener listener) {
+        if (!checkCallingPermission(android.Manifest.permission.RETRIEVE_WINDOW_INFO,
+                "addDisplayContentChangeListener()")) {
+            throw new SecurityException("Requires RETRIEVE_WINDOW_INFO permission");
+        }
+        synchronized(mWindowMap) {
+            DisplayContent displayContent = getDisplayContent(displayId);
+            if (displayContent.mDisplayContentChangeListeners == null) {
+                displayContent.mDisplayContentChangeListeners =
+                        new RemoteCallbackList<IDisplayContentChangeListener>();
+            displayContent.mDisplayContentChangeListeners.register(listener);
+            }
+        }
+    }
+
+    public void removeDisplayContentChangeListener(int displayId,
+            IDisplayContentChangeListener listener) {
+        if (!checkCallingPermission(android.Manifest.permission.RETRIEVE_WINDOW_INFO,
+                "removeDisplayContentChangeListener()")) {
+            throw new SecurityException("Requires RETRIEVE_WINDOW_INFO permission");
+        }
+        synchronized(mWindowMap) {
+            DisplayContent displayContent = getDisplayContent(displayId);
+            if (displayContent.mDisplayContentChangeListeners != null) {
+                displayContent.mDisplayContentChangeListeners.unregister(listener);
+                if (displayContent.mDisplayContentChangeListeners
+                        .getRegisteredCallbackCount() == 0) {
+                    displayContent.mDisplayContentChangeListeners = null;
+                }
+            }
+        }
+    }
+
+    void scheduleNotifyWindowTranstionIfNeededLocked(WindowState window, int transition) {
+        DisplayContent displayContent = window.mDisplayContent;
+        if (displayContent.mDisplayContentChangeListeners != null) {
+            WindowInfo info = getWindowInfoForWindowStateLocked(window);
+            mH.obtainMessage(H.NOTIFY_WINDOW_TRANSITION, transition, 0, info).sendToTarget();
+        }
+    }
+
+    private void handleNotifyWindowTranstion(int transition, WindowInfo info) {
+        RemoteCallbackList<IDisplayContentChangeListener> callbacks = null;
+        synchronized (mWindowMap) {
+            DisplayContent displayContent = getDisplayContent(info.displayId);
+            if (displayContent == null) {
+                return;
+            }
+            callbacks = displayContent.mDisplayContentChangeListeners;
+            if (callbacks == null) {
+                return;
+            }
+        }
+        final int callbackCount = callbacks.beginBroadcast();
+        try {
+            for (int i = 0; i < callbackCount; i++) {
+                try {
+                    callbacks.getBroadcastItem(i).onWindowTransition(info.displayId,
+                            transition, info);
+                } catch (RemoteException re) {
+                    /* ignore */
+                }
+            }
+        } finally {
+            callbacks.finishBroadcast();
+        }
+    }
+
+    private void scheduleNotifyRotationChangedIfNeededLocked(DisplayContent displayContent,
+            int rotation) {
+        if (displayContent.mDisplayContentChangeListeners != null
+                && displayContent.mDisplayContentChangeListeners.getRegisteredCallbackCount() > 0) {
+            mH.obtainMessage(H.NOTIFY_ROTATION_CHANGED, displayContent.getDisplayId(),
+                    rotation).sendToTarget();
+        }
+    }
+
+    private void handleNotifyRotationChanged(int displayId, int rotation) {
+        RemoteCallbackList<IDisplayContentChangeListener> callbacks = null;
+        synchronized (mWindowMap) {
+            DisplayContent displayContent = getDisplayContent(displayId);
+            if (displayContent == null) {
+                return;
+            }
+            callbacks = displayContent.mDisplayContentChangeListeners;
+            if (callbacks == null) {
+                return;
+            }
+        }
+        try {
+            final int watcherCount = callbacks.beginBroadcast();
+            for (int i = 0; i < watcherCount; i++) {
+                try {
+                    callbacks.getBroadcastItem(i).onRotationChanged(rotation);
+                } catch (RemoteException re) {
+                    /* ignore */
+                }
+            }
+        } finally {
+            callbacks.finishBroadcast();
+        }
+    }
+
     public void addWindowChangeListener(WindowChangeListener listener) {
         synchronized(mWindowMap) {
             mWindowChangeListeners.add(listener);
@@ -6274,6 +6586,7 @@
     }
 
     private void adjustDisplaySizeRanges(DisplayInfo displayInfo, int rotation, int dw, int dh) {
+        // TODO: Multidisplay: for now only use with default display.
         final int width = mPolicy.getConfigDisplayWidth(dw, dh, rotation);
         if (width < displayInfo.smallestNominalAppWidth) {
             displayInfo.smallestNominalAppWidth = width;
@@ -6292,6 +6605,7 @@
 
     private int reduceConfigLayout(int curLayout, int rotation, float density,
             int dw, int dh) {
+        // TODO: Multidisplay: for now only use with default display.
         // Get the app screen size at this rotation.
         int w = mPolicy.getNonDecorDisplayWidth(dw, dh, rotation);
         int h = mPolicy.getNonDecorDisplayHeight(dw, dh, rotation);
@@ -6371,6 +6685,8 @@
 
     private void computeSizeRangesAndScreenLayout(DisplayInfo displayInfo, boolean rotated,
                   int dw, int dh, float density, Configuration outConfig) {
+        // TODO: Multidisplay: for now only use with default display.
+
         // We need to determine the smallest width that will occur under normal
         // operation.  To this, start with the base screen size and compute the
         // width under the different possible rotations.  We need to un-rotate
@@ -6404,6 +6720,7 @@
 
     private int reduceCompatConfigWidthSize(int curSize, int rotation, DisplayMetrics dm,
             int dw, int dh) {
+        // TODO: Multidisplay: for now only use with default display.
         dm.noncompatWidthPixels = mPolicy.getNonDecorDisplayWidth(dw, dh, rotation);
         dm.noncompatHeightPixels = mPolicy.getNonDecorDisplayHeight(dw, dh, rotation);
         float scale = CompatibilityInfo.computeCompatibleScaling(dm, null);
@@ -6415,9 +6732,10 @@
     }
 
     private int computeCompatSmallestWidth(boolean rotated, DisplayMetrics dm, int dw, int dh) {
+        // TODO: Multidisplay: for now only use with default display.
         mTmpDisplayMetrics.setTo(dm);
-        dm = mTmpDisplayMetrics;
-        int unrotDw, unrotDh;
+        final DisplayMetrics tmpDm = mTmpDisplayMetrics;
+        final int unrotDw, unrotDh;
         if (rotated) {
             unrotDw = dh;
             unrotDh = dw;
@@ -6425,10 +6743,10 @@
             unrotDw = dw;
             unrotDh = dh;
         }
-        int sw = reduceCompatConfigWidthSize(0, Surface.ROTATION_0, dm, unrotDw, unrotDh);
-        sw = reduceCompatConfigWidthSize(sw, Surface.ROTATION_90, dm, unrotDh, unrotDw);
-        sw = reduceCompatConfigWidthSize(sw, Surface.ROTATION_180, dm, unrotDw, unrotDh);
-        sw = reduceCompatConfigWidthSize(sw, Surface.ROTATION_270, dm, unrotDh, unrotDw);
+        int sw = reduceCompatConfigWidthSize(0, Surface.ROTATION_0, tmpDm, unrotDw, unrotDh);
+        sw = reduceCompatConfigWidthSize(sw, Surface.ROTATION_90, tmpDm, unrotDh, unrotDw);
+        sw = reduceCompatConfigWidthSize(sw, Surface.ROTATION_180, tmpDm, unrotDw, unrotDh);
+        sw = reduceCompatConfigWidthSize(sw, Surface.ROTATION_270, tmpDm, unrotDh, unrotDw);
         return sw;
     }
 
@@ -6737,21 +7055,6 @@
         }
     }
 
-    public boolean getWindowFrame(IBinder token, Rect outBounds) {
-        if (!checkCallingPermission(android.Manifest.permission.RETRIEVE_WINDOW_INFO,
-                "getWindowFrame()")) {
-            throw new SecurityException("Requires RETRIEVE_WINDOW_INFO permission.");
-        }
-        synchronized (mWindowMap) {
-            WindowState windowState = mWindowMap.get(token);
-            if (windowState != null) {
-                outBounds.set(windowState.getFrameLw());
-                return true;
-            }
-        }
-        return false;
-    }
-
     private WindowState getFocusedWindow() {
         synchronized (mWindowMap) {
             return getFocusedWindowLocked();
@@ -6817,10 +7120,6 @@
                 displayInfo.appWidth, displayInfo.appHeight);
 
             final DisplayContent displayContent = getDefaultDisplayContent();
-            mInputManager.setDisplaySize(displayContent.getDisplayId(),
-                    displayContent.mInitialDisplayWidth, displayContent.mInitialDisplayHeight);
-            mInputManager.setDisplayOrientation(displayContent.getDisplayId(),
-                    mDefaultDisplay.getRotation());
             mPolicy.setInitialDisplaySize(mDefaultDisplay, displayContent.mInitialDisplayWidth,
                     displayContent.mInitialDisplayHeight, displayContent.mInitialDisplayDensity);
         }
@@ -6899,6 +7198,13 @@
         public static final int UPDATE_ANIM_PARAMETERS = 25;
         public static final int SHOW_STRICT_MODE_VIOLATION = 26;
         public static final int DO_ANIMATION_CALLBACK = 27;
+        public static final int NOTIFY_ROTATION_CHANGED = 28;
+        public static final int NOTIFY_WINDOW_TRANSITION = 29;
+        public static final int NOTIFY_RECTANGLE_ON_SCREEN_REQUESTED = 30;
+
+        public static final int DO_DISPLAY_ADDED = 31;
+        public static final int DO_DISPLAY_REMOVED = 32;
+        public static final int DO_DISPLAY_CHANGED = 33;
 
         public static final int ANIMATOR_WHAT_OFFSET = 100000;
         public static final int SET_TRANSPARENT_REGION = ANIMATOR_WHAT_OFFSET + 1;
@@ -7337,6 +7643,46 @@
                     }
                     break;
                 }
+
+                case NOTIFY_ROTATION_CHANGED: {
+                    final int displayId = msg.arg1;
+                    final int rotation = msg.arg2;
+                    handleNotifyRotationChanged(displayId, rotation);
+                    break;
+                }
+
+                case NOTIFY_WINDOW_TRANSITION: {
+                    final int transition = msg.arg1;
+                    WindowInfo info = (WindowInfo) msg.obj;
+                    handleNotifyWindowTranstion(transition, info);
+                    break;
+                }
+
+                case NOTIFY_RECTANGLE_ON_SCREEN_REQUESTED: {
+                    final int displayId = msg.arg1;
+                    final boolean immediate = (msg.arg2 == 1);
+                    Rect rectangle = (Rect) msg.obj;
+                    handleNotifyRectangleOnScreenRequested(displayId, rectangle, immediate);
+                    break;
+                }
+
+                case DO_DISPLAY_ADDED:
+                    synchronized (mWindowMap) {
+                        handleDisplayAddedLocked(msg.arg1);
+                    }
+                    break;
+
+                case DO_DISPLAY_REMOVED:
+                    synchronized (mWindowMap) {
+                        handleDisplayRemovedLocked(msg.arg1);
+                    }
+                    break;
+
+                case DO_DISPLAY_CHANGED:
+                    synchronized (mWindowMap) {
+                        handleDisplayChangedLocked(msg.arg1);
+                    }
+                    break;
             }
             if (DEBUG_WINDOW_TRACE) {
                 Slog.v(TAG, "handleMessage: exit");
@@ -7582,6 +7928,7 @@
     }
 
     private void reconfigureDisplayLocked(DisplayContent displayContent) {
+        // TODO: Multidisplay: for now only use with default display.
         mPolicy.setInitialDisplaySize(mDefaultDisplay, displayContent.mBaseDisplayWidth,
                 displayContent.mBaseDisplayHeight, displayContent.mBaseDisplayDensity);
 
@@ -7874,6 +8221,7 @@
         }
         displayContent.layoutNeeded = false;
         WindowList windows = displayContent.getWindowList();
+        boolean isDefaultDisplay = displayContent.isDefaultDisplay;
 
         DisplayInfo displayInfo = displayContent.getDisplayInfo();
         final int dw = displayInfo.logicalWidth;
@@ -7895,9 +8243,12 @@
 
         WindowStateAnimator universeBackground = null;
 
-        mPolicy.beginLayoutLw(dw, dh, mRotation);
-        mSystemDecorLayer = mPolicy.getSystemDecorRectLw(mSystemDecorRect);
-        mScreenRect.set(0, 0, dw, dh);
+        mPolicy.beginLayoutLw(isDefaultDisplay, dw, dh, mRotation);
+        if (isDefaultDisplay) {
+            // Not needed on non-default displays.
+            mSystemDecorLayer = mPolicy.getSystemDecorRectLw(mSystemDecorRect);
+            mScreenRect.set(0, 0, dw, dh);
+        }
 
         int seq = mLayoutSeq+1;
         if (seq < 0) seq = 0;
@@ -7932,7 +8283,7 @@
                         + (atoken != null && atoken.hiddenRequested)
                         + " mAttachedHidden=" + win.mAttachedHidden);
             }
-            
+
             // If this view is GONE, then skip it -- keep the current
             // frame, and let the caller know so they can ignore it
             // if they want.  (We do the normal layout for INVISIBLE
@@ -8518,10 +8869,6 @@
             Slog.v(TAG, "performLayoutAndPlaceSurfacesLockedInner: entry. Called by "
                     + Debug.getCallers(3));
         }
-        if (mDefaultDisplay == null) {
-            Slog.i(TAG, "skipping performLayoutAndPlaceSurfacesLockedInner with no mDisplay");
-            return;
-        }
 
         final long currentTime = SystemClock.uptimeMillis();
 
@@ -8552,8 +8899,6 @@
         final DisplayInfo defaultInfo = defaultDisplay.getDisplayInfo();
         final int defaultDw = defaultInfo.logicalWidth;
         final int defaultDh = defaultInfo.logicalHeight;
-        final int defaultInnerDw = defaultInfo.appWidth;
-        final int defaultInnerDh = defaultInfo.appHeight;
 
         if (SHOW_LIGHT_TRANSACTIONS) Slog.i(TAG,
                 ">>> OPEN TRANSACTION performLayoutAndPlaceSurfaces");
@@ -8635,16 +8980,18 @@
                     if (DEBUG_LAYOUT_REPEATS) debugLayoutRepeats("loop number "
                             + mLayoutRepeatCount, displayContent.pendingLayoutChanges);
 
-                    mPolicy.beginPostLayoutPolicyLw(dw, dh);
-                    for (i = windows.size() - 1; i >= 0; i--) {
-                        WindowState w = windows.get(i);
-                        if (w.mHasSurface) {
-                            mPolicy.applyPostLayoutPolicyLw(w, w.mAttrs);
+                    if (isDefaultDisplay) {
+                        mPolicy.beginPostLayoutPolicyLw(dw, dh);
+                        for (i = windows.size() - 1; i >= 0; i--) {
+                            WindowState w = windows.get(i);
+                            if (w.mHasSurface) {
+                                mPolicy.applyPostLayoutPolicyLw(w, w.mAttrs);
+                            }
                         }
+                        displayContent.pendingLayoutChanges |= mPolicy.finishPostLayoutPolicyLw();
+                        if (DEBUG_LAYOUT_REPEATS) debugLayoutRepeats(
+                            "after finishPostLayoutPolicyLw", displayContent.pendingLayoutChanges);
                     }
-                    displayContent.pendingLayoutChanges |= mPolicy.finishPostLayoutPolicyLw();
-                    if (DEBUG_LAYOUT_REPEATS) debugLayoutRepeats("after finishPostLayoutPolicyLw",
-                        displayContent.pendingLayoutChanges);
                 } while (displayContent.pendingLayoutChanges != 0);
 
                 mInnerFields.mObscured = false;
@@ -8700,8 +9047,9 @@
                     // Moved from updateWindowsAndWallpaperLocked().
                     if (w.mHasSurface) {
                         // Take care of the window being ready to display.
-                        if (isDefaultDisplay
-                                && winAnimator.commitFinishDrawingLocked(currentTime)) {
+                        final boolean committed =
+                                winAnimator.commitFinishDrawingLocked(currentTime);
+                        if (isDefaultDisplay && committed) {
                             if ((w.mAttrs.flags
                                     & WindowManager.LayoutParams.FLAG_SHOW_WALLPAPER) != 0) {
                                 if (WindowManagerService.DEBUG_WALLPAPER) Slog.v(TAG,
@@ -9124,6 +9472,7 @@
         }
     }
 
+    @Override
     public void requestTraversal() {
         synchronized (mWindowMap) {
             requestTraversalLocked();
@@ -9256,7 +9605,7 @@
             }
             for (int i = 0; i < count; ++i) {
                 final DisplayContent displayContent = getDisplayContent(pendingLayouts.keyAt(i));
-                displayContent.pendingLayoutChanges = pendingLayouts.valueAt(i);
+                displayContent.pendingLayoutChanges |= pendingLayouts.valueAt(i);
             }
 
             mWindowDetachedWallpaper = animToLayout.mWindowDetachedWallpaper;
@@ -10080,7 +10429,7 @@
                 }
                 pw.println();
             }
-            pw.print("mTransactionSequence="); pw.println(mTransactionSequence);
+            pw.print("  mTransactionSequence="); pw.println(mTransactionSequence);
             pw.print("  mDisplayFrozen="); pw.print(mDisplayFrozen);
                     pw.print(" mWindowsFreezingScreen="); pw.print(mWindowsFreezingScreen);
                     pw.print(" mAppsFreezingScreen="); pw.print(mAppsFreezingScreen);
@@ -10148,7 +10497,7 @@
 
     boolean dumpWindows(PrintWriter pw, String name, String[] args,
             int opti, boolean dumpAll) {
-        ArrayList<WindowState> windows = new ArrayList<WindowState>();
+        WindowList windows = new WindowList();
         if ("visible".equals(name)) {
             synchronized(mWindowMap) {
                 final AllWindowsIterator iterator = new AllWindowsIterator(REVERSE_ITERATOR);
@@ -10356,6 +10705,14 @@
         }
     }
 
+    public void createDisplayContent(final Display display) {
+        if (display == null) {
+            throw new IllegalArgumentException("getDisplayContent: display must not be null");
+        }
+        final DisplayContent displayContent = new DisplayContent(display);
+        mDisplayContents.put(display.getDisplayId(), displayContent);
+    }
+
     public DisplayContent getDisplayContent(final int displayId) {
         DisplayContent displayContent = mDisplayContents.get(displayId);
         if (displayContent == null) {
@@ -10463,4 +10820,40 @@
     public WindowList getWindowList(final Display display) {
         return getDisplayContent(display.getDisplayId()).getWindowList();
     }
+
+    @Override
+    public void onDisplayAdded(int displayId) {
+        mH.sendMessage(mH.obtainMessage(H.DO_DISPLAY_ADDED, displayId, 0));
+    }
+
+    private void handleDisplayAddedLocked(int displayId) {
+        createDisplayContent(mDisplayManager.getDisplay(displayId));
+    }
+
+    @Override
+    public void onDisplayRemoved(int displayId) {
+        mH.sendMessage(mH.obtainMessage(H.DO_DISPLAY_REMOVED, displayId, 0));
+    }
+
+    private void handleDisplayRemovedLocked(int displayId) {
+        final DisplayContent displayContent = getDisplayContent(displayId);
+        mDisplayContents.delete(displayId);
+        WindowList windows = displayContent.getWindowList();
+        for (int i = windows.size() - 1; i >= 0; --i) {
+            final WindowState win = windows.get(i);
+            removeWindowLocked(win.mSession, win);
+        }
+    }
+
+    @Override
+    public void onDisplayChanged(int displayId) {
+        mH.sendMessage(mH.obtainMessage(H.DO_DISPLAY_CHANGED, displayId, 0));
+    }
+
+    private void handleDisplayChangedLocked(int displayId) {
+        final DisplayContent displayContent = getDisplayContent(displayId);
+        if (displayContent != null) {
+            displayContent.updateDisplayInfo();
+        }
+    }
 }
diff --git a/services/java/com/android/server/wm/WindowState.java b/services/java/com/android/server/wm/WindowState.java
index 6711445..478475d 100644
--- a/services/java/com/android/server/wm/WindowState.java
+++ b/services/java/com/android/server/wm/WindowState.java
@@ -514,6 +514,21 @@
         }
     }
 
+    MagnificationSpec getWindowMagnificationSpecLocked() {
+        MagnificationSpec spec = mDisplayContent.mMagnificationSpec;
+        if (spec != null && !spec.isNop()) {
+            if (mAttachedWindow != null) {
+                if (!mPolicy.canMagnifyWindow(mAttachedWindow.mAttrs)) {
+                    return null;
+                }
+            }
+            if (!mPolicy.canMagnifyWindow(mAttrs)) {
+                return null;
+            }
+        }
+        return spec;
+    }
+
     @Override
     public Rect getFrameLw() {
         return mFrame;
@@ -990,6 +1005,11 @@
         return mClient.asBinder().isBinderAlive();
     }
 
+    @Override
+    public boolean isDefaultDisplay() {
+        return mDisplayContent.isDefaultDisplay;
+    }
+
     boolean isOtherUsersAppWindow() {
         final int type = mAttrs.type;
         if ((UserHandle.getUserId(mOwnerUid) != mService.mCurrentUserId)
diff --git a/services/java/com/android/server/wm/WindowStateAnimator.java b/services/java/com/android/server/wm/WindowStateAnimator.java
index 9bb7299..8912c73 100644
--- a/services/java/com/android/server/wm/WindowStateAnimator.java
+++ b/services/java/com/android/server/wm/WindowStateAnimator.java
@@ -3,7 +3,6 @@
 package com.android.server.wm;
 
 import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_STARTING;
-
 import static com.android.server.wm.WindowManagerService.LayoutFields.SET_ORIENTATION_CHANGE_COMPLETE;
 import static com.android.server.wm.WindowManagerService.LayoutFields.SET_TURN_ON_SCREEN;
 
@@ -887,6 +886,11 @@
                 tmpMatrix.postConcat(
                         mService.mAnimator.mScreenRotationAnimation.getEnterTransformation().getMatrix());
             }
+            MagnificationSpec spec = mWin.getWindowMagnificationSpecLocked();
+            if (spec != null && !spec.isNop()) {
+                tmpMatrix.postScale(spec.mScale, spec.mScale);
+                tmpMatrix.postTranslate(spec.mOffsetX, spec.mOffsetY);
+            }
 
             // "convert" it into SurfaceFlinger's format
             // (a 2x2 matrix + an offset)
@@ -954,16 +958,30 @@
         if (WindowManagerService.localLOGV) Slog.v(
                 TAG, "computeShownFrameLocked: " + this +
                 " not attached, mAlpha=" + mAlpha);
-        if (mAnimator.mUniverseBackground != null &&
-                mWin.mAttrs.type != WindowManager.LayoutParams.TYPE_UNIVERSE_BACKGROUND
-                && mWin.mBaseLayer < mAnimator.mAboveUniverseLayer) {
+
+        final boolean applyUniverseTransformation = (mAnimator.mUniverseBackground != null
+                && mWin.mAttrs.type != WindowManager.LayoutParams.TYPE_UNIVERSE_BACKGROUND
+                && mWin.mBaseLayer < mAnimator.mAboveUniverseLayer);
+        MagnificationSpec spec = mWin.getWindowMagnificationSpecLocked();
+        if (applyUniverseTransformation || spec != null) {
             final Rect frame = mWin.mFrame;
             final float tmpFloats[] = mService.mTmpFloats;
             final Matrix tmpMatrix = mWin.mTmpMatrix;
+
             tmpMatrix.setScale(mWin.mGlobalScale, mWin.mGlobalScale);
             tmpMatrix.postTranslate(frame.left + mWin.mXOffset, frame.top + mWin.mYOffset);
-            tmpMatrix.postConcat(mAnimator.mUniverseBackground.mUniverseTransform.getMatrix());
+
+            if (applyUniverseTransformation) {
+                tmpMatrix.postConcat(mAnimator.mUniverseBackground.mUniverseTransform.getMatrix());
+            }
+
+            if (spec != null && !spec.isNop()) {
+                tmpMatrix.postScale(spec.mScale, spec.mScale);
+                tmpMatrix.postTranslate(spec.mOffsetX, spec.mOffsetY);
+            }
+
             tmpMatrix.getValues(tmpFloats);
+
             mHaveMatrix = true;
             mDsDx = tmpFloats[Matrix.MSCALE_X];
             mDtDx = tmpFloats[Matrix.MSKEW_Y];
@@ -973,8 +991,12 @@
             float y = tmpFloats[Matrix.MTRANS_Y];
             int w = frame.width();
             int h = frame.height();
-            mWin.mShownFrame.set(x, y, x+w, y+h);
-            mShownAlpha = mAlpha * mAnimator.mUniverseBackground.mUniverseTransform.getAlpha();
+            mWin.mShownFrame.set(x, y, x + w, y + h);
+
+            mShownAlpha = mAlpha;
+            if (applyUniverseTransformation) {
+                mShownAlpha *= mAnimator.mUniverseBackground.mUniverseTransform.getAlpha();
+            }
         } else {
             mWin.mShownFrame.set(mWin.mFrame);
             if (mWin.mXOffset != 0 || mWin.mYOffset != 0) {
@@ -1016,12 +1038,16 @@
 
     void updateSurfaceWindowCrop(final boolean recoveringMemory) {
         final WindowState w = mWin;
+        DisplayInfo displayInfo = w.mDisplayContent.getDisplayInfo();
 
         // Need to recompute a new system decor rect each time.
         if ((w.mAttrs.flags & LayoutParams.FLAG_SCALED) != 0) {
             // Currently can't do this cropping for scaled windows.  We'll
             // just keep the crop rect the same as the source surface.
             w.mSystemDecorRect.set(0, 0, w.mRequestedWidth, w.mRequestedHeight);
+        } else if (!w.isDefaultDisplay()) {
+            // On a different display is easy, just use the entire display.
+            w.mSystemDecorRect.set(0, 0, displayInfo.logicalWidth, displayInfo.logicalHeight);
         } else if (w.mLayer >= mService.mSystemDecorLayer) {
             // Above the decor layer is easy, just use the entire window.
             // Unless we have a universe background...  in which case all the
@@ -1431,8 +1457,8 @@
         } else {
             transit = WindowManagerPolicy.TRANSIT_SHOW;
         }
-
         applyAnimationLocked(transit, true);
+        mService.scheduleNotifyWindowTranstionIfNeededLocked(mWin, transit);
     }
 
     // TODO(cmautner): Move back to WindowState?
diff --git a/services/jni/com_android_server_input_InputManagerService.cpp b/services/jni/com_android_server_input_InputManagerService.cpp
index 495d4ab..5e36bf8 100644
--- a/services/jni/com_android_server_input_InputManagerService.cpp
+++ b/services/jni/com_android_server_input_InputManagerService.cpp
@@ -164,9 +164,7 @@
 
     void dump(String8& dump);
 
-    void setDisplaySize(int32_t displayId, int32_t width, int32_t height,
-            int32_t externalWidth, int32_t externalHeight);
-    void setDisplayOrientation(int32_t displayId, int32_t orientation, int32_t externalOrientation);
+    void setDisplayViewport(bool external, const DisplayViewport& viewport);
 
     status_t registerInputChannel(JNIEnv* env, const sp<InputChannel>& inputChannel,
             const sp<InputWindowHandle>& inputWindowHandle, bool monitor);
@@ -223,10 +221,8 @@
     Mutex mLock;
     struct Locked {
         // Display size information.
-        int32_t displayWidth, displayHeight; // -1 when not initialized
-        int32_t displayOrientation;
-        int32_t displayExternalWidth, displayExternalHeight; // -1 when not initialized
-        int32_t displayExternalOrientation;
+        DisplayViewport internalViewport;
+        DisplayViewport externalViewport;
 
         // System UI visibility.
         int32_t systemUiVisibility;
@@ -274,13 +270,6 @@
 
     {
         AutoMutex _l(mLock);
-        mLocked.displayWidth = -1;
-        mLocked.displayHeight = -1;
-        mLocked.displayOrientation = DISPLAY_ORIENTATION_0;
-        mLocked.displayExternalWidth = -1;
-        mLocked.displayExternalHeight = -1;
-        mLocked.displayExternalOrientation = DISPLAY_ORIENTATION_0;
-
         mLocked.systemUiVisibility = ASYSTEM_UI_VISIBILITY_STATUS_BAR_VISIBLE;
         mLocked.pointerSpeed = 0;
         mLocked.pointerGesturesEnabled = true;
@@ -316,57 +305,26 @@
     return false;
 }
 
-void NativeInputManager::setDisplaySize(int32_t displayId, int32_t width, int32_t height,
-        int32_t externalWidth, int32_t externalHeight) {
+void NativeInputManager::setDisplayViewport(bool external, const DisplayViewport& viewport) {
     bool changed = false;
-    if (displayId == 0) {
+    {
         AutoMutex _l(mLock);
 
-        if (mLocked.displayWidth != width || mLocked.displayHeight != height) {
+        DisplayViewport& v = external ? mLocked.externalViewport : mLocked.internalViewport;
+        if (v != viewport) {
             changed = true;
-            mLocked.displayWidth = width;
-            mLocked.displayHeight = height;
+            v = viewport;
 
-            sp<PointerController> controller = mLocked.pointerController.promote();
-            if (controller != NULL) {
-                controller->setDisplaySize(width, height);
+            if (!external) {
+                sp<PointerController> controller = mLocked.pointerController.promote();
+                if (controller != NULL) {
+                    controller->setDisplayViewport(
+                            viewport.logicalRight - viewport.logicalLeft,
+                            viewport.logicalBottom - viewport.logicalTop,
+                            viewport.orientation);
+                }
             }
         }
-
-        if (mLocked.displayExternalWidth != externalWidth
-                || mLocked.displayExternalHeight != externalHeight) {
-            changed = true;
-            mLocked.displayExternalWidth = externalWidth;
-            mLocked.displayExternalHeight = externalHeight;
-        }
-    }
-
-    if (changed) {
-        mInputManager->getReader()->requestRefreshConfiguration(
-                InputReaderConfiguration::CHANGE_DISPLAY_INFO);
-    }
-}
-
-void NativeInputManager::setDisplayOrientation(int32_t displayId, int32_t orientation,
-        int32_t externalOrientation) {
-    bool changed = false;
-    if (displayId == 0) {
-        AutoMutex _l(mLock);
-
-        if (mLocked.displayOrientation != orientation) {
-            changed = true;
-            mLocked.displayOrientation = orientation;
-
-            sp<PointerController> controller = mLocked.pointerController.promote();
-            if (controller != NULL) {
-                controller->setDisplayOrientation(orientation);
-            }
-        }
-
-        if (mLocked.displayExternalOrientation != externalOrientation) {
-            changed = true;
-            mLocked.displayExternalOrientation = externalOrientation;
-        }
     }
 
     if (changed) {
@@ -448,11 +406,8 @@
 
         outConfig->showTouches = mLocked.showTouches;
 
-        outConfig->setDisplayInfo(0, false /*external*/,
-                mLocked.displayWidth, mLocked.displayHeight, mLocked.displayOrientation);
-        outConfig->setDisplayInfo(0, true /*external*/,
-                mLocked.displayExternalWidth, mLocked.displayExternalHeight,
-                mLocked.displayExternalOrientation);
+        outConfig->setDisplayInfo(false /*external*/, mLocked.internalViewport);
+        outConfig->setDisplayInfo(true /*external*/, mLocked.externalViewport);
     } // release lock
 }
 
@@ -466,8 +421,11 @@
         controller = new PointerController(this, mLooper, mLocked.spriteController);
         mLocked.pointerController = controller;
 
-        controller->setDisplaySize(mLocked.displayWidth, mLocked.displayHeight);
-        controller->setDisplayOrientation(mLocked.displayOrientation);
+        DisplayViewport& v = mLocked.internalViewport;
+        controller->setDisplayViewport(
+                v.logicalRight - v.logicalLeft,
+                v.logicalBottom - v.logicalTop,
+                v.orientation);
 
         JNIEnv* env = jniEnv();
         jobject pointerIconObj = env->CallObjectMethod(mServiceObj,
@@ -1032,22 +990,24 @@
     }
 }
 
-static void nativeSetDisplaySize(JNIEnv* env, jclass clazz, jint ptr,
-        jint displayId, jint width, jint height, jint externalWidth, jint externalHeight) {
+static void nativeSetDisplayViewport(JNIEnv* env, jclass clazz, jint ptr, jboolean external,
+        jint displayId, jint orientation,
+        jint logicalLeft, jint logicalTop, jint logicalRight, jint logicalBottom,
+        jint physicalLeft, jint physicalTop, jint physicalRight, jint physicalBottom) {
     NativeInputManager* im = reinterpret_cast<NativeInputManager*>(ptr);
 
-    // XXX we could get this from the SurfaceFlinger directly instead of requiring it
-    // to be passed in like this, not sure which is better but leaving it like this
-    // keeps the window manager in direct control of when display transitions propagate down
-    // to the input dispatcher
-    im->setDisplaySize(displayId, width, height, externalWidth, externalHeight);
-}
-
-static void nativeSetDisplayOrientation(JNIEnv* env, jclass clazz,
-        jint ptr, jint displayId, jint orientation, jint externalOrientation) {
-    NativeInputManager* im = reinterpret_cast<NativeInputManager*>(ptr);
-
-    im->setDisplayOrientation(displayId, orientation, externalOrientation);
+    DisplayViewport v;
+    v.displayId = displayId;
+    v.orientation = orientation;
+    v.logicalLeft = logicalLeft;
+    v.logicalTop = logicalTop;
+    v.logicalRight = logicalRight;
+    v.logicalBottom = logicalBottom;
+    v.physicalLeft = physicalLeft;
+    v.physicalTop = physicalTop;
+    v.physicalRight = physicalRight;
+    v.physicalBottom = physicalBottom;
+    im->setDisplayViewport(external, v);
 }
 
 static jint nativeGetScanCodeState(JNIEnv* env, jclass clazz,
@@ -1328,10 +1288,8 @@
             (void*) nativeInit },
     { "nativeStart", "(I)V",
             (void*) nativeStart },
-    { "nativeSetDisplaySize", "(IIIIII)V",
-            (void*) nativeSetDisplaySize },
-    { "nativeSetDisplayOrientation", "(IIII)V",
-            (void*) nativeSetDisplayOrientation },
+    { "nativeSetDisplayViewport", "(IZIIIIIIIIII)V",
+            (void*) nativeSetDisplayViewport },
     { "nativeGetScanCodeState", "(IIII)I",
             (void*) nativeGetScanCodeState },
     { "nativeGetKeyCodeState", "(IIII)I",
diff --git a/test-runner/src/android/test/mock/MockPackageManager.java b/test-runner/src/android/test/mock/MockPackageManager.java
index 19eb8d2..cd7ee76 100644
--- a/test-runner/src/android/test/mock/MockPackageManager.java
+++ b/test-runner/src/android/test/mock/MockPackageManager.java
@@ -140,6 +140,12 @@
         throw new UnsupportedOperationException();
     }
 
+    /** @hide */
+    @Override
+    public List<PackageInfo> getInstalledPackages(int flags, int userId) {
+        throw new UnsupportedOperationException();
+    }
+
     @Override
     public int checkPermission(String permName, String pkgName) {
         throw new UnsupportedOperationException();
@@ -215,6 +221,13 @@
         throw new UnsupportedOperationException();
     }
 
+    /** @hide */
+    @Override
+    public List<ResolveInfo> queryIntentActivitiesForUser(Intent intent,
+                                                   int flags, int userId) {
+        throw new UnsupportedOperationException();
+    }
+
     @Override
     public List<ResolveInfo> queryIntentActivityOptions(ComponentName caller,
             Intent[] specifics, Intent intent, int flags) {
diff --git a/tests/HwAccelerationTest/AndroidManifest.xml b/tests/HwAccelerationTest/AndroidManifest.xml
index aebc594..4e229ec 100644
--- a/tests/HwAccelerationTest/AndroidManifest.xml
+++ b/tests/HwAccelerationTest/AndroidManifest.xml
@@ -42,6 +42,15 @@
         </activity>
 
         <activity
+                android:name="TJunctionActivity"
+                android:label="_T-Junction">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="android.intent.category.LAUNCHER" />
+            </intent-filter>
+        </activity>
+
+        <activity
                 android:name="TextPathActivity"
                 android:label="_TextPath">
             <intent-filter>
diff --git a/tests/HwAccelerationTest/src/com/android/test/hwui/ColoredRectsActivity.java b/tests/HwAccelerationTest/src/com/android/test/hwui/ColoredRectsActivity.java
index e8cdbc3..7ea2a62d 100644
--- a/tests/HwAccelerationTest/src/com/android/test/hwui/ColoredRectsActivity.java
+++ b/tests/HwAccelerationTest/src/com/android/test/hwui/ColoredRectsActivity.java
@@ -113,6 +113,12 @@
                 canvas.rotate(45);
                 canvas.drawRect(0, 0, 20, 10, p);
                 canvas.restore();
+                canvas.save();
+                canvas.translate(mOffset + 280, yOffset);
+                canvas.scale(0.5f, 8);
+                canvas.rotate(0.5f);
+                canvas.drawRect(0, 0, 80, 5, p);
+                canvas.restore();
                 canvas.restore();
 
                 yOffset += 100;
diff --git a/tests/HwAccelerationTest/src/com/android/test/hwui/LinesActivity.java b/tests/HwAccelerationTest/src/com/android/test/hwui/LinesActivity.java
index f0abb50..eed0ec8 100644
--- a/tests/HwAccelerationTest/src/com/android/test/hwui/LinesActivity.java
+++ b/tests/HwAccelerationTest/src/com/android/test/hwui/LinesActivity.java
@@ -153,6 +153,14 @@
             canvas.drawLine(10.0f, 45.0f, 20.0f, 55.0f, mSmallPaint);
             canvas.drawLine(10.0f, 60.0f, 50.0f, 60.0f, mHairLinePaint);
             canvas.restore();
+
+            canvas.save();
+            canvas.scale(10.0f, 50.0f);
+            mSmallPaint.setStrokeWidth(0.0f);
+            canvas.drawLine(20.0f, 9.0f, 30.0f, 11.0f, mSmallPaint);
+            mSmallPaint.setStrokeWidth(1.0f);
+            canvas.drawLine(30.0f, 9.0f, 40.0f, 11.0f, mSmallPaint);
+            canvas.restore();
         }
     }
 }
diff --git a/tests/HwAccelerationTest/src/com/android/test/hwui/TJunctionActivity.java b/tests/HwAccelerationTest/src/com/android/test/hwui/TJunctionActivity.java
new file mode 100644
index 0000000..d2bcae9
--- /dev/null
+++ b/tests/HwAccelerationTest/src/com/android/test/hwui/TJunctionActivity.java
@@ -0,0 +1,81 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.test.hwui;
+
+import android.app.Activity;
+import android.content.Context;
+import android.graphics.Canvas;
+import android.graphics.Paint;
+import android.os.Bundle;
+import android.view.View;
+
+@SuppressWarnings("UnusedDeclaration")
+public class TJunctionActivity extends Activity {
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        setContentView(new TJunctionView(this));
+    }
+
+    private class TJunctionView extends View {
+        private final Paint mPaint;
+
+        public TJunctionView(Context context) {
+            super(context);
+
+            setLayerType(LAYER_TYPE_HARDWARE, null);
+
+            mPaint = new Paint();
+        }
+
+        @Override
+        protected void onDraw(Canvas canvas) {
+            super.onDraw(canvas);
+
+            mPaint.setColor(0xffff0000);
+
+            canvas.translate(10.0f, 10.0f);
+            canvas.drawRect(0.0f, 0.0f, 100.0f, 50.0f, mPaint);
+
+            mPaint.setColor(0xff00ff00);
+
+            canvas.translate(50.0f, 50.0f);
+            canvas.drawRect(0.0f, 0.0f, 100.0f, 50.0f, mPaint);
+
+            mPaint.setColor(0xff0000ff);
+
+            canvas.translate(-25.0f, 50.0f);
+            canvas.drawRect(0.0f, 0.0f, 100.0f, 50.0f, mPaint);
+
+            mPaint.setColor(0xffffffff);
+
+            canvas.translate(150.0f, 75.0f);
+            canvas.drawRect(0.0f, 0.0f, 100.0f, 50.0f, mPaint);
+
+            canvas.translate(-50.0f, 75.0f);
+            canvas.drawRect(0.0f, 0.0f, 100.0f, 50.0f, mPaint);
+
+            canvas.translate(-75.0f, 50.0f);
+            canvas.drawRect(0.0f, 0.0f, 100.0f, 50.0f, mPaint);
+
+            canvas.translate(150.0f, 0.0f);
+            canvas.drawRect(0.0f, 0.0f, 100.0f, 50.0f, mPaint);
+
+            invalidate();
+        }
+    }
+}
diff --git a/tests/RenderScriptTests/ImageProcessing/res/drawable-nodpi/city.png b/tests/RenderScriptTests/ImageProcessing/res/drawable-nodpi/city.png
deleted file mode 100644
index 856eeff..0000000
--- a/tests/RenderScriptTests/ImageProcessing/res/drawable-nodpi/city.png
+++ /dev/null
Binary files differ
diff --git a/tests/RenderScriptTests/ImageProcessing/res/drawable-nodpi/img1600x1067.jpg b/tests/RenderScriptTests/ImageProcessing/res/drawable-nodpi/img1600x1067.jpg
new file mode 100644
index 0000000..05d3ee2
--- /dev/null
+++ b/tests/RenderScriptTests/ImageProcessing/res/drawable-nodpi/img1600x1067.jpg
Binary files differ
diff --git a/tests/RenderScriptTests/ImageProcessing/res/drawable-nodpi/img640x427.jpg b/tests/RenderScriptTests/ImageProcessing/res/drawable-nodpi/img640x427.jpg
new file mode 100644
index 0000000..5bce392
--- /dev/null
+++ b/tests/RenderScriptTests/ImageProcessing/res/drawable-nodpi/img640x427.jpg
Binary files differ
diff --git a/tests/RenderScriptTests/ImageProcessing/src/com/android/rs/image/ColorMatrix.java b/tests/RenderScriptTests/ImageProcessing/src/com/android/rs/image/ColorMatrix.java
index 87a2de1..2ac40a1 100644
--- a/tests/RenderScriptTests/ImageProcessing/src/com/android/rs/image/ColorMatrix.java
+++ b/tests/RenderScriptTests/ImageProcessing/src/com/android/rs/image/ColorMatrix.java
@@ -33,9 +33,11 @@
     private ScriptC_colormatrix mScript;
     private ScriptIntrinsicColorMatrix mIntrinsic;
     private boolean mUseIntrinsic;
+    private boolean mUseGrey;
 
-    public ColorMatrix(boolean useIntrinsic) {
+    public ColorMatrix(boolean useIntrinsic, boolean useGrey) {
         mUseIntrinsic = useIntrinsic;
+        mUseGrey = useGrey;
     }
 
     public void createTest(android.content.res.Resources res) {
@@ -46,7 +48,11 @@
 
         if (mUseIntrinsic) {
             mIntrinsic = ScriptIntrinsicColorMatrix.create(mRS, Element.U8_4(mRS));
-            mIntrinsic.setColorMatrix(m);
+            if (mUseGrey) {
+                mIntrinsic.setGreyscale();
+            } else {
+                mIntrinsic.setColorMatrix(m);
+            }
         } else {
             mScript = new ScriptC_colormatrix(mRS, res, R.raw.colormatrix);
             mScript.invoke_setMatrix(m);
diff --git a/tests/RenderScriptTests/ImageProcessing/src/com/android/rs/image/ImageProcessingActivity.java b/tests/RenderScriptTests/ImageProcessing/src/com/android/rs/image/ImageProcessingActivity.java
index 001dea8..37577eb 100644
--- a/tests/RenderScriptTests/ImageProcessing/src/com/android/rs/image/ImageProcessingActivity.java
+++ b/tests/RenderScriptTests/ImageProcessing/src/com/android/rs/image/ImageProcessingActivity.java
@@ -180,12 +180,15 @@
             mTest = new Convolve3x3(true);
             break;
         case 19:
-            mTest = new ColorMatrix(false);
+            mTest = new ColorMatrix(false, false);
             break;
         case 20:
-            mTest = new ColorMatrix(true);
+            mTest = new ColorMatrix(true, false);
             break;
         case 21:
+            mTest = new ColorMatrix(true, true);
+            break;
+        case 22:
             mTest = new Copy();
             break;
         }
@@ -200,7 +203,7 @@
     }
 
     void setupTests() {
-        mTestNames = new String[22];
+        mTestNames = new String[23];
         mTestNames[0] = "Levels Vec3 Relaxed";
         mTestNames[1] = "Levels Vec4 Relaxed";
         mTestNames[2] = "Levels Vec3 Full";
@@ -222,7 +225,8 @@
         mTestNames[18] = "Intrinsics Convolve 3x3";
         mTestNames[19] = "ColorMatrix";
         mTestNames[20] = "Intrinsics ColorMatrix";
-        mTestNames[21] = "Copy";
+        mTestNames[21] = "Intrinsics ColorMatrix Grey";
+        mTestNames[22] = "Copy";
         mTestSpinner.setAdapter(new ArrayAdapter<String>(
             this, R.layout.spinner_layout, mTestNames));
     }
@@ -243,8 +247,8 @@
         super.onCreate(savedInstanceState);
         setContentView(R.layout.main);
 
-        mBitmapIn = loadBitmap(R.drawable.city);
-        mBitmapOut = loadBitmap(R.drawable.city);
+        mBitmapIn = loadBitmap(R.drawable.img1600x1067);
+        mBitmapOut = loadBitmap(R.drawable.img1600x1067);
 
         mSurfaceView = (SurfaceView) findViewById(R.id.surface);
 
diff --git a/tools/aapt/AaptAssets.cpp b/tools/aapt/AaptAssets.cpp
index 438a670..5b71adc 100644
--- a/tools/aapt/AaptAssets.cpp
+++ b/tools/aapt/AaptAssets.cpp
@@ -995,12 +995,12 @@
                 (out->screenLayout&~ResTable_config::MASK_LAYOUTDIR)
                 | ResTable_config::LAYOUTDIR_ANY;
         return true;
-    } else if (strcmp(name, "ltr") == 0) {
+    } else if (strcmp(name, "ldltr") == 0) {
         if (out) out->screenLayout =
                 (out->screenLayout&~ResTable_config::MASK_LAYOUTDIR)
                 | ResTable_config::LAYOUTDIR_LTR;
         return true;
-    } else if (strcmp(name, "rtl") == 0) {
+    } else if (strcmp(name, "ldrtl") == 0) {
         if (out) out->screenLayout =
                 (out->screenLayout&~ResTable_config::MASK_LAYOUTDIR)
                 | ResTable_config::LAYOUTDIR_RTL;
diff --git a/tools/aapt/Android.mk b/tools/aapt/Android.mk
index 482f43e..d9b0681 100644
--- a/tools/aapt/Android.mk
+++ b/tools/aapt/Android.mk
@@ -34,7 +34,6 @@
 endif
 
 
-LOCAL_C_INCLUDES += external/expat/lib
 LOCAL_C_INCLUDES += external/libpng
 LOCAL_C_INCLUDES += external/zlib
 LOCAL_C_INCLUDES += build/libs/host/include
diff --git a/tools/aapt/StringPool.h b/tools/aapt/StringPool.h
index d501008..16050b2 100644
--- a/tools/aapt/StringPool.h
+++ b/tools/aapt/StringPool.h
@@ -21,7 +21,7 @@
 #include <ctype.h>
 #include <errno.h>
 
-#include <expat.h>
+#include <libexpat/expat.h>
 
 using namespace android;
 
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeWindowManager.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeWindowManager.java
index 5516339..5d64e8a 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeWindowManager.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeWindowManager.java
@@ -22,22 +22,21 @@
 import android.content.res.CompatibilityInfo;
 import android.content.res.Configuration;
 import android.graphics.Bitmap;
-import android.graphics.Point;
-import android.graphics.Rect;
 import android.os.IBinder;
 import android.os.IRemoteCallback;
 import android.os.RemoteException;
 import android.util.DisplayMetrics;
 import android.view.Display;
-import android.view.DisplayInfo;
 import android.view.Display_Delegate;
 import android.view.Gravity;
 import android.view.IApplicationToken;
+import android.view.IDisplayContentChangeListener;
 import android.view.IInputFilter;
 import android.view.IOnKeyguardExitResult;
 import android.view.IRotationWatcher;
 import android.view.IWindowManager;
 import android.view.IWindowSession;
+import android.view.WindowInfo;
 
 import java.util.List;
 
@@ -293,7 +292,6 @@
     @Override
     public void setAppOrientation(IApplicationToken arg0, int arg1) throws RemoteException {
         // TODO Auto-generated method stub
-
     }
 
     @Override
@@ -301,7 +299,6 @@
             CharSequence arg4, int arg5, int arg6, int arg7, IBinder arg8, boolean arg9)
             throws RemoteException {
         // TODO Auto-generated method stub
-
     }
 
     @Override
@@ -313,19 +310,16 @@
     @Override
     public void setAppWillBeHidden(IBinder arg0) throws RemoteException {
         // TODO Auto-generated method stub
-
     }
 
     @Override
     public void setEventDispatching(boolean arg0) throws RemoteException {
         // TODO Auto-generated method stub
-
     }
 
     @Override
     public void setFocusedApp(IBinder arg0, boolean arg1) throws RemoteException {
         // TODO Auto-generated method stub
-
     }
 
     @Override
@@ -341,13 +335,11 @@
     @Override
     public void setInTouchMode(boolean arg0) throws RemoteException {
         // TODO Auto-generated method stub
-
     }
 
     @Override
     public void setNewConfiguration(Configuration arg0) throws RemoteException {
         // TODO Auto-generated method stub
-
     }
 
     @Override
@@ -358,19 +350,16 @@
     @Override
     public void setStrictModeVisualIndicatorPreference(String arg0) throws RemoteException {
         // TODO Auto-generated method stub
-
     }
 
     @Override
     public void showStrictModeViolation(boolean arg0) throws RemoteException {
         // TODO Auto-generated method stub
-
     }
 
     @Override
     public void startAppFreezingScreen(IBinder arg0, int arg1) throws RemoteException {
         // TODO Auto-generated method stub
-
     }
 
     @Override
@@ -382,13 +371,11 @@
     @Override
     public void statusBarVisibilityChanged(int arg0) throws RemoteException {
         // TODO Auto-generated method stub
-
     }
 
     @Override
     public void stopAppFreezingScreen(IBinder arg0, boolean arg1) throws RemoteException {
         // TODO Auto-generated method stub
-
     }
 
     @Override
@@ -400,7 +387,6 @@
     @Override
     public void thawRotation() throws RemoteException {
         // TODO Auto-generated method stub
-
     }
 
     @Override
@@ -453,12 +439,6 @@
     }
 
     @Override
-    public boolean getWindowFrame(IBinder token, Rect outBounds) {
-        // TODO Auto-generated method stub
-        return false;
-    }
-
-    @Override
     public float getWindowCompatibilityScale(IBinder windowToken) throws RemoteException {
         // TODO Auto-generated method stub
         return 0;
@@ -468,4 +448,34 @@
     public void setInputFilter(IInputFilter filter) throws RemoteException {
         // TODO Auto-generated method stub
     }
+
+    @Override
+    public void magnifyDisplay(int dipslayId, float scale, float offsetX, float offsetY)
+            throws RemoteException {
+        // TODO Auto-generated method stub
+    }
+
+    @Override
+    public void addDisplayContentChangeListener(int displayId,
+            IDisplayContentChangeListener listener) throws RemoteException {
+        // TODO Auto-generated method stub
+    }
+
+    @Override
+    public void removeDisplayContentChangeListener(int displayId,
+            IDisplayContentChangeListener listener) throws RemoteException {
+        // TODO Auto-generated method stub
+    }
+
+    @Override
+    public WindowInfo getWindowInfo(IBinder token) throws RemoteException {
+        // TODO Auto-generated method stub
+        return null;
+    }
+
+    @Override
+    public void getVisibleWindowsForDisplay(int displayId, List<WindowInfo> outInfos)
+            throws RemoteException {
+        // TODO Auto-generated method stub
+    }
 }
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeWindowSession.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeWindowSession.java
index 691eca7..67b0a9c 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeWindowSession.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeWindowSession.java
@@ -194,4 +194,9 @@
         // pass for now.
         return null;
     }
+
+    @Override
+    public void onRectangleOnScreenRequested(IBinder window, Rect rectangle, boolean immediate) {
+        // pass for now.
+    }
 }
diff --git a/voip/java/android/net/sip/SimpleSessionDescription.java b/voip/java/android/net/sip/SimpleSessionDescription.java
index 29166dc..9fcd21d 100644
--- a/voip/java/android/net/sip/SimpleSessionDescription.java
+++ b/voip/java/android/net/sip/SimpleSessionDescription.java
@@ -18,6 +18,7 @@
 
 import java.util.ArrayList;
 import java.util.Arrays;
+import java.util.Locale;
 
 /**
  * An object used to manipulate messages of Session Description Protocol (SDP).
@@ -66,7 +67,7 @@
     public SimpleSessionDescription(long sessionId, String address) {
         address = (address.indexOf(':') < 0 ? "IN IP4 " : "IN IP6 ") + address;
         mFields.parse("v=0");
-        mFields.parse(String.format("o=- %d %d %s", sessionId,
+        mFields.parse(String.format(Locale.US, "o=- %d %d %s", sessionId,
                 System.currentTimeMillis(), address));
         mFields.parse("s=-");
         mFields.parse("t=0 0");
diff --git a/wifi/java/android/net/wifi/WifiNative.java b/wifi/java/android/net/wifi/WifiNative.java
index b9feb34..805faa6 100644
--- a/wifi/java/android/net/wifi/WifiNative.java
+++ b/wifi/java/android/net/wifi/WifiNative.java
@@ -500,6 +500,14 @@
         }
     }
 
+    public boolean setWfdEnable(boolean enable) {
+        return doBooleanCommand("SET wifi_display " + (enable ? "1" : "0"));
+    }
+
+    public boolean setWfdDeviceInfo(String hex) {
+        return doBooleanCommand("WFD_SUBELEM_SET 0 " + hex);
+    }
+
     /**
      * "sta" prioritizes STA connection over P2P and "p2p" prioritizes
      * P2P connection over STA
diff --git a/wifi/java/android/net/wifi/p2p/WifiP2pDevice.java b/wifi/java/android/net/wifi/p2p/WifiP2pDevice.java
index c86ec8b..0228d1b 100644
--- a/wifi/java/android/net/wifi/p2p/WifiP2pDevice.java
+++ b/wifi/java/android/net/wifi/p2p/WifiP2pDevice.java
@@ -107,12 +107,14 @@
     /** Device connection status */
     public int status = UNAVAILABLE;
 
-    /** Detailed device string pattern
+    /** @hide */
+    public WifiP2pWfdInfo wfdInfo;
+
+    /** Detailed device string pattern with WFD info
      * Example:
-     *  P2P-DEVICE-FOUND fa:7b:7a:42:02:13 p2p_dev_addr=fa:7b:7a:42:02:13
-     *  pri_dev_type=1-0050F204-1 name='p2p-TEST1' config_methods=0x188 dev_capab=0x27
-     *  group_capab=0x0
-     *
+     *  P2P-DEVICE-FOUND 00:18:6b:de:a3:6e p2p_dev_addr=00:18:6b:de:a3:6e
+     *  pri_dev_type=1-0050F204-1 name='DWD-300-DEA36E' config_methods=0x188
+     *  dev_capab=0x21 group_capab=0x9
      */
     private static final Pattern detailedDevicePattern = Pattern.compile(
         "((?:[0-9a-f]{2}:){5}[0-9a-f]{2}) " +
@@ -122,7 +124,8 @@
         "name='(.*)' " +
         "config_methods=(0x[0-9a-fA-F]+) " +
         "dev_capab=(0x[0-9a-fA-F]+) " +
-        "group_capab=(0x[0-9a-fA-F]+)"
+        "group_capab=(0x[0-9a-fA-F]+)" +
+        "( wfd_dev_info=000006([0-9a-fA-F]+))?"
     );
 
     /** 2 token device address pattern
@@ -151,7 +154,7 @@
      * @param string formats supported include
      *  P2P-DEVICE-FOUND fa:7b:7a:42:02:13 p2p_dev_addr=fa:7b:7a:42:02:13
      *  pri_dev_type=1-0050F204-1 name='p2p-TEST1' config_methods=0x188 dev_capab=0x27
-     *  group_capab=0x0
+     *  group_capab=0x0 wfd_dev_info=000006015d022a0032
      *
      *  P2P-DEVICE-LOST p2p_dev_addr=fa:7b:7a:42:02:13
      *
@@ -203,6 +206,12 @@
                 wpsConfigMethodsSupported = parseHex(match.group(6));
                 deviceCapability = parseHex(match.group(7));
                 groupCapability = parseHex(match.group(8));
+                if (match.group(9) != null) {
+                    String str = match.group(10);
+                    wfdInfo = new WifiP2pWfdInfo(parseHex(str.substring(0,4)),
+                            parseHex(str.substring(4,8)),
+                            parseHex(str.substring(8,12)));
+                }
                 break;
         }
 
@@ -273,6 +282,7 @@
         sbuf.append("\n grpcapab: ").append(groupCapability);
         sbuf.append("\n devcapab: ").append(deviceCapability);
         sbuf.append("\n status: ").append(status);
+        sbuf.append("\n wfdInfo: ").append(wfdInfo);
         return sbuf.toString();
     }
 
@@ -292,6 +302,7 @@
             deviceCapability = source.deviceCapability;
             groupCapability = source.groupCapability;
             status = source.status;
+            wfdInfo = source.wfdInfo;
         }
     }
 
@@ -305,6 +316,12 @@
         dest.writeInt(deviceCapability);
         dest.writeInt(groupCapability);
         dest.writeInt(status);
+        if (wfdInfo != null) {
+            dest.writeInt(1);
+            wfdInfo.writeToParcel(dest, flags);
+        } else {
+            dest.writeInt(0);
+        }
     }
 
     /** Implement the Parcelable interface */
@@ -320,6 +337,9 @@
                 device.deviceCapability = in.readInt();
                 device.groupCapability = in.readInt();
                 device.status = in.readInt();
+                if (in.readInt() == 1) {
+                    device.wfdInfo = WifiP2pWfdInfo.CREATOR.createFromParcel(in);
+                }
                 return device;
             }
 
diff --git a/wifi/java/android/net/wifi/p2p/WifiP2pDeviceList.java b/wifi/java/android/net/wifi/p2p/WifiP2pDeviceList.java
index 48cdbc2..157dc50 100644
--- a/wifi/java/android/net/wifi/p2p/WifiP2pDeviceList.java
+++ b/wifi/java/android/net/wifi/p2p/WifiP2pDeviceList.java
@@ -35,10 +35,9 @@
  */
 public class WifiP2pDeviceList implements Parcelable {
 
-    private HashMap<String, WifiP2pDevice> mDevices;
+    private final HashMap<String, WifiP2pDevice> mDevices = new HashMap<String, WifiP2pDevice>();
 
     public WifiP2pDeviceList() {
-        mDevices = new HashMap<String, WifiP2pDevice>();
     }
 
     /** copy constructor */
@@ -52,7 +51,6 @@
 
     /** @hide */
     public WifiP2pDeviceList(ArrayList<WifiP2pDevice> devices) {
-        mDevices = new HashMap<String, WifiP2pDevice>();
         for (WifiP2pDevice device : devices) {
             if (device.deviceAddress != null) {
                 mDevices.put(device.deviceAddress, device);
diff --git a/wifi/java/android/net/wifi/p2p/WifiP2pGroupList.java b/wifi/java/android/net/wifi/p2p/WifiP2pGroupList.java
index 3459a5a..98f0972 100644
--- a/wifi/java/android/net/wifi/p2p/WifiP2pGroupList.java
+++ b/wifi/java/android/net/wifi/p2p/WifiP2pGroupList.java
@@ -16,6 +16,7 @@
 package android.net.wifi.p2p;
 
 import java.util.Collection;
+import java.util.Map;
 
 import android.os.Parcel;
 import android.os.Parcelable;
@@ -32,8 +33,9 @@
 
     private static final int CREDENTIAL_MAX_NUM             =   32;
 
-    private LruCache<Integer, WifiP2pGroup> mGroups;
-    private GroupDeleteListener mListener;
+    private final LruCache<Integer, WifiP2pGroup> mGroups;
+    private final GroupDeleteListener mListener;
+
     private boolean isClearCalled = false;
 
     public interface GroupDeleteListener {
@@ -41,10 +43,10 @@
     }
 
     WifiP2pGroupList() {
-        this(null);
+        this(null, null);
     }
 
-    WifiP2pGroupList(GroupDeleteListener listener) {
+    WifiP2pGroupList(WifiP2pGroupList source, GroupDeleteListener listener) {
         mListener = listener;
         mGroups = new LruCache<Integer, WifiP2pGroup>(CREDENTIAL_MAX_NUM) {
             @Override
@@ -55,6 +57,12 @@
                 }
             }
         };
+
+        if (source != null) {
+            for (Map.Entry<Integer, WifiP2pGroup> item : source.mGroups.snapshot().entrySet()) {
+                mGroups.put(item.getKey(), item.getValue());
+            }
+        }
     }
 
     /**
diff --git a/wifi/java/android/net/wifi/p2p/WifiP2pInfo.java b/wifi/java/android/net/wifi/p2p/WifiP2pInfo.java
index dce315a..8972b7e 100644
--- a/wifi/java/android/net/wifi/p2p/WifiP2pInfo.java
+++ b/wifi/java/android/net/wifi/p2p/WifiP2pInfo.java
@@ -44,8 +44,8 @@
     public String toString() {
         StringBuffer sbuf = new StringBuffer();
         sbuf.append("groupFormed: ").append(groupFormed)
-            .append("isGroupOwner: ").append(isGroupOwner)
-            .append("groupOwnerAddress: ").append(groupOwnerAddress);
+            .append(" isGroupOwner: ").append(isGroupOwner)
+            .append(" groupOwnerAddress: ").append(groupOwnerAddress);
         return sbuf.toString();
     }
 
diff --git a/wifi/java/android/net/wifi/p2p/WifiP2pManager.java b/wifi/java/android/net/wifi/p2p/WifiP2pManager.java
index 96d3a7f..6edc232 100644
--- a/wifi/java/android/net/wifi/p2p/WifiP2pManager.java
+++ b/wifi/java/android/net/wifi/p2p/WifiP2pManager.java
@@ -455,6 +455,13 @@
     /** @hide */
     public static final int RESPONSE_PERSISTENT_GROUP_INFO          = BASE + 63;
 
+    /** @hide */
+    public static final int SET_WFD_INFO                            = BASE + 64;
+    /** @hide */
+    public static final int SET_WFD_INFO_FAILED                     = BASE + 65;
+    /** @hide */
+    public static final int SET_WFD_INFO_SUCCEEDED                  = BASE + 66;
+
     /**
      * Create a new WifiP2pManager instance. Applications use
      * {@link android.content.Context#getSystemService Context.getSystemService()} to retrieve
@@ -742,6 +749,7 @@
                     case WifiP2pManager.CLEAR_SERVICE_REQUESTS_FAILED:
                     case WifiP2pManager.SET_DEVICE_NAME_FAILED:
                     case WifiP2pManager.DELETE_PERSISTENT_GROUP_FAILED:
+                    case WifiP2pManager.SET_WFD_INFO_FAILED:
                         if (listener != null) {
                             ((ActionListener) listener).onFailure(message.arg1);
                         }
@@ -762,6 +770,7 @@
                     case WifiP2pManager.CLEAR_SERVICE_REQUESTS_SUCCEEDED:
                     case WifiP2pManager.SET_DEVICE_NAME_SUCCEEDED:
                     case WifiP2pManager.DELETE_PERSISTENT_GROUP_SUCCEEDED:
+                    case WifiP2pManager.SET_WFD_INFO_SUCCEEDED:
                         if (listener != null) {
                             ((ActionListener) listener).onSuccess();
                         }
@@ -1297,6 +1306,13 @@
         c.mAsyncChannel.sendMessage(SET_DEVICE_NAME, 0, c.putListener(listener), d);
     }
 
+    /** @hide */
+    public void setWFDInfo(
+            Channel c, WifiP2pWfdInfo wfdInfo,
+            ActionListener listener) {
+        checkChannel(c);
+        c.mAsyncChannel.sendMessage(SET_WFD_INFO, 0, c.putListener(listener), wfdInfo);
+    }
 
     /**
      * Set dialog listener to over-ride system dialogs on p2p events. This function
diff --git a/wifi/java/android/net/wifi/p2p/WifiP2pService.java b/wifi/java/android/net/wifi/p2p/WifiP2pService.java
index c34d70e..3575d97 100644
--- a/wifi/java/android/net/wifi/p2p/WifiP2pService.java
+++ b/wifi/java/android/net/wifi/p2p/WifiP2pService.java
@@ -359,8 +359,8 @@
         private WifiNative mWifiNative = new WifiNative(mInterface);
         private WifiMonitor mWifiMonitor = new WifiMonitor(this, mWifiNative);
 
-        private WifiP2pDeviceList mPeers = new WifiP2pDeviceList();
-        private WifiP2pGroupList mGroups = new WifiP2pGroupList(
+        private final WifiP2pDeviceList mPeers = new WifiP2pDeviceList();
+        private final WifiP2pGroupList mGroups = new WifiP2pGroupList(null,
                 new GroupDeleteListener() {
             @Override
             public void onDeleteGroup(int netId) {
@@ -370,7 +370,7 @@
                 sendP2pPersistentGroupsChangedBroadcast();
             }
         });
-        private WifiP2pInfo mWifiP2pInfo = new WifiP2pInfo();
+        private final WifiP2pInfo mWifiP2pInfo = new WifiP2pInfo();
         private WifiP2pGroup mGroup;
 
         // Saved WifiP2pConfig for a peer connection
@@ -496,18 +496,25 @@
                     replyToMessage(message, WifiP2pManager.DELETE_PERSISTENT_GROUP,
                             WifiP2pManager.BUSY);
                     break;
+                case WifiP2pManager.SET_WFD_INFO:
+                    replyToMessage(message, WifiP2pManager.SET_WFD_INFO_FAILED,
+                            WifiP2pManager.BUSY);
+                    break;
                 case WifiP2pManager.REQUEST_PEERS:
-                    replyToMessage(message, WifiP2pManager.RESPONSE_PEERS, mPeers);
+                    replyToMessage(message, WifiP2pManager.RESPONSE_PEERS,
+                            new WifiP2pDeviceList(mPeers));
                     break;
                 case WifiP2pManager.REQUEST_CONNECTION_INFO:
-                    replyToMessage(message, WifiP2pManager.RESPONSE_CONNECTION_INFO, mWifiP2pInfo);
+                    replyToMessage(message, WifiP2pManager.RESPONSE_CONNECTION_INFO,
+                            new WifiP2pInfo(mWifiP2pInfo));
                     break;
                 case WifiP2pManager.REQUEST_GROUP_INFO:
-                    replyToMessage(message, WifiP2pManager.RESPONSE_GROUP_INFO, mGroup);
+                    replyToMessage(message, WifiP2pManager.RESPONSE_GROUP_INFO,
+                            mGroup != null ? new WifiP2pGroup(mGroup) : null);
                     break;
                 case WifiP2pManager.REQUEST_PERSISTENT_GROUP_INFO:
                     replyToMessage(message, WifiP2pManager.RESPONSE_PERSISTENT_GROUP_INFO,
-                            mGroups);
+                            new WifiP2pGroupList(mGroups, null));
                     break;
                 case WifiP2pManager.SET_DIALOG_LISTENER:
                     String appPkgName = (String)message.getData().getString(
@@ -629,6 +636,10 @@
                     replyToMessage(message, WifiP2pManager.DELETE_PERSISTENT_GROUP,
                             WifiP2pManager.P2P_UNSUPPORTED);
                     break;
+                case WifiP2pManager.SET_WFD_INFO:
+                    replyToMessage(message, WifiP2pManager.SET_WFD_INFO_FAILED,
+                            WifiP2pManager.P2P_UNSUPPORTED);
+                    break;
                default:
                     return NOT_HANDLED;
             }
@@ -741,6 +752,7 @@
                     transitionTo(mP2pDisablingState);
                     break;
                 case WifiP2pManager.SET_DEVICE_NAME:
+                {
                     WifiP2pDevice d = (WifiP2pDevice) message.obj;
                     if (d != null && setAndPersistDeviceName(d.deviceName)) {
                         if (DBG) logd("set device name " + d.deviceName);
@@ -750,6 +762,18 @@
                                 WifiP2pManager.ERROR);
                     }
                     break;
+                }
+                case WifiP2pManager.SET_WFD_INFO:
+                {
+                    WifiP2pWfdInfo d = (WifiP2pWfdInfo) message.obj;
+                    if (d != null && setWfdInfo(d)) {
+                        replyToMessage(message, WifiP2pManager.SET_WFD_INFO_SUCCEEDED);
+                    } else {
+                        replyToMessage(message, WifiP2pManager.SET_WFD_INFO_FAILED,
+                                WifiP2pManager.ERROR);
+                    }
+                    break;
+                }
                 case WifiP2pManager.DISCOVER_PEERS:
                     // do not send service discovery request while normal find operation.
                     clearSupplicantServiceRequest();
@@ -1476,7 +1500,7 @@
         public void exit() {
             mSavedProvDiscDevice = null;
             updateThisDevice(WifiP2pDevice.AVAILABLE);
-            setWifiP2pInfoOnGroupTermination();
+            resetWifiP2pInfo();
             mNetworkInfo.setDetailedState(NetworkInfo.DetailedState.DISCONNECTED, null, null);
             sendP2pConnectionChangedBroadcast();
         }
@@ -1955,7 +1979,7 @@
         mWifiP2pInfo.groupOwnerAddress = NetworkUtils.numericToInetAddress(serverAddress);
     }
 
-    private void setWifiP2pInfoOnGroupTermination() {
+    private void resetWifiP2pInfo() {
         mWifiP2pInfo.groupFormed = false;
         mWifiP2pInfo.isGroupOwner = false;
         mWifiP2pInfo.groupOwnerAddress = null;
@@ -2018,6 +2042,27 @@
         return true;
     }
 
+    private boolean setWfdInfo(WifiP2pWfdInfo wfdInfo) {
+        boolean success;
+
+        if (!wfdInfo.isWfdEnabled()) {
+            success = mWifiNative.setWfdEnable(false);
+        } else {
+            success =
+                mWifiNative.setWfdEnable(true)
+                && mWifiNative.setWfdDeviceInfo(wfdInfo.getDeviceInfoHex());
+        }
+
+        if (!success) {
+            loge("Failed to set wfd properties");
+            return false;
+        }
+
+        mThisDevice.wfdInfo = wfdInfo;
+        sendThisDeviceChangedBroadcast();
+        return true;
+    }
+
     private void initializeP2pSettings() {
         mWifiNative.setPersistentReconnect(true);
         mThisDevice.deviceName = getPersistedDeviceName();
@@ -2050,6 +2095,9 @@
     }
 
     private void handleGroupCreationFailure() {
+        resetWifiP2pInfo();
+        mNetworkInfo.setDetailedState(NetworkInfo.DetailedState.FAILED, null, null);
+        sendP2pConnectionChangedBroadcast();
         mSavedPeerConfig = null;
         /* After cancelling group formation, new connections on existing peers can fail
          * at supplicant. Flush and restart discovery */
diff --git a/wifi/java/android/net/wifi/p2p/WifiP2pWfdInfo.java b/wifi/java/android/net/wifi/p2p/WifiP2pWfdInfo.java
new file mode 100644
index 0000000..b6bbfc4
--- /dev/null
+++ b/wifi/java/android/net/wifi/p2p/WifiP2pWfdInfo.java
@@ -0,0 +1,192 @@
+/*
+ * Copyright (C) 2012 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.net.wifi.p2p;
+
+import android.os.Parcelable;
+import android.os.Parcel;
+
+/**
+ * A class representing Wifi Display information for a device
+ * @hide
+ */
+public class WifiP2pWfdInfo implements Parcelable {
+
+    private static final String TAG = "WifiP2pWfdInfo";
+
+    private boolean mWfdEnabled;
+
+    private int mDeviceInfo;
+
+    public static final int WFD_SOURCE              = 0;
+    public static final int PRIMARY_SINK            = 1;
+    public static final int SECONDARY_SINK          = 2;
+    public static final int SOURCE_OR_PRIMARY_SINK  = 3;
+
+    /* Device information bitmap */
+    /** One of {@link #WFD_SOURCE}, {@link #PRIMARY_SINK}, {@link #SECONDARY_SINK}
+     * or {@link #SOURCE_OR_PRIMARY_SINK}
+     */
+    private static final int DEVICE_TYPE                            = 0x3;
+    private static final int COUPLED_SINK_SUPPORT_AT_SOURCE         = 0x4;
+    private static final int COUPLED_SINK_SUPPORT_AT_SINK           = 0x8;
+    private static final int SESSION_AVAILABLE                      = 0x30;
+    private static final int SESSION_AVAILABLE_BIT1                 = 0x10;
+    private static final int SESSION_AVAILABLE_BIT2                 = 0x20;
+
+    private int mCtrlPort;
+
+    private int mMaxThroughput;
+
+    public WifiP2pWfdInfo() {
+    }
+
+    public WifiP2pWfdInfo(int devInfo, int ctrlPort, int maxTput) {
+        mWfdEnabled = true;
+        mDeviceInfo = devInfo;
+        mCtrlPort = ctrlPort;
+        mMaxThroughput = maxTput;
+    }
+
+    public boolean isWfdEnabled() {
+        return mWfdEnabled;
+    }
+
+    public void setWfdEnabled(boolean enabled) {
+        mWfdEnabled = enabled;
+    }
+
+    public int getDeviceType() {
+        return (mDeviceInfo & DEVICE_TYPE);
+    }
+
+    public boolean setDeviceType(int deviceType) {
+        if (deviceType >= WFD_SOURCE && deviceType <= SOURCE_OR_PRIMARY_SINK) {
+            mDeviceInfo |= deviceType;
+            return true;
+        }
+        return false;
+    }
+
+    public boolean isCoupledSinkSupportedAtSource() {
+        return (mDeviceInfo & COUPLED_SINK_SUPPORT_AT_SINK) != 0;
+    }
+
+    public void setCoupledSinkSupportAtSource(boolean enabled) {
+        if (enabled ) {
+            mDeviceInfo |= COUPLED_SINK_SUPPORT_AT_SINK;
+        } else {
+            mDeviceInfo &= ~COUPLED_SINK_SUPPORT_AT_SINK;
+        }
+    }
+
+    public boolean isCoupledSinkSupportedAtSink() {
+        return (mDeviceInfo & COUPLED_SINK_SUPPORT_AT_SINK) != 0;
+    }
+
+    public void setCoupledSinkSupportAtSink(boolean enabled) {
+        if (enabled ) {
+            mDeviceInfo |= COUPLED_SINK_SUPPORT_AT_SINK;
+        } else {
+            mDeviceInfo &= ~COUPLED_SINK_SUPPORT_AT_SINK;
+        }
+    }
+
+    public boolean isSessionAvailable() {
+        return (mDeviceInfo & SESSION_AVAILABLE) != 0;
+    }
+
+    public void setSessionAvailable(boolean enabled) {
+        if (enabled) {
+            mDeviceInfo |= SESSION_AVAILABLE_BIT1;
+            mDeviceInfo &= ~SESSION_AVAILABLE_BIT2;
+        } else {
+            mDeviceInfo &= ~SESSION_AVAILABLE;
+        }
+    }
+
+    public int getControlPort() {
+        return mCtrlPort;
+    }
+
+    public void setControlPort(int port) {
+        mCtrlPort = port;
+    }
+
+    public void setMaxThroughput(int maxThroughput) {
+        mMaxThroughput = maxThroughput;
+    }
+
+    public int getMaxThroughput() {
+        return mMaxThroughput;
+    }
+
+    public String getDeviceInfoHex() {
+        return String.format("%04x%04x%04x%04x", 6, mDeviceInfo, mCtrlPort, mMaxThroughput);
+    }
+
+    public String toString() {
+        StringBuffer sbuf = new StringBuffer();
+        sbuf.append("WFD enabled: ").append(mWfdEnabled);
+        sbuf.append("WFD DeviceInfo: ").append(mDeviceInfo);
+        sbuf.append("\n WFD CtrlPort: ").append(mCtrlPort);
+        sbuf.append("\n WFD MaxThroughput: ").append(mMaxThroughput);
+        return sbuf.toString();
+    }
+
+    /** Implement the Parcelable interface */
+    public int describeContents() {
+        return 0;
+    }
+
+    /** copy constructor */
+    public WifiP2pWfdInfo(WifiP2pWfdInfo source) {
+        if (source != null) {
+            mDeviceInfo = source.mDeviceInfo;
+            mCtrlPort = source.mCtrlPort;
+            mMaxThroughput = source.mMaxThroughput;
+        }
+    }
+
+    /** Implement the Parcelable interface */
+    public void writeToParcel(Parcel dest, int flags) {
+        dest.writeInt(mWfdEnabled ? 1 : 0);
+        dest.writeInt(mDeviceInfo);
+        dest.writeInt(mCtrlPort);
+        dest.writeInt(mMaxThroughput);
+    }
+
+    public void readFromParcel(Parcel in) {
+        mWfdEnabled = (in.readInt() == 1);
+        mDeviceInfo = in.readInt();
+        mCtrlPort = in.readInt();
+        mMaxThroughput = in.readInt();
+    }
+
+    /** Implement the Parcelable interface */
+    public static final Creator<WifiP2pWfdInfo> CREATOR =
+        new Creator<WifiP2pWfdInfo>() {
+            public WifiP2pWfdInfo createFromParcel(Parcel in) {
+                WifiP2pWfdInfo device = new WifiP2pWfdInfo();
+                device.readFromParcel(in);
+                return device;
+            }
+
+            public WifiP2pWfdInfo[] newArray(int size) {
+                return new WifiP2pWfdInfo[size];
+            }
+        };
+}