Merge "Fix issue #7273573: Need API to find out if activity is destroyed" into jb-mr1-dev
diff --git a/api/17.txt b/api/17.txt
index c6b548e..e86de90 100644
--- a/api/17.txt
+++ b/api/17.txt
@@ -5834,6 +5834,7 @@
     field public static final java.lang.String ACTION_POWER_DISCONNECTED = "android.intent.action.ACTION_POWER_DISCONNECTED";
     field public static final java.lang.String ACTION_POWER_USAGE_SUMMARY = "android.intent.action.POWER_USAGE_SUMMARY";
     field public static final java.lang.String ACTION_PROVIDER_CHANGED = "android.intent.action.PROVIDER_CHANGED";
+    field public static final java.lang.String ACTION_QUICK_CLOCK = "android.intent.action.QUICK_CLOCK";
     field public static final java.lang.String ACTION_REBOOT = "android.intent.action.REBOOT";
     field public static final java.lang.String ACTION_RUN = "android.intent.action.RUN";
     field public static final java.lang.String ACTION_SCREEN_OFF = "android.intent.action.SCREEN_OFF";
@@ -18816,11 +18817,14 @@
     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 ALWAYS_FINISH_ACTIVITIES = "always_finish_activities";
+    field public static final java.lang.String ANIMATOR_DURATION_SCALE = "animator_duration_scale";
     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 DEBUG_APP = "debug_app";
     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 HTTP_PROXY = "http_proxy";
@@ -18831,10 +18835,13 @@
     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 SHOW_PROCESSES = "show_processes";
     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 TRANSITION_ANIMATION_SCALE = "transition_animation_scale";
     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 WAIT_FOR_DEBUGGER = "wait_for_debugger";
     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";
@@ -18846,6 +18853,7 @@
     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";
+    field public static final java.lang.String WINDOW_ANIMATION_SCALE = "window_animation_scale";
   }
 
   public static class Settings.NameValueTable implements android.provider.BaseColumns {
@@ -18960,9 +18968,9 @@
     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 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 deprecated 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 deprecated java.lang.String AUTO_TIME = "auto_time";
     field public static final deprecated java.lang.String AUTO_TIME_ZONE = "auto_time_zone";
@@ -18972,7 +18980,7 @@
     field public static final android.net.Uri CONTENT_URI;
     field public static final deprecated java.lang.String DATA_ROAMING = "data_roaming";
     field public static final java.lang.String DATE_FORMAT = "date_format";
-    field public static final java.lang.String DEBUG_APP = "debug_app";
+    field public static final deprecated java.lang.String DEBUG_APP = "debug_app";
     field public static final android.net.Uri DEFAULT_ALARM_ALERT_URI;
     field public static final android.net.Uri DEFAULT_NOTIFICATION_URI;
     field public static final android.net.Uri DEFAULT_RINGTONE_URI;
@@ -19011,7 +19019,7 @@
     field public static final deprecated java.lang.String SETTINGS_CLASSNAME = "settings_classname";
     field public static final java.lang.String SETUP_WIZARD_HAS_RUN = "setup_wizard_has_run";
     field public static final java.lang.String SHOW_GTALK_SERVICE_STATUS = "SHOW_GTALK_SERVICE_STATUS";
-    field public static final java.lang.String SHOW_PROCESSES = "show_processes";
+    field public static final deprecated 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 deprecated java.lang.String STAY_ON_WHILE_PLUGGED_IN = "stay_on_while_plugged_in";
@@ -19021,7 +19029,7 @@
     field public static final java.lang.String TEXT_AUTO_REPLACE = "auto_replace";
     field public static final java.lang.String TEXT_SHOW_PASSWORD = "show_password";
     field public static final java.lang.String TIME_12_24 = "time_12_24";
-    field public static final java.lang.String TRANSITION_ANIMATION_SCALE = "transition_animation_scale";
+    field public static final deprecated java.lang.String TRANSITION_ANIMATION_SCALE = "transition_animation_scale";
     field public static final deprecated java.lang.String USB_MASS_STORAGE_ENABLED = "usb_mass_storage_enabled";
     field public static final java.lang.String USER_ROTATION = "user_rotation";
     field public static final deprecated java.lang.String USE_GOOGLE_MAIL = "use_google_mail";
@@ -19034,8 +19042,8 @@
     field public static final java.lang.String[] VOLUME_SETTINGS;
     field public static final java.lang.String VOLUME_SYSTEM = "volume_system";
     field public static final java.lang.String VOLUME_VOICE = "volume_voice";
-    field public static final java.lang.String WAIT_FOR_DEBUGGER = "wait_for_debugger";
-    field public static final java.lang.String WALLPAPER_ACTIVITY = "wallpaper_activity";
+    field public static final deprecated java.lang.String WAIT_FOR_DEBUGGER = "wait_for_debugger";
+    field public static final deprecated java.lang.String WALLPAPER_ACTIVITY = "wallpaper_activity";
     field public static final deprecated java.lang.String WIFI_MAX_DHCP_RETRY_COUNT = "wifi_max_dhcp_retry_count";
     field public static final deprecated java.lang.String WIFI_MOBILE_DATA_TRANSITION_WAKELOCK_TIMEOUT_MS = "wifi_mobile_data_transition_wakelock_timeout_ms";
     field public static final deprecated java.lang.String WIFI_NETWORKS_AVAILABLE_NOTIFICATION_ON = "wifi_networks_available_notification_on";
@@ -19063,7 +19071,7 @@
     field public static final deprecated java.lang.String WIFI_WATCHDOG_PING_COUNT = "wifi_watchdog_ping_count";
     field public static final deprecated java.lang.String WIFI_WATCHDOG_PING_DELAY_MS = "wifi_watchdog_ping_delay_ms";
     field public static final deprecated java.lang.String WIFI_WATCHDOG_PING_TIMEOUT_MS = "wifi_watchdog_ping_timeout_ms";
-    field public static final java.lang.String WINDOW_ANIMATION_SCALE = "window_animation_scale";
+    field public static final deprecated java.lang.String WINDOW_ANIMATION_SCALE = "window_animation_scale";
   }
 
   public class SyncStateContract {
@@ -23713,6 +23721,7 @@
   public final class Display {
     method public void getCurrentSizeRange(android.graphics.Point, android.graphics.Point);
     method public int getDisplayId();
+    method public int getFlags();
     method public deprecated int getHeight();
     method public void getMetrics(android.util.DisplayMetrics);
     method public java.lang.String getName();
@@ -23727,6 +23736,7 @@
     method public deprecated int getWidth();
     method public boolean isValid();
     field public static final int DEFAULT_DISPLAY = 0; // 0x0
+    field public static final int FLAG_SUPPORTS_PROTECTED_BUFFERS = 1; // 0x1
   }
 
   public class DragEvent implements android.os.Parcelable {
diff --git a/api/current.txt b/api/current.txt
index c6b548e..e86de90 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -5834,6 +5834,7 @@
     field public static final java.lang.String ACTION_POWER_DISCONNECTED = "android.intent.action.ACTION_POWER_DISCONNECTED";
     field public static final java.lang.String ACTION_POWER_USAGE_SUMMARY = "android.intent.action.POWER_USAGE_SUMMARY";
     field public static final java.lang.String ACTION_PROVIDER_CHANGED = "android.intent.action.PROVIDER_CHANGED";
+    field public static final java.lang.String ACTION_QUICK_CLOCK = "android.intent.action.QUICK_CLOCK";
     field public static final java.lang.String ACTION_REBOOT = "android.intent.action.REBOOT";
     field public static final java.lang.String ACTION_RUN = "android.intent.action.RUN";
     field public static final java.lang.String ACTION_SCREEN_OFF = "android.intent.action.SCREEN_OFF";
@@ -18816,11 +18817,14 @@
     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 ALWAYS_FINISH_ACTIVITIES = "always_finish_activities";
+    field public static final java.lang.String ANIMATOR_DURATION_SCALE = "animator_duration_scale";
     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 DEBUG_APP = "debug_app";
     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 HTTP_PROXY = "http_proxy";
@@ -18831,10 +18835,13 @@
     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 SHOW_PROCESSES = "show_processes";
     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 TRANSITION_ANIMATION_SCALE = "transition_animation_scale";
     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 WAIT_FOR_DEBUGGER = "wait_for_debugger";
     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";
@@ -18846,6 +18853,7 @@
     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";
+    field public static final java.lang.String WINDOW_ANIMATION_SCALE = "window_animation_scale";
   }
 
   public static class Settings.NameValueTable implements android.provider.BaseColumns {
@@ -18960,9 +18968,9 @@
     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 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 deprecated 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 deprecated java.lang.String AUTO_TIME = "auto_time";
     field public static final deprecated java.lang.String AUTO_TIME_ZONE = "auto_time_zone";
@@ -18972,7 +18980,7 @@
     field public static final android.net.Uri CONTENT_URI;
     field public static final deprecated java.lang.String DATA_ROAMING = "data_roaming";
     field public static final java.lang.String DATE_FORMAT = "date_format";
-    field public static final java.lang.String DEBUG_APP = "debug_app";
+    field public static final deprecated java.lang.String DEBUG_APP = "debug_app";
     field public static final android.net.Uri DEFAULT_ALARM_ALERT_URI;
     field public static final android.net.Uri DEFAULT_NOTIFICATION_URI;
     field public static final android.net.Uri DEFAULT_RINGTONE_URI;
@@ -19011,7 +19019,7 @@
     field public static final deprecated java.lang.String SETTINGS_CLASSNAME = "settings_classname";
     field public static final java.lang.String SETUP_WIZARD_HAS_RUN = "setup_wizard_has_run";
     field public static final java.lang.String SHOW_GTALK_SERVICE_STATUS = "SHOW_GTALK_SERVICE_STATUS";
-    field public static final java.lang.String SHOW_PROCESSES = "show_processes";
+    field public static final deprecated 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 deprecated java.lang.String STAY_ON_WHILE_PLUGGED_IN = "stay_on_while_plugged_in";
@@ -19021,7 +19029,7 @@
     field public static final java.lang.String TEXT_AUTO_REPLACE = "auto_replace";
     field public static final java.lang.String TEXT_SHOW_PASSWORD = "show_password";
     field public static final java.lang.String TIME_12_24 = "time_12_24";
-    field public static final java.lang.String TRANSITION_ANIMATION_SCALE = "transition_animation_scale";
+    field public static final deprecated java.lang.String TRANSITION_ANIMATION_SCALE = "transition_animation_scale";
     field public static final deprecated java.lang.String USB_MASS_STORAGE_ENABLED = "usb_mass_storage_enabled";
     field public static final java.lang.String USER_ROTATION = "user_rotation";
     field public static final deprecated java.lang.String USE_GOOGLE_MAIL = "use_google_mail";
@@ -19034,8 +19042,8 @@
     field public static final java.lang.String[] VOLUME_SETTINGS;
     field public static final java.lang.String VOLUME_SYSTEM = "volume_system";
     field public static final java.lang.String VOLUME_VOICE = "volume_voice";
-    field public static final java.lang.String WAIT_FOR_DEBUGGER = "wait_for_debugger";
-    field public static final java.lang.String WALLPAPER_ACTIVITY = "wallpaper_activity";
+    field public static final deprecated java.lang.String WAIT_FOR_DEBUGGER = "wait_for_debugger";
+    field public static final deprecated java.lang.String WALLPAPER_ACTIVITY = "wallpaper_activity";
     field public static final deprecated java.lang.String WIFI_MAX_DHCP_RETRY_COUNT = "wifi_max_dhcp_retry_count";
     field public static final deprecated java.lang.String WIFI_MOBILE_DATA_TRANSITION_WAKELOCK_TIMEOUT_MS = "wifi_mobile_data_transition_wakelock_timeout_ms";
     field public static final deprecated java.lang.String WIFI_NETWORKS_AVAILABLE_NOTIFICATION_ON = "wifi_networks_available_notification_on";
@@ -19063,7 +19071,7 @@
     field public static final deprecated java.lang.String WIFI_WATCHDOG_PING_COUNT = "wifi_watchdog_ping_count";
     field public static final deprecated java.lang.String WIFI_WATCHDOG_PING_DELAY_MS = "wifi_watchdog_ping_delay_ms";
     field public static final deprecated java.lang.String WIFI_WATCHDOG_PING_TIMEOUT_MS = "wifi_watchdog_ping_timeout_ms";
-    field public static final java.lang.String WINDOW_ANIMATION_SCALE = "window_animation_scale";
+    field public static final deprecated java.lang.String WINDOW_ANIMATION_SCALE = "window_animation_scale";
   }
 
   public class SyncStateContract {
@@ -23713,6 +23721,7 @@
   public final class Display {
     method public void getCurrentSizeRange(android.graphics.Point, android.graphics.Point);
     method public int getDisplayId();
+    method public int getFlags();
     method public deprecated int getHeight();
     method public void getMetrics(android.util.DisplayMetrics);
     method public java.lang.String getName();
@@ -23727,6 +23736,7 @@
     method public deprecated int getWidth();
     method public boolean isValid();
     field public static final int DEFAULT_DISPLAY = 0; // 0x0
+    field public static final int FLAG_SUPPORTS_PROTECTED_BUFFERS = 1; // 0x1
   }
 
   public class DragEvent implements android.os.Parcelable {
diff --git a/core/java/android/app/ContextImpl.java b/core/java/android/app/ContextImpl.java
index c41405b..59fa1e0 100644
--- a/core/java/android/app/ContextImpl.java
+++ b/core/java/android/app/ContextImpl.java
@@ -1703,6 +1703,7 @@
         if (packageName.equals("system") || packageName.equals("android")) {
             final ContextImpl context = new ContextImpl(mMainThread.getSystemContext());
             context.mBasePackageName = mBasePackageName;
+            context.mUser = user;
             return context;
         }
 
diff --git a/core/java/android/content/Intent.java b/core/java/android/content/Intent.java
index d4f6c06..c14a703 100644
--- a/core/java/android/content/Intent.java
+++ b/core/java/android/content/Intent.java
@@ -2414,6 +2414,12 @@
     public static final String ACTION_USER_INFO_CHANGED =
             "android.intent.action.USER_INFO_CHANGED";
 
+    /**
+     * Sent when the user taps on the clock widget in the system's "quick settings" area.
+     */
+    public static final String ACTION_QUICK_CLOCK =
+            "android.intent.action.QUICK_CLOCK";
+
     // ---------------------------------------------------------------------
     // ---------------------------------------------------------------------
     // Standard intent categories (see addCategory()).
diff --git a/core/java/android/content/pm/PackageUserState.java b/core/java/android/content/pm/PackageUserState.java
index 7b3d8cd..3579977 100644
--- a/core/java/android/content/pm/PackageUserState.java
+++ b/core/java/android/content/pm/PackageUserState.java
@@ -34,14 +34,6 @@
     public HashSet<String> enabledComponents;
 
     public PackageUserState() {
-        this(true);
-    }
-
-    /** @hide */
-    public PackageUserState(boolean isSystem) {
-        if (!isSystem) {
-            stopped = notLaunched = true;
-        }
         installed = true;
         enabled = COMPONENT_ENABLED_STATE_DEFAULT;
     }
diff --git a/core/java/android/hardware/usb/IUsbManager.aidl b/core/java/android/hardware/usb/IUsbManager.aidl
index 98bd4f5..8286686 100644
--- a/core/java/android/hardware/usb/IUsbManager.aidl
+++ b/core/java/android/hardware/usb/IUsbManager.aidl
@@ -44,12 +44,12 @@
     /* Sets the default package for a USB device
      * (or clears it if the package name is null)
      */
-    void setDevicePackage(in UsbDevice device, String packageName);
+    void setDevicePackage(in UsbDevice device, String packageName, int userId);
 
     /* Sets the default package for a USB accessory
      * (or clears it if the package name is null)
      */
-    void setAccessoryPackage(in UsbAccessory accessory, String packageName);
+    void setAccessoryPackage(in UsbAccessory accessory, String packageName, int userId);
 
     /* Returns true if the caller has permission to access the device. */
     boolean hasDevicePermission(in UsbDevice device);
@@ -77,10 +77,10 @@
     void grantAccessoryPermission(in UsbAccessory accessory, int uid);
 
     /* Returns true if the USB manager has default preferences or permissions for the package */
-    boolean hasDefaults(String packageName);
+    boolean hasDefaults(String packageName, int userId);
 
     /* Clears default preferences and permissions for the package */
-    void clearDefaults(String packageName);
+    void clearDefaults(String packageName, int userId);
 
     /* Sets the current USB function. */
     void setCurrentFunction(String function, boolean makeDefault);
diff --git a/core/java/android/inputmethodservice/InputMethodService.java b/core/java/android/inputmethodservice/InputMethodService.java
index cf3b802..f07002e 100644
--- a/core/java/android/inputmethodservice/InputMethodService.java
+++ b/core/java/android/inputmethodservice/InputMethodService.java
@@ -683,8 +683,8 @@
                 com.android.internal.R.layout.input_method, null);
         mWindow.setContentView(mRootView);
         mRootView.getViewTreeObserver().addOnComputeInternalInsetsListener(mInsetsComputer);
-        if (Settings.System.getInt(getContentResolver(),
-                Settings.System.FANCY_IME_ANIMATIONS, 0) != 0) {
+        if (Settings.Global.getInt(getContentResolver(),
+                Settings.Global.FANCY_IME_ANIMATIONS, 0) != 0) {
             mWindow.getWindow().setWindowAnimations(
                     com.android.internal.R.style.Animation_InputMethodFancy);
         }
diff --git a/core/java/android/net/CaptivePortalTracker.java b/core/java/android/net/CaptivePortalTracker.java
index 9b11094..ce71e6b 100644
--- a/core/java/android/net/CaptivePortalTracker.java
+++ b/core/java/android/net/CaptivePortalTracker.java
@@ -31,6 +31,7 @@
 import android.os.Message;
 import android.os.RemoteException;
 import android.provider.Settings;
+import android.telephony.TelephonyManager;
 import android.util.Log;
 
 import com.android.internal.util.State;
@@ -63,6 +64,7 @@
     private boolean mNotificationShown = false;
     private boolean mIsCaptivePortalCheckEnabled = false;
     private IConnectivityManager mConnService;
+    private TelephonyManager mTelephonyManager;
     private Context mContext;
     private NetworkInfo mNetworkInfo;
 
@@ -84,6 +86,7 @@
 
         mContext = context;
         mConnService = cs;
+        mTelephonyManager = (TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE);
 
         IntentFilter filter = new IntentFilter();
         filter.addAction(ConnectivityManager.CONNECTIVITY_ACTION);
@@ -326,17 +329,33 @@
 
         if (visible) {
             CharSequence title;
-            if (mNetworkInfo.getType() == ConnectivityManager.TYPE_WIFI) {
-                title = r.getString(R.string.wifi_available_sign_in, 0);
-            } else {
-                title = r.getString(R.string.network_available_sign_in, 0);
+            CharSequence details;
+            int icon;
+            switch (mNetworkInfo.getType()) {
+                case ConnectivityManager.TYPE_WIFI:
+                    title = r.getString(R.string.wifi_available_sign_in, 0);
+                    details = r.getString(R.string.network_available_sign_in_detailed,
+                            mNetworkInfo.getExtraInfo());
+                    icon = R.drawable.stat_notify_wifi_in_range;
+                    break;
+                case ConnectivityManager.TYPE_MOBILE:
+                    title = r.getString(R.string.network_available_sign_in, 0);
+                    // TODO: Change this to pull from NetworkInfo once a printable
+                    // name has been added to it
+                    details = mTelephonyManager.getNetworkOperatorName();
+                    icon = R.drawable.stat_notify_rssi_in_range;
+                    break;
+                default:
+                    title = r.getString(R.string.network_available_sign_in, 0);
+                    details = r.getString(R.string.network_available_sign_in_detailed,
+                            mNetworkInfo.getExtraInfo());
+                    icon = R.drawable.stat_notify_rssi_in_range;
+                    break;
             }
-            CharSequence details = r.getString(R.string.network_available_sign_in_detailed,
-                    mNetworkInfo.getExtraInfo());
 
             Notification notification = new Notification();
             notification.when = 0;
-            notification.icon = com.android.internal.R.drawable.stat_notify_wifi_in_range;
+            notification.icon = icon;
             notification.flags = Notification.FLAG_AUTO_CANCEL;
             Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse(mUrl));
             intent.setFlags(Intent.FLAG_ACTIVITY_BROUGHT_TO_FRONT |
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index 8f1210b..2a8cf21 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -19,6 +19,7 @@
 import android.annotation.SdkConstant;
 import android.annotation.SdkConstant.SdkConstantType;
 import android.app.SearchManager;
+import android.app.WallpaperManager;
 import android.content.ComponentName;
 import android.content.ContentResolver;
 import android.content.ContentValues;
@@ -940,6 +941,17 @@
             MOVED_TO_GLOBAL.add(Settings.Global.STAY_ON_WHILE_PLUGGED_IN);
             MOVED_TO_GLOBAL.add(Settings.Global.WIFI_SLEEP_POLICY);
             MOVED_TO_GLOBAL.add(Settings.Global.MODE_RINGER);
+            MOVED_TO_GLOBAL.add(Settings.Global.WINDOW_ANIMATION_SCALE);
+            MOVED_TO_GLOBAL.add(Settings.Global.TRANSITION_ANIMATION_SCALE);
+            MOVED_TO_GLOBAL.add(Settings.Global.ANIMATOR_DURATION_SCALE);
+            MOVED_TO_GLOBAL.add(Settings.Global.FANCY_IME_ANIMATIONS);
+            MOVED_TO_GLOBAL.add(Settings.Global.COMPATIBILITY_MODE);
+            MOVED_TO_GLOBAL.add(Settings.Global.EMERGENCY_TONE);
+            MOVED_TO_GLOBAL.add(Settings.Global.CALL_AUTO_RETRY);
+            MOVED_TO_GLOBAL.add(Settings.Global.DEBUG_APP);
+            MOVED_TO_GLOBAL.add(Settings.Global.WAIT_FOR_DEBUGGER);
+            MOVED_TO_GLOBAL.add(Settings.Global.SHOW_PROCESSES);
+            MOVED_TO_GLOBAL.add(Settings.Global.ALWAYS_FINISH_ACTIVITIES);
         }
 
         /**
@@ -1608,14 +1620,20 @@
 
         /**
          * Name of an application package to be debugged.
+         *
+         * @deprecated Use {@link Global#DEBUG_APP} instead
          */
-        public static final String DEBUG_APP = "debug_app";
+        @Deprecated
+        public static final String DEBUG_APP = Global.DEBUG_APP;
 
         /**
          * If 1, when launching DEBUG_APP it will wait for the debugger before
          * starting user code.  If 0, it will run normally.
+         *
+         * @deprecated Use {@link Global#WAIT_FOR_DEBUGGER} instead
          */
-        public static final String WAIT_FOR_DEBUGGER = "wait_for_debugger";
+        @Deprecated
+        public static final String WAIT_FOR_DEBUGGER = Global.WAIT_FOR_DEBUGGER;
 
         /**
          * Whether or not to dim the screen. 0=no  1=yes
@@ -1630,14 +1648,6 @@
         public static final String SCREEN_OFF_TIMEOUT = "screen_off_timeout";
 
         /**
-         * If 0, the compatibility mode is off for all applications.
-         * If 1, older applications run under compatibility mode.
-         * TODO: remove this settings before code freeze (bug/1907571)
-         * @hide
-         */
-        public static final String COMPATIBILITY_MODE = "compatibility_mode";
-
-        /**
          * The screen backlight brightness between 0 and 255.
          */
         public static final String SCREEN_BRIGHTNESS = "screen_brightness";
@@ -1666,16 +1676,21 @@
 
         /**
          * Control whether the process CPU usage meter should be shown.
+         *
+         * @deprecated Use {@link Global#SHOW_PROCESSES} instead
          */
-        public static final String SHOW_PROCESSES = "show_processes";
+        @Deprecated
+        public static final String SHOW_PROCESSES = Global.SHOW_PROCESSES;
 
         /**
          * If 1, the activity manager will aggressively finish activities and
          * processes as soon as they are no longer needed.  If 0, the normal
          * extended lifetime is used.
+         *
+         * @deprecated Use {@link Global#ALWAYS_FINISH_ACTIVITIES} instead
          */
-        public static final String ALWAYS_FINISH_ACTIVITIES =
-                "always_finish_activities";
+        @Deprecated
+        public static final String ALWAYS_FINISH_ACTIVITIES = Global.ALWAYS_FINISH_ACTIVITIES;
 
         /**
          * Determines which streams are affected by ringer mode changes. The
@@ -1899,7 +1914,10 @@
 
         /**
          * Name of activity to use for wallpaper on the home screen.
+         *
+         * @deprecated Use {@link WallpaperManager} instead.
          */
+        @Deprecated
         public static final String WALLPAPER_ACTIVITY = "wallpaper_activity";
 
         /**
@@ -1943,28 +1961,30 @@
         /**
          * Scaling factor for normal window animations. Setting to 0 will disable window
          * animations.
+         *
+         * @deprecated Use {@link Global#WINDOW_ANIMATION_SCALE} instead
          */
-        public static final String WINDOW_ANIMATION_SCALE = "window_animation_scale";
+        @Deprecated
+        public static final String WINDOW_ANIMATION_SCALE = Global.WINDOW_ANIMATION_SCALE;
 
         /**
          * Scaling factor for activity transition animations. Setting to 0 will disable window
          * animations.
+         *
+         * @deprecated Use {@link Global#TRANSITION_ANIMATION_SCALE} instead
          */
-        public static final String TRANSITION_ANIMATION_SCALE = "transition_animation_scale";
+        @Deprecated
+        public static final String TRANSITION_ANIMATION_SCALE = Global.TRANSITION_ANIMATION_SCALE;
 
         /**
          * Scaling factor for Animator-based animations. This affects both the start delay and
          * duration of all such animations. Setting to 0 will cause animations to end immediately.
          * The default value is 1.
+         *
+         * @deprecated Use {@link Global#ANIMATOR_DURATION_SCALE} instead
          */
-        public static final String ANIMATOR_DURATION_SCALE = "animator_duration_scale";
-
-        /**
-         * Scaling factor for normal window animations. Setting to 0 will disable window
-         * animations.
-         * @hide
-         */
-        public static final String FANCY_IME_ANIMATIONS = "fancy_ime_animations";
+        @Deprecated
+        public static final String ANIMATOR_DURATION_SCALE = Global.ANIMATOR_DURATION_SCALE;
 
         /**
          * Control whether the accelerometer will be used to change screen
@@ -2028,23 +2048,6 @@
         public static final String DTMF_TONE_TYPE_WHEN_DIALING = "dtmf_tone_type";
 
         /**
-         * CDMA only settings
-         * Emergency Tone  0 = Off
-         *                 1 = Alert
-         *                 2 = Vibrate
-         * @hide
-         */
-        public static final String EMERGENCY_TONE = "emergency_tone";
-
-        /**
-         * CDMA only settings
-         * Whether the auto retry is enabled. The value is
-         * boolean (1 or 0).
-         * @hide
-         */
-        public static final String CALL_AUTO_RETRY = "call_auto_retry";
-
-        /**
          * Whether the hearing aid is enabled. The value is
          * boolean (1 or 0).
          * @hide
@@ -2296,8 +2299,8 @@
             DATE_FORMAT,
             DTMF_TONE_WHEN_DIALING,
             DTMF_TONE_TYPE_WHEN_DIALING,
-            EMERGENCY_TONE,
-            CALL_AUTO_RETRY,
+            Global.EMERGENCY_TONE,
+            Global.CALL_AUTO_RETRY,
             HEARING_AID,
             TTY_MODE,
             SOUND_EFFECTS_ENABLED,
@@ -2695,6 +2698,8 @@
             MOVED_TO_GLOBAL.add(Settings.Global.GLOBAL_HTTP_PROXY_EXCLUSION_LIST);
             MOVED_TO_GLOBAL.add(Settings.Global.SET_GLOBAL_HTTP_PROXY);
             MOVED_TO_GLOBAL.add(Settings.Global.DEFAULT_DNS_SERVER);
+            MOVED_TO_GLOBAL.add(Settings.Global.PREFERRED_NETWORK_MODE);
+            MOVED_TO_GLOBAL.add(Settings.Global.PREFERRED_CDMA_SUBSCRIPTION);
         }
 
         /**
@@ -3653,20 +3658,6 @@
                 = "allowed_geolocation_origins";
 
         /**
-         * The preferred network mode   7 = Global
-         *                              6 = EvDo only
-         *                              5 = CDMA w/o EvDo
-         *                              4 = CDMA / EvDo auto
-         *                              3 = GSM / WCDMA auto
-         *                              2 = WCDMA only
-         *                              1 = GSM only
-         *                              0 = GSM / WCDMA preferred
-         * @hide
-         */
-        public static final String PREFERRED_NETWORK_MODE =
-                "preferred_network_mode";
-
-        /**
          * The preferred TTY mode     0 = TTy Off, CDMA default
          *                            1 = TTY Full
          *                            2 = TTY HCO
@@ -3677,14 +3668,6 @@
                 "preferred_tty_mode";
 
         /**
-         * The cdma subscription 0 = Subscription from RUIM, when available
-         *                       1 = Subscription from NV
-         * @hide
-         */
-        public static final String PREFERRED_CDMA_SUBSCRIPTION =
-                "preferred_cdma_subscription";
-
-        /**
          * Whether the enhanced voice privacy mode is enabled.
          * 0 = normal voice privacy
          * 1 = enhanced voice privacy
@@ -5170,6 +5153,104 @@
             return BLUETOOTH_INPUT_DEVICE_PRIORITY_PREFIX + address.toUpperCase();
         }
 
+        /**
+         * Scaling factor for normal window animations. Setting to 0 will
+         * disable window animations.
+         */
+        public static final String WINDOW_ANIMATION_SCALE = "window_animation_scale";
+
+        /**
+         * Scaling factor for activity transition animations. Setting to 0 will
+         * disable window animations.
+         */
+        public static final String TRANSITION_ANIMATION_SCALE = "transition_animation_scale";
+
+        /**
+         * Scaling factor for Animator-based animations. This affects both the
+         * start delay and duration of all such animations. Setting to 0 will
+         * cause animations to end immediately. The default value is 1.
+         */
+        public static final String ANIMATOR_DURATION_SCALE = "animator_duration_scale";
+
+        /**
+         * Scaling factor for normal window animations. Setting to 0 will
+         * disable window animations.
+         *
+         * @hide
+         */
+        public static final String FANCY_IME_ANIMATIONS = "fancy_ime_animations";
+
+        /**
+         * If 0, the compatibility mode is off for all applications.
+         * If 1, older applications run under compatibility mode.
+         * TODO: remove this settings before code freeze (bug/1907571)
+         * @hide
+         */
+        public static final String COMPATIBILITY_MODE = "compatibility_mode";
+
+        /**
+         * CDMA only settings
+         * Emergency Tone  0 = Off
+         *                 1 = Alert
+         *                 2 = Vibrate
+         * @hide
+         */
+        public static final String EMERGENCY_TONE = "emergency_tone";
+
+        /**
+         * CDMA only settings
+         * Whether the auto retry is enabled. The value is
+         * boolean (1 or 0).
+         * @hide
+         */
+        public static final String CALL_AUTO_RETRY = "call_auto_retry";
+
+        /**
+         * The preferred network mode   7 = Global
+         *                              6 = EvDo only
+         *                              5 = CDMA w/o EvDo
+         *                              4 = CDMA / EvDo auto
+         *                              3 = GSM / WCDMA auto
+         *                              2 = WCDMA only
+         *                              1 = GSM only
+         *                              0 = GSM / WCDMA preferred
+         * @hide
+         */
+        public static final String PREFERRED_NETWORK_MODE =
+                "preferred_network_mode";
+
+        /**
+         * The cdma subscription 0 = Subscription from RUIM, when available
+         *                       1 = Subscription from NV
+         * @hide
+         */
+        public static final String PREFERRED_CDMA_SUBSCRIPTION =
+                "preferred_cdma_subscription";
+
+        /**
+         * Name of an application package to be debugged.
+         */
+        public static final String DEBUG_APP = "debug_app";
+
+        /**
+         * If 1, when launching DEBUG_APP it will wait for the debugger before
+         * starting user code.  If 0, it will run normally.
+         */
+        public static final String WAIT_FOR_DEBUGGER = "wait_for_debugger";
+
+        /**
+         * Control whether the process CPU usage meter should be shown.
+         */
+        public static final String SHOW_PROCESSES = "show_processes";
+
+        /**
+         * If 1, the activity manager will aggressively finish activities and
+         * processes as soon as they are no longer needed.  If 0, the normal
+         * extended lifetime is used.
+         */
+        public static final String ALWAYS_FINISH_ACTIVITIES =
+                "always_finish_activities";
+
         // Populated lazily, guarded by class object:
         private static NameValueCache sNameValueCache = new NameValueCache(
                     SYS_PROP_SETTING_VERSION,
diff --git a/core/java/android/view/Display.java b/core/java/android/view/Display.java
index cf58458..662dc45 100644
--- a/core/java/android/view/Display.java
+++ b/core/java/android/view/Display.java
@@ -79,38 +79,23 @@
     public static final int DEFAULT_DISPLAY = 0;
 
     /**
-     * Display flag: Indicates that the display supports secure video output.
+     * Display flag: Indicates that the display supports compositing content
+     * that is stored in protected graphics buffers.
      * <p>
-     * This flag is used to indicate that the display supports content protection
-     * mechanisms for secure video output at the display interface, such as HDCP.
-     * These mechanisms may be used to protect secure content as it leaves the device.
+     * Secure (DRM) video decoders may allocate protected graphics buffers to request that
+     * a hardware-protected path be provided between the video decoder and the external
+     * display sink.  If a hardware-protected path is not available, then content stored
+     * in protected graphics buffers may not be composited.
      * </p><p>
-     * While mirroring content to multiple displays, it can happen that certain
-     * display devices support secure video output while other display devices do not.
-     * The secure content will be shown only on the display devices that support
-     * secure video output and will be blanked on other display devices that do
-     * not support secure video output.
-     * </p><p>
-     * This flag mainly applies to external display devices such as HDMI or
-     * Wifi display.  Built-in display devices are usually considered secure.
+     * If this flag is not set, then the display device does not support compositing
+     * protected buffers; the user may see a blank region on the screen instead of
+     * the protected content.  An application can use this flag as a hint that it should
+     * select an alternate content stream or adopt a different strategy for decoding
+     * content that does not rely on protected buffers so as to ensure that the user
+     * can view the content on the display as expected.
      * </p>
-     *
-     * @hide pending review
      */
-    public static final int FLAG_SUPPORTS_SECURE_VIDEO_OUTPUT = 1 << 0;
-
-    /**
-     * Display flag: Indicates that the display supports secure in-memory video buffers.
-     * <p>
-     * This flag is used to indicate that the display supports content protection
-     * mechanisms for in-memory video buffers, such as secure memory areas.
-     * These mechanisms may be used to protect secure video buffers in memory from
-     * the video decoder to the display compositor and the video interface.
-     * </p>
-     *
-     * @hide pending review
-     */
-    public static final int FLAG_SUPPORTS_SECURE_VIDEO_BUFFERS = 1 << 1;
+    public static final int FLAG_SUPPORTS_PROTECTED_BUFFERS = 1 << 0;
 
     /**
      * Internal method to create a display.
@@ -196,7 +181,7 @@
      *
      * @return The display flags.
      *
-     * @hide pending review
+     * @see #FLAG_SUPPORTS_PROTECTED_BUFFERS
      */
     public int getFlags() {
         synchronized (this) {
diff --git a/core/java/android/view/DisplayInfo.java b/core/java/android/view/DisplayInfo.java
index c968ec5..fe05634 100644
--- a/core/java/android/view/DisplayInfo.java
+++ b/core/java/android/view/DisplayInfo.java
@@ -299,11 +299,8 @@
 
     private static String flagsToString(int flags) {
         StringBuilder result = new StringBuilder();
-        if ((flags & Display.FLAG_SUPPORTS_SECURE_VIDEO_OUTPUT) != 0) {
-            result.append(", FLAG_SUPPORTS_SECURE_VIDEO_OUTPUT");
-        }
-        if ((flags & Display.FLAG_SUPPORTS_SECURE_VIDEO_BUFFERS) != 0) {
-            result.append(", FLAG_SUPPORTS_SECURE_VIDEO_BUFFERS");
+        if ((flags & Display.FLAG_SUPPORTS_PROTECTED_BUFFERS) != 0) {
+            result.append(", FLAG_SUPPORTS_PROTECTED_BUFFERS");
         }
         return result.toString();
     }
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index 63ec577..2d083b6 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -5871,6 +5871,8 @@
                     ((layoutDirection << PFLAG2_LAYOUT_DIRECTION_MASK_SHIFT) & PFLAG2_LAYOUT_DIRECTION_MASK);
             // We need to resolve all RTL properties as they all depend on layout direction
             resolveRtlPropertiesIfNeeded();
+            requestLayout();
+            invalidate(true);
         }
     }
 
@@ -6466,11 +6468,6 @@
             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();
@@ -11573,8 +11570,6 @@
         if (!isDrawablesResolved()) {
             resolveDrawables();
         }
-        requestLayout();
-        invalidate(true);
         onRtlPropertiesChanged(getLayoutDirection());
     }
 
diff --git a/core/java/android/widget/AbsListView.java b/core/java/android/widget/AbsListView.java
index 7f0af09..871f752 100644
--- a/core/java/android/widget/AbsListView.java
+++ b/core/java/android/widget/AbsListView.java
@@ -1055,30 +1055,30 @@
 
             if (mChoiceMode == CHOICE_MODE_MULTIPLE ||
                     (mChoiceMode == CHOICE_MODE_MULTIPLE_MODAL && mChoiceActionMode != null)) {
-                boolean newValue = !mCheckStates.get(position, false);
-                mCheckStates.put(position, newValue);
+                boolean checked = !mCheckStates.get(position, false);
+                mCheckStates.put(position, checked);
                 if (mCheckedIdStates != null && mAdapter.hasStableIds()) {
-                    if (newValue) {
+                    if (checked) {
                         mCheckedIdStates.put(mAdapter.getItemId(position), position);
                     } else {
                         mCheckedIdStates.delete(mAdapter.getItemId(position));
                     }
                 }
-                if (newValue) {
+                if (checked) {
                     mCheckedItemCount++;
                 } else {
                     mCheckedItemCount--;
                 }
                 if (mChoiceActionMode != null) {
                     mMultiChoiceModeCallback.onItemCheckedStateChanged(mChoiceActionMode,
-                            position, id, newValue);
+                            position, id, checked);
                     dispatchItemClick = false;
                 }
                 checkedStateChanged = true;
             } else if (mChoiceMode == CHOICE_MODE_SINGLE) {
-                boolean newValue = !mCheckStates.get(position, false);
-                if (newValue) {
-                    mCheckStates.clear();
+                boolean checked = !mCheckStates.get(position, false);
+                mCheckStates.clear();
+                if (checked) {
                     mCheckStates.put(position, true);
                     if (mCheckedIdStates != null && mAdapter.hasStableIds()) {
                         mCheckedIdStates.clear();
diff --git a/core/java/com/android/internal/widget/LockPatternUtils.java b/core/java/com/android/internal/widget/LockPatternUtils.java
index 84e1d95..f987fc5 100644
--- a/core/java/com/android/internal/widget/LockPatternUtils.java
+++ b/core/java/com/android/internal/widget/LockPatternUtils.java
@@ -125,7 +125,9 @@
     private final ContentResolver mContentResolver;
     private DevicePolicyManager mDevicePolicyManager;
     private ILockSettings mLockSettingsService;
-    private int mCurrentUserId = UserHandle.USER_NULL;
+
+    // The current user is set by KeyguardViewMediator and shared by all LockPatternUtils.
+    private static volatile int sCurrentUserId = UserHandle.USER_NULL;
 
     public DevicePolicyManager getDevicePolicyManager() {
         if (mDevicePolicyManager == null) {
@@ -215,13 +217,13 @@
     }
 
     public void setCurrentUser(int userId) {
-        mCurrentUserId = userId;
+        sCurrentUserId = userId;
     }
 
     public int getCurrentUser() {
-        if (mCurrentUserId != UserHandle.USER_NULL) {
+        if (sCurrentUserId != UserHandle.USER_NULL) {
             // Someone is regularly updating using setCurrentUser() use that value.
-            return mCurrentUserId;
+            return sCurrentUserId;
         }
         try {
             return ActivityManagerNative.getDefault().getCurrentUser().id;
diff --git a/core/jni/android/graphics/TextLayoutCache.cpp b/core/jni/android/graphics/TextLayoutCache.cpp
index ba8cea4..4669c37 100644
--- a/core/jni/android/graphics/TextLayoutCache.cpp
+++ b/core/jni/android/graphics/TextLayoutCache.cpp
@@ -111,7 +111,7 @@
 
         // Compute advances and store them
         mShaper->computeValues(value.get(), paint,
-                reinterpret_cast<const UChar*>(text), start, count,
+                reinterpret_cast<const UChar*>(key.getText()), start, count,
                 size_t(contextCount), int(dirFlags));
 
         if (mDebugEnabled) {
@@ -139,15 +139,12 @@
             // Update current cache size
             mSize += size;
 
-            // Copy the text when we insert the new entry
-            key.internalTextCopy();
-
             bool putOne = mCache.put(key, value);
             LOG_ALWAYS_FATAL_IF(!putOne, "Failed to put an entry into the cache.  "
                     "This indicates that the cache already has an entry with the "
                     "same key but it should not since we checked earlier!"
                     " - start = %d, count = %d, contextCount = %d - Text = '%s'",
-                    start, count, contextCount, String8(text + start, count).string());
+                    start, count, contextCount, String8(key.getText() + start, count).string());
 
             if (mDebugEnabled) {
                 nsecs_t totalTime = systemTime(SYSTEM_TIME_MONOTONIC) - startTime;
@@ -158,7 +155,7 @@
                         value.get(), start, count, contextCount, size, mMaxSize - mSize,
                         value->getElapsedTime() * 0.000001f,
                         (totalTime - value->getElapsedTime()) * 0.000001f,
-                        String8(text + start, count).string());
+                        String8(key.getText() + start, count).string());
             }
         } else {
             if (mDebugEnabled) {
@@ -168,7 +165,7 @@
                         " - Compute time %0.6f ms - Text = '%s'",
                         start, count, contextCount, size, mMaxSize - mSize,
                         value->getElapsedTime() * 0.000001f,
-                        String8(text + start, count).string());
+                        String8(key.getText() + start, count).string());
             }
         }
     } else {
@@ -188,7 +185,7 @@
                         value->getElapsedTime() * 0.000001f,
                         elapsedTimeThruCacheGet * 0.000001f,
                         deltaPercent,
-                        String8(text + start, count).string());
+                        String8(key.getText() + start, count).string());
             }
             if (mCacheHitCount % DEFAULT_DUMP_STATS_CACHE_HIT_INTERVAL == 0) {
                 dumpCacheStats();
@@ -225,15 +222,16 @@
 /**
  * TextLayoutCacheKey
  */
-TextLayoutCacheKey::TextLayoutCacheKey(): text(NULL), start(0), count(0), contextCount(0),
+TextLayoutCacheKey::TextLayoutCacheKey(): start(0), count(0), contextCount(0),
         dirFlags(0), typeface(NULL), textSize(0), textSkewX(0), textScaleX(0), flags(0),
         hinting(SkPaint::kNo_Hinting), variant(SkPaint::kDefault_Variant), language()  {
 }
 
 TextLayoutCacheKey::TextLayoutCacheKey(const SkPaint* paint, const UChar* text,
         size_t start, size_t count, size_t contextCount, int dirFlags) :
-            text(text), start(start), count(count), contextCount(contextCount),
+            start(start), count(count), contextCount(contextCount),
             dirFlags(dirFlags) {
+    textCopy.setTo(text, contextCount);
     typeface = paint->getTypeface();
     textSize = paint->getTextSize();
     textSkewX = paint->getTextSkewX();
@@ -245,7 +243,6 @@
 }
 
 TextLayoutCacheKey::TextLayoutCacheKey(const TextLayoutCacheKey& other) :
-        text(NULL),
         textCopy(other.textCopy),
         start(other.start),
         count(other.count),
@@ -259,9 +256,6 @@
         hinting(other.hinting),
         variant(other.variant),
         language(other.language) {
-    if (other.text) {
-        textCopy.setTo(other.text, other.contextCount);
-    }
 }
 
 int TextLayoutCacheKey::compare(const TextLayoutCacheKey& lhs, const TextLayoutCacheKey& rhs) {
@@ -304,11 +298,6 @@
     return memcmp(lhs.getText(), rhs.getText(), lhs.contextCount * sizeof(UChar));
 }
 
-void TextLayoutCacheKey::internalTextCopy() {
-    textCopy.setTo(text, contextCount);
-    text = NULL;
-}
-
 size_t TextLayoutCacheKey::getSize() const {
     return sizeof(TextLayoutCacheKey) + sizeof(UChar) * contextCount;
 }
diff --git a/core/jni/android/graphics/TextLayoutCache.h b/core/jni/android/graphics/TextLayoutCache.h
index 1f4e22c..9994393 100644
--- a/core/jni/android/graphics/TextLayoutCache.h
+++ b/core/jni/android/graphics/TextLayoutCache.h
@@ -77,20 +77,15 @@
     TextLayoutCacheKey(const TextLayoutCacheKey& other);
 
     /**
-     * We need to copy the text when we insert the key into the cache itself.
-     * We don't need to copy the text when we are only comparing keys.
-     */
-    void internalTextCopy();
-
-    /**
      * Get the size of the Cache key.
      */
     size_t getSize() const;
 
     static int compare(const TextLayoutCacheKey& lhs, const TextLayoutCacheKey& rhs);
 
+    inline const UChar* getText() const { return textCopy.string(); }
+
 private:
-    const UChar* text; // if text is NULL, use textCopy
     String16 textCopy;
     size_t start;
     size_t count;
@@ -105,8 +100,6 @@
     SkPaint::FontVariant variant;
     SkLanguage language;
 
-    inline const UChar* getText() const { return text ? text : textCopy.string(); }
-
 }; // TextLayoutCacheKey
 
 inline int strictly_order_type(const TextLayoutCacheKey& lhs, const TextLayoutCacheKey& rhs) {
@@ -316,6 +309,12 @@
     TextLayoutEngine();
     virtual ~TextLayoutEngine();
 
+    /**
+     * Note: this method currently does a defensive copy of the text argument, in case
+     * there is concurrent mutation of it. The contract may change, and may in the
+     * future require the caller to guarantee that the contents will not change during
+     * the call. Be careful of this when doing optimization.
+     **/
     sp<TextLayoutValue> getValue(const SkPaint* paint, const jchar* text, jint start,
             jint count, jint contextCount, jint dirFlags);
 
diff --git a/core/res/res/drawable-hdpi/stat_notify_rssi_in_range.png b/core/res/res/drawable-hdpi/stat_notify_rssi_in_range.png
new file mode 100644
index 0000000..74977e6
--- /dev/null
+++ b/core/res/res/drawable-hdpi/stat_notify_rssi_in_range.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/stat_notify_rssi_in_range.png b/core/res/res/drawable-mdpi/stat_notify_rssi_in_range.png
new file mode 100644
index 0000000..62e4fe9
--- /dev/null
+++ b/core/res/res/drawable-mdpi/stat_notify_rssi_in_range.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/stat_notify_rssi_in_range.png b/core/res/res/drawable-xhdpi/stat_notify_rssi_in_range.png
new file mode 100644
index 0000000..c0586d8
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/stat_notify_rssi_in_range.png
Binary files differ
diff --git a/core/res/res/layout-land/keyguard_host_view.xml b/core/res/res/layout-land/keyguard_host_view.xml
index 18e23f0..ac943cb 100644
--- a/core/res/res/layout-land/keyguard_host_view.xml
+++ b/core/res/res/layout-land/keyguard_host_view.xml
@@ -28,17 +28,16 @@
     android:orientation="horizontal">
 
     <include layout="@layout/keyguard_widget_region"
-        android:layout_width="0dip"
-        android:layout_height="230dip"
-        android:layout_weight=".45"/>
+        android:layout_width="0dp"
+        android:layout_weight=".45" />
 
     <com.android.internal.policy.impl.keyguard.KeyguardSecurityViewFlipper
         android:id="@+id/view_flipper"
-        android:layout_width="0dip"
+        android:layout_width="0dp"
         android:layout_height="match_parent"
         android:layout_weight="0.55"
-        android:layout_marginLeft="8dip"
-        android:layout_marginRight="8dip"
+        android:layout_marginLeft="8dp"
+        android:layout_marginRight="8dp"
         android:gravity="center">
 
         <!-- SelectorView is always used, so add it here. The rest are loaded dynamically -->
diff --git a/core/res/res/layout/keyguard_multi_user_avatar.xml b/core/res/res/layout/keyguard_multi_user_avatar.xml
index a3621c0..df3ee00 100644
--- a/core/res/res/layout/keyguard_multi_user_avatar.xml
+++ b/core/res/res/layout/keyguard_multi_user_avatar.xml
@@ -37,4 +37,4 @@
         android:textSize="12sp"
         android:background="#99FFFFFF"
         android:textColor="#ff000000"/>
-</com.android.internal.policy.impl.keyguard.KeyguardMultiUserAvatar>
\ No newline at end of file
+</com.android.internal.policy.impl.keyguard.KeyguardMultiUserAvatar>
diff --git a/core/res/res/layout/keyguard_multi_user_selector.xml b/core/res/res/layout/keyguard_multi_user_selector.xml
index c599fd5dd..5a6e998 100644
--- a/core/res/res/layout/keyguard_multi_user_selector.xml
+++ b/core/res/res/layout/keyguard_multi_user_selector.xml
@@ -21,7 +21,8 @@
     android:orientation="horizontal"
     android:layout_width="match_parent"
     android:layout_height="match_parent"
-    android:layout_gravity="center">
+    android:layout_gravity="center"
+    android:contentDescription="@string/keyguard_accessibility_user_selector">
 
     <com.android.internal.policy.impl.keyguard.KeyguardSubdivisionLayout
         android:id="@+id/keyguard_users_grid"
diff --git a/core/res/res/layout/keyguard_selector_view.xml b/core/res/res/layout/keyguard_selector_view.xml
index 710a78e..8ef3b75 100644
--- a/core/res/res/layout/keyguard_selector_view.xml
+++ b/core/res/res/layout/keyguard_selector_view.xml
@@ -29,10 +29,7 @@
     <include layout="@layout/keyguard_widget_region"
         android:layout_width="match_parent"
         android:layout_height="0dip"
-        android:layout_weight="0.45"
-        android:layout_marginTop="35dip"
-        android:layout_marginLeft="33dip"
-        android:layout_marginRight="33dip"/>
+        android:layout_weight="0.45" />
 
     <RelativeLayout
         android:layout_width="wrap_content"
diff --git a/core/res/res/layout/keyguard_status_view.xml b/core/res/res/layout/keyguard_status_view.xml
index d8adc93..c7f6863 100644
--- a/core/res/res/layout/keyguard_status_view.xml
+++ b/core/res/res/layout/keyguard_status_view.xml
@@ -20,16 +20,17 @@
 <!-- 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:id="@+id/keyguard_status_view"
     android:layout_width="wrap_content"
     android:layout_height="wrap_content"
-    android:id="@+id/keyguard_status_view"
     android:gravity="center_horizontal">
 
     <com.android.internal.policy.impl.keyguard.KeyguardStatusView
         android:orientation="vertical"
         android:layout_width="match_parent"
         android:layout_height="match_parent"
-        android:gravity="center_horizontal">
+        android:gravity="center_horizontal"
+        android:contentDescription="@string/keyguard_accessibility_status">
 
         <com.android.internal.policy.impl.keyguard.ClockView
             android:id="@+id/clock_view"
diff --git a/core/res/res/layout/keyguard_transport_control_view.xml b/core/res/res/layout/keyguard_transport_control_view.xml
index c40aa66..5a6083a 100644
--- a/core/res/res/layout/keyguard_transport_control_view.xml
+++ b/core/res/res/layout/keyguard_transport_control_view.xml
@@ -26,7 +26,8 @@
     <FrameLayout
         android:layout_width="match_parent"
         android:layout_height="match_parent"
-        android:foreground="@drawable/ic_lockscreen_player_background">
+        android:foreground="@drawable/ic_lockscreen_player_background"
+        android:contentDescription="@string/keygaurd_accessibility_media_controls">
         <!-- Use ImageView for its cropping features; otherwise could be android:background -->
         <ImageView
             android:id="@+id/albumart"
diff --git a/core/res/res/layout/keyguard_widget_region.xml b/core/res/res/layout/keyguard_widget_region.xml
index 123d105..7bf06ed 100644
--- a/core/res/res/layout/keyguard_widget_region.xml
+++ b/core/res/res/layout/keyguard_widget_region.xml
@@ -25,44 +25,45 @@
         android:visibility="gone"
         android:gravity="center"
         android:orientation="vertical">
-    <Space
-        android:layout_width="match_parent"
-        android:layout_height="0dip"
-        android:layout_weight="1" />
     <com.android.internal.policy.impl.keyguard.KeyguardWidgetPager
         android:id="@+id/app_widget_container"
         android:layout_width="match_parent"
-        android:layout_height="@dimen/kg_widget_container_height">
-            <!-- TODO: Remove this when supported as a widget -->
-            <include layout="@layout/keyguard_status_view"/>
-            <include layout="@layout/keyguard_transport_control_view"/>
+        android:layout_height="0dp"
+        android:layout_weight="1"
+        android:clipChildren="false"
+        android:clipToPadding="false">
     </com.android.internal.policy.impl.keyguard.KeyguardWidgetPager>
     <LinearLayout
         android:layout_width="match_parent"
-        android:layout_height="0dip"
-        android:layout_weight="1"
-        android:orientation="horizontal">
+        android:layout_height="10dp"
+        android:orientation="horizontal"
+        android:paddingLeft="@dimen/kg_widget_pager_horizontal_padding"
+        android:paddingRight="@dimen/kg_widget_pager_horizontal_padding">
         <com.android.internal.policy.impl.keyguard.KeyguardGlowStripView
             android:id="@+id/left_strip"
-            android:layout_width="0dip"
+            android:paddingTop="@dimen/kg_runway_lights_vertical_padding"
+            android:paddingBottom="@dimen/kg_runway_lights_vertical_padding"
+            android:layout_width="0dp"
             android:layout_height="match_parent"
             android:layout_weight="1"
             prvandroid:numDots="5"
-            prvandroid:dotSize="7dip"
+            prvandroid:dotSize="@dimen/kg_runway_lights_height"
             prvandroid:leftToRight="false"
             prvandroid:glowDot="@*android:drawable/ic_lockscreen_glowdot" />
         <Space
-            android:layout_width="0dip"
+            android:layout_width="0dp"
             android:layout_height="match_parent"
             android:layout_weight="1.6"/>
         <com.android.internal.policy.impl.keyguard.KeyguardGlowStripView
             android:id="@+id/right_strip"
-            android:layout_width="0dip"
+            android:paddingTop="@dimen/kg_runway_lights_vertical_padding"
+            android:paddingBottom="@dimen/kg_runway_lights_vertical_padding"
+            android:layout_width="0dp"
             android:layout_height="match_parent"
             android:layout_weight="1"
             prvandroid:numDots="5"
-            prvandroid:dotSize="7dip"
+            prvandroid:dotSize="@dimen/kg_runway_lights_height"
             prvandroid:leftToRight="true"
             prvandroid:glowDot="@*android:drawable/ic_lockscreen_glowdot" />
     </LinearLayout>
-</com.android.internal.policy.impl.keyguard.KeyguardWidgetRegion>
\ No newline at end of file
+</com.android.internal.policy.impl.keyguard.KeyguardWidgetRegion>
diff --git a/core/res/res/values-mcc310/config.xml b/core/res/res/values-mcc310/config.xml
new file mode 100644
index 0000000..df398f9
--- /dev/null
+++ b/core/res/res/values-mcc310/config.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+** 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.
+*/
+-->
+
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+
+    <!-- Whether safe headphone volume is enabled or not (country specific). -->
+    <bool name="config_safe_media_volume_enabled">false</bool>
+
+</resources>
diff --git a/core/res/res/values-mcc311/config.xml b/core/res/res/values-mcc311/config.xml
new file mode 100644
index 0000000..df398f9
--- /dev/null
+++ b/core/res/res/values-mcc311/config.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+** 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.
+*/
+-->
+
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+
+    <!-- Whether safe headphone volume is enabled or not (country specific). -->
+    <bool name="config_safe_media_volume_enabled">false</bool>
+
+</resources>
diff --git a/core/res/res/values-mcc312/config.xml b/core/res/res/values-mcc312/config.xml
new file mode 100644
index 0000000..df398f9
--- /dev/null
+++ b/core/res/res/values-mcc312/config.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+** 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.
+*/
+-->
+
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+
+    <!-- Whether safe headphone volume is enabled or not (country specific). -->
+    <bool name="config_safe_media_volume_enabled">false</bool>
+
+</resources>
diff --git a/core/res/res/values-mcc313/config.xml b/core/res/res/values-mcc313/config.xml
new file mode 100644
index 0000000..df398f9
--- /dev/null
+++ b/core/res/res/values-mcc313/config.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+** 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.
+*/
+-->
+
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+
+    <!-- Whether safe headphone volume is enabled or not (country specific). -->
+    <bool name="config_safe_media_volume_enabled">false</bool>
+
+</resources>
diff --git a/core/res/res/values-mcc314/config.xml b/core/res/res/values-mcc314/config.xml
new file mode 100644
index 0000000..df398f9
--- /dev/null
+++ b/core/res/res/values-mcc314/config.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+** 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.
+*/
+-->
+
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+
+    <!-- Whether safe headphone volume is enabled or not (country specific). -->
+    <bool name="config_safe_media_volume_enabled">false</bool>
+
+</resources>
diff --git a/core/res/res/values-mcc315/config.xml b/core/res/res/values-mcc315/config.xml
new file mode 100644
index 0000000..df398f9
--- /dev/null
+++ b/core/res/res/values-mcc315/config.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+** 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.
+*/
+-->
+
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+
+    <!-- Whether safe headphone volume is enabled or not (country specific). -->
+    <bool name="config_safe_media_volume_enabled">false</bool>
+
+</resources>
diff --git a/core/res/res/values-mcc316/config.xml b/core/res/res/values-mcc316/config.xml
new file mode 100644
index 0000000..df398f9
--- /dev/null
+++ b/core/res/res/values-mcc316/config.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+** 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.
+*/
+-->
+
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+
+    <!-- Whether safe headphone volume is enabled or not (country specific). -->
+    <bool name="config_safe_media_volume_enabled">false</bool>
+
+</resources>
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index f143d50..16960c8 100755
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -964,4 +964,21 @@
          on the headphone/microphone jack. When false use the older uevent framework. -->
     <bool name="config_useDevInputEventForAudioJack">false</bool>
 
+    <!-- Whether safe headphone volume is enabled or not (country specific). -->
+    <bool name="config_safe_media_volume_enabled">true</bool>
+
+    <!-- Set to true if the wifi display supports compositing content stored
+         in gralloc protected buffers.  For this to be true, there must exist
+         a protected hardware path for surface flinger to composite and send
+         protected buffers to the wifi display video encoder.
+
+         If this flag is false, we advise applications not to use protected
+         buffers (if possible) when presenting content to a wifi display because
+         the content may be blanked.
+
+         This flag controls whether the {@link Display#FLAG_SUPPORTS_PROTECTED_BUFFERS}
+         flag is set for wifi displays.
+    -->
+    <bool name="config_wifiDisplaySupportsProtectedBuffers">false</bool>
+
 </resources>
diff --git a/core/res/res/values/dimens.xml b/core/res/res/values/dimens.xml
index 01a35b0..289adf4 100644
--- a/core/res/res/values/dimens.xml
+++ b/core/res/res/values/dimens.xml
@@ -254,9 +254,6 @@
     <!-- Height of widget view in keyguard. -->
     <dimen name="kg_widget_view_height">0dp</dimen>
 
-    <!-- Padding surrounding each widget page -->
-    <dimen name="kg_widget_page_padding">10dp</dimen>
-
     <!-- Size of the clock font in keyguard's status view -->
     <dimen name="kg_status_clock_font_size">94dp</dimen>
 
@@ -285,8 +282,20 @@
     <!-- Space reserved at the bottom of secure views (pin/pattern/password/SIM pin/SIM puk) -->
     <dimen name="kg_secure_padding_height">46dp</dimen>
 
-    <!-- The height of the widget container -->
-    <dimen name="kg_widget_container_height">200dp</dimen>
+    <!-- The height of the runway lights strip -->
+    <dimen name="kg_runway_lights_height">7dp</dimen>
+
+    <!-- The height of the runway lights strip -->
+    <dimen name="kg_runway_lights_vertical_padding">3dp</dimen>
+
+    <!-- Horizontal padding for the widget pager -->
+    <dimen name="kg_widget_pager_horizontal_padding">16dp</dimen>
+
+    <!-- Top padding for the widget pager -->
+    <dimen name="kg_widget_pager_top_padding">16dp</dimen>
+
+    <!-- Bottom padding for the widget pager -->
+    <dimen name="kg_widget_pager_bottom_padding">6dp</dimen>
 
     <!-- Touch slop for the global toggle accessibility gesture -->
     <dimen name="accessibility_touch_slop">80dip</dimen>
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index 2f9ce0c..fb8005a 100755
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -2272,6 +2272,15 @@
     <!-- Accessibility description sent when user completes drawing a pattern. [CHAR LIMIT=NONE] -->
     <string name="lockscreen_access_pattern_detected">Pattern completed</string>
 
+    <!-- Accessibility description sent when user changes the current lock screen widget. [CHAR_LIMIT=none] -->
+    <string name="keyguard_accessibility_widget_changed">%1$s. Widget %2$d of %3$d.</string>
+    <!-- Accessibility description of the lock screen user selector widget. [CHAR_LIMIT=none] -->
+    <string name="keyguard_accessibility_user_selector">User selector</string>
+    <!-- Accessibility description of the lock screen status widget. [CHAR_LIMIT=none] -->
+    <string name="keyguard_accessibility_status">Status</string>
+    <!-- Accessibility description of the lock media control widget. [CHAR_LIMIT=none] -->
+    <string name="keygaurd_accessibility_media_controls">Media controls</string>
+
     <!-- Password keyboard strings. Used by LockScreen and Settings --><skip />
     <!-- Label for "switch to symbols" key.  Must be short to fit on key! -->
     <string name="password_keyboard_label_symbol_key">\?123</string>
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index 0b30324..8ac0ad5 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -261,6 +261,7 @@
   <java-symbol type="bool" name="config_ui_enableFadingMarquee" />
   <java-symbol type="bool" name="config_use_strict_phone_number_comparation" />
   <java-symbol type="bool" name="config_voice_capable" />
+  <java-symbol type="bool" name="config_wifiDisplaySupportsProtectedBuffers" />
   <java-symbol type="bool" name="preferences_prefer_dual_pane" />
   <java-symbol type="bool" name="skip_restoring_network_selection" />
   <java-symbol type="bool" name="split_action_bar_is_narrow" />
@@ -272,7 +273,8 @@
   <java-symbol type="bool" name="config_bluetooth_default_profiles" />
   <java-symbol type="bool" name="config_enableWifiDisplay" />
   <java-symbol type="bool" name="config_useDevInputEventForAudioJack" />
-  
+  <java-symbol type="bool" name="config_safe_media_volume_enabled" />
+
   <java-symbol type="integer" name="config_cursorWindowSize" />
   <java-symbol type="integer" name="config_longPressOnPowerBehavior" />
   <java-symbol type="integer" name="config_max_pan_devices" />
@@ -547,6 +549,10 @@
   <java-symbol type="string" name="keyboardview_keycode_enter" />
   <java-symbol type="string" name="keyboardview_keycode_mode_change" />
   <java-symbol type="string" name="keyboardview_keycode_shift" />
+  <java-symbol type="string" name="keygaurd_accessibility_media_controls" />
+  <java-symbol type="string" name="keyguard_accessibility_status" />
+  <java-symbol type="string" name="keyguard_accessibility_user_selector" />
+  <java-symbol type="string" name="keyguard_accessibility_widget_changed" />
   <java-symbol type="string" name="kilobyteShort" />
   <java-symbol type="string" name="last_month" />
   <java-symbol type="string" name="launchBrowserDefault" />
@@ -947,6 +953,7 @@
   <java-symbol type="drawable" name="platlogo_alt" />
   <java-symbol type="drawable" name="stat_notify_sync_error" />
   <java-symbol type="drawable" name="stat_notify_wifi_in_range" />
+  <java-symbol type="drawable" name="stat_notify_rssi_in_range" />
   <java-symbol type="drawable" name="stat_sys_gps_on" />
   <java-symbol type="drawable" name="stat_sys_tether_wifi" />
   <java-symbol type="drawable" name="status_bar_background" />
@@ -1096,6 +1103,7 @@
   <java-symbol type="xml" name="kg_password_kbd_numeric" />
   <java-symbol type="xml" name="power_profile" />
   <java-symbol type="xml" name="time_zones_by_country" />
+  <java-symbol type="xml" name="sms_short_codes" />
 
   <java-symbol type="raw" name="accessibility_gestures" />
   <java-symbol type="raw" name="incognito_mode_start_page" />
@@ -1184,7 +1192,9 @@
   <java-symbol type="dimen" name="navigation_bar_height_landscape" />
   <java-symbol type="dimen" name="navigation_bar_width" />
   <java-symbol type="dimen" name="status_bar_height" />
-  <java-symbol type="dimen" name="kg_widget_page_padding" />
+  <java-symbol type="dimen" name="kg_widget_pager_horizontal_padding" />
+  <java-symbol type="dimen" name="kg_widget_pager_top_padding" />
+  <java-symbol type="dimen" name="kg_widget_pager_bottom_padding" />
   <java-symbol type="drawable" name="ic_jog_dial_sound_off" />
   <java-symbol type="drawable" name="ic_jog_dial_sound_on" />
   <java-symbol type="drawable" name="ic_jog_dial_unlock" />
@@ -1327,6 +1337,8 @@
   <java-symbol type="layout" name="screen_title" />
   <java-symbol type="layout" name="screen_title_icons" />
   <java-symbol type="layout" name="keyguard_host_view" />
+  <java-symbol type="layout" name="keyguard_transport_control_view" />
+  <java-symbol type="layout" name="keyguard_status_view" />
   <java-symbol type="string" name="abbrev_wday_month_day_no_year" />
   <java-symbol type="string" name="android_upgrading_title" />
   <java-symbol type="string" name="bugreport_title" />
diff --git a/core/res/res/xml/sms_short_codes.xml b/core/res/res/xml/sms_short_codes.xml
new file mode 100644
index 0000000..8b395af
--- /dev/null
+++ b/core/res/res/xml/sms_short_codes.xml
@@ -0,0 +1,189 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+** 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.
+*/
+-->
+
+<!-- Regex patterns for SMS short codes by country. -->
+<shortcodes>
+
+    <!-- The country attribute is the ISO country code of the user's account (from SIM card or NV).
+         The pattern attribute is a regex that matches all SMS short codes for the country.
+         The premium attribute is a regex that matches premium rate SMS short codes.
+         The free attribute matches short codes that we know will not cost the user, such as
+         emergency numbers. The standard attribute matches short codes that are billed at the
+         standard SMS rate. The user is warned when the destination phone number matches the
+         "pattern" or "premium" regexes, and does not match the "free" or "standard" regexes. -->
+
+    <!-- Harmonised European Short Codes are 6 digit numbers starting with 116 (free helplines).
+         Premium patterns include short codes from: http://aonebill.com/coverage&tariffs
+         and http://mobilcent.com/info-worldwide.asp and extracted from:
+         http://smscoin.net/software/engine/WordPress/Paid+SMS-registration/ -->
+
+    <!-- Albania: 5 digits, known short codes listed -->
+    <shortcode country="al" pattern="\\d{5}" premium="15191|55[56]00" />
+
+    <!-- Armenia: 3-4 digits, emergency numbers 10[123] -->
+    <shortcode country="am" pattern="\\d{3,4}" premium="11[2456]1|3024" free="10[123]" />
+
+    <!-- Austria: 10 digits, premium prefix 09xx, plus EU -->
+    <shortcode country="at" pattern="11\\d{4}" premium="09.*" free="116\\d{3}" />
+
+    <!-- Australia: 6 or 8 digits starting with "19" -->
+    <shortcode country="au" pattern="19(?:\\d{4}|\\d{6})" premium="19998882" />
+
+    <!-- Azerbaijan: 4-5 digits, known premium codes listed -->
+    <shortcode country="az" pattern="\\d{4,5}" premium="330[12]|87744|901[234]|93(?:94|101)|9426|9525" />
+
+    <!-- Belgium: 4 digits, plus EU: http://www.mobileweb.be/en/mobileweb/sms-numberplan.asp -->
+    <shortcode country="be" premium="\\d{4}" free="8\\d{3}|116\\d{3}" />
+
+    <!-- Bulgaria: 4-5 digits, plus EU -->
+    <shortcode country="bg" pattern="\\d{4,5}" premium="18(?:16|423)|19(?:1[56]|35)" free="116\\d{3}" />
+
+    <!-- Belarus: 4 digits -->
+    <shortcode country="by" pattern="\\d{4}" premium="3336|4161|444[4689]|501[34]|7781" />
+
+    <!-- Canada: 5-6 digits -->
+    <shortcode country="ca" pattern="\\d{5,6}" premium="60999|88188" />
+
+    <!-- Switzerland: 3-5 digits: http://www.swisscom.ch/fxres/kmu/thirdpartybusiness_code_of_conduct_en.pdf -->
+    <shortcode country="ch" pattern="[2-9]\\d{2,4}" premium="543|83111" />
+
+    <!-- China: premium shortcodes start with "1066", free shortcodes start with "1065":
+         http://clients.txtnation.com/entries/197192-china-premium-sms-short-code-requirements -->
+    <shortcode country="cn" premium="1066.*" free="1065.*" />
+
+    <!-- Cyprus: 4-6 digits (not confirmed), known premium codes listed, plus EU -->
+    <shortcode country="cy" pattern="\\d{4,6}" premium="7510" free="116\\d{3}" />
+
+    <!-- Czech Republic: 7-8 digits, starting with 9, plus EU:
+         http://www.o2.cz/osobni/en/services-by-alphabet/91670-premium_sms.html -->
+    <shortcode country="cz" premium="9\\d{6,7}" free="116\\d{3}" />
+
+    <!-- Germany: 4-5 digits plus 1232xxx (premium codes from http://www.vodafone.de/infofaxe/537.pdf and http://premiumdienste.eplus.de/pdf/kodex.pdf), plus EU. To keep the premium regex from being too large, it only includes payment processors that have been used by SMS malware, with the regular pattern matching the other premium short codes. -->
+    <shortcode country="de" pattern="\\d{4,5}|1232\\d{3}" premium="11(?:111|833)|1232(?:013|021|060|075|286|358)|118(?:44|80|86)|20[25]00|220(?:21|22|88|99)|221(?:14|21)|223(?:44|53|77)|224[13]0|225(?:20|59|90)|226(?:06|10|20|26|30|40|56|70)|227(?:07|33|39|66|76|78|79|88|99)|228(?:08|11|66|77)|23300|30030|3[12347]000|330(?:33|55|66)|33(?:233|331|366|533)|34(?:34|567)|37000|40(?:040|123|444|[3568]00)|41(?:010|414)|44(?:000|044|344|44[24]|544)|50005|50100|50123|50555|51000|52(?:255|783)|54(?:100|2542)|55(?:077|[24]00|222|333|55|[12369]55)|56(?:789|886)|60800|6[13]000|66(?:[12348]66|566|766|777|88|999)|68888|70(?:07|123|777)|76766|77(?:007|070|222|444|[567]77)|80(?:008|123|888)|82(?:002|[378]00|323|444|472|474|488|727)|83(?:005|[169]00|333|830)|84(?:141|300|32[34]|343|488|499|777|888)|85888|86(?:188|566|640|644|650|677|868|888)|870[24]9|871(?:23|[49]9)|872(?:1[0-8]|49|99)|87499|875(?:49|55|99)|876(?:0[1367]|1[1245678]|54|99)|877(?:00|99)|878(?:15|25|3[567]|8[12])|87999|880(?:08|44|55|77|99)|88688|888(?:03|10|8|89)|8899|90(?:009|999)|99999" free="116\\d{3}" />
+
+    <!-- Denmark: see http://iprs.webspacecommerce.com/Denmark-Premium-Rate-Numbers -->
+    <shortcode country="dk" pattern="\\d{4,5}" premium="1\\d{3}" free="116\\d{3}" />
+
+    <!-- Estonia: short codes 3-5 digits starting with 1, plus premium 7 digit numbers starting with 90, plus EU.
+         http://www.tja.ee/public/documents/Elektrooniline_side/Oigusaktid/ENG/Estonian_Numbering_Plan_annex_06_09_2010.mht -->
+    <shortcode country="ee" pattern="1\\d{2,4}" premium="90\\d{5}|15330|1701[0-3]" free="116\\d{3}" />
+
+    <!-- Spain: 5-6 digits: 25xxx, 27xxx, 280xx, 35xxx, 37xxx, 795xxx, 797xxx, 995xxx, 997xxx, plus EU.
+         http://www.legallink.es/?q=en/content/which-current-regulatory-status-premium-rate-services-spain -->
+    <shortcode country="es" premium="[23][57]\\d{3}|280\\d{2}|[79]9[57]\\d{3}" free="116\\d{3}" />
+
+    <!-- Finland: 5-6 digits, premium 0600, 0700: http://en.wikipedia.org/wiki/Telephone_numbers_in_Finland -->
+    <shortcode country="fi" pattern="\\d{5,6}" premium="0600.*|0700.*|171(?:59|63)" free="116\\d{3}" />
+
+    <!-- France: 5 digits, free: 3xxxx, premium [4-8]xxxx, plus EU:
+         http://clients.txtnation.com/entries/161972-france-premium-sms-short-code-requirements -->
+    <shortcode country="fr" premium="[4-8]\\d{4}" free="3\\d{4}|116\\d{3}" />
+
+    <!-- United Kingdom (Great Britain): 4-6 digits, common codes [5-8]xxxx, plus EU:
+         http://www.short-codes.com/media/Co-regulatoryCodeofPracticeforcommonshortcodes170206.pdf -->
+    <shortcode country="gb" pattern="\\d{4,6}" premium="[5-8]\\d{4}" free="116\\d{3}" />
+
+    <!-- Georgia: 4 digits, known premium codes listed -->
+    <shortcode country="ge" pattern="\\d{4}" premium="801[234]|888[239]" />
+
+    <!-- Greece: 5 digits (54xxx, 19yxx, x=0-9, y=0-5): http://www.cmtelecom.com/premium-sms/greece -->
+    <shortcode country="gr" pattern="\\d{5}" premium="54\\d{3}|19[0-5]\\d{2}" free="116\\d{3}" />
+
+    <!-- Hungary: 4 or 10 digits starting with 1 or 0, plus EU:
+         http://clients.txtnation.com/entries/209633-hungary-premium-sms-short-code-regulations -->
+    <shortcode country="hu" pattern="[01](?:\\d{3}|\\d{9})" premium="0691227910|1784" free="116\\d{3}" />
+
+    <!-- Ireland: 5 digits, 5xxxx (50xxx=free, 5[12]xxx=standard), plus EU:
+         http://www.comreg.ie/_fileupload/publications/ComReg1117.pdf -->
+    <shortcode country="ie" pattern="\\d{5}" premium="5[3-9]\\d{3}" free="50\\d{3}|116\\d{3}" standard="5[12]\\d{3}" />
+
+    <!-- Israel: 4 digits, known premium codes listed -->
+    <shortcode country="il" pattern="\\d{4}" premium="4422|4545" />
+
+    <!-- Italy: 5 digits (premium=4xxxx), plus EU:
+         http://clients.txtnation.com/attachments/token/di5kfblvubttvlw/?name=Italy_CASP_EN.pdf -->
+    <shortcode country="it" pattern="\\d{5}" premium="4\\d{4}" free="116\\d{3}" />
+
+    <!-- Kyrgyzstan: 4 digits, known premium codes listed -->
+    <shortcode country="kg" pattern="\\d{4}" premium="415[2367]|444[69]" />
+
+    <!-- Kazakhstan: 4 digits, known premium codes listed: http://smscoin.net/info/pricing-kazakhstan/ -->
+    <shortcode country="kz" pattern="\\d{4}" premium="335[02]|4161|444[469]|77[2359]0|8444|919[3-5]|968[2-5]" />
+
+    <!-- Lithuania: 3-5 digits, known premium codes listed, plus EU -->
+    <shortcode country="lt" pattern="\\d{3,5}" premium="13[89]1|1394|16[34]5" free="116\\d{3}" />
+
+    <!-- Luxembourg: 5 digits, 6xxxx, plus EU:
+         http://www.luxgsm.lu/assets/files/filepage/file_1253803400.pdf -->
+    <shortcode country="lu" premium="6\\d{4}" free="116\\d{3}" />
+
+    <!-- Latvia: 4 digits, known premium codes listed, plus EU -->
+    <shortcode country="lv" pattern="\\d{4}" premium="18(?:19|63|7[1-4])" free="116\\d{3}" />
+
+    <!-- Mexico: 4-5 digits (not confirmed), known premium codes listed -->
+    <shortcode country="mx" pattern="\\d{4,5}" premium="53035|7766" />
+
+    <!-- Malaysia: 5 digits: http://www.skmm.gov.my/attachment/Consumer_Regulation/Mobile_Content_Services_FAQs.pdf -->
+    <shortcode country="my" pattern="\\d{5}" premium="32298|33776" />
+
+    <!-- The Netherlands, 4 digits, known premium codes listed, plus EU -->
+    <shortcode country="nl" pattern="\\d{4}" premium="4466|5040" free="116\\d{3}" />
+
+    <!-- Norway: 4-5 digits (not confirmed), known premium codes listed -->
+    <shortcode country="no" pattern="\\d{4,5}" premium="2201|222[67]" />
+
+    <!-- New Zealand: 3-4 digits, known premium codes listed -->
+    <shortcode country="nz" pattern="\\d{3,4}" premium="3903|8995" />
+
+    <!-- Poland: 4-5 digits (not confirmed), known premium codes listed, plus EU -->
+    <shortcode country="pl" pattern="\\d{4,5}" premium="74240|79(?:10|866)|92525" free="116\\d{3}" />
+
+    <!-- Portugal: 5 digits, plus EU:
+         http://clients.txtnation.com/entries/158326-portugal-premium-sms-short-code-regulations -->
+    <shortcode country="pt" premium="6[1289]\\d{3}" free="116\\d{3}" />
+
+    <!-- Romania: 4 digits, plus EU: http://www.simplus.ro/en/resources/glossary-of-terms/ -->
+    <shortcode country="ro" pattern="\\d{4}" premium="12(?:63|66|88)|13(?:14|80)" free="116\\d{3}" />
+
+    <!-- Russia: 4 digits, known premium codes listed: http://smscoin.net/info/pricing-russia/ -->
+    <shortcode country="ru" pattern="\\d{4}" premium="1(?:1[56]1|899)|2(?:09[57]|322|47[46]|880|990)|3[589]33|4161|44(?:4[3-9]|81)|77(?:33|81)" />
+
+    <!-- Sweden: 5 digits (72xxx), plus EU: http://www.viatel.se/en/premium-sms/ -->
+    <shortcode country="se" premium="72\\d{3}" free="116\\d{3}" />
+
+    <!-- Singapore: 5 digits: http://clients.txtnation.com/entries/306442-singapore-premium-sms-short-code-requirements
+         Free government directory info at 74688: http://app.sgdi.gov.sg/sms_help.asp -->
+    <shortcode country="sg" pattern="7\\d{4}" premium="73800" standard="74688" />
+
+    <!-- Slovenia: 4 digits (premium=3xxx, 6xxx, 8xxx), plus EU: http://www.cmtelecom.com/premium-sms/slovenia -->
+    <shortcode country="si" pattern="\\d{4}" premium="[368]\\d{3}" free="116\\d{3}" />
+
+    <!-- Slovakia: 4 digits (premium), plus EU: http://www.cmtelecom.com/premium-sms/slovakia -->
+    <shortcode country="sk" premium="\\d{4}" free="116\\d{3}" />
+
+    <!-- Tajikistan: 4 digits, known premium codes listed -->
+    <shortcode country="tj" pattern="\\d{4}" premium="11[3-7]1|4161|4333|444[689]" />
+
+    <!-- Ukraine: 4 digits, known premium codes listed -->
+    <shortcode country="ua" pattern="\\d{4}" premium="444[3-9]|70[579]4|7540" />
+
+    <!-- USA: 5-6 digits (premium codes from https://www.premiumsmsrefunds.com/ShortCodes.htm) -->
+    <shortcode country="us" pattern="\\d{5,6}" premium="20433|21(?:344|472)|22715|23(?:333|847)|24(?:15|28)0|25209|27(?:449|606|663)|28498|305(?:00|83)|32(?:340|941)|33(?:166|786|849)|34746|35(?:182|564)|37975|38(?:135|146|254)|41(?:366|463)|42335|43(?:355|500)|44(?:578|711|811)|45814|46(?:157|173|327)|46666|47553|48(?:221|277|669)|50(?:844|920)|51(?:062|368)|52944|54(?:723|892)|55928|56483|57370|59(?:182|187|252|342)|60339|61(?:266|982)|62478|64(?:219|898)|65(?:108|500)|69(?:208|388)|70877|71851|72(?:078|087|465)|73(?:288|588|882|909|997)|74(?:034|332|815)|76426|79213|81946|83177|84(?:103|685)|85797|86(?:234|236|666)|89616|90(?:715|842|938)|91(?:362|958)|94719|95297|96(?:040|666|835|969)|97(?:142|294|688)|99(?:689|796|807)" />
+
+</shortcodes>
diff --git a/docs/html/guide/topics/data/data-storage.jd b/docs/html/guide/topics/data/data-storage.jd
index e9d2d25..2603a06 100644
--- a/docs/html/guide/topics/data/data-storage.jd
+++ b/docs/html/guide/topics/data/data-storage.jd
@@ -232,7 +232,12 @@
 (non-removable) storage. Files saved to the external storage are world-readable and can
 be modified by the user when they enable USB mass storage to transfer files on a computer.</p>
 
-<p class="caution"><strong>Caution:</strong> External files can disappear if the user mounts the
+<p>It's possible that a device using a partition of the
+internal storage for the external storage may also offer an SD card slot. In this case,
+the SD card is <em>not</em> part of the external storage and your app cannot access it (the extra
+storage is intended only for user-provided media that the system scans).</p>
+
+<p class="caution"><strong>Caution:</strong> External storage can become unavailable if the user mounts the
 external storage on a computer or removes the media, and there's no security enforced upon files you
 save to the external storage. All applications can read and write files placed on the external
 storage and the user can remove them.</p>
diff --git a/docs/html/training/basics/data-storage/databases.jd b/docs/html/training/basics/data-storage/databases.jd
new file mode 100644
index 0000000..3a717dd
--- /dev/null
+++ b/docs/html/training/basics/data-storage/databases.jd
@@ -0,0 +1,322 @@
+page.title=Saving Data in SQL Databases
+parent.title=Data Storage
+parent.link=index.html
+
+trainingnavtop=true
+previous.title=Saving Data in Files
+previous.link=files.html
+
+@jd:body
+
+
+<div id="tb-wrapper">
+<div id="tb">
+
+<h2>This lesson teaches you to</h2>
+<ol>
+  <li><a href="#DefineContract">Define a Schema and Contract</a></li>
+  <li><a href="#DbHelper">Create a Database Using a SQL Helper</a></li>
+  <li><a href="#WriteDbRow">Put Information into a Database</a></li>
+  <li><a href="#ReadDbRow">Read Information from a Database</a></li>
+  <li><a href="#DeleteDbRow">Delete Information from a Database</a></li>
+  <li><a href="#UpdateDbRow">Update a Database</a></li>
+</ol>
+
+<h2>You should also read</h2>
+<ul>
+  <li><a href="{@docRoot}guide/topics/data/data-storage.html#db">Using Databases</a></li>
+</ul>
+
+<!--
+<h2>Try it out</h2>
+
+<div class="download-box">
+  <a href="{@docRoot}shareables/training/Sample.zip" class="button">Download the sample</a>
+  <p class="filename">Sample.zip</p>
+</div>
+-->
+
+</div>
+</div>
+
+
+<p>Saving data to a database is ideal for repeating or structured data,
+such as contact information. This class assumes that you are
+familiar with SQL databases in general and helps you get started with
+SQLite databases on Android. The APIs you'll need to use a database
+on Android are available in the  {@link android.database.sqlite} package.</p>
+
+
+<h2 id="DefineContract">Define a Schema and Contract</h2>
+
+<p>One of the main principles of SQL databases is the schema: a formal
+declaration of how the database is organized. The schema is reflected in the SQL
+statements that you use to create your database.  You may find it helpful to
+create a companion class, known as a <em>contract</em> class, which explicitly specifies
+the layout of your schema in a systematic and self-documenting way.</p>
+
+<p>A contract class is a container for constants that define names for URIs,
+tables, and columns. The contract class allows you to use the same constants
+across all the other classes in the same package. This lets you change a column
+name in one place and have it propagate throughout your code.</p>
+
+<p>A good way to organize a contract class is to put definitions that are
+global to your whole database in the root level of the class. Then create an inner
+class for each table that enumerates its columns.</p>
+
+<p class="note"><strong>Note:</strong> By implementing the {@link
+android.provider.BaseColumns} interface, your inner class can inherit a primary
+key field called {@code _ID} that some Android classes such as cursor adaptors
+will expect it to have.  It's not required, but this can help your database
+work harmoniously with the Android framework.</p>
+
+<p>For example, this snippet defines the table name and column names for a
+single table:</p>
+
+
+<pre>
+public static abstract class FeedEntry implements BaseColumns {
+    public static final String TABLE_NAME = &quot;entry&quot;;
+    public static final String COLUMN_NAME_ENTRY_ID = &quot;entryid&quot;;
+    public static final String COLUMN_NAME_TITLE = &quot;title&quot;;
+    public static final String COLUMN_NAME_SUBTITLE = &quot;subtitle&quot;;
+    ...
+}
+</pre>
+
+
+<p>To prevent someone from accidentally instantiating the contract class, give
+it an empty constructor.  </p>
+
+<pre>
+// Prevents the FeedReaderContract class from being instantiated.
+private FeedReaderContract() {}
+</pre>
+
+
+
+<h2 id="DbHelper">Create a Database Using a SQL Helper</h2>
+
+<p>Once you have defined how your database looks, you should implement methods
+that create and maintain the database and tables.  Here are some typical
+statements that create and delete a table:</P>
+
+<pre>
+private static final String TEXT_TYPE = &quot; TEXT&quot;;
+private static final String COMMA_SEP = &quot;,&quot;;
+private static final String SQL_CREATE_ENTRIES =
+    &quot;CREATE TABLE &quot; + FeedReaderContract.FeedEntry.TABLE_NAME + &quot; (&quot; +
+    FeedReaderContract.FeedEntry._ID + &quot; INTEGER PRIMARY KEY,&quot; +
+    FeedReaderContract.FeedEntry.COLUMN_NAME_ENTRY_ID + TEXT_TYPE + COMMA_SEP +
+    FeedReaderContract.FeedEntry.COLUMN_NAME_TITLE + TEXT_TYPE + COMMA_SEP +
+    ... // Any other options for the CREATE command
+    &quot; )&quot;;
+
+private static final String SQL_DELETE_ENTRIES =
+    &quot;DROP TABLE IF EXISTS &quot; + TABLE_NAME_ENTRIES;
+</pre>
+
+<p>Just like files that you save on the device's <a
+href="{@docRoot}guide/topics/data/data-storage.html#filesInternal">internal
+storage</a>, Android stores your database in private disk space that's associated
+application. Your data is secure, because by default this area is not
+accessible to other applications.</p>
+
+<p>A useful set of APIs is available in the {@link
+android.database.sqlite.SQLiteOpenHelper} class. 
+When you use this class to obtain references to your database, the system
+performs the potentially 
+long-running operations of creating and updating the database only when
+needed and <em>not during app startup</em>. All you need to do is call 
+{@link android.database.sqlite.SQLiteOpenHelper#getWritableDatabase} or
+{@link android.database.sqlite.SQLiteOpenHelper#getReadableDatabase}.</p>
+
+<p class="note"><strong>Note:</strong> Because they can be long-running,
+be sure that you call {@link
+android.database.sqlite.SQLiteOpenHelper#getWritableDatabase} or {@link
+android.database.sqlite.SQLiteOpenHelper#getReadableDatabase} in a background thread,
+such as with {@link android.os.AsyncTask} or {@link android.app.IntentService}.</p>
+
+<p>To use {@link android.database.sqlite.SQLiteOpenHelper}, create a subclass that
+overrides the {@link
+android.database.sqlite.SQLiteOpenHelper#onCreate onCreate()}, {@link
+android.database.sqlite.SQLiteOpenHelper#onUpgrade onUpgrade()} and {@link
+android.database.sqlite.SQLiteOpenHelper#onOpen onOpen()} callback methods. You may also
+want to implement {@link android.database.sqlite.SQLiteOpenHelper#onDowngrade onDowngrade()},
+but it's not required.</p>
+
+<p>For example, here's an implementation of {@link
+android.database.sqlite.SQLiteOpenHelper} that uses some of the commands shown above:</p>
+
+<pre>
+public class FeedReaderDbHelper extends SQLiteOpenHelper {
+    // If you change the database schema, you must increment the database version.
+    public static final int DATABASE_VERSION = 1;
+    public static final String DATABASE_NAME = &quot;FeedReader.db&quot;;
+
+    public FeedReaderDbHelper(Context context) {
+        super(context, DATABASE_NAME, null, DATABASE_VERSION);
+    }
+    public void onCreate(SQLiteDatabase db) {
+        db.execSQL(SQL_CREATE_ENTRIES);
+    }
+    public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
+        // This database is only a cache for online data, so its upgrade policy is
+        // to simply to discard the data and start over
+        db.execSQL(SQL_DELETE_ENTRIES);
+        onCreate(db);
+    }
+    public void onDowngrade(SQLiteDatabase db, int oldVersion, int newVersion) {
+        onUpgrade(db, oldVersion, newVersion);
+    }
+}
+</pre>
+
+<p>To access your database, instantiate your subclass of {@link
+android.database.sqlite.SQLiteOpenHelper}:</p>
+
+<pre>
+FeedReaderDbHelper mDbHelper = new FeedReaderDbHelper(getContext());
+</pre>
+
+
+
+
+<h2 id="WriteDbRow">Put Information into a Database</h2>
+
+<p>Insert data into the database by passing a {@link android.content.ContentValues}
+object to the {@link android.database.sqlite.SQLiteDatabase#insert insert()} method:</p>
+
+<pre>
+// Gets the data repository in write mode
+SQLiteDatabase db = mDbHelper.getWritableDatabase();
+
+// Create a new map of values, where column names are the keys
+ContentValues values = new ContentValues();
+values.put(FeedReaderContract.FeedEntry.COLUMN_NAME_ENTRY_ID, id);
+values.put(FeedReaderContract.FeedEntry.COLUMN_NAME_TITLE, title);
+values.put(FeedReaderContract.FeedEntry.COLUMN_NAME_CONTENT, content);
+
+// Insert the new row, returning the primary key value of the new row
+long newRowId;
+newRowId = db.insert(
+         FeedReaderContract.FeedEntry.TABLE_NAME,
+         FeedReaderContract.FeedEntry.COLUMN_NAME_NULLABLE,
+         values);
+</pre>
+
+<p>The first argument for {@link android.database.sqlite.SQLiteDatabase#insert insert()}
+is simply the table name. The second argument provides
+the name of a column in which the framework can insert NULL in the event that the
+{@link android.content.ContentValues} is empty (if you instead set this to {@code "null"},
+then the framework will not insert a row when there are no values).</p>
+
+
+
+
+<h2 id="ReadDbRow">Read Information from a Database</h2>
+
+<p>To read from a database, use the {@link android.database.sqlite.SQLiteDatabase#query query()}
+method, passing it your selection criteria and desired columns.
+The method combines elements of {@link android.database.sqlite.SQLiteDatabase#insert insert()}
+and {@link android.database.sqlite.SQLiteDatabase#update update()}, except the column list
+defines the data you want to fetch, rather than the data to insert. The results of the query
+are returned to you in a {@link android.database.Cursor} object.</p>
+
+<pre>
+SQLiteDatabase db = mDbHelper.getReadableDatabase();
+
+// Define a <em>projection</em> that specifies which columns from the database
+// you will actually use after this query.
+String[] projection = {
+    FeedReaderContract.FeedEntry._ID,
+    FeedReaderContract.FeedEntry.COLUMN_NAME_TITLE,
+    FeedReaderContract.FeedEntry.COLUMN_NAME_UPDATED,
+    ...
+    };
+
+// How you want the results sorted in the resulting Cursor
+String sortOrder =
+    FeedReaderContract.FeedEntry.COLUMN_NAME_UPDATED + " DESC";
+
+Cursor c = db.query(
+    FeedReaderContract.FeedEntry.TABLE_NAME,  // The table to query
+    projection,                               // The columns to return
+    selection,                                // The columns for the WHERE clause
+    selectionArgs,                            // The values for the WHERE clause
+    null,                                     // don't group the rows
+    null,                                     // don't filter by row groups
+    sortOrder                                 // The sort order
+    );
+</pre>
+
+<p>To look at a row in the cursor, use one of the {@link android.database.Cursor} move
+methods, which you must always call before you begin reading values. Generally, you should start
+by calling {@link android.database.Cursor#moveToFirst}, which places the "read position" on the
+first entry in the results. For each row, you can read a column's value by calling one of the
+{@link android.database.Cursor} get methods, such as {@link android.database.Cursor#getString
+getString()} or {@link android.database.Cursor#getLong getLong()}. For each of the get methods,
+you must pass the index position of the column you desire, which you can get by calling
+{@link android.database.Cursor#getColumnIndex getColumnIndex()} or
+{@link android.database.Cursor#getColumnIndexOrThrow getColumnIndexOrThrow()}.
+For example:</p>
+
+<pre>
+cursor.moveToFirst();
+long itemId = cursor.getLong(
+    cursor.getColumnIndexOrThrow(FeedReaderContract.FeedEntry._ID)
+);
+</pre>
+
+
+
+
+<h2 id="DeleteDbRow">Delete Information from a Database</h2>
+
+<p>To delete rows from a table, you need to provide selection criteria that
+identify the rows. The database API provides a mechanism for creating selection
+criteria that protects against SQL injection. The mechanism divides the
+selection specification into a selection clause and selection arguments. The
+clause defines the columns to look at, and also allows you to combine column
+tests. The arguments are values to test against that are bound into the clause.
+Because the result isn't handled the same as a regular SQL statement, it is
+immune to SQL injection.</p>
+
+<pre>
+// Define 'where' part of query.
+String selection = FeedReaderContract.FeedEntry.COLUMN_NAME_ENTRY_ID + &quot; LIKE ?&quot;;
+// Specify arguments in placeholder order.
+String[] selelectionArgs = { String.valueOf(rowId) };
+// Issue SQL statement.
+db.delete(table_name, mySelection, selectionArgs);
+</pre>
+
+
+
+<h2 id="UpdateDbRow">Update a Database</h2>
+
+<p>When you need to modify a subset of your database values, use the {@link
+android.database.sqlite.SQLiteDatabase#update update()} method.</p>
+
+<p>Updating the table combines the content values syntax of {@link
+android.database.sqlite.SQLiteDatabase#insert insert()}  with the {@code where} syntax
+of {@link android.database.sqlite.SQLiteDatabase#delete delete()}.</p>
+
+<pre>
+SQLiteDatabase db = mDbHelper.getReadableDatabase();
+
+// New value for one column
+ContentValues values = new ContentValues();
+values.put(FeedReaderContract.FeedEntry.COLUMN_NAME_TITLE, title);
+
+// Which row to update, based on the ID
+String selection = FeedReaderContract.FeedEntry.COLUMN_NAME_ENTRY_ID + &quot; LIKE ?&quot;;
+String[] selelectionArgs = { String.valueOf(rowId) };
+
+int count = db.update(
+    FeedReaderDbHelper.FeedEntry.TABLE_NAME,
+    values,
+    selection,
+    selectionArgs);
+</pre>
+
diff --git a/docs/html/training/basics/data-storage/files.jd b/docs/html/training/basics/data-storage/files.jd
new file mode 100644
index 0000000..dd081a6
--- /dev/null
+++ b/docs/html/training/basics/data-storage/files.jd
@@ -0,0 +1,382 @@
+page.title=Saving Files
+parent.title=Data Storage
+parent.link=index.html
+
+trainingnavtop=true
+
+@jd:body
+
+
+<div id="tb-wrapper">
+<div id="tb">
+
+<h2>This lesson teaches you to</h2>
+<ol>
+  <li><a href="#InternalVsExternalStorage">Choose Internal or External Storage</a></li>
+  <li><a href="#GetWritePermission">Obtain Permissions for External Storage</a></li>
+  <li><a href="#WriteInternalStorage">Save a File on Internal Storage</a></li>
+  <li><a href="#WriteExternalStorage">Save a File on External Storage</a></li>
+  <li><a href="#GetFreeSpace">Query Free Space</a></li>
+  <li><a href="#DeleteFile">Delete a File</a></li>
+</ol>
+
+<h2>You should also read</h2>
+<ul>
+  <li><a href="{@docRoot}guide/topics/data/data-storage.html#filesInternal">Using the Internal
+Storage</a></li>
+  <li><a href="{@docRoot}guide/topics/data/data-storage.html#filesExternal">Using the External
+Storage</a></li>
+</ul>
+
+</div>
+</div>
+
+<p>Android uses a file system that's
+similar to disk-based file systems on other platforms. This lesson describes
+how to work with the Android file system to read and write files with the {@link java.io.File}
+APIs.</p>
+
+<p>A {@link java.io.File} object is suited to reading or writing large amounts of data in
+start-to-finish order without skipping around. For example, it's good for image files or
+anything exchanged over a network.</p>
+
+<p>This lesson shows how to perform basic file-related tasks in your app.
+The lesson assumes that you are familiar with the basics of the Linux file system and the
+standard file input/output APIs in {@link java.io}.</p>
+
+
+<h2 id="InternalVsExternalStorage">Choose Internal or External Storage</h2>
+
+<p>All Android devices have two file storage areas: "internal" and "external" storage.  These names
+come from the early days of Android, when most devices offered built-in non-volatile memory
+(internal storage), plus a removable storage medium such as a micro SD card (external storage).
+Some devices divide the permanent storage space into "internal" and "external" partitions, so even
+without a removable storage medium, there are always two storage spaces and
+the API behavior is the same whether the external storage is removable or not.
+The following lists summarize the facts about each storage space.</p>
+
+<div class="col-5" style="margin-left:0">
+<p><b>Internal storage:</b></p>
+<ul>
+<li>It's always available.</li>
+<li>Files saved here are accessible by only your app by default.</li>
+<li>When the user uninstalls your app, the system removes all your app's files from
+internal storage.</li>
+</ul>
+<p>Internal storage is best when you want to be sure that neither the user nor other apps can
+access your files.</p>
+</div>
+
+<div class="col-7" style="margin-right:0">
+<p><b>External storage:</b></p>
+<ul>
+<li>It's not always available, because the user can mount the external storage as USB storage
+and in some cases remove it from the device.</li>
+<li>It's world-readable, so
+files saved here may be read outside of your control.</li>
+<li>When the user uninstalls your app, the system removes your app's files from here
+only if you save them in the directory from {@link android.content.Context#getExternalFilesDir
+getExternalFilesDir()}.</li>
+</ul>
+<p>External storage is the best
+place for files that don't require access restrictions and for files that you want to share
+with other apps or allow the user to access with a computer.</p>
+</div>
+
+
+<p class="note" style="clear:both">
+<strong>Tip:</strong> Although apps are installed onto the internal storage by
+default, you can specify the <a
+href="{@docRoot}guide/topics/manifest/manifest-element.html#install">{@code
+android:installLocation}</a> attribute in your manifest so your app may
+be installed on external storage. Users appreciate this option when the APK size is very large and
+they have an external storage space that's larger than the internal storage. For more
+information, see <a
+href="{@docRoot}guide/topics/data/install-location.html">App Install Location</a>.</p>
+
+
+<h2 id="GetWritePermission">Obtain Permissions for External Storage</h2>
+
+<p>To write to the external storage, you must request the
+  {@link android.Manifest.permission#WRITE_EXTERNAL_STORAGE} permission in your <a
+href="{@docRoot}guide/topics/manifest/manifest-intro.html">manifest file</a>:</p>
+
+<pre>
+&lt;manifest ...>
+    &lt;uses-permission android:name=&quot;android.permission.WRITE_EXTERNAL_STORAGE&quot; /&gt;
+    ...
+&lt;/manifest>
+</pre>
+
+<div class="caution"><p><strong>Caution:</strong>
+Currently, all apps have the ability to read the external storage
+without a special permission. However, this will change in a future release. If your app needs
+to read the external storage (but not write to it), then you will need to declare the {@link
+android.Manifest.permission#READ_EXTERNAL_STORAGE} permission. To ensure that your app continues
+to work as expected, you should declare this permission now, before the change takes effect.</p>
+<pre>
+&lt;manifest ...>
+    &lt;uses-permission android:name=&quot;android.permission.READ_EXTERNAL_STORAGE&quot; /&gt;
+    ...
+&lt;/manifest>
+</pre>
+<p>However, if your app uses the {@link android.Manifest.permission#WRITE_EXTERNAL_STORAGE}
+permission, then it implicitly has permission to read the external storage as well.</p>
+</div>
+
+<p>You don’t need any permissions to save files on the internal
+storage. Your application always has permission to read and
+write files in its internal storage directory.</p>
+
+
+
+
+
+<h2 id="WriteInternalStorage">Save a File on Internal Storage</h2>
+
+<p>When saving a file to internal storage, you can acquire the appropriate directory as a
+{@link java.io.File} by calling one of two methods:</p>
+
+<dl>
+  <dt>{@link android.content.Context#getFilesDir}</dt>
+  <dd>Returns a {@link java.io.File} representing an internal directory for your app.</dd>
+  <dt>{@link android.content.Context#getCacheDir}</dt>
+  <dd>Returns a {@link java.io.File} representing an internal directory for your app's temporary
+cache files. Be sure to delete each file once it is no
+longer needed and implement a reasonable size limit for the amount of memory you use at any given
+time, such as 1MB. If the system begins running low on storage, it may delete your cache files
+without warning.</dd>
+</dl>
+
+<p>To create a new file in one of these directories, you can use the {@link
+java.io.File#File(File,String) File()} constructor, passing the {@link java.io.File} provided by one
+of the above methods that specifies your internal storage directory. For example:</p>
+
+<pre>
+File file = new File(context.getFilesDir(), filename);
+</pre>
+
+<p>Alternatively, you can call {@link
+android.content.Context#openFileOutput openFileOutput()} to get a {@link java.io.FileOutputStream}
+that writes to a file in your internal directory. For example, here's
+how to write some text to a file:</p>
+
+<pre>
+String filename = "myfile";
+String string = "Hello world!";
+FileOutputStream outputStream;
+
+try {
+  outputStream = openFileOutput(filename, Context.MODE_PRIVATE);
+  outputStream.write(string.getBytes());
+  outputStream.close();
+} catch (Exception e) {
+  e.printStackTrace();
+}
+</pre>
+
+<p>Or, if you need to cache some files, you should instead use {@link
+java.io.File#createTempFile createTempFile()}. For example, the following method extracts the
+file name from a {@link java.net.URL} and creates a file with that name
+in your app's internal cache directory:</p>
+
+<pre>
+public File getTempFile(Context context, String url) {
+    File file;
+    try {
+        String fileName = Uri.parse(url).getLastPathSegment();
+        file = File.createTempFile(fileName, null, context.getCacheDir());
+    catch (IOException e) {
+        // Error while creating file
+    }
+    return file;
+}
+</pre>
+
+<p class="note"><strong>Note:</strong>
+Your app's internal storage directory is specified
+by your app's package name in a special location of the Android file system.
+Technically, another app can read your internal files if you set
+the file mode to be readable. However, the other app would also need to know your app package
+name and file names. Other apps cannot browse your internal directories and do not have
+read or write access unless you explicitly set the files to be readable or writable. So as long
+as you use {@link android.content.Context#MODE_PRIVATE} for your files on the internal storage,
+they are never accessible to other apps.</p>
+
+
+
+
+
+<h2 id="WriteExternalStorage">Save a File on External Storage</h2>
+
+<p>Because the external storage may be unavailable&mdash;such as when the user has mounted the
+storage to a PC or has removed the SD card that provides the external storage&mdash;you
+should always verify that the volume is available before accessing it. You can query the external
+storage state by calling {@link android.os.Environment#getExternalStorageState}. If the returned
+state is equal to {@link android.os.Environment#MEDIA_MOUNTED}, then you can read and
+write your files. For example, the following methods are useful to determine the storage
+availability:</p>
+
+<pre>
+/* Checks if external storage is available for read and write */
+public boolean isExternalStorageWritable() {
+    String state = Environment.getExternalStorageState();
+    if (Environment.MEDIA_MOUNTED.equals(state)) {
+        return true;
+    }
+    return false;
+}
+
+/* Checks if external storage is available to at least read */
+public boolean isExternalStorageReadable() {
+    String state = Environment.getExternalStorageState();
+    if (Environment.MEDIA_MOUNTED.equals(state) ||
+        Environment.MEDIA_MOUNTED_READ_ONLY.equals(state)) {
+        return true;
+    }
+    return false;
+}
+</pre>
+
+<p>Although the external storage is modifiable by the user and other apps, there are two
+categories of files you might save here:</p>
+
+<dl>
+  <dt>Public files</dt>
+  <dd>Files that
+should be freely available to other apps and to the user. When the user uninstalls your app,
+these files should remain available to the user.
+  <p>For example, photos captured by your app or other downloaded files.</p>
+  </dd>
+  <dt>Private files</dt>
+  <dd>Files that rightfully belong to your app and should be deleted when the user uninstalls
+  your app. Although these files are technically accessible by the user and other apps because they
+  are on the external storage, they are files that realistically don't provide value to the user
+  outside your app. When the user uninstalls your app, the system deletes
+  all files in your app's external private  directory. 
+  <p>For example, additional resources downloaded by your app or temporary media files.</p>
+  </dd>
+</dl>
+
+<p>If you want to save public files on the external storage, use the
+{@link android.os.Environment#getExternalStoragePublicDirectory
+getExternalStoragePublicDirectory()} method to get a {@link java.io.File} representing
+the appropriate directory on the external storage. The method takes an argument specifying
+the type of file you want to save so that they can be logically organized with other public
+files, such as {@link android.os.Environment#DIRECTORY_MUSIC} or {@link
+android.os.Environment#DIRECTORY_PICTURES}. For example:</p>
+
+<pre>
+public File getAlbumStorageDir(String albumName) {
+    // Get the directory for the user's public pictures directory. 
+    File file = new File(Environment.getExternalStoragePublicDirectory(
+            Environment.DIRECTORY_PICTURES), albumName);
+    if (!file.mkdirs()) {
+        Log.e(LOG_TAG, "Directory not created");
+    }
+    return file;
+}
+</pre>
+
+
+<p>If you want to save files that are private to your app, you can acquire the
+appropriate directory by calling {@link
+android.content.Context#getExternalFilesDir getExternalFilesDir()} and passing it a name indicating
+the type of directory you'd like. Each directory created this way is added to a parent
+directory that encapsulates all your app's external storage files, which the system deletes when the
+user uninstalls your app.</p>
+
+<p>For example, here's a method you can use to create a directory for an individual photo album:</p>
+
+<pre>
+public File getAlbumStorageDir(Context context, String albumName) {
+    // Get the directory for the app's private pictures directory. 
+    File file = new File(context.getExternalFilesDir(
+            Environment.DIRECTORY_PICTURES), albumName);
+    if (!file.mkdirs()) {
+        Log.e(LOG_TAG, "Directory not created");
+    }
+    return file;
+}
+</pre>
+
+<p>If none of the pre-defined sub-directory names suit your files, you can instead call {@link
+android.content.Context#getExternalFilesDir getExternalFilesDir()} and pass {@code null}. This
+returns the root directory for your app's private directory on the external storage.</p>
+
+<p>Remember that {@link android.content.Context#getExternalFilesDir getExternalFilesDir()}
+creates a directory inside a directory that is deleted when the user uninstalls your app.
+If the files you're saving should remain available after the user uninstalls your
+app&mdash;such as when your app is a camera and the user will want to keep the photos&mdash;you
+should instead use {@link android.os.Environment#getExternalStoragePublicDirectory
+getExternalStoragePublicDirectory()}.</p>
+
+
+<p>Regardless of whether you use {@link
+android.os.Environment#getExternalStoragePublicDirectory
+getExternalStoragePublicDirectory()} for files that are shared or
+{@link android.content.Context#getExternalFilesDir
+getExternalFilesDir()} for files that are private to your app, it's important that you use
+directory names provided by API constants like
+{@link android.os.Environment#DIRECTORY_PICTURES}. These directory names ensure
+that the files are treated properly by the system. For instance, files saved in {@link
+android.os.Environment#DIRECTORY_RINGTONES} are categorized by the system media scanner as ringtones
+instead of music.</p>
+
+
+
+
+<h2 id="GetFreeSpace">Query Free Space</h2>
+
+<p>If you know ahead of time how much data you're saving, you can find out
+whether sufficient space is available without causing an {@link
+java.io.IOException} by calling {@link java.io.File#getFreeSpace} or {@link
+java.io.File#getTotalSpace}. These methods provide the current available space and the
+total space in the storage volume, respectively. This information is also useful to avoid filling
+the storage volume above a certain threshold.</p>
+
+<p>However, the system does not guarantee that you can write as many bytes as are
+indicated by {@link java.io.File#getFreeSpace}.  If the number returned is a
+few MB more than the size of the data you want to save, or if the file system
+is less than 90% full, then it's probably safe to proceed.
+Otherwise, you probably shouldn't write to storage.</p>
+
+<p class="note"><strong>Note:</strong> You aren't required to check the amount of available space
+before you save your file. You can instead try writing the file right away, then
+catch an {@link java.io.IOException} if one occurs. You may need to do
+this if you don't know exactly how much space you need. For example, if you
+change the file's encoding before you save it by converting a PNG image to
+JPEG, you won't know the file's size beforehand.</p>
+
+
+
+
+<h2 id="DeleteFile">Delete a File</h2>
+
+<p>You should always delete files that you no longer need. The most straightforward way to delete a
+file is to have the opened file reference call {@link java.io.File#delete} on itself.</p>
+
+<pre>
+myFile.delete();
+</pre>
+
+<p>If the file is saved on internal storage, you can also ask the {@link android.content.Context} to locate and
+delete a file by calling {@link android.content.Context#deleteFile deleteFile()}:</p>
+
+<pre>
+myContext.deleteFile(fileName);
+</pre>
+
+<div class="note">
+<p><strong>Note:</strong> When the user uninstalls your app, the Android system deletes
+the following:</p> 
+<ul>
+<li>All files you saved on internal storage</li>
+<li>All files you saved on external storage using {@link
+android.content.Context#getExternalFilesDir getExternalFilesDir()}.</li>
+</ul>
+<p>However, you should manually delete all cached files created with
+{@link android.content.Context#getCacheDir()} on a regular basis and also regularly delete
+other files you no longer need.</p>
+</div>
+
diff --git a/docs/html/training/basics/data-storage/index.jd b/docs/html/training/basics/data-storage/index.jd
new file mode 100644
index 0000000..99bb2614
--- /dev/null
+++ b/docs/html/training/basics/data-storage/index.jd
@@ -0,0 +1,55 @@
+page.title=Saving Data
+
+trainingnavtop=true
+startpage=true
+
+@jd:body
+
+<div id="tb-wrapper">
+<div id="tb">
+
+<h2>Dependencies and prerequisites</h2>
+<ul>
+  <li>Android 1.6 (API Level 4) or higher</li>
+  <li>Familiarity with Map key-value collections</li>
+  <li>Familiarity with the Java file I/O API</li>
+  <li>Familiarity with SQL databases</li>
+</ul>
+
+<h2>You should also read</h2>
+<ul>
+  <li><a href="{@docRoot}guide/topics/data/data-storage.html">Storage Options</a></li>
+</ul>
+
+</div>
+</div>
+
+<p>Most Android apps need to save data, even if only to save information about the app state
+during {@link android.app.Activity#onPause onPause()} so the user's progress is not lost. Most
+non-trivial apps also need to save user settings, and some apps must manage large
+amounts of information in files and databases. This class introduces you to the
+principal data storage options in Android, including:</p>
+
+<ul>
+    <li>Saving key-value pairs of simple data types in a shared preferences
+file</li>
+    <li>Saving arbitrary files in Android's file system</li>
+    <li>Using databases managed by SQLite</li>
+</ul>
+
+
+<h2>Lessons</h2>
+
+<dl>
+  <dt><b><a href="shared-preferences.html">Saving Data in Shared Preferences</a></b></dt>
+    <dd>Learn to use a shared preferences file for storing small amounts of information in
+key-value pairs.</dd>
+
+  <dt><b><a href="files.html">Saving Data in Files</a></b></dt>
+    <dd>Learn to save a basic file, such as to store long sequences of data that
+        are generally read in order.</dd>
+
+ <dt><b><a href="databases.html">Saving Data in SQL Databases</a></b></dt>
+   <dd>Learn to use a SQLite database to read and write structured data.</dd>
+
+</dl>
diff --git a/docs/html/training/basics/data-storage/shared-preferences.jd b/docs/html/training/basics/data-storage/shared-preferences.jd
new file mode 100644
index 0000000..67f45cb
--- /dev/null
+++ b/docs/html/training/basics/data-storage/shared-preferences.jd
@@ -0,0 +1,121 @@
+page.title=Saving Key-Value Sets
+parent.title=Data Storage
+parent.link=index.html
+
+trainingnavtop=true
+
+@jd:body
+
+
+<div id="tb-wrapper">
+<div id="tb">
+
+<h2>This lesson teaches you to</h2>
+<ol>
+  <li><a href="#GetSharedPreferences">Get a Handle to a SharedPreferences</a></li>
+  <li><a href="#WriteSharedPreference">Write to Shared Preferences</a></li>
+  <li><a href="#ReadSharedPreference">Read from Shared Preferences</a></li>
+</ol>
+
+<h2>You should also read</h2>
+<ul>
+  <li><a href="{@docRoot}guide/topics/data/data-storage.html#pref">Using Shared Preferences</a></li>
+</ul>
+
+</div>
+</div>
+
+
+<p>If you have a relatively small collection of key-values that you'd like to save,
+you should use the {@link android.content.SharedPreferences} APIs.
+A {@link android.content.SharedPreferences} object points to a file containing
+key-value pairs and provides simple methods to read and write them. Each
+{@link android.content.SharedPreferences} file is
+managed by the framework and can be private or shared.</p>
+
+<p>This class shows you how to use the {@link android.content.SharedPreferences} APIs to store and
+retrieve simple values.</p>
+
+<p class="note"><strong>Note:</strong> The {@link android.content.SharedPreferences} APIs are
+only for reading and writing key-value pairs and you should not confuse them with the
+{@link android.preference.Preference} APIs, which help you build a user interface
+for your app settings (although they use {@link android.content.SharedPreferences} as their
+implementation to save the app settings). For information about using the {@link
+android.preference.Preference} APIs, see the <a href="{@docRoot}guide/topics/ui/settings.html"
+>Settings</a> guide.</p>
+
+<h2 id="GetSharedPreferences">Get a Handle to a SharedPreferences</h2>
+
+<p>You can create a new shared preference file or access an existing
+one by calling one of two methods:</p>
+<ul>
+  <li>{@link android.content.Context#getSharedPreferences(String,int)
+getSharedPreferences()} &mdash; Use this if you need multiple shared preference files identified
+by name, which you specify with the first parameter. You can call this from any
+{@link android.content.Context} in your app.</li>
+  <li>{@link android.app.Activity#getPreferences(int) getPreferences()} &mdash; Use this from an
+{@link android.app.Activity} if you need
+to use only one shared preference file for the activity. Because this retrieves a default shared
+preference file that belongs to the activity, you don't need to supply a name.</li>
+</ul>
+
+<p>For example, the following code is executed inside a {@link android.app.Fragment}.
+It accesses the shared preferences file that's
+identified by the resource string {@code R.string.preference_file_key} and opens it using
+the private mode so the file is accessible by only your app.</p>
+
+<pre>
+Context context = getActivity();
+SharedPreferences sharedPref = context.getSharedPreferences(
+        getString(R.string.preference_file_key), Context.MODE_PRIVATE);
+</pre>
+
+<p>When naming your shared preference files, you should use a name that's uniquely identifiable
+to your app, such as {@code "com.example.myapp.PREFERENCE_FILE_KEY"}</p>
+
+<p>Alternatively, if you need just one shared preference file for your activity, you can use the
+{@link android.app.Activity#getPreferences(int) getPreferences()} method:</p>
+
+<pre>
+SharedPreferences sharedPref = getActivity().getPreferences(Context.MODE_PRIVATE);
+</pre>
+
+<p class="caution"><strong>Caution:</strong> If you create a shared preferences file
+with {@link android.content.Context#MODE_WORLD_READABLE} or {@link
+android.content.Context#MODE_WORLD_WRITEABLE}, then any other apps that know the file identifier
+can access your data.</p>
+
+
+<h2 id="WriteSharedPreference">Write to Shared Preferences</h2>
+
+<p>To write to a shared preferences file, create a {@link
+android.content.SharedPreferences.Editor} by calling {@link
+android.content.SharedPreferences#edit} on your {@link android.content.SharedPreferences}.</p>
+
+<p>Pass the keys and values you want to write with methods such as {@link
+android.content.SharedPreferences.Editor#putInt putInt()} and {@link
+android.content.SharedPreferences.Editor#putString putString()}. Then call {@link
+android.content.SharedPreferences.Editor#commit} to save the changes. For example:</p>
+
+<pre>
+SharedPreferences sharedPref = getActivity().getPreferences(Context.MODE_PRIVATE);
+SharedPreferences.Editor editor = sharedPref.edit();
+editor.putInt(getString(R.string.saved_high_score), newHighScore);
+editor.commit();
+</pre>
+
+
+<h2 id="ReadSharedPreference">Read from Shared Preferences</h2>
+
+<p>To retrieve values from a shared preferences file, call methods such as {@link
+android.content.SharedPreferences#getInt getInt()} and {@link
+android.content.SharedPreferences#getString getString()}, providing the key for the value
+you want, and optionally a default value to return if the key isn't
+present. For example:</p>
+
+<pre>
+SharedPreferences sharedPref = getActivity().getPreferences(Context.MODE_PRIVATE);
+long default = getResources().getInteger(R.string.saved_high_score_default));
+long highScore = sharedPref.getInt(getString(R.string.saved_high_score), default);
+</pre>
+
diff --git a/docs/html/training/training_toc.cs b/docs/html/training/training_toc.cs
index b70ba3f..0952885 100644
--- a/docs/html/training/training_toc.cs
+++ b/docs/html/training/training_toc.cs
@@ -104,6 +104,26 @@
       </li>
 
       <li class="nav-section">
+        <div class="nav-section-header"><a href="<?cs var:toroot?>training/basics/data-storage/index.html">
+            <span class="en">Saving Data</span>
+          </a></div>
+        <ul>
+          <li><a href="<?cs var:toroot ?>training/basics/data-storage/shared-preferences.html">
+            <span class="en">Saving Key-Value Sets</span>
+          </a>
+          </li>
+          <li><a href="<?cs var:toroot ?>training/basics/data-storage/files.html">
+            <span class="en">Saving Files</span>
+          </a>
+          </li>
+          <li><a href="<?cs var:toroot ?>training/basics/data-storage/databases.html">
+            <span class="en">Saving Data in SQL Databases</span>
+          </a>
+          </li>
+        </ul>
+      </li>
+
+      <li class="nav-section">
         <div class="nav-section-header"><a href="<?cs var:toroot ?>training/basics/intents/index.html">
             <span class="en">Interacting with Other Apps</span>
           </a></div>
diff --git a/graphics/java/android/graphics/drawable/GradientDrawable.java b/graphics/java/android/graphics/drawable/GradientDrawable.java
index 2ca54d4..8374b10 100644
--- a/graphics/java/android/graphics/drawable/GradientDrawable.java
+++ b/graphics/java/android/graphics/drawable/GradientDrawable.java
@@ -478,6 +478,9 @@
             mFillPaint.setAlpha(currFillAlpha);
             mFillPaint.setDither(mDither);
             mFillPaint.setColorFilter(mColorFilter);
+            if (mColorFilter != null && !mGradientState.mHasSolidColor) {
+                mFillPaint.setColor(0xff000000);
+            }
             if (haveStroke) {
                 mStrokePaint.setAlpha(currStrokeAlpha);
                 mStrokePaint.setDither(mDither);
@@ -513,7 +516,10 @@
                         canvas.drawRoundRect(mRect, rad, rad, mStrokePaint);
                     }
                 } else {
-                    canvas.drawRect(mRect, mFillPaint);
+                    if (mFillPaint.getColor() != 0 || mColorFilter != null ||
+                            mFillPaint.getShader() != null) {
+                        canvas.drawRect(mRect, mFillPaint);
+                    }
                     if (haveStroke) {
                         canvas.drawRect(mRect, mStrokePaint);
                     }
@@ -736,6 +742,9 @@
 
                     mFillPaint.setShader(new LinearGradient(x0, y0, x1, y1,
                             colors, st.mPositions, Shader.TileMode.CLAMP));
+                    if (!mGradientState.mHasSolidColor) {
+                        mFillPaint.setColor(0xff000000);
+                    }
                 } else if (st.mGradient == RADIAL_GRADIENT) {
                     x0 = r.left + (r.right - r.left) * st.mCenterX;
                     y0 = r.top + (r.bottom - r.top) * st.mCenterY;
@@ -745,6 +754,9 @@
                     mFillPaint.setShader(new RadialGradient(x0, y0,
                             level * st.mGradientRadius, colors, null,
                             Shader.TileMode.CLAMP));
+                    if (!mGradientState.mHasSolidColor) {
+                        mFillPaint.setColor(0xff000000);
+                    }
                 } else if (st.mGradient == SWEEP_GRADIENT) {
                     x0 = r.left + (r.right - r.left) * st.mCenterX;
                     y0 = r.top + (r.bottom - r.top) * st.mCenterY;
@@ -775,6 +787,9 @@
 
                     }
                     mFillPaint.setShader(new SweepGradient(x0, y0, tempColors, tempPositions));
+                    if (!mGradientState.mHasSolidColor) {
+                        mFillPaint.setColor(0xff000000);
+                    }
                 }
             }
         }
@@ -1251,6 +1266,11 @@
     private void initializeWithState(GradientState state) {
         if (state.mHasSolidColor) {
             mFillPaint.setColor(state.mSolidColor);
+        } else if (state.mColors == null) {
+            // If we don't have a solid color and we don't have a gradient,
+            // the app is stroking the shape, set the color to the default
+            // value of state.mSolidColor
+            mFillPaint.setColor(0);
         }
         mPadding = state.mPadding;
         if (state.mStrokeWidth >= 0) {
diff --git a/libs/hwui/OpenGLRenderer.cpp b/libs/hwui/OpenGLRenderer.cpp
index c2e6ee3..7c23e4b 100644
--- a/libs/hwui/OpenGLRenderer.cpp
+++ b/libs/hwui/OpenGLRenderer.cpp
@@ -2440,16 +2440,33 @@
     return drawShape(left, top, texture, paint);
 }
 
+// See SkPaintDefaults.h
+#define SkPaintDefaults_MiterLimit SkIntToScalar(4)
+
 status_t OpenGLRenderer::drawRect(float left, float top, float right, float bottom, SkPaint* p) {
     if (mSnapshot->isIgnored() || quickRejectPreStroke(left, top, right, bottom, p)) {
         return DrawGlInfo::kStatusDone;
     }
 
-    // only fill style is supported by drawConvexPath, since others have to handle joins
     if (p->getStyle() != SkPaint::kFill_Style) {
-        mCaches.activeTexture(0);
-        const PathTexture* texture = mCaches.rectShapeCache.getRect(right - left, bottom - top, p);
-        return drawShape(left, top, texture, p);
+        // only fill style is supported by drawConvexPath, since others have to handle joins
+        if (p->getPathEffect() != 0 || p->getStrokeJoin() != SkPaint::kMiter_Join ||
+                p->getStrokeMiter() != SkPaintDefaults_MiterLimit) {
+            mCaches.activeTexture(0);
+            const PathTexture* texture =
+                    mCaches.rectShapeCache.getRect(right - left, bottom - top, p);
+            return drawShape(left, top, texture, p);
+        }
+
+        SkPath path;
+        SkRect rect = SkRect::MakeLTRB(left, top, right, bottom);
+        if (p->getStyle() == SkPaint::kStrokeAndFill_Style) {
+            rect.outset(p->getStrokeWidth() / 2, p->getStrokeWidth() / 2);
+        }
+        path.addRect(rect);
+        drawConvexPath(path, p);
+
+        return DrawGlInfo::kStatusDrew;
     }
 
     if (p->isAntiAlias() && !mSnapshot->transform->isSimple()) {
diff --git a/media/java/android/media/AudioService.java b/media/java/android/media/AudioService.java
index a754ef3..61418fb 100644
--- a/media/java/android/media/AudioService.java
+++ b/media/java/android/media/AudioService.java
@@ -63,6 +63,7 @@
 import android.provider.Settings.System;
 import android.speech.RecognizerIntent;
 import android.telephony.PhoneStateListener;
+import android.telephony.ServiceState;
 import android.telephony.TelephonyManager;
 import android.text.TextUtils;
 import android.util.Log;
@@ -155,6 +156,8 @@
     private static final int MSG_SET_FORCE_RSX_USE = 24;        // force remote submix audio routing
     private static final int MSG_CHECK_MUSIC_ACTIVE = 25;
     private static final int MSG_BROADCAST_AUDIO_BECOMING_NOISY = 26;
+    private static final int MSG_CONFIGURE_SAFE_MEDIA_VOLUME = 27;
+    private static final int MSG_CONFIGURE_SAFE_MEDIA_VOLUME_FORCED = 28;
 
     // flags for MSG_PERSIST_VOLUME indicating if current and/or last audible volume should be
     // persisted
@@ -429,6 +432,8 @@
             AudioSystem.DEVICE_OUT_DGTL_DOCK_HEADSET |
             AudioSystem.DEVICE_OUT_ALL_USB;
 
+    private final boolean mMonitorOrientation;
+
     ///////////////////////////////////////////////////////////////////////////
     // Construction
     ///////////////////////////////////////////////////////////////////////////
@@ -439,8 +444,6 @@
         mContentResolver = context.getContentResolver();
         mVoiceCapable = mContext.getResources().getBoolean(
                 com.android.internal.R.bool.config_voice_capable);
-        mSafeMediaVolumeIndex = mContext.getResources().getInteger(
-                com.android.internal.R.integer.config_safe_media_volume_index) * 10;
 
         PowerManager pm = (PowerManager)context.getSystemService(Context.POWER_SERVICE);
         mMediaEventWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "handleMediaEvent");
@@ -465,13 +468,10 @@
         updateStreamVolumeAlias(false /*updateVolumes*/);
         createStreamStates();
 
-        mSafeMediaVolumeEnabled = new Boolean(true);
-        synchronized (mSafeMediaVolumeEnabled) {
-            enforceSafeMediaVolume();
-        }
-
         mMediaServerOk = true;
 
+        mSafeMediaVolumeState = new Integer(SAFE_MEDIA_VOLUME_NOT_CONFIGURED);
+
         // Call setRingerModeInt() to apply correct mute
         // state on streams affected by ringer mode.
         mRingerModeMutedStreams = 0;
@@ -491,11 +491,12 @@
         intentFilter.addAction(Intent.ACTION_SCREEN_OFF);
         intentFilter.addAction(Intent.ACTION_USER_SWITCHED);
 
+        intentFilter.addAction(Intent.ACTION_CONFIGURATION_CHANGED);
         // Register a configuration change listener only if requested by system properties
         // to monitor orientation changes (off by default)
-        if (SystemProperties.getBoolean("ro.audio.monitorOrientation", false)) {
+        mMonitorOrientation = SystemProperties.getBoolean("ro.audio.monitorOrientation", false);
+        if (mMonitorOrientation) {
             Log.v(TAG, "monitoring device orientation");
-            intentFilter.addAction(Intent.ACTION_CONFIGURATION_CHANGED);
             // initialize orientation in AudioSystem
             setOrientationForAudioSystem();
         }
@@ -1736,7 +1737,8 @@
                 streamState.readSettings();
 
                 // unmute stream that was muted but is not affect by mute anymore
-                if (streamState.muteCount() != 0 && !isStreamAffectedByMute(streamType)) {
+                if (streamState.muteCount() != 0 && !isStreamAffectedByMute(streamType) &&
+                        !isStreamMutedByRingerMode(streamType)) {
                     int size = streamState.mDeathHandlers.size();
                     for (int i = 0; i < size; i++) {
                         streamState.mDeathHandlers.get(i).mMuteCount = 1;
@@ -1748,8 +1750,8 @@
 
         checkAllAliasStreamVolumes();
 
-        synchronized (mSafeMediaVolumeEnabled) {
-            if (mSafeMediaVolumeEnabled) {
+        synchronized (mSafeMediaVolumeState) {
+            if (mSafeMediaVolumeState == SAFE_MEDIA_VOLUME_ACTIVE) {
                 enforceSafeMediaVolume();
             }
         }
@@ -2212,8 +2214,8 @@
     }
 
     private void onCheckMusicActive() {
-        synchronized (mSafeMediaVolumeEnabled) {
-            if (!mSafeMediaVolumeEnabled) {
+        synchronized (mSafeMediaVolumeState) {
+            if (mSafeMediaVolumeState == SAFE_MEDIA_VOLUME_INACTIVE) {
                 int device = getDeviceForStream(AudioSystem.STREAM_MUSIC);
 
                 if ((device & mSafeMediaVolumeDevices) != 0) {
@@ -2241,6 +2243,25 @@
         }
     }
 
+    private void onConfigureSafeVolume(boolean force) {
+        synchronized (mSafeMediaVolumeState) {
+            int mcc = mContext.getResources().getConfiguration().mcc;
+            if ((mMcc != mcc) || ((mMcc == 0) && force)) {
+                mSafeMediaVolumeIndex = mContext.getResources().getInteger(
+                        com.android.internal.R.integer.config_safe_media_volume_index) * 10;
+                boolean safeMediaVolumeEnabled = mContext.getResources().getBoolean(
+                        com.android.internal.R.bool.config_safe_media_volume_enabled);
+                if (safeMediaVolumeEnabled) {
+                    mSafeMediaVolumeState = SAFE_MEDIA_VOLUME_ACTIVE;
+                    enforceSafeMediaVolume();
+                } else {
+                    mSafeMediaVolumeState = SAFE_MEDIA_VOLUME_DISABLED;
+                }
+                mMcc = mcc;
+            }
+        }
+    }
+
     ///////////////////////////////////////////////////////////////////////////
     // Internal methods
     ///////////////////////////////////////////////////////////////////////////
@@ -2571,6 +2592,18 @@
         public synchronized void readSettings() {
             int remainingDevices = AudioSystem.DEVICE_OUT_ALL;
 
+            // do not read system stream volume from settings: this stream is always aliased
+            // to another stream type and its volume is never persisted. Values in settings can
+            // only be stale values
+            if ((mStreamType == AudioSystem.STREAM_SYSTEM) ||
+                    (mStreamType == AudioSystem.STREAM_SYSTEM_ENFORCED)) {
+                mLastAudibleIndex.put(AudioSystem.DEVICE_OUT_DEFAULT,
+                                          10 * AudioManager.DEFAULT_STREAM_VOLUME[mStreamType]);
+                mIndex.put(AudioSystem.DEVICE_OUT_DEFAULT,
+                               10 * AudioManager.DEFAULT_STREAM_VOLUME[mStreamType]);
+                return;
+            }
+
             for (int i = 0; remainingDevices != 0; i++) {
                 int device = (1 << i);
                 if ((device & remainingDevices) == 0) {
@@ -2601,11 +2634,8 @@
 
                 // a last audible index of 0 should never be stored for ring and notification
                 // streams on phones (voice capable devices).
-                // same for system stream on phones and tablets
-                if ((lastAudibleIndex == 0) &&
-                        ((mVoiceCapable &&
-                                (mStreamVolumeAlias[mStreamType] == AudioSystem.STREAM_RING)) ||
-                         (mStreamVolumeAlias[mStreamType] == AudioSystem.STREAM_SYSTEM))) {
+                if ((lastAudibleIndex == 0) && mVoiceCapable &&
+                                (mStreamVolumeAlias[mStreamType] == AudioSystem.STREAM_RING)) {
                     lastAudibleIndex = AudioManager.DEFAULT_STREAM_VOLUME[mStreamType];
                     // Correct the data base
                     sendMsg(mAudioHandler,
@@ -2619,11 +2649,9 @@
                 mLastAudibleIndex.put(device, getValidIndex(10 * lastAudibleIndex));
                 // the initial index should never be 0 for ring and notification streams on phones
                 // (voice capable devices) if not in silent or vibrate mode.
-                // same for system stream on phones and tablets
                 if ((index == 0) && (mRingerMode == AudioManager.RINGER_MODE_NORMAL) &&
-                        ((mVoiceCapable &&
-                                (mStreamVolumeAlias[mStreamType] == AudioSystem.STREAM_RING)) ||
-                         (mStreamVolumeAlias[mStreamType] == AudioSystem.STREAM_SYSTEM))) {
+                        mVoiceCapable &&
+                        (mStreamVolumeAlias[mStreamType] == AudioSystem.STREAM_RING)) {
                     index = lastAudibleIndex;
                     // Correct the data base
                     sendMsg(mAudioHandler,
@@ -3185,7 +3213,7 @@
                     restoreMasterVolume();
 
                     // Reset device orientation (if monitored for this device)
-                    if (SystemProperties.getBoolean("ro.audio.monitorOrientation", false)) {
+                    if (mMonitorOrientation) {
                         setOrientationForAudioSystem();
                     }
 
@@ -3290,6 +3318,11 @@
                 case MSG_BROADCAST_AUDIO_BECOMING_NOISY:
                     onSendBecomingNoisyIntent();
                     break;
+
+                case MSG_CONFIGURE_SAFE_MEDIA_VOLUME_FORCED:
+                case MSG_CONFIGURE_SAFE_MEDIA_VOLUME:
+                    onConfigureSafeVolume((msg.what == MSG_CONFIGURE_SAFE_MEDIA_VOLUME_FORCED));
+                    break;
             }
         }
     }
@@ -3739,6 +3772,14 @@
                     adapter.getProfileProxy(mContext, mBluetoothProfileServiceListener,
                                             BluetoothProfile.A2DP);
                 }
+
+                sendMsg(mAudioHandler,
+                        MSG_CONFIGURE_SAFE_MEDIA_VOLUME_FORCED,
+                        SENDMSG_REPLACE,
+                        0,
+                        0,
+                        null,
+                        SAFE_VOLUME_CONFIGURE_TIMEOUT_MS);
             } else if (action.equals(Intent.ACTION_PACKAGE_REMOVED)) {
                 if (!intent.getBooleanExtra(Intent.EXTRA_REPLACING, false)) {
                     // a package is being removed, not replaced
@@ -5512,11 +5553,21 @@
         try {
             // reading new orientation "safely" (i.e. under try catch) in case anything
             // goes wrong when obtaining resources and configuration
-            int newOrientation = context.getResources().getConfiguration().orientation;
-            if (newOrientation != mDeviceOrientation) {
-                mDeviceOrientation = newOrientation;
-                setOrientationForAudioSystem();
+            Configuration config = context.getResources().getConfiguration();
+            if (mMonitorOrientation) {
+                int newOrientation = config.orientation;
+                if (newOrientation != mDeviceOrientation) {
+                    mDeviceOrientation = newOrientation;
+                    setOrientationForAudioSystem();
+                }
             }
+            sendMsg(mAudioHandler,
+                    MSG_CONFIGURE_SAFE_MEDIA_VOLUME,
+                    SENDMSG_REPLACE,
+                    0,
+                    0,
+                    null,
+                    0);
         } catch (Exception e) {
             Log.e(TAG, "Error retrieving device orientation: " + e);
         }
@@ -5587,12 +5638,21 @@
     // overlay.
     //==========================================================================================
 
-    // mSafeMediaVolumeEnabled indicates whether the media volume is limited over headphones.
-    // It is true by default when headphones or a headset are inserted and can be overriden by
-    // calling AudioService.disableSafeMediaVolume() (when user opts out).
-    private Boolean mSafeMediaVolumeEnabled;
+    // mSafeMediaVolumeState indicates whether the media volume is limited over headphones.
+    // It is SAFE_MEDIA_VOLUME_NOT_CONFIGURED at boot time until a network service is connected
+    // or the configure time is elapsed. It is then set to SAFE_MEDIA_VOLUME_ACTIVE or
+    // SAFE_MEDIA_VOLUME_DISABLED according to country option. If not SAFE_MEDIA_VOLUME_DISABLED, it
+    // can be set to SAFE_MEDIA_VOLUME_INACTIVE by calling AudioService.disableSafeMediaVolume()
+    // (when user opts out).
+    private final int SAFE_MEDIA_VOLUME_NOT_CONFIGURED = 0;
+    private final int SAFE_MEDIA_VOLUME_DISABLED = 1;
+    private final int SAFE_MEDIA_VOLUME_INACTIVE = 2;
+    private final int SAFE_MEDIA_VOLUME_ACTIVE = 3;
+    private Integer mSafeMediaVolumeState;
+
+    private int mMcc = 0;
     // mSafeMediaVolumeIndex is the cached value of config_safe_media_volume_index property
-    private final int mSafeMediaVolumeIndex;
+    private int mSafeMediaVolumeIndex;
     // mSafeMediaVolumeDevices lists the devices for which safe media volume is enforced,
     private final int mSafeMediaVolumeDevices = AudioSystem.DEVICE_OUT_WIRED_HEADSET |
                                                 AudioSystem.DEVICE_OUT_WIRED_HEADPHONE;
@@ -5602,22 +5662,27 @@
     private int mMusicActiveMs;
     private static final int UNSAFE_VOLUME_MUSIC_ACTIVE_MS_MAX = (20 * 3600 * 1000); // 20 hours
     private static final int MUSIC_ACTIVE_POLL_PERIOD_MS = 60000;  // 1 minute polling interval
+    private static final int SAFE_VOLUME_CONFIGURE_TIMEOUT_MS = 30000;  // 30s after boot completed
 
     private void setSafeMediaVolumeEnabled(boolean on) {
-        synchronized (mSafeMediaVolumeEnabled) {
-            if (on && !mSafeMediaVolumeEnabled) {
-                enforceSafeMediaVolume();
-            } else if (!on && mSafeMediaVolumeEnabled) {
-                mMusicActiveMs = 0;
-                sendMsg(mAudioHandler,
-                        MSG_CHECK_MUSIC_ACTIVE,
-                        SENDMSG_REPLACE,
-                        0,
-                        0,
-                        null,
-                        MUSIC_ACTIVE_POLL_PERIOD_MS);
+        synchronized (mSafeMediaVolumeState) {
+            if ((mSafeMediaVolumeState != SAFE_MEDIA_VOLUME_NOT_CONFIGURED) &&
+                    (mSafeMediaVolumeState != SAFE_MEDIA_VOLUME_DISABLED)) {
+                if (on && (mSafeMediaVolumeState == SAFE_MEDIA_VOLUME_INACTIVE)) {
+                    mSafeMediaVolumeState = SAFE_MEDIA_VOLUME_ACTIVE;
+                    enforceSafeMediaVolume();
+                } else if (!on && (mSafeMediaVolumeState == SAFE_MEDIA_VOLUME_ACTIVE)) {
+                    mSafeMediaVolumeState = SAFE_MEDIA_VOLUME_INACTIVE;
+                    mMusicActiveMs = 0;
+                    sendMsg(mAudioHandler,
+                            MSG_CHECK_MUSIC_ACTIVE,
+                            SENDMSG_REPLACE,
+                            0,
+                            0,
+                            null,
+                            MUSIC_ACTIVE_POLL_PERIOD_MS);
+                }
             }
-            mSafeMediaVolumeEnabled = on;
         }
     }
 
@@ -5659,8 +5724,8 @@
     }
 
     private boolean checkSafeMediaVolume(int streamType, int index, int device) {
-        synchronized (mSafeMediaVolumeEnabled) {
-            if (mSafeMediaVolumeEnabled &&
+        synchronized (mSafeMediaVolumeState) {
+            if ((mSafeMediaVolumeState == SAFE_MEDIA_VOLUME_ACTIVE) &&
                     (mStreamVolumeAlias[streamType] == AudioSystem.STREAM_MUSIC) &&
                     ((device & mSafeMediaVolumeDevices) != 0) &&
                     (index > mSafeMediaVolumeIndex)) {
@@ -5672,7 +5737,7 @@
     }
 
     public void disableSafeMediaVolume() {
-        synchronized (mSafeMediaVolumeEnabled) {
+        synchronized (mSafeMediaVolumeState) {
             setSafeMediaVolumeEnabled(false);
         }
     }
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java b/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java
index f69c0af..2716b04 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java
@@ -68,7 +68,7 @@
     // 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 = 90;
+    private static final int DATABASE_VERSION = 91;
 
     private Context mContext;
     private int mUserHandle;
@@ -1400,6 +1400,39 @@
             upgradeVersion = 90;
         }
 
+        if (upgradeVersion == 90) {
+            if (mUserHandle == UserHandle.USER_OWNER) {
+                db.beginTransaction();
+                try {
+                    String[] systemToGlobal = {
+                            Settings.Global.WINDOW_ANIMATION_SCALE,
+                            Settings.Global.TRANSITION_ANIMATION_SCALE,
+                            Settings.Global.ANIMATOR_DURATION_SCALE,
+                            Settings.Global.FANCY_IME_ANIMATIONS,
+                            Settings.Global.COMPATIBILITY_MODE,
+                            Settings.Global.EMERGENCY_TONE,
+                            Settings.Global.CALL_AUTO_RETRY,
+                            Settings.Global.DEBUG_APP,
+                            Settings.Global.WAIT_FOR_DEBUGGER,
+                            Settings.Global.SHOW_PROCESSES,
+                            Settings.Global.ALWAYS_FINISH_ACTIVITIES,
+                    };
+                    String[] secureToGlobal = {
+                            Settings.Global.PREFERRED_NETWORK_MODE,
+                            Settings.Global.PREFERRED_CDMA_SUBSCRIPTION,
+                    };
+
+                    moveSettingsToNewTable(db, TABLE_SYSTEM, TABLE_GLOBAL, systemToGlobal, true);
+                    moveSettingsToNewTable(db, TABLE_SECURE, TABLE_GLOBAL, secureToGlobal, true);
+
+                    db.setTransactionSuccessful();
+                } finally {
+                    db.endTransaction();
+                }
+            }
+            upgradeVersion = 91;
+        }
+
         // *** Remember to update DATABASE_VERSION above!
 
         if (upgradeVersion != currentVersion) {
@@ -1816,12 +1849,6 @@
             loadIntegerSetting(stmt, Settings.System.SCREEN_OFF_TIMEOUT,
                     R.integer.def_screen_off_timeout);
 
-            // Set default cdma emergency tone
-            loadSetting(stmt, Settings.System.EMERGENCY_TONE, 0);
-
-            // Set default cdma call auto retry
-            loadSetting(stmt, Settings.System.CALL_AUTO_RETRY, 0);
-
             // Set default cdma DTMF type
             loadSetting(stmt, Settings.System.DTMF_TONE_TYPE_WHEN_DIALING, 0);
 
@@ -1846,9 +1873,6 @@
 
             loadBooleanSetting(stmt, Settings.System.NOTIFICATION_LIGHT_PULSE,
                     R.bool.def_notification_pulse);
-            loadSetting(stmt, Settings.Global.SET_INSTALL_LOCATION, 0);
-            loadSetting(stmt, Settings.Global.DEFAULT_INSTALL_LOCATION,
-                    PackageHelper.APP_INSTALL_AUTO);
 
             loadUISoundEffectsSettings(stmt);
 
@@ -1912,16 +1936,6 @@
                 loadSetting(stmt, Settings.Secure.WIFI_WATCHDOG_WATCH_LIST, wifiWatchList);
             }
 
-            // Set the preferred network mode to 0 = Global, CDMA default
-            int type;
-            if (TelephonyManager.getLteOnCdmaModeStatic() == PhoneConstants.LTE_ON_CDMA_TRUE) {
-                type = Phone.NT_MODE_GLOBAL;
-            } else {
-                type = SystemProperties.getInt("ro.telephony.default_network",
-                        RILConstants.PREFERRED_NETWORK_MODE);
-            }
-            loadSetting(stmt, Settings.Secure.PREFERRED_NETWORK_MODE, type);
-
             // Don't do this.  The SystemServer will initialize ADB_ENABLED from a
             // persistent system property instead.
             //loadSetting(stmt, Settings.Secure.ADB_ENABLED, 0);
@@ -2105,6 +2119,26 @@
             loadStringSetting(stmt, Settings.Global.UNLOCK_SOUND,
                     R.string.def_unlock_sound);
 
+            loadSetting(stmt, Settings.Global.SET_INSTALL_LOCATION, 0);
+            loadSetting(stmt, Settings.Global.DEFAULT_INSTALL_LOCATION,
+                    PackageHelper.APP_INSTALL_AUTO);
+
+            // Set default cdma emergency tone
+            loadSetting(stmt, Settings.Global.EMERGENCY_TONE, 0);
+
+            // Set default cdma call auto retry
+            loadSetting(stmt, Settings.Global.CALL_AUTO_RETRY, 0);
+
+            // Set the preferred network mode to 0 = Global, CDMA default
+            int type;
+            if (TelephonyManager.getLteOnCdmaModeStatic() == PhoneConstants.LTE_ON_CDMA_TRUE) {
+                type = Phone.NT_MODE_GLOBAL;
+            } else {
+                type = SystemProperties.getInt("ro.telephony.default_network",
+                        RILConstants.PREFERRED_NETWORK_MODE);
+            }
+            loadSetting(stmt, Settings.Global.PREFERRED_NETWORK_MODE, type);
+
             // --- New global settings start here
         } finally {
             if (stmt != null) stmt.close();
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
index 10f96cc..cc6656d 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
@@ -227,6 +227,8 @@
         sSecureGlobalKeys.add(Settings.Global.GLOBAL_HTTP_PROXY_EXCLUSION_LIST);
         sSecureGlobalKeys.add(Settings.Global.SET_GLOBAL_HTTP_PROXY);
         sSecureGlobalKeys.add(Settings.Global.DEFAULT_DNS_SERVER);
+        sSecureGlobalKeys.add(Settings.Global.PREFERRED_NETWORK_MODE);
+        sSecureGlobalKeys.add(Settings.Global.PREFERRED_CDMA_SUBSCRIPTION);
 
         // Keys from the 'system' table now moved to 'global'
         // These must match Settings.System.MOVED_TO_GLOBAL
@@ -249,6 +251,17 @@
         sSystemGlobalKeys.add(Settings.Global.STAY_ON_WHILE_PLUGGED_IN);
         sSystemGlobalKeys.add(Settings.Global.WIFI_SLEEP_POLICY);
         sSystemGlobalKeys.add(Settings.Global.MODE_RINGER);
+        sSystemGlobalKeys.add(Settings.Global.WINDOW_ANIMATION_SCALE);
+        sSystemGlobalKeys.add(Settings.Global.TRANSITION_ANIMATION_SCALE);
+        sSystemGlobalKeys.add(Settings.Global.ANIMATOR_DURATION_SCALE);
+        sSystemGlobalKeys.add(Settings.Global.FANCY_IME_ANIMATIONS);
+        sSystemGlobalKeys.add(Settings.Global.COMPATIBILITY_MODE);
+        sSystemGlobalKeys.add(Settings.Global.EMERGENCY_TONE);
+        sSystemGlobalKeys.add(Settings.Global.CALL_AUTO_RETRY);
+        sSystemGlobalKeys.add(Settings.Global.DEBUG_APP);
+        sSystemGlobalKeys.add(Settings.Global.WAIT_FOR_DEBUGGER);
+        sSystemGlobalKeys.add(Settings.Global.SHOW_PROCESSES);
+        sSystemGlobalKeys.add(Settings.Global.ALWAYS_FINISH_ACTIVITIES);
     }
 
     private boolean settingMovedToGlobal(final String name) {
diff --git a/packages/SystemUI/res/layout-land/status_bar_recent_item.xml b/packages/SystemUI/res/layout-land/status_bar_recent_item.xml
index c293fe6..10e313e 100644
--- a/packages/SystemUI/res/layout-land/status_bar_recent_item.xml
+++ b/packages/SystemUI/res/layout-land/status_bar_recent_item.xml
@@ -24,13 +24,16 @@
     android:layout_width="wrap_content"
     android:paddingLeft="@dimen/status_bar_recents_item_padding"
     android:paddingRight="@dimen/status_bar_recents_item_padding"
-    android:importantForAccessibility="no">
+    android:importantForAccessibility="no"
+    android:clipChildren="false">
 
     <RelativeLayout android:id="@+id/recent_item"
         android:layout_gravity="center_vertical"
         android:layout_height="wrap_content"
         android:layout_width="wrap_content"
-        android:paddingTop="@*android:dimen/status_bar_height">
+        android:paddingTop="@*android:dimen/status_bar_height"
+        android:clipChildren="false"
+        android:clipToPadding="false">
 
         <FrameLayout android:id="@+id/app_thumbnail"
             android:layout_width="wrap_content"
diff --git a/packages/SystemUI/res/layout/quick_settings_tile_time.xml b/packages/SystemUI/res/layout/quick_settings_tile_time.xml
index 4ffbf52..910e1f6 100644
--- a/packages/SystemUI/res/layout/quick_settings_tile_time.xml
+++ b/packages/SystemUI/res/layout/quick_settings_tile_time.xml
@@ -29,10 +29,11 @@
         android:hand_hour="@drawable/ic_qs_clock_hour"
         android:hand_minute="@drawable/ic_qs_clock_minute"
         />
-    <com.android.systemui.statusbar.policy.QuickSettingsDateView
+    <com.android.systemui.statusbar.policy.DateView
         android:textAppearance="@style/TextAppearance.QuickSettings.TileView"
         android:layout_width="wrap_content"
         android:layout_height="wrap_content"
         android:layout_gravity="center_horizontal"
+        android:gravity="center"
         />
-</LinearLayout>
\ No newline at end of file
+</LinearLayout>
diff --git a/packages/SystemUI/res/layout/status_bar_expanded.xml b/packages/SystemUI/res/layout/status_bar_expanded.xml
index ffcead0..7f6098a 100644
--- a/packages/SystemUI/res/layout/status_bar_expanded.xml
+++ b/packages/SystemUI/res/layout/status_bar_expanded.xml
@@ -29,6 +29,12 @@
     android:layout_marginLeft="@dimen/notification_panel_margin_left"
     >
 
+    <View
+        android:id="@+id/handle"
+        android:layout_width="match_parent"
+        android:layout_height="@dimen/close_handle_height"
+        />
+
     <include
         layout="@layout/carrier_label"
         android:layout_height="@dimen/carrier_label_height"
@@ -75,10 +81,4 @@
                 />
         </ScrollView>
     </LinearLayout>
-
-    <View
-        android:id="@+id/handle"
-        android:layout_width="match_parent"
-        android:layout_height="@dimen/close_handle_height"
-        />
 </com.android.systemui.statusbar.phone.NotificationPanelView><!-- end of sliding panel -->
diff --git a/packages/SystemUI/res/layout/status_bar_recent_item.xml b/packages/SystemUI/res/layout/status_bar_recent_item.xml
index fc247d6..e2b5723 100644
--- a/packages/SystemUI/res/layout/status_bar_recent_item.xml
+++ b/packages/SystemUI/res/layout/status_bar_recent_item.xml
@@ -24,12 +24,14 @@
     android:layout_width="match_parent"
     android:paddingTop="@dimen/status_bar_recents_item_padding"
     android:paddingBottom="@dimen/status_bar_recents_item_padding"
+    android:clipChildren="false"
     android:importantForAccessibility="no">
 
     <RelativeLayout android:id="@+id/recent_item"
         android:layout_gravity="center_horizontal"
         android:layout_height="wrap_content"
-        android:layout_width="wrap_content">
+        android:layout_width="wrap_content"
+        android:clipChildren="false">
 
         <TextView android:id="@+id/app_label"
             android:layout_width="@dimen/status_bar_recents_app_label_width"
diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml
index 62289fb..5023d23 100644
--- a/packages/SystemUI/res/values/dimens.xml
+++ b/packages/SystemUI/res/values/dimens.xml
@@ -50,6 +50,10 @@
     <dimen name="status_bar_recents_app_label_left_margin">0dip</dimen>
     <!-- Padding between recents items -->
     <dimen name="status_bar_recents_item_padding">0dip</dimen>
+    <!-- When recents first appears, how far the icon and label of the primary activity
+         travel -->
+    <dimen name="status_bar_recents_app_icon_translate_distance">100dp</dimen>
+
     <!-- Where to place the app icon over the thumbnail -->
     <dimen name="status_bar_recents_app_icon_left_margin">0dp</dimen>
     <dimen name="status_bar_recents_app_icon_top_margin">8dp</dimen>
diff --git a/packages/SystemUI/src/com/android/systemui/SystemUIApplication.java b/packages/SystemUI/src/com/android/systemui/SystemUIApplication.java
index f97d4ff..c120690 100644
--- a/packages/SystemUI/src/com/android/systemui/SystemUIApplication.java
+++ b/packages/SystemUI/src/com/android/systemui/SystemUIApplication.java
@@ -19,9 +19,12 @@
 import android.app.Application;
 
 import com.android.systemui.recent.RecentTasksLoader;
+import com.android.systemui.recent.RecentsActivity;
 
 public class SystemUIApplication extends Application {
     private RecentTasksLoader mRecentTasksLoader;
+    private boolean mWaitingForWinAnimStart;
+    private RecentsActivity.WindowAnimationStartListener mWinAnimStartListener;
 
     public RecentTasksLoader getRecentTasksLoader() {
         if (mRecentTasksLoader == null) {
@@ -29,4 +32,28 @@
         }
         return mRecentTasksLoader;
     }
+
+    public void setWaitingForWinAnimStart(boolean waiting) {
+        mWaitingForWinAnimStart = waiting;
+    }
+
+    public void setWindowAnimationStartListener(
+            RecentsActivity.WindowAnimationStartListener startListener) {
+        mWinAnimStartListener = startListener;
+    }
+
+    public RecentsActivity.WindowAnimationStartListener getWindowAnimationListener() {
+        return mWinAnimStartListener;
+    }
+
+    public void onWindowAnimationStart() {
+        if (mWinAnimStartListener != null) {
+            mWinAnimStartListener.onWindowAnimationStart();
+        }
+        mWaitingForWinAnimStart = false;
+    }
+
+    public boolean isWaitingForWindowAnimationStart() {
+        return mWaitingForWinAnimStart;
+    }
 }
\ No newline at end of file
diff --git a/packages/SystemUI/src/com/android/systemui/recent/RecentsActivity.java b/packages/SystemUI/src/com/android/systemui/recent/RecentsActivity.java
index 7ff7b17..f93da08 100644
--- a/packages/SystemUI/src/com/android/systemui/recent/RecentsActivity.java
+++ b/packages/SystemUI/src/com/android/systemui/recent/RecentsActivity.java
@@ -51,6 +51,10 @@
         }
     };
 
+    public static interface WindowAnimationStartListener {
+        void onWindowAnimationStart();
+    }
+
     public class TouchOutsideListener implements View.OnTouchListener {
         private StatusBarPanel mPanel;
 
@@ -88,15 +92,15 @@
     @Override
     public void onStart() {
         mShowing = true;
+        if (mRecentsPanel != null) {
+            mRecentsPanel.refreshViews();
+        }
         super.onStart();
     }
 
     @Override
     public void onResume() {
         mForeground = true;
-        if (mRecentsPanel != null) {
-            mRecentsPanel.refreshViews();
-        }
         super.onResume();
     }
 
@@ -150,6 +154,7 @@
         mIntentFilter = new IntentFilter();
         mIntentFilter.addAction(CLOSE_RECENTS_INTENT);
         registerReceiver(mIntentReceiver, mIntentFilter);
+        app.setWindowAnimationStartListener(mRecentsPanel);
         super.onCreate(savedInstanceState);
     }
 
@@ -164,6 +169,7 @@
         final RecentTasksLoader recentTasksLoader = app.getRecentTasksLoader();
         recentTasksLoader.setRecentsPanel(null, mRecentsPanel);
         unregisterReceiver(mIntentReceiver);
+        app.setWindowAnimationStartListener(null);
         super.onDestroy();
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/recent/RecentsHorizontalScrollView.java b/packages/SystemUI/src/com/android/systemui/recent/RecentsHorizontalScrollView.java
index 4aa2095..50b32f9 100644
--- a/packages/SystemUI/src/com/android/systemui/recent/RecentsHorizontalScrollView.java
+++ b/packages/SystemUI/src/com/android/systemui/recent/RecentsHorizontalScrollView.java
@@ -156,19 +156,19 @@
         }
         setLayoutTransition(transitioner);
 
-        // Scroll to end after layout.
-        final ViewTreeObserver observer = getViewTreeObserver();
+        // Scroll to end after initial layout.
 
         final OnGlobalLayoutListener updateScroll = new OnGlobalLayoutListener() {
                 public void onGlobalLayout() {
                     mLastScrollPosition = scrollPositionOfMostRecent();
                     scrollTo(mLastScrollPosition, 0);
+                    final ViewTreeObserver observer = getViewTreeObserver();
                     if (observer.isAlive()) {
                         observer.removeOnGlobalLayoutListener(this);
                     }
                 }
             };
-        observer.addOnGlobalLayoutListener(updateScroll);
+        getViewTreeObserver().addOnGlobalLayoutListener(updateScroll);
     }
 
     @Override
diff --git a/packages/SystemUI/src/com/android/systemui/recent/RecentsPanelView.java b/packages/SystemUI/src/com/android/systemui/recent/RecentsPanelView.java
index 005b4a2..3a89059 100644
--- a/packages/SystemUI/src/com/android/systemui/recent/RecentsPanelView.java
+++ b/packages/SystemUI/src/com/android/systemui/recent/RecentsPanelView.java
@@ -18,12 +18,15 @@
 
 import android.animation.Animator;
 import android.animation.LayoutTransition;
+import android.animation.TimeInterpolator;
+import android.app.Activity;
 import android.app.ActivityManager;
 import android.app.ActivityManagerNative;
 import android.app.ActivityOptions;
 import android.app.TaskStackBuilder;
 import android.content.Context;
 import android.content.Intent;
+import android.content.res.Configuration;
 import android.content.res.Resources;
 import android.content.res.TypedArray;
 import android.graphics.Bitmap;
@@ -45,6 +48,7 @@
 import android.view.ViewGroup;
 import android.view.accessibility.AccessibilityEvent;
 import android.view.animation.AnimationUtils;
+import android.view.animation.DecelerateInterpolator;
 import android.widget.AdapterView;
 import android.widget.AdapterView.OnItemClickListener;
 import android.widget.BaseAdapter;
@@ -55,6 +59,7 @@
 import android.widget.TextView;
 
 import com.android.systemui.R;
+import com.android.systemui.SystemUIApplication;
 import com.android.systemui.statusbar.BaseStatusBar;
 import com.android.systemui.statusbar.phone.PhoneStatusBar;
 import com.android.systemui.statusbar.tablet.StatusBarPanel;
@@ -63,7 +68,7 @@
 import java.util.ArrayList;
 
 public class RecentsPanelView extends FrameLayout implements OnItemClickListener, RecentsCallback,
-        StatusBarPanel, Animator.AnimatorListener {
+        StatusBarPanel, Animator.AnimatorListener, RecentsActivity.WindowAnimationStartListener {
     static final String TAG = "RecentsPanelView";
     static final boolean DEBUG = TabletStatusBar.DEBUG || PhoneStatusBar.DEBUG || false;
     private PopupMenu mPopup;
@@ -75,6 +80,7 @@
     private boolean mShowing;
     private boolean mWaitingToShow;
     private int mNumItemsWaitingForThumbnailsAndIcons;
+    private ViewHolder mItemToAnimateInWhenWindowAnimationIsFinished;
 
     private RecentTasksLoader mRecentTasksLoader;
     private ArrayList<TaskDescription> mRecentTaskDescriptions;
@@ -109,6 +115,7 @@
         ImageView iconView;
         TextView labelView;
         TextView descriptionView;
+        View calloutLine;
         TaskDescription taskDescription;
         boolean loadedThumbnailAndIcon;
     }
@@ -148,6 +155,7 @@
                 holder.iconView.setImageBitmap(mRecentTasksLoader.getDefaultIcon());
             }
             holder.labelView = (TextView) convertView.findViewById(R.id.app_label);
+            holder.calloutLine = convertView.findViewById(R.id.recents_callout_line);
             holder.descriptionView = (TextView) convertView.findViewById(R.id.app_description);
 
             convertView.setTag(holder);
@@ -173,6 +181,28 @@
                 updateIcon(holder, td.getIcon(), true, false);
                 mNumItemsWaitingForThumbnailsAndIcons--;
             }
+            if (index == 0) {
+                final Activity activity = (Activity) RecentsPanelView.this.getContext();
+                final SystemUIApplication app = (SystemUIApplication) activity.getApplication();
+                if (app.isWaitingForWindowAnimationStart()) {
+                    mItemToAnimateInWhenWindowAnimationIsFinished = holder;
+                    final int translation = -getResources().getDimensionPixelSize(
+                            R.dimen.status_bar_recents_app_icon_translate_distance);
+                    final Configuration config = getResources().getConfiguration();
+                    if (config.orientation == Configuration.ORIENTATION_PORTRAIT) {
+                        for (View v :
+                            new View[] { holder.iconView, holder.labelView, holder.calloutLine }) {
+                            if (v != null) {
+                                v.setAlpha(0f);
+                                v.setTranslationX(translation);
+                            }
+                        }
+                    } else {
+                        holder.iconView.setAlpha(0f);
+                        holder.iconView.setTranslationY(translation);
+                    }
+                }
+            }
 
             holder.thumbnailView.setTag(td);
             holder.thumbnailView.setOnLongClickListener(new OnLongClickDelegate(convertView));
@@ -506,6 +536,23 @@
         return null;
     }
 
+    public void onWindowAnimationStart() {
+        if (mItemToAnimateInWhenWindowAnimationIsFinished != null) {
+            final int startDelay = 100;
+            final int duration = 250;
+            final ViewHolder holder = mItemToAnimateInWhenWindowAnimationIsFinished;
+            final TimeInterpolator cubic = new DecelerateInterpolator(1.5f);
+            for (View v :
+                new View[] { holder.iconView, holder.labelView, holder.calloutLine }) {
+                if (v != null) {
+                    v.animate().translationX(0).translationY(0).alpha(1f).setStartDelay(startDelay)
+                            .setDuration(duration).setInterpolator(cubic);
+                }
+            }
+            mItemToAnimateInWhenWindowAnimationIsFinished = null;
+        }
+    }
+
     public void clearRecentTasksList() {
         // Clear memory used by screenshots
         if (mRecentTaskDescriptions != null) {
diff --git a/packages/SystemUI/src/com/android/systemui/recent/RecentsVerticalScrollView.java b/packages/SystemUI/src/com/android/systemui/recent/RecentsVerticalScrollView.java
index a0f197dd..5e0df49 100644
--- a/packages/SystemUI/src/com/android/systemui/recent/RecentsVerticalScrollView.java
+++ b/packages/SystemUI/src/com/android/systemui/recent/RecentsVerticalScrollView.java
@@ -165,19 +165,18 @@
         }
         setLayoutTransition(transitioner);
 
-        // Scroll to end after layout.
-        final ViewTreeObserver observer = getViewTreeObserver();
-
+        // Scroll to end after initial layout.
         final OnGlobalLayoutListener updateScroll = new OnGlobalLayoutListener() {
                 public void onGlobalLayout() {
                     mLastScrollPosition = scrollPositionOfMostRecent();
                     scrollTo(0, mLastScrollPosition);
+                    final ViewTreeObserver observer = getViewTreeObserver();
                     if (observer.isAlive()) {
                         observer.removeOnGlobalLayoutListener(this);
                     }
                 }
             };
-        observer.addOnGlobalLayoutListener(updateScroll);
+        getViewTreeObserver().addOnGlobalLayoutListener(updateScroll);
     }
 
     @Override
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java
index d7b1b35..e88f9cd 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java
@@ -544,7 +544,7 @@
                             - p.getFontMetricsInt().top;
                     float descriptionTextSize = res
                             .getDimensionPixelSize(R.dimen.status_bar_recents_app_description_text_size);
-                    p.setTextSize(labelTextSize);
+                    p.setTextSize(descriptionTextSize);
                     float descriptionTextHeight = p.getFontMetricsInt().bottom
                             - p.getFontMetricsInt().top;
 
@@ -567,10 +567,17 @@
                             + recentsItemTopPadding + thumbBgPadding + statusBarHeight);
                 }
 
+                final SystemUIApplication app =
+                        (SystemUIApplication) ((Service) mContext).getApplication();
+                app.setWaitingForWinAnimStart(true);
                 ActivityOptions opts = ActivityOptions.makeThumbnailScaleDownAnimation(
                         getStatusBarView(),
                         first, x, y,
-                        null);
+                        new ActivityOptions.OnAnimationStartedListener() {
+                            public void onAnimationStarted() {
+                                app.onWindowAnimationStart();
+                            }
+                        });
                 mContext.startActivityAsUser(intent, opts.toBundle(), new UserHandle(
                         UserHandle.USER_CURRENT));
             }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelBar.java
index f623692..6b9bc89 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelBar.java
@@ -83,7 +83,11 @@
         // figure out which panel needs to be talked to here
         if (event.getAction() == MotionEvent.ACTION_DOWN) {
             final PanelView panel = selectPanelForTouchX(event.getX());
-            LOG("PanelBar.onTouch: state=%d ACTION_DOWN: panel %s", mState, panel);
+            boolean enabled = panel.isEnabled();
+            LOG("PanelBar.onTouch: state=%d ACTION_DOWN: panel %s %s", mState, panel,
+                    (enabled ? "" : " (disabled)"));
+            if (!enabled)
+                return false;
             startOpeningPanel(panel);
         }
         final boolean result = mTouchingPanel.getHandle().dispatchTouchEvent(event);
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 12e749d..493a92a 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
@@ -30,6 +30,7 @@
 import android.content.Intent;
 import android.content.IntentFilter;
 import android.content.res.Resources;
+import android.database.ContentObserver;
 import android.graphics.Canvas;
 import android.graphics.ColorFilter;
 import android.graphics.PixelFormat;
@@ -39,6 +40,7 @@
 import android.graphics.drawable.Drawable;
 import android.graphics.drawable.NinePatchDrawable;
 import android.inputmethodservice.InputMethodService;
+import android.os.Handler;
 import android.os.IBinder;
 import android.os.Message;
 import android.os.RemoteException;
@@ -259,6 +261,26 @@
         }
     };
 
+    // ensure quick settings is disabled until the current user makes it through the setup wizard
+    private boolean mUserSetup = false;
+    private ContentObserver mUserSetupObserver = new ContentObserver(new Handler()) {
+        @Override
+        public void onChange(boolean selfChange) {
+            final boolean userSetup = 0 != Settings.Secure.getIntForUser(
+                    mContext.getContentResolver(),
+                    Settings.Secure.USER_SETUP_COMPLETE,
+                    0 /*default */,
+                    mCurrentUserId);
+            if (userSetup != mUserSetup) {
+                mUserSetup = userSetup;
+                if (mSettingsPanel != null)
+                    mSettingsPanel.setEnabled(mUserSetup);
+                if (!mUserSetup && mStatusBarView != null)
+                    animateCollapseQuickSettings();
+            }
+        }
+    };
+
     @Override
     public void start() {
         mDisplay = ((WindowManager)mContext.getSystemService(Context.WINDOW_SERVICE))
@@ -461,6 +483,9 @@
         filter.addAction(Intent.ACTION_SCREEN_ON);
         context.registerReceiver(mBroadcastReceiver, filter);
 
+        // listen for USER_SETUP_COMPLETE setting (per-user)
+        resetUserSetupObserver();
+
         return mStatusBarView;
     }
 
@@ -1827,8 +1852,18 @@
         if (MULTIUSER_DEBUG) mNotificationPanelDebugText.setText("USER " + newUserId);
         animateCollapsePanels();
         updateNotificationIcons();
+        resetUserSetupObserver();
     }
-    
+
+    private void resetUserSetupObserver() {
+        mContext.getContentResolver().unregisterContentObserver(mUserSetupObserver);
+        mUserSetupObserver.onChange(false);
+        mContext.getContentResolver().registerContentObserver(
+                Settings.Secure.getUriFor(Settings.Secure.USER_SETUP_COMPLETE), true,
+                mUserSetupObserver,
+                mCurrentUserId);
+    }
+
     private void setIntruderAlertVisibility(boolean vis) {
         if (!ENABLE_INTRUDERS) return;
         if (DEBUG) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickSettings.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickSettings.java
index d63d517..c31e138 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickSettings.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickSettings.java
@@ -275,7 +275,8 @@
         timeTile.setOnClickListener(new View.OnClickListener() {
             @Override
             public void onClick(View v) {
-                startSettingsActivity(android.provider.Settings.ACTION_DATE_SETTINGS);
+                // Quick. Clock. Quick. Clock. Quick. Clock.
+                startSettingsActivity(Intent.ACTION_QUICK_CLOCK);
             }
         });
         mModel.addTimeTile(timeTile, new QuickSettingsModel.RefreshCallback() {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/QuickSettingsDateView.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/QuickSettingsDateView.java
deleted file mode 100644
index c52f94b..0000000
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/QuickSettingsDateView.java
+++ /dev/null
@@ -1,45 +0,0 @@
-/*
- * 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/packages/SystemUI/src/com/android/systemui/usb/UsbAccessoryUriActivity.java b/packages/SystemUI/src/com/android/systemui/usb/UsbAccessoryUriActivity.java
index 5007cf4..ff06630 100644
--- a/packages/SystemUI/src/com/android/systemui/usb/UsbAccessoryUriActivity.java
+++ b/packages/SystemUI/src/com/android/systemui/usb/UsbAccessoryUriActivity.java
@@ -26,6 +26,7 @@
 import android.hardware.usb.UsbAccessory;
 import android.hardware.usb.UsbManager;
 import android.os.Bundle;
+import android.os.UserHandle;
 import android.util.Log;
 
 import com.android.internal.app.AlertActivity;
@@ -90,7 +91,7 @@
             intent.addCategory(Intent.CATEGORY_BROWSABLE);
             intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
             try {
-                startActivity(intent);
+                startActivityAsUser(intent, UserHandle.CURRENT);
             } catch (ActivityNotFoundException e) {
                 Log.e(TAG, "startActivity failed for " + mUri);
             }
diff --git a/packages/SystemUI/src/com/android/systemui/usb/UsbConfirmActivity.java b/packages/SystemUI/src/com/android/systemui/usb/UsbConfirmActivity.java
index 030a261..3eccccd 100644
--- a/packages/SystemUI/src/com/android/systemui/usb/UsbConfirmActivity.java
+++ b/packages/SystemUI/src/com/android/systemui/usb/UsbConfirmActivity.java
@@ -16,23 +16,21 @@
 
 package com.android.systemui.usb;
 
-import android.app.Activity;
 import android.app.AlertDialog;
 import android.content.ComponentName;
 import android.content.Context;
 import android.content.DialogInterface;
 import android.content.Intent;
-import android.content.pm.ApplicationInfo;
 import android.content.pm.PackageManager;
 import android.content.pm.ResolveInfo;
 import android.hardware.usb.IUsbManager;
-import android.hardware.usb.UsbDevice;
 import android.hardware.usb.UsbAccessory;
+import android.hardware.usb.UsbDevice;
 import android.hardware.usb.UsbManager;
 import android.os.Bundle;
 import android.os.IBinder;
-import android.os.RemoteException;
 import android.os.ServiceManager;
+import android.os.UserHandle;
 import android.util.Log;
 import android.view.LayoutInflater;
 import android.view.View;
@@ -42,7 +40,6 @@
 
 import com.android.internal.app.AlertActivity;
 import com.android.internal.app.AlertController;
-
 import com.android.systemui.R;
 
 public class UsbConfirmActivity extends AlertActivity
@@ -62,10 +59,10 @@
     public void onCreate(Bundle icicle) {
         super.onCreate(icicle);
 
-       Intent intent = getIntent();
-        mDevice = (UsbDevice)intent.getParcelableExtra(UsbManager.EXTRA_DEVICE);
+        Intent intent = getIntent();
+        mDevice = (UsbDevice) intent.getParcelableExtra(UsbManager.EXTRA_DEVICE);
         mAccessory = (UsbAccessory)intent.getParcelableExtra(UsbManager.EXTRA_ACCESSORY);
-        mResolveInfo = (ResolveInfo)intent.getParcelableExtra("rinfo");
+        mResolveInfo = (ResolveInfo) intent.getParcelableExtra("rinfo");
 
         PackageManager packageManager = getPackageManager();
         String appName = mResolveInfo.loadLabel(packageManager).toString();
@@ -117,7 +114,8 @@
             try {
                 IBinder b = ServiceManager.getService(USB_SERVICE);
                 IUsbManager service = IUsbManager.Stub.asInterface(b);
-                int uid = mResolveInfo.activityInfo.applicationInfo.uid;
+                final int uid = mResolveInfo.activityInfo.applicationInfo.uid;
+                final int userId = UserHandle.myUserId();
                 boolean alwaysUse = mAlwaysUse.isChecked();
                 Intent intent = null;
 
@@ -129,9 +127,10 @@
                     service.grantDevicePermission(mDevice, uid);
                     // set or clear default setting
                     if (alwaysUse) {
-                        service.setDevicePackage(mDevice, mResolveInfo.activityInfo.packageName);
+                        service.setDevicePackage(
+                                mDevice, mResolveInfo.activityInfo.packageName, userId);
                     } else {
-                        service.setDevicePackage(mDevice, null);
+                        service.setDevicePackage(mDevice, null, userId);
                     }
                 } else if (mAccessory != null) {
                     intent = new Intent(UsbManager.ACTION_USB_ACCESSORY_ATTACHED);
@@ -141,10 +140,10 @@
                     service.grantAccessoryPermission(mAccessory, uid);
                     // set or clear default setting
                     if (alwaysUse) {
-                        service.setAccessoryPackage(mAccessory,
-                                mResolveInfo.activityInfo.packageName);
+                        service.setAccessoryPackage(
+                                mAccessory, mResolveInfo.activityInfo.packageName, userId);
                     } else {
-                        service.setAccessoryPackage(mAccessory, null);
+                        service.setAccessoryPackage(mAccessory, null, userId);
                     }
                 }
 
@@ -152,7 +151,7 @@
                 intent.setComponent(
                     new ComponentName(mResolveInfo.activityInfo.packageName,
                             mResolveInfo.activityInfo.name));
-                startActivity(intent);
+                startActivityAsUser(intent, new UserHandle(userId));
             } catch (Exception e) {
                 Log.e(TAG, "Unable to start activity", e);
             }
diff --git a/packages/SystemUI/src/com/android/systemui/usb/UsbPermissionActivity.java b/packages/SystemUI/src/com/android/systemui/usb/UsbPermissionActivity.java
index c384f50..6e88d0d 100644
--- a/packages/SystemUI/src/com/android/systemui/usb/UsbPermissionActivity.java
+++ b/packages/SystemUI/src/com/android/systemui/usb/UsbPermissionActivity.java
@@ -32,6 +32,7 @@
 import android.os.IBinder;
 import android.os.RemoteException;
 import android.os.ServiceManager;
+import android.os.UserHandle;
 import android.util.Log;
 import android.view.LayoutInflater;
 import android.view.View;
@@ -67,7 +68,7 @@
         mDevice = (UsbDevice)intent.getParcelableExtra(UsbManager.EXTRA_DEVICE);
         mAccessory = (UsbAccessory)intent.getParcelableExtra(UsbManager.EXTRA_ACCESSORY);
         mPendingIntent = (PendingIntent)intent.getParcelableExtra(Intent.EXTRA_INTENT);
-        mUid = intent.getIntExtra("uid", 0);
+        mUid = intent.getIntExtra(Intent.EXTRA_UID, -1);
         mPackageName = intent.getStringExtra("package");
 
         PackageManager packageManager = getPackageManager();
@@ -128,7 +129,8 @@
                 if (mPermissionGranted) {
                     service.grantDevicePermission(mDevice, mUid);
                     if (mAlwaysUse.isChecked()) {
-                        service.setDevicePackage(mDevice, mPackageName);
+                        final int userId = UserHandle.getUserId(mUid);
+                        service.setDevicePackage(mDevice, mPackageName, userId);
                     }
                 }
             }
@@ -137,7 +139,8 @@
                 if (mPermissionGranted) {
                     service.grantAccessoryPermission(mAccessory, mUid);
                     if (mAlwaysUse.isChecked()) {
-                        service.setAccessoryPackage(mAccessory, mPackageName);
+                        final int userId = UserHandle.getUserId(mUid);
+                        service.setAccessoryPackage(mAccessory, mPackageName, userId);
                     }
                 }
             }
diff --git a/packages/SystemUI/src/com/android/systemui/usb/UsbResolverActivity.java b/packages/SystemUI/src/com/android/systemui/usb/UsbResolverActivity.java
index f61ecb1..9928f7f 100644
--- a/packages/SystemUI/src/com/android/systemui/usb/UsbResolverActivity.java
+++ b/packages/SystemUI/src/com/android/systemui/usb/UsbResolverActivity.java
@@ -16,8 +16,6 @@
 
 package com.android.systemui.usb;
 
-import com.android.internal.app.ResolverActivity;
-
 import android.content.ActivityNotFoundException;
 import android.content.Intent;
 import android.content.pm.ResolveInfo;
@@ -30,9 +28,11 @@
 import android.os.Parcelable;
 import android.os.RemoteException;
 import android.os.ServiceManager;
+import android.os.UserHandle;
 import android.util.Log;
 import android.widget.CheckBox;
 
+import com.android.internal.app.ResolverActivity;
 import com.android.systemui.R;
 
 import java.util.ArrayList;
@@ -92,34 +92,36 @@
         super.onDestroy();
     }
 
+    @Override
     protected void onIntentSelected(ResolveInfo ri, Intent intent, boolean alwaysCheck) {
         try {
             IBinder b = ServiceManager.getService(USB_SERVICE);
             IUsbManager service = IUsbManager.Stub.asInterface(b);
-            int uid = ri.activityInfo.applicationInfo.uid;
+            final int uid = ri.activityInfo.applicationInfo.uid;
+            final int userId = UserHandle.myUserId();
 
             if (mDevice != null) {
                 // grant permission for the device
                 service.grantDevicePermission(mDevice, uid);
                 // set or clear default setting
                 if (alwaysCheck) {
-                    service.setDevicePackage(mDevice, ri.activityInfo.packageName);
+                    service.setDevicePackage(mDevice, ri.activityInfo.packageName, userId);
                 } else {
-                    service.setDevicePackage(mDevice, null);
+                    service.setDevicePackage(mDevice, null, userId);
                 }
             } else if (mAccessory != null) {
                 // grant permission for the accessory
                 service.grantAccessoryPermission(mAccessory, uid);
                 // set or clear default setting
                 if (alwaysCheck) {
-                    service.setAccessoryPackage(mAccessory, ri.activityInfo.packageName);
+                    service.setAccessoryPackage(mAccessory, ri.activityInfo.packageName, userId);
                 } else {
-                    service.setAccessoryPackage(mAccessory, null);
+                    service.setAccessoryPackage(mAccessory, null, userId);
                 }
             }
 
             try {
-                startActivity(intent);
+                startActivityAsUser(intent, new UserHandle(userId));
             } catch (ActivityNotFoundException e) {
                 Log.e(TAG, "startActivity failed", e);
             }
diff --git a/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java b/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
index 93f2aa5..5af32e9 100755
--- a/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
+++ b/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
@@ -2573,11 +2573,13 @@
         final boolean hasNavBar = (isDefaultDisplay && mHasNavigationBar
                 && mNavigationBar != null && mNavigationBar.isVisibleLw());
 
+        final int adjust = sim & SOFT_INPUT_MASK_ADJUST;
+
         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);
+                setAttachedWindowFrames(win, fl, adjust, attached, true, pf, df, cf, vf);
             } else {
                 // Give the window full screen.
                 pf.left = df.left = cf.left = mUnrestrictedScreenLeft;
@@ -2596,8 +2598,6 @@
             attrs.gravity = Gravity.BOTTOM;
             mDockLayer = win.getSurfaceLayer();
         } else {
-            final int adjust = sim & SOFT_INPUT_MASK_ADJUST;
-
             if ((fl & (FLAG_LAYOUT_IN_SCREEN | FLAG_FULLSCREEN | FLAG_LAYOUT_INSET_DECOR))
                     == (FLAG_LAYOUT_IN_SCREEN | FLAG_LAYOUT_INSET_DECOR)
                     && (sysUiFl & View.SYSTEM_UI_FLAG_FULLSCREEN) == 0) {
@@ -2611,7 +2611,7 @@
                 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);
+                    setAttachedWindowFrames(win, fl, adjust, attached, true, pf, df, cf, vf);
                 } else {
                     if (attrs.type == TYPE_STATUS_BAR_PANEL
                             || attrs.type == TYPE_STATUS_BAR_SUB_PANEL) {
diff --git a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardFaceUnlockView.java b/policy/src/com/android/internal/policy/impl/keyguard/KeyguardFaceUnlockView.java
index 5922810..8776a80 100644
--- a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardFaceUnlockView.java
+++ b/policy/src/com/android/internal/policy/impl/keyguard/KeyguardFaceUnlockView.java
@@ -153,7 +153,8 @@
             if (mBiometricUnlock != null) {
                 mBiometricUnlock.stop();
             }
-            mLockPatternUtils.setCurrentUser(userId);
+            // No longer required; static value set by KeyguardViewMediator
+            // mLockPatternUtils.setCurrentUser(userId);
         }
     };
 
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 a7fc1a1..8e7e07f 100644
--- a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardHostView.java
+++ b/policy/src/com/android/internal/policy/impl/keyguard/KeyguardHostView.java
@@ -67,6 +67,7 @@
     private AppWidgetHost mAppWidgetHost;
     private KeyguardWidgetPager mAppWidgetContainer;
     private ViewFlipper mSecurityViewContainer;
+    private KeyguardTransportControlView mTransportControl;
     private boolean mEnableMenuKey;
     private boolean mIsVerifyUnlockOnly;
     private boolean mEnableFallback; // TODO: This should get the value from KeyguardPatternView
@@ -80,7 +81,6 @@
     private KeyguardSecurityModel mSecurityModel;
 
     private Rect mTempRect = new Rect();
-    private KeyguardTransportControlView mTransportControl;
 
     /*package*/ interface TransportCallback {
         void hide();
@@ -145,45 +145,7 @@
         kgwr.setVisibility(VISIBLE);
         mSecurityViewContainer = (ViewFlipper) findViewById(R.id.view_flipper);
 
-        // This code manages showing/hiding the transport control. We keep it around and only
-        // add it to the hierarchy if it needs to be present.
-        mTransportControl =
-                (KeyguardTransportControlView) findViewById(R.id.keyguard_transport_control);
-        if (mTransportControl != null) {
-            mTransportControl.setKeyguardCallback(new TransportCallback() {
-                boolean mSticky = false;
-                @Override
-                public void hide() {
-                    int page = getWidgetPosition(R.id.keyguard_transport_control);
-                    if (page != -1 && !mSticky) {
-                        if (page == mAppWidgetContainer.getCurrentPage()) {
-                            // Switch back to clock view if music was showing.
-                            mAppWidgetContainer
-                                .setCurrentPage(getWidgetPosition(R.id.keyguard_status_view));
-                        }
-                        mAppWidgetContainer.removeView(mTransportControl);
-                        // XXX keep view attached to hierarchy so we still get show/hide events
-                        // from AudioManager
-                        KeyguardHostView.this.addView(mTransportControl);
-                        mTransportControl.setVisibility(View.GONE);
-                        showAppropriateWidgetPage();
-                    }
-                }
-
-                @Override
-                public void show() {
-                    if (getWidgetPosition(R.id.keyguard_transport_control) == -1) {
-                        KeyguardHostView.this.removeView(mTransportControl);
-                        mAppWidgetContainer.addView(mTransportControl,
-                                getWidgetPosition(R.id.keyguard_status_view) + 1);
-                        mTransportControl.setVisibility(View.VISIBLE);
-                        // Once shown, leave it showing
-                        mSticky = true;
-                        showAppropriateWidgetPage();
-                    }
-                }
-            });
-        }
+        addDefaultWidgets();
         updateSecurityViews();
         setSystemUiVisibility(getSystemUiVisibility() | View.STATUS_BAR_DISABLE_BACK);
     }
@@ -702,6 +664,52 @@
         }
     }
 
+    private void addDefaultWidgets() {
+        LayoutInflater inflater = LayoutInflater.from(mContext);
+        inflater.inflate(R.layout.keyguard_status_view, mAppWidgetContainer, true);
+        inflater.inflate(R.layout.keyguard_transport_control_view, mAppWidgetContainer, true);
+
+        mTransportControl =
+            (KeyguardTransportControlView) findViewById(R.id.keyguard_transport_control);
+
+
+        // This code manages showing/hiding the transport control. We keep it around and only
+        // add it to the hierarchy if it needs to be present.
+        if (mTransportControl != null) {
+            mTransportControl.setKeyguardCallback(new TransportCallback() {
+                boolean mSticky = false;
+                @Override
+                public void hide() {
+                    int page = getWidgetPosition(R.id.keyguard_transport_control);
+                    if (page != -1 && !mSticky) {
+                        if (page == mAppWidgetContainer.getCurrentPage()) {
+                            // Switch back to clock view if music was showing.
+                            mAppWidgetContainer
+                                .setCurrentPage(getWidgetPosition(R.id.keyguard_status_view));
+                        }
+                        mAppWidgetContainer.removeView(mTransportControl);
+                        // XXX keep view attached to hierarchy so we still get show/hide events
+                        // from AudioManager
+                        KeyguardHostView.this.addView(mTransportControl);
+                        mTransportControl.setVisibility(View.GONE);
+                    }
+                }
+
+                @Override
+                public void show() {
+                    if (getWidgetPosition(R.id.keyguard_transport_control) == -1) {
+                        KeyguardHostView.this.removeView(mTransportControl);
+                        mAppWidgetContainer.addView(mTransportControl,
+                                getWidgetPosition(R.id.keyguard_status_view) + 1);
+                        mTransportControl.setVisibility(View.VISIBLE);
+                        // Once shown, leave it showing
+                        mSticky = true;
+                    }
+                }
+            });
+        }
+    }
+
     private void maybePopulateWidgets() {
         DevicePolicyManager dpm =
                 (DevicePolicyManager) mContext.getSystemService(Context.DEVICE_POLICY_SERVICE);
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 1977b529..4003754 100644
--- a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardSelectorView.java
+++ b/policy/src/com/android/internal/policy/impl/keyguard/KeyguardSelectorView.java
@@ -23,6 +23,8 @@
 import android.content.ComponentName;
 import android.content.Context;
 import android.content.Intent;
+import android.content.pm.PackageManager;
+import android.content.pm.ResolveInfo;
 import android.os.RemoteException;
 import android.os.UserHandle;
 import android.provider.MediaStore;
@@ -38,6 +40,8 @@
 import com.android.internal.widget.multiwaveview.GlowPadView.OnTriggerListener;
 import com.android.internal.R;
 
+import java.util.List;
+
 public class KeyguardSelectorView extends LinearLayout implements KeyguardSecurityView {
     private static final boolean DEBUG = KeyguardHostView.DEBUG;
     private static final String TAG = "SecuritySelectorView";
@@ -118,12 +122,39 @@
         this(context, null);
     }
 
+    private boolean wouldLaunchResolverActivity(Intent intent) {
+        PackageManager packageManager = mContext.getPackageManager();
+        ResolveInfo resolved = packageManager.resolveActivityAsUser(intent,
+                PackageManager.MATCH_DEFAULT_ONLY, mLockPatternUtils.getCurrentUser());
+        final List<ResolveInfo> appList = packageManager.queryIntentActivitiesAsUser(
+                intent, PackageManager.MATCH_DEFAULT_ONLY, mLockPatternUtils.getCurrentUser());
+        // If the list contains the above resolved activity, then it can't be
+        // ResolverActivity itself.
+        for (int i = 0; i < appList.size(); i++) {
+            ResolveInfo tmp = appList.get(i);
+            if (tmp.activityInfo.name.equals(resolved.activityInfo.name)
+                    && tmp.activityInfo.packageName.equals(resolved.activityInfo.packageName)) {
+                return false;
+            }
+        }
+        return true;
+    }
+
     protected void launchCamera() {
         if (mLockPatternUtils.isSecure()) {
             // Launch the secure version of the camera
-            Intent intent = new Intent(MediaStore.INTENT_ACTION_STILL_IMAGE_CAMERA_SECURE);
+            final Intent intent = new Intent(MediaStore.INTENT_ACTION_STILL_IMAGE_CAMERA_SECURE);
             intent.addFlags(Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS);
-            launchActivity(intent, true);
+
+            if (wouldLaunchResolverActivity(intent)) {
+                // TODO: Show disambiguation dialog instead.
+                // For now, we'll treat this like launching any other app from secure keyguard.
+                // When they do, user sees the system's ResolverActivity which lets them choose
+                // which secure camera to use.
+                launchActivity(intent, false);
+            } else {
+                launchActivity(intent, true);
+            }
         } else {
             // Launch the normal camera
             launchActivity(new Intent(MediaStore.INTENT_ACTION_STILL_IMAGE_CAMERA), false);
diff --git a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardViewMediator.java b/policy/src/com/android/internal/policy/impl/keyguard/KeyguardViewMediator.java
index 514ada6..59aed24 100644
--- a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardViewMediator.java
+++ b/policy/src/com/android/internal/policy/impl/keyguard/KeyguardViewMediator.java
@@ -894,6 +894,8 @@
 
     /**
      * Update the newUserId. Call while holding WindowManagerService lock.
+     * NOTE: Should only be called by KeyguardViewMediator in response to the user id changing.
+     *
      * @param newUserId The id of the incoming user.
      */
     public void setCurrentUser(int newUserId) {
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 70a6ffa..d17c128 100644
--- a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardWidgetFrame.java
+++ b/policy/src/com/android/internal/policy/impl/keyguard/KeyguardWidgetFrame.java
@@ -33,7 +33,6 @@
 public class KeyguardWidgetFrame extends FrameLayout {
     private final static PorterDuffXfermode sAddBlendMode =
             new PorterDuffXfermode(PorterDuff.Mode.ADD);
-    private static int sWidgetPagePadding;
     private static Drawable sLeftOverscrollDrawable;
     private static Drawable sRightOverscrollDrawable;
 
@@ -52,13 +51,16 @@
 
     public KeyguardWidgetFrame(Context context, AttributeSet attrs, int defStyle) {
         super(context, attrs, defStyle);
+        Resources res = context.getResources();
         if (sLeftOverscrollDrawable == null) {
-            Resources res = context.getResources();
             sLeftOverscrollDrawable = res.getDrawable(R.drawable.kg_widget_overscroll_layer_left);
             sRightOverscrollDrawable = res.getDrawable(R.drawable.kg_widget_overscroll_layer_right);
-            sWidgetPagePadding = res.getDimensionPixelSize(R.dimen.kg_widget_page_padding);
         }
-        setPadding(sWidgetPagePadding, sWidgetPagePadding, sWidgetPagePadding, sWidgetPagePadding);
+
+        int hPadding = res.getDimensionPixelSize(R.dimen.kg_widget_pager_horizontal_padding);
+        int topPadding = res.getDimensionPixelSize(R.dimen.kg_widget_pager_top_padding);
+        int bottomPadding = res.getDimensionPixelSize(R.dimen.kg_widget_pager_bottom_padding);
+        setPadding(hPadding, topPadding, hPadding, bottomPadding);
     }
 
     @Override
@@ -76,8 +78,8 @@
     @Override
     protected void onSizeChanged(int w, int h, int oldw, int oldh) {
         super.onSizeChanged(w, h, oldw, oldh);
-        mForegroundRect.set(sWidgetPagePadding, sWidgetPagePadding,
-                w - sWidgetPagePadding, h - sWidgetPagePadding);
+        mForegroundRect.set(getPaddingLeft(), getPaddingTop(),
+                w - getPaddingRight(), h - getPaddingBottom());
     }
 
     void setOverScrollAmount(float r, boolean left) {
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 4af7a25..a1603dc 100644
--- a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardWidgetPager.java
+++ b/policy/src/com/android/internal/policy/impl/keyguard/KeyguardWidgetPager.java
@@ -27,6 +27,8 @@
 
 import android.widget.FrameLayout;
 
+import com.android.internal.R;
+
 public class KeyguardWidgetPager extends PagedView {
     ZInterpolator mZInterpolator = new ZInterpolator(0.5f);
     private static float CAMERA_DISTANCE = 10000;
@@ -47,6 +49,9 @@
 
     public KeyguardWidgetPager(Context context, AttributeSet attrs, int defStyle) {
         super(context, attrs, defStyle);
+        if (getImportantForAccessibility() == View.IMPORTANT_FOR_ACCESSIBILITY_AUTO) {
+            setImportantForAccessibility(View.IMPORTANT_FOR_ACCESSIBILITY_YES);
+        }
     }
 
     /*
@@ -60,6 +65,7 @@
         // The framework adds a default padding to AppWidgetHostView. We don't need this padding
         // for the Keyguard, so we override it to be 0.
         widget.setPadding(0,  0, 0, 0);
+        widget.setContentDescription(widget.getAppWidgetInfo().label);
         frame.addView(widget, lp);
         addView(frame);
     }
@@ -90,6 +96,21 @@
     }
 
     @Override
+    public String getCurrentPageDescription() {
+        final int nextPageIndex = getNextPage();
+        if (nextPageIndex >= 0 && nextPageIndex < getChildCount()) {
+            KeyguardWidgetFrame frame = (KeyguardWidgetFrame) getChildAt(nextPageIndex);
+            CharSequence title = frame.getChildAt(0).getContentDescription();
+            if (title == null) {
+                title = "";
+            }
+            return mContext.getString(R.string.keyguard_accessibility_widget_changed,
+                    title, nextPageIndex + 1, getChildCount());
+        }
+        return super.getCurrentPageDescription();
+    }
+
+    @Override
     protected void overScroll(float amount) {
         acceleratedOverScroll(amount);
     }
diff --git a/policy/src/com/android/internal/policy/impl/keyguard_obsolete/KeyguardViewMediator.java b/policy/src/com/android/internal/policy/impl/keyguard_obsolete/KeyguardViewMediator.java
index 8ff8dad..3de1428 100644
--- a/policy/src/com/android/internal/policy/impl/keyguard_obsolete/KeyguardViewMediator.java
+++ b/policy/src/com/android/internal/policy/impl/keyguard_obsolete/KeyguardViewMediator.java
@@ -392,14 +392,14 @@
         mScreenOn = mPM.isScreenOn();
 
         mLockSounds = new SoundPool(1, AudioManager.STREAM_SYSTEM, 0);
-        String soundPath = Settings.System.getString(cr, Settings.System.LOCK_SOUND);
+        String soundPath = Settings.Global.getString(cr, Settings.Global.LOCK_SOUND);
         if (soundPath != null) {
             mLockSoundId = mLockSounds.load(soundPath, 1);
         }
         if (soundPath == null || mLockSoundId == 0) {
             if (DEBUG) Log.d(TAG, "failed to load sound from " + soundPath);
         }
-        soundPath = Settings.System.getString(cr, Settings.System.UNLOCK_SOUND);
+        soundPath = Settings.Global.getString(cr, Settings.Global.UNLOCK_SOUND);
         if (soundPath != null) {
             mUnlockSoundId = mLockSounds.load(soundPath, 1);
         }
diff --git a/services/java/com/android/server/accessibility/AccessibilityInputFilter.java b/services/java/com/android/server/accessibility/AccessibilityInputFilter.java
index f1a03de..eb414fa 100644
--- a/services/java/com/android/server/accessibility/AccessibilityInputFilter.java
+++ b/services/java/com/android/server/accessibility/AccessibilityInputFilter.java
@@ -119,13 +119,16 @@
             mCurrentDeviceId = deviceId;
         }
         mPm.userActivity(event.getEventTime(), false);
-        MotionEvent motionEvent = (MotionEvent) event;
-        mEventHandler.onMotionEvent(motionEvent, policyFlags);
+        MotionEvent rawEvent = (MotionEvent) event;
+        MotionEvent transformedEvent = MotionEvent.obtain(rawEvent);
+        mEventHandler.onMotionEvent(transformedEvent, rawEvent, policyFlags);
+        transformedEvent.recycle();
     }
 
     @Override
-    public void onMotionEvent(MotionEvent event, int policyFlags) {
-        sendInputEvent(event, policyFlags);
+    public void onMotionEvent(MotionEvent transformedEvent, MotionEvent rawEvent,
+            int policyFlags) {
+        sendInputEvent(transformedEvent, policyFlags);
     }
 
     @Override
diff --git a/services/java/com/android/server/accessibility/EventStreamTransformation.java b/services/java/com/android/server/accessibility/EventStreamTransformation.java
index b715570..3289a15 100644
--- a/services/java/com/android/server/accessibility/EventStreamTransformation.java
+++ b/services/java/com/android/server/accessibility/EventStreamTransformation.java
@@ -57,12 +57,15 @@
 interface EventStreamTransformation {
 
     /**
-     * Receives a motion event.
+     * Receives motion event. Passed are the event transformed by previous
+     * transformations and the raw event to which no transformations have
+     * been applied.
      *
-     * @param event The motion event.
+     * @param event The transformed motion event.
+     * @param rawEvent The raw motion event.
      * @param policyFlags Policy flags for the event.
      */
-    public void onMotionEvent(MotionEvent event, int policyFlags);
+    public void onMotionEvent(MotionEvent event, MotionEvent rawEvent, int policyFlags);
 
     /**
      * Receives an accessibility event.
diff --git a/services/java/com/android/server/accessibility/ScreenMagnifier.java b/services/java/com/android/server/accessibility/ScreenMagnifier.java
index b7327080..14762a1 100644
--- a/services/java/com/android/server/accessibility/ScreenMagnifier.java
+++ b/services/java/com/android/server/accessibility/ScreenMagnifier.java
@@ -183,8 +183,8 @@
                 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);
+        mWindowAnimationScale = Settings.Global.getFloat(context.getContentResolver(),
+                Settings.Global.WINDOW_ANIMATION_SCALE, DEFAULT_WINDOW_ANIMATION_SCALE);
 
         mMagnificationController = new MagnificationController(mShortAnimationDuration);
         mDisplayProvider = new DisplayProvider(context, mWindowManager);
@@ -203,14 +203,15 @@
     }
 
     @Override
-    public void onMotionEvent(MotionEvent event, int policyFlags) {
+    public void onMotionEvent(MotionEvent event, MotionEvent rawEvent,
+            int policyFlags) {
         mMagnifiedContentInteractonStateHandler.onMotionEvent(event);
         switch (mCurrentState) {
             case STATE_DELEGATING: {
-                handleMotionEventStateDelegating(event, policyFlags);
+                handleMotionEventStateDelegating(event, rawEvent, policyFlags);
             } break;
             case STATE_DETECTING: {
-                mDetectingStateHandler.onMotionEvent(event, policyFlags);
+                mDetectingStateHandler.onMotionEvent(event, rawEvent, policyFlags);
             } break;
             case STATE_VIEWPORT_DRAGGING: {
                 mStateViewportDraggingHandler.onMotionEvent(event, policyFlags);
@@ -259,7 +260,8 @@
         mScreenStateObserver.destroy();
     }
 
-    private void handleMotionEventStateDelegating(MotionEvent event, int policyFlags) {
+    private void handleMotionEventStateDelegating(MotionEvent event,
+            MotionEvent rawEvent, int policyFlags) {
         if (event.getActionMasked() == MotionEvent.ACTION_UP) {
             if (mDetectingStateHandler.mDelayedEventQueue == null) {
                 transitionToState(STATE_DETECTING);
@@ -290,7 +292,7 @@
                         coords, 0, 0, 1.0f, 1.0f, event.getDeviceId(), 0, event.getSource(),
                         event.getFlags());
             }
-            mNext.onMotionEvent(event, policyFlags);
+            mNext.onMotionEvent(event, rawEvent, policyFlags);
         }
     }
 
@@ -533,8 +535,8 @@
             }
         };
 
-        public void onMotionEvent(MotionEvent event, int policyFlags) {
-            cacheDelayedMotionEvent(event, policyFlags);
+        public void onMotionEvent(MotionEvent event, MotionEvent rawEvent, int policyFlags) {
+            cacheDelayedMotionEvent(event, rawEvent, policyFlags);
             final int action = event.getActionMasked();
             switch (action) {
                 case MotionEvent.ACTION_DOWN: {
@@ -640,8 +642,10 @@
             }
         }
 
-        private void cacheDelayedMotionEvent(MotionEvent event, int policyFlags) {
-            MotionEventInfo info = MotionEventInfo.obtain(event, policyFlags);
+        private void cacheDelayedMotionEvent(MotionEvent event, MotionEvent rawEvent,
+                int policyFlags) {
+            MotionEventInfo info = MotionEventInfo.obtain(event, rawEvent,
+                    policyFlags);
             if (mDelayedEventQueue == null) {
                 mDelayedEventQueue = info;
             } else {
@@ -657,7 +661,8 @@
             while (mDelayedEventQueue != null) {
                 MotionEventInfo info = mDelayedEventQueue;
                 mDelayedEventQueue = info.mNext;
-                ScreenMagnifier.this.onMotionEvent(info.mEvent, info.mPolicyFlags);
+                ScreenMagnifier.this.onMotionEvent(info.mEvent, info.mRawEvent,
+                        info.mPolicyFlags);
                 info.recycle();
             }
         }
@@ -738,9 +743,11 @@
         private boolean mInPool;
 
         public MotionEvent mEvent;
+        public MotionEvent mRawEvent;
         public int mPolicyFlags;
 
-        public static MotionEventInfo obtain(MotionEvent event, int policyFlags) {
+        public static MotionEventInfo obtain(MotionEvent event, MotionEvent rawEvent,
+                int policyFlags) {
             synchronized (sLock) {
                 MotionEventInfo info;
                 if (sPoolSize > 0) {
@@ -752,13 +759,15 @@
                 } else {
                     info = new MotionEventInfo();
                 }
-                info.initialize(event, policyFlags);
+                info.initialize(event, rawEvent, policyFlags);
                 return info;
             }
         }
 
-        private void initialize(MotionEvent event, int policyFlags) {
+        private void initialize(MotionEvent event, MotionEvent rawEvent,
+                int policyFlags) {
             mEvent = MotionEvent.obtain(event);
+            mRawEvent = MotionEvent.obtain(rawEvent);
             mPolicyFlags = policyFlags;
         }
 
@@ -780,6 +789,8 @@
         private void clear() {
             mEvent.recycle();
             mEvent = null;
+            mRawEvent.recycle();
+            mRawEvent = null;
             mPolicyFlags = 0;
         }
     }
diff --git a/services/java/com/android/server/accessibility/TouchExplorer.java b/services/java/com/android/server/accessibility/TouchExplorer.java
index 6e57d1f..c9f89b1 100644
--- a/services/java/com/android/server/accessibility/TouchExplorer.java
+++ b/services/java/com/android/server/accessibility/TouchExplorer.java
@@ -162,7 +162,7 @@
     private EventStreamTransformation mNext;
 
     // Helper to track gesture velocity.
-    private VelocityTracker mVelocityTracker;
+    private final VelocityTracker mVelocityTracker = VelocityTracker.obtain();
 
     // Helper class to track received pointers.
     private final ReceivedPointerTracker mReceivedPointerTracker;
@@ -198,7 +198,7 @@
     private GestureLibrary mGestureLibrary;
 
     // The long pressing pointer id if coordinate remapping is needed.
-    private int mLongPressingPointerId;
+    private int mLongPressingPointerId = -1;
 
     // The long pressing pointer X if coordinate remapping is needed.
     private int mLongPressingPointerDeltaX;
@@ -309,18 +309,18 @@
     }
 
     @Override
-    public void onMotionEvent(MotionEvent event, int policyFlags) {
+    public void onMotionEvent(MotionEvent event, MotionEvent rawEvent, int policyFlags) {
         if (DEBUG) {
             Slog.d(LOG_TAG, "Received event: " + event + ", policyFlags=0x"
                     + Integer.toHexString(policyFlags));
             Slog.d(LOG_TAG, getStateSymbolicName(mCurrentState));
         }
 
-        mReceivedPointerTracker.onMotionEvent(event);
+        mReceivedPointerTracker.onMotionEvent(rawEvent);
 
         switch(mCurrentState) {
             case STATE_TOUCH_EXPLORING: {
-                handleMotionEventStateTouchExploring(event, policyFlags);
+                handleMotionEventStateTouchExploring(event, rawEvent, policyFlags);
             } break;
             case STATE_DRAGGING: {
                 handleMotionEventStateDragging(event, policyFlags);
@@ -329,7 +329,7 @@
                 handleMotionEventStateDelegating(event, policyFlags);
             } break;
             case STATE_GESTURE_DETECTING: {
-                handleMotionEventGestureDetecting(event, policyFlags);
+                handleMotionEventGestureDetecting(rawEvent, policyFlags);
             } break;
             default:
                 throw new IllegalStateException("Illegal state: " + mCurrentState);
@@ -382,16 +382,15 @@
      * Handles a motion event in touch exploring state.
      *
      * @param event The event to be handled.
+     * @param rawEvent The raw (unmodified) motion event.
      * @param policyFlags The policy flags associated with the event.
      */
-    private void handleMotionEventStateTouchExploring(MotionEvent event, int policyFlags) {
+    private void handleMotionEventStateTouchExploring(MotionEvent event, MotionEvent rawEvent,
+            int policyFlags) {
         ReceivedPointerTracker receivedTracker = mReceivedPointerTracker;
         final int activePointerCount = receivedTracker.getActivePointerCount();
 
-        if (mVelocityTracker == null) {
-            mVelocityTracker = VelocityTracker.obtain();
-        }
-        mVelocityTracker.addMovement(event);
+        mVelocityTracker.addMovement(rawEvent);
 
         mDoubleTapDetector.onMotionEvent(event, policyFlags);
 
@@ -410,7 +409,7 @@
                 // have a distance slop before getting into gesture detection
                 // mode and not using the points within this slop significantly
                 // decreases the quality of gesture recognition.
-                handleMotionEventGestureDetecting(event, policyFlags);
+                handleMotionEventGestureDetecting(rawEvent, policyFlags);
                 //$FALL-THROUGH$
             case MotionEvent.ACTION_POINTER_DOWN: {
                 switch (activePointerCount) {
@@ -471,12 +470,13 @@
                             // have a distance slop before getting into gesture detection
                             // mode and not using the points within this slop significantly
                             // decreases the quality of gesture recognition.
-                            handleMotionEventGestureDetecting(event, policyFlags);
-
+                            handleMotionEventGestureDetecting(rawEvent, policyFlags);
+                            // It is *important* to use the distance traveled by the pointers
+                            // on the screen which may or may not be magnified.
                             final float deltaX = receivedTracker.getReceivedPointerDownX(pointerId)
-                                - event.getX(pointerIndex);
+                                - rawEvent.getX(pointerIndex);
                             final float deltaY = receivedTracker.getReceivedPointerDownY(pointerId)
-                                - event.getY(pointerIndex);
+                                - rawEvent.getY(pointerIndex);
                             final double moveDelta = Math.hypot(deltaX, deltaY);
                             // The user has moved enough for us to decide.
                             if (moveDelta > mDoubleTapSlop) {
@@ -491,6 +491,7 @@
                                     // We have to perform gesture detection, so
                                     // clear the current state and try to detect.
                                     mCurrentState = STATE_GESTURE_DETECTING;
+                                    mVelocityTracker.clear();
                                     mSendHoverEnterDelayed.remove();
                                     mSendHoverExitDelayed.remove();
                                     mPerformLongPressDelayed.remove();
@@ -535,10 +536,12 @@
                             // If the user is touch exploring the second pointer may be
                             // performing a double tap to activate an item without need
                             // for the user to lift his exploring finger.
+                            // It is *important* to use the distance traveled by the pointers
+                            // on the screen which may or may not be magnified.
                             final float deltaX = receivedTracker.getReceivedPointerDownX(pointerId)
-                                    - event.getX(pointerIndex);
+                                    - rawEvent.getX(pointerIndex);
                             final float deltaY = receivedTracker.getReceivedPointerDownY(pointerId)
-                                    - event.getY(pointerIndex);
+                                    - rawEvent.getY(pointerIndex);
                             final double moveDelta = Math.hypot(deltaX, deltaY);
                             if (moveDelta < mDoubleTapSlop) {
                                 break;
@@ -565,6 +568,7 @@
                             mCurrentState = STATE_DELEGATING;
                             sendDownForAllActiveNotInjectedPointers(event, policyFlags);
                         }
+                        mVelocityTracker.clear();
                     } break;
                     default: {
                         // More than one pointer so the user is not touch exploring
@@ -585,6 +589,7 @@
                         // More than two pointers are delegated to the view hierarchy.
                         mCurrentState = STATE_DELEGATING;
                         sendDownForAllActiveNotInjectedPointers(event, policyFlags);
+                        mVelocityTracker.clear();
                     }
                 }
             } break;
@@ -615,10 +620,7 @@
                         }
                     } break;
                 }
-                if (mVelocityTracker != null) {
-                    mVelocityTracker.clear();
-                    mVelocityTracker = null;
-                }
+                mVelocityTracker.clear();
             } break;
             case MotionEvent.ACTION_CANCEL: {
                 clear(event, policyFlags);
@@ -700,10 +702,24 @@
                     }
                 }
             } break;
+            case MotionEvent.ACTION_POINTER_UP: {
+                 final int pointerId = event.getPointerId(event.getActionIndex());
+                 if (pointerId == mDraggingPointerId) {
+                     mDraggingPointerId = INVALID_POINTER_ID;
+                     // Send an event to the end of the drag gesture.
+                     sendMotionEvent(event, MotionEvent.ACTION_UP, pointerIdBits, policyFlags);
+                 }
+            } break;
             case MotionEvent.ACTION_UP: {
                 // Announce the end of a new touch interaction.
                 sendAccessibilityEvent(
                         AccessibilityEvent.TYPE_TOUCH_INTERACTION_END);
+                final int pointerId = event.getPointerId(event.getActionIndex());
+                if (pointerId == mDraggingPointerId) {
+                    mDraggingPointerId = INVALID_POINTER_ID;
+                    // Send an event to the end of the drag gesture.
+                    sendMotionEvent(event, MotionEvent.ACTION_UP, pointerIdBits, policyFlags);
+                }
                 mCurrentState = STATE_TOUCH_EXPLORING;
             } break;
             case MotionEvent.ACTION_CANCEL: {
@@ -1046,7 +1062,10 @@
         // Make sure that the user will see the event.
         policyFlags |= WindowManagerPolicy.FLAG_PASS_TO_USER;
         if (mNext != null) {
-            mNext.onMotionEvent(event, policyFlags);
+            // TODO: For now pass null for the raw event since the touch
+            //       explorer is the last event transformation and it does
+            //       not care about the raw event.
+            mNext.onMotionEvent(event, null, policyFlags);
         }
 
         mInjectedPointerTracker.onMotionEvent(event);
diff --git a/services/java/com/android/server/display/DisplayDeviceInfo.java b/services/java/com/android/server/display/DisplayDeviceInfo.java
index f0cd0f5..b4dab86 100644
--- a/services/java/com/android/server/display/DisplayDeviceInfo.java
+++ b/services/java/com/android/server/display/DisplayDeviceInfo.java
@@ -38,9 +38,15 @@
     public static final int FLAG_SUPPORTS_ROTATION = 1 << 1;
 
     /**
-     * Flag: Indicates that this display device can show secure surfaces.
+     * Flag: Indicates that this display device has secure video output, such as HDCP.
      */
-    public static final int FLAG_SUPPORTS_SECURE_VIDEO_OUTPUT = 1 << 2;
+    public static final int FLAG_SECURE = 1 << 2;
+
+    /**
+     * Flag: Indicates that this display device supports compositing
+     * from gralloc protected buffers.
+     */
+    public static final int FLAG_SUPPORTS_PROTECTED_BUFFERS = 1 << 3;
 
     /**
      * Touch attachment: Display does not receive touch.
@@ -182,8 +188,11 @@
         if ((flags & FLAG_SUPPORTS_ROTATION) != 0) {
             msg.append(", FLAG_SUPPORTS_ROTATION");
         }
-        if ((flags & FLAG_SUPPORTS_SECURE_VIDEO_OUTPUT) != 0) {
-            msg.append(", FLAG_SUPPORTS_SECURE_VIDEO_OUTPUT");
+        if ((flags & FLAG_SECURE) != 0) {
+            msg.append(", FLAG_SECURE");
+        }
+        if ((flags & FLAG_SUPPORTS_PROTECTED_BUFFERS) != 0) {
+            msg.append(", FLAG_SUPPORTS_PROTECTED_BUFFERS");
         }
         return msg.toString();
     }
diff --git a/services/java/com/android/server/display/HeadlessDisplayAdapter.java b/services/java/com/android/server/display/HeadlessDisplayAdapter.java
index f3bec1d..7ec537f 100644
--- a/services/java/com/android/server/display/HeadlessDisplayAdapter.java
+++ b/services/java/com/android/server/display/HeadlessDisplayAdapter.java
@@ -60,7 +60,8 @@
                 mInfo.xDpi = 160;
                 mInfo.yDpi = 160;
                 mInfo.flags = DisplayDeviceInfo.FLAG_DEFAULT_DISPLAY
-                        | DisplayDeviceInfo.FLAG_SUPPORTS_SECURE_VIDEO_OUTPUT;
+                        | DisplayDeviceInfo.FLAG_SECURE
+                        | DisplayDeviceInfo.FLAG_SUPPORTS_PROTECTED_BUFFERS;
                 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 9c51463..679a67e 100644
--- a/services/java/com/android/server/display/LocalDisplayAdapter.java
+++ b/services/java/com/android/server/display/LocalDisplayAdapter.java
@@ -124,11 +124,16 @@
                 mInfo.width = mPhys.width;
                 mInfo.height = mPhys.height;
                 mInfo.refreshRate = mPhys.refreshRate;
+
+                // Assume that all built-in displays have secure output (eg. HDCP) and
+                // support compositing from gralloc protected buffers.
+                mInfo.flags = DisplayDeviceInfo.FLAG_SECURE
+                        | DisplayDeviceInfo.FLAG_SUPPORTS_PROTECTED_BUFFERS;
+
                 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_SUPPORTS_SECURE_VIDEO_OUTPUT
+                    mInfo.flags |= DisplayDeviceInfo.FLAG_DEFAULT_DISPLAY
                             | DisplayDeviceInfo.FLAG_SUPPORTS_ROTATION;
                     mInfo.densityDpi = (int)(mPhys.density * 160 + 0.5f);
                     mInfo.xDpi = mPhys.xDpi;
@@ -137,7 +142,6 @@
                 } else {
                     mInfo.name = getContext().getResources().getString(
                             com.android.internal.R.string.display_manager_hdmi_display_name);
-                    mInfo.flags = DisplayDeviceInfo.FLAG_SUPPORTS_SECURE_VIDEO_OUTPUT;
                     mInfo.touch = DisplayDeviceInfo.TOUCH_EXTERNAL;
                     mInfo.setAssumedDensityForExternalDisplay(mPhys.width, mPhys.height);
                 }
diff --git a/services/java/com/android/server/display/LogicalDisplay.java b/services/java/com/android/server/display/LogicalDisplay.java
index 3607de15..c4b749c 100644
--- a/services/java/com/android/server/display/LogicalDisplay.java
+++ b/services/java/com/android/server/display/LogicalDisplay.java
@@ -179,8 +179,8 @@
         if (!Objects.equal(mPrimaryDisplayDeviceInfo, deviceInfo)) {
             mBaseDisplayInfo.layerStack = mLayerStack;
             mBaseDisplayInfo.flags = 0;
-            if ((deviceInfo.flags & DisplayDeviceInfo.FLAG_SUPPORTS_SECURE_VIDEO_OUTPUT) != 0) {
-                mBaseDisplayInfo.flags |= Display.FLAG_SUPPORTS_SECURE_VIDEO_OUTPUT;
+            if ((deviceInfo.flags & DisplayDeviceInfo.FLAG_SUPPORTS_PROTECTED_BUFFERS) != 0) {
+                mBaseDisplayInfo.flags |= Display.FLAG_SUPPORTS_PROTECTED_BUFFERS;
             }
             mBaseDisplayInfo.name = deviceInfo.name;
             mBaseDisplayInfo.appWidth = deviceInfo.width;
@@ -299,7 +299,9 @@
     }
 
     public void dumpLocked(PrintWriter pw) {
+        pw.println("mDisplayId=" + mDisplayId);
         pw.println("mLayerStack=" + mLayerStack);
+        pw.println("mHasContent=" + mHasContent);
         pw.println("mPrimaryDisplayDevice=" + (mPrimaryDisplayDevice != null ?
                 mPrimaryDisplayDevice.getNameLocked() : "null"));
         pw.println("mBaseDisplayInfo=" + mBaseDisplayInfo);
diff --git a/services/java/com/android/server/display/OverlayDisplayAdapter.java b/services/java/com/android/server/display/OverlayDisplayAdapter.java
index 0767fc0..dfacf2a 100644
--- a/services/java/com/android/server/display/OverlayDisplayAdapter.java
+++ b/services/java/com/android/server/display/OverlayDisplayAdapter.java
@@ -19,14 +19,11 @@
 import com.android.internal.util.DumpUtils;
 import com.android.internal.util.IndentingPrintWriter;
 
-import android.content.BroadcastReceiver;
 import android.content.Context;
-import android.content.Intent;
-import android.content.IntentFilter;
 import android.database.ContentObserver;
+import android.graphics.SurfaceTexture;
 import android.os.Handler;
 import android.os.IBinder;
-import android.os.UserHandle;
 import android.provider.Settings;
 import android.util.DisplayMetrics;
 import android.util.Slog;
@@ -192,28 +189,42 @@
         private final int mDensityDpi;
 
         private Surface mSurface;
+        private SurfaceTexture mSurfaceTexture;
         private DisplayDeviceInfo mInfo;
 
         public OverlayDisplayDevice(IBinder displayToken, String name,
                 int width, int height, float refreshRate, int densityDpi,
-                Surface surface) {
+                SurfaceTexture surfaceTexture) {
             super(OverlayDisplayAdapter.this, displayToken);
             mName = name;
             mWidth = width;
             mHeight = height;
             mRefreshRate = refreshRate;
             mDensityDpi = densityDpi;
-            mSurface = surface;
+            mSurfaceTexture = surfaceTexture;
         }
 
-        public void clearSurfaceLocked() {
-            mSurface = null;
+        public void clearSurfaceTextureLocked() {
+            if (mSurfaceTexture != null) {
+                mSurfaceTexture = null;
+            }
             sendTraversalRequestLocked();
         }
 
         @Override
         public void performTraversalInTransactionLocked() {
-            setSurfaceInTransactionLocked(mSurface);
+            if (mSurfaceTexture != null) {
+                if (mSurface == null) {
+                    mSurface = new Surface(mSurfaceTexture);
+                }
+                setSurfaceInTransactionLocked(mSurface);
+            } else {
+                setSurfaceInTransactionLocked(null);
+                if (mSurface != null) {
+                    mSurface.destroy();
+                    mSurface = null;
+                }
+            }
         }
 
         @Override
@@ -227,7 +238,7 @@
                 mInfo.densityDpi = mDensityDpi;
                 mInfo.xDpi = mDensityDpi;
                 mInfo.yDpi = mDensityDpi;
-                mInfo.flags = DisplayDeviceInfo.FLAG_SUPPORTS_SECURE_VIDEO_OUTPUT;
+                mInfo.flags = 0;
                 mInfo.touch = DisplayDeviceInfo.TOUCH_NONE;
             }
             return mInfo;
@@ -268,11 +279,11 @@
 
         // Called on the UI thread.
         @Override
-        public void onWindowCreated(Surface surface, float refreshRate) {
+        public void onWindowCreated(SurfaceTexture surfaceTexture, float refreshRate) {
             synchronized (getSyncRoot()) {
                 IBinder displayToken = Surface.createDisplay(mName);
                 mDevice = new OverlayDisplayDevice(displayToken, mName,
-                        mWidth, mHeight, refreshRate, mDensityDpi, surface);
+                        mWidth, mHeight, refreshRate, mDensityDpi, surfaceTexture);
 
                 sendDisplayDeviceEventLocked(mDevice, DISPLAY_DEVICE_EVENT_ADDED);
             }
@@ -283,7 +294,7 @@
         public void onWindowDestroyed() {
             synchronized (getSyncRoot()) {
                 if (mDevice != null) {
-                    mDevice.clearSurfaceLocked();
+                    mDevice.clearSurfaceTextureLocked();
                     sendDisplayDeviceEventLocked(mDevice, DISPLAY_DEVICE_EVENT_REMOVED);
                 }
             }
diff --git a/services/java/com/android/server/display/OverlayDisplayWindow.java b/services/java/com/android/server/display/OverlayDisplayWindow.java
index d08f65f..a0edced 100644
--- a/services/java/com/android/server/display/OverlayDisplayWindow.java
+++ b/services/java/com/android/server/display/OverlayDisplayWindow.java
@@ -29,7 +29,6 @@
 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;
@@ -146,6 +145,7 @@
         }
     }
 
+    @Override
     public void dump(PrintWriter pw) {
         pw.println("mWindowVisible=" + mWindowVisible);
         pw.println("mWindowX=" + mWindowX);
@@ -291,8 +291,7 @@
         @Override
         public void onSurfaceTextureAvailable(SurfaceTexture surfaceTexture,
                 int width, int height) {
-            mListener.onWindowCreated(new Surface(surfaceTexture),
-                    mDefaultDisplayInfo.refreshRate);
+            mListener.onWindowCreated(surfaceTexture, mDefaultDisplayInfo.refreshRate);
         }
 
         @Override
@@ -361,7 +360,7 @@
      * Watches for significant changes in the overlay display window lifecycle.
      */
     public interface Listener {
-        public void onWindowCreated(Surface surface, float refreshRate);
+        public void onWindowCreated(SurfaceTexture surfaceTexture, 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
index 4a89be7..b2beb5e 100644
--- a/services/java/com/android/server/display/WifiDisplayAdapter.java
+++ b/services/java/com/android/server/display/WifiDisplayAdapter.java
@@ -50,7 +50,8 @@
 final class WifiDisplayAdapter extends DisplayAdapter {
     private static final String TAG = "WifiDisplayAdapter";
 
-    private PersistentDataStore mPersistentDataStore;
+    private final PersistentDataStore mPersistentDataStore;
+    private final boolean mSupportsProtectedBuffers;
 
     private WifiDisplayController mDisplayController;
     private WifiDisplayDevice mDisplayDevice;
@@ -70,6 +71,8 @@
             PersistentDataStore persistentDataStore) {
         super(syncRoot, context, handler, listener, TAG);
         mPersistentDataStore = persistentDataStore;
+        mSupportsProtectedBuffers = context.getResources().getBoolean(
+                com.android.internal.R.bool.config_wifiDisplaySupportsProtectedBuffers);
     }
 
     @Override
@@ -84,6 +87,7 @@
         pw.println("mAvailableDisplays=" + Arrays.toString(mAvailableDisplays));
         pw.println("mRememberedDisplays=" + Arrays.toString(mRememberedDisplays));
         pw.println("mPendingStatusChangeBroadcast=" + mPendingStatusChangeBroadcast);
+        pw.println("mSupportsProtectedBuffers=" + mSupportsProtectedBuffers);
 
         // Try to dump the controller state.
         if (mDisplayController == null) {
@@ -217,7 +221,10 @@
 
         int deviceFlags = 0;
         if ((flags & RemoteDisplay.DISPLAY_FLAG_SECURE) != 0) {
-            deviceFlags |= DisplayDeviceInfo.FLAG_SUPPORTS_SECURE_VIDEO_OUTPUT;
+            deviceFlags |= DisplayDeviceInfo.FLAG_SECURE;
+        }
+        if (mSupportsProtectedBuffers) {
+            deviceFlags |= DisplayDeviceInfo.FLAG_SUPPORTS_PROTECTED_BUFFERS;
         }
 
         float refreshRate = 60.0f; // TODO: get this for real
diff --git a/services/java/com/android/server/pm/PackageManagerService.java b/services/java/com/android/server/pm/PackageManagerService.java
index 75bc265..08b9038 100644
--- a/services/java/com/android/server/pm/PackageManagerService.java
+++ b/services/java/com/android/server/pm/PackageManagerService.java
@@ -851,7 +851,8 @@
                             state.setVerifierResponse(Binder.getCallingUid(),
                                     PackageManager.VERIFICATION_ALLOW_WITHOUT_SUFFICIENT);
                             broadcastPackageVerified(verificationId, args.packageURI,
-                                    PackageManager.VERIFICATION_ALLOW);
+                                    PackageManager.VERIFICATION_ALLOW,
+                                    state.getInstallArgs().getUser());
                             try {
                                 ret = args.copyApk(mContainerService, true);
                             } catch (RemoteException e) {
@@ -859,7 +860,8 @@
                             }
                         } else {
                             broadcastPackageVerified(verificationId, args.packageURI,
-                                    PackageManager.VERIFICATION_REJECT);
+                                    PackageManager.VERIFICATION_REJECT,
+                                    state.getInstallArgs().getUser());
                         }
 
                         processPendingInstall(args, ret);
@@ -889,7 +891,7 @@
                         if (state.isInstallAllowed()) {
                             ret = PackageManager.INSTALL_FAILED_INTERNAL_ERROR;
                             broadcastPackageVerified(verificationId, args.packageURI,
-                                    response.code);
+                                    response.code, state.getInstallArgs().getUser());
                             try {
                                 ret = args.copyApk(mContainerService, true);
                             } catch (RemoteException e) {
@@ -5741,14 +5743,15 @@
     }
 
     private void broadcastPackageVerified(int verificationId, Uri packageUri,
-            int verificationCode) {
+            int verificationCode, UserHandle user) {
         final Intent intent = new Intent(Intent.ACTION_PACKAGE_VERIFIED);
         intent.setDataAndType(packageUri, PACKAGE_MIME_TYPE);
         intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
         intent.putExtra(PackageManager.EXTRA_VERIFICATION_ID, verificationId);
         intent.putExtra(PackageManager.EXTRA_VERIFICATION_RESULT, verificationCode);
 
-        mContext.sendBroadcast(intent, android.Manifest.permission.PACKAGE_VERIFICATION_AGENT);
+        mContext.sendBroadcastAsUser(intent, user,
+                android.Manifest.permission.PACKAGE_VERIFICATION_AGENT);
     }
 
     private ComponentName matchComponentForVerifier(String packageName,
@@ -6477,7 +6480,7 @@
                                 final Intent sufficientIntent = new Intent(verification);
                                 sufficientIntent.setComponent(verifierComponent);
 
-                                mContext.sendBroadcast(sufficientIntent);
+                                mContext.sendBroadcastAsUser(sufficientIntent, getUser());
                             }
                         }
                     }
@@ -6492,7 +6495,7 @@
                          * target BroadcastReceivers have run.
                          */
                         verification.setComponent(requiredVerifierComponent);
-                        mContext.sendOrderedBroadcast(verification,
+                        mContext.sendOrderedBroadcastAsUser(verification, getUser(),
                                 android.Manifest.permission.PACKAGE_VERIFICATION_AGENT,
                                 new BroadcastReceiver() {
                                     @Override
@@ -6779,6 +6782,10 @@
         protected boolean isFwdLocked() {
             return (flags & PackageManager.INSTALL_FORWARD_LOCK) != 0;
         }
+
+        UserHandle getUser() {
+            return user;
+        }
     }
 
     class FileInstallArgs extends InstallArgs {
@@ -9027,9 +9034,9 @@
         mSystemReady = true;
 
         // Read the compatibilty setting when the system is ready.
-        boolean compatibilityModeEnabled = android.provider.Settings.System.getInt(
+        boolean compatibilityModeEnabled = android.provider.Settings.Global.getInt(
                 mContext.getContentResolver(),
-                android.provider.Settings.System.COMPATIBILITY_MODE, 1) == 1;
+                android.provider.Settings.Global.COMPATIBILITY_MODE, 1) == 1;
         PackageParser.setCompatibilityModeEnabled(compatibilityModeEnabled);
         if (DEBUG_SETTINGS) {
             Log.d(TAG, "compatibility mode:" + compatibilityModeEnabled);
diff --git a/services/java/com/android/server/pm/PackageSettingBase.java b/services/java/com/android/server/pm/PackageSettingBase.java
index 6a363a8..ae1b213 100644
--- a/services/java/com/android/server/pm/PackageSettingBase.java
+++ b/services/java/com/android/server/pm/PackageSettingBase.java
@@ -65,8 +65,7 @@
     boolean permissionsFixed;
     boolean haveGids;
 
-    private static final PackageUserState DEFAULT_USER_STATE = new PackageUserState(false);
-    private static final PackageUserState DEFAULT_SYSTEM_USER_STATE = new PackageUserState(true);
+    private static final PackageUserState DEFAULT_USER_STATE = new PackageUserState();
 
     // Whether this package is currently stopped, thus can not be
     // started until explicitly launched by the user.
@@ -176,7 +175,7 @@
     private PackageUserState modifyUserState(int userId) {
         PackageUserState state = userState.get(userId);
         if (state == null) {
-            state = new PackageUserState((pkgFlags&ApplicationInfo.FLAG_SYSTEM) != 0);
+            state = new PackageUserState();
             userState.put(userId, state);
         }
         return state;
@@ -187,8 +186,7 @@
         if (state != null) {
             return state;
         }
-        return ((pkgFlags&ApplicationInfo.FLAG_SYSTEM) != 0)
-                ? DEFAULT_SYSTEM_USER_STATE : DEFAULT_USER_STATE;
+        return DEFAULT_USER_STATE;
     }
 
     void setEnabled(int state, int userId) {
diff --git a/services/java/com/android/server/usb/UsbDeviceManager.java b/services/java/com/android/server/usb/UsbDeviceManager.java
index 10011aa..95797ef 100644
--- a/services/java/com/android/server/usb/UsbDeviceManager.java
+++ b/services/java/com/android/server/usb/UsbDeviceManager.java
@@ -16,9 +16,9 @@
 
 package com.android.server.usb;
 
-import android.app.PendingIntent;
 import android.app.Notification;
 import android.app.NotificationManager;
+import android.app.PendingIntent;
 import android.content.BroadcastReceiver;
 import android.content.ComponentName;
 import android.content.ContentResolver;
@@ -30,23 +30,19 @@
 import android.database.ContentObserver;
 import android.hardware.usb.UsbAccessory;
 import android.hardware.usb.UsbManager;
-import android.net.Uri;
-import android.os.Binder;
-import android.os.Bundle;
 import android.os.FileUtils;
 import android.os.Handler;
 import android.os.HandlerThread;
 import android.os.Looper;
 import android.os.Message;
-import android.os.Parcelable;
 import android.os.ParcelFileDescriptor;
 import android.os.Process;
-import android.os.UserHandle;
-import android.os.storage.StorageManager;
-import android.os.storage.StorageVolume;
 import android.os.SystemClock;
 import android.os.SystemProperties;
 import android.os.UEventObserver;
+import android.os.UserHandle;
+import android.os.storage.StorageManager;
+import android.os.storage.StorageVolume;
 import android.provider.Settings;
 import android.util.Pair;
 import android.util.Slog;
@@ -56,10 +52,9 @@
 import java.io.FileNotFoundException;
 import java.io.IOException;
 import java.io.PrintWriter;
-import java.util.ArrayList;
+import java.util.HashMap;
 import java.util.LinkedList;
 import java.util.List;
-import java.util.HashMap;
 import java.util.Map;
 import java.util.Scanner;
 
@@ -106,9 +101,12 @@
     private UsbHandler mHandler;
     private boolean mBootCompleted;
 
+    private final Object mLock = new Object();
+
     private final Context mContext;
     private final ContentResolver mContentResolver;
-    private final UsbSettingsManager mSettingsManager;
+    // @GuardedBy("mLock")
+    private UsbSettingsManager mCurrentSettings;
     private NotificationManager mNotificationManager;
     private final boolean mHasUsbAccessory;
     private boolean mUseUsbNotification;
@@ -149,10 +147,9 @@
         }
     };
 
-    public UsbDeviceManager(Context context, UsbSettingsManager settingsManager) {
+    public UsbDeviceManager(Context context) {
         mContext = context;
         mContentResolver = context.getContentResolver();
-        mSettingsManager = settingsManager;
         PackageManager pm = mContext.getPackageManager();
         mHasUsbAccessory = pm.hasSystemFeature(PackageManager.FEATURE_USB_ACCESSORY);
         initRndisAddress();
@@ -175,6 +172,18 @@
         }
     }
 
+    public void setCurrentSettings(UsbSettingsManager settings) {
+        synchronized (mLock) {
+            mCurrentSettings = settings;
+        }
+    }
+
+    private UsbSettingsManager getCurrentSettings() {
+        synchronized (mLock) {
+            return mCurrentSettings;
+        }
+    }
+
     public void systemReady() {
         if (DEBUG) Slog.d(TAG, "systemReady");
 
@@ -516,7 +525,7 @@
                     Slog.d(TAG, "entering USB accessory mode: " + mCurrentAccessory);
                     // defer accessoryAttached if system is not ready
                     if (mBootCompleted) {
-                        mSettingsManager.accessoryAttached(mCurrentAccessory);
+                        getCurrentSettings().accessoryAttached(mCurrentAccessory);
                     } // else handle in mBootCompletedReceiver
                 } else {
                     Slog.e(TAG, "nativeGetAccessoryStrings failed");
@@ -529,7 +538,7 @@
 
                 if (mCurrentAccessory != null) {
                     if (mBootCompleted) {
-                        mSettingsManager.accessoryDetached(mCurrentAccessory);
+                        getCurrentSettings().accessoryDetached(mCurrentAccessory);
                     }
                     mCurrentAccessory = null;
                     mAccessoryStrings = null;
@@ -618,7 +627,7 @@
                 case MSG_BOOT_COMPLETED:
                     mBootCompleted = true;
                     if (mCurrentAccessory != null) {
-                        mSettingsManager.accessoryAttached(mCurrentAccessory);
+                        getCurrentSettings().accessoryAttached(mCurrentAccessory);
                     }
                     if (mDebuggingManager != null) {
                         mDebuggingManager.setAdbEnabled(mAdbEnabled);
@@ -774,7 +783,7 @@
                     + currentAccessory;
             throw new IllegalArgumentException(error);
         }
-        mSettingsManager.checkPermission(accessory);
+        getCurrentSettings().checkPermission(accessory);
         return nativeOpenAccessory();
     }
 
diff --git a/services/java/com/android/server/usb/UsbHostManager.java b/services/java/com/android/server/usb/UsbHostManager.java
index 0a0ff59..175ae6f 100644
--- a/services/java/com/android/server/usb/UsbHostManager.java
+++ b/services/java/com/android/server/usb/UsbHostManager.java
@@ -16,35 +16,19 @@
 
 package com.android.server.usb;
 
-import android.app.PendingIntent;
-import android.content.BroadcastReceiver;
-import android.content.ContentResolver;
 import android.content.Context;
-import android.content.Intent;
-import android.content.IntentFilter;
-import android.hardware.usb.IUsbManager;
 import android.hardware.usb.UsbConstants;
 import android.hardware.usb.UsbDevice;
 import android.hardware.usb.UsbEndpoint;
 import android.hardware.usb.UsbInterface;
-import android.hardware.usb.UsbManager;
-import android.net.Uri;
-import android.os.Binder;
 import android.os.Bundle;
-import android.os.Handler;
-import android.os.Message;
-import android.os.Parcelable;
 import android.os.ParcelFileDescriptor;
-import android.os.UEventObserver;
-import android.provider.Settings;
+import android.os.Parcelable;
 import android.util.Slog;
 
-import java.io.File;
 import java.io.FileDescriptor;
-import java.io.FileReader;
 import java.io.PrintWriter;
 import java.util.HashMap;
-import java.util.List;
 
 /**
  * UsbHostManager manages USB state in host mode.
@@ -54,22 +38,35 @@
     private static final boolean LOG = false;
 
     // contains all connected USB devices
-    private final HashMap<String,UsbDevice> mDevices = new HashMap<String,UsbDevice>();
+    private final HashMap<String, UsbDevice> mDevices = new HashMap<String, UsbDevice>();
 
     // USB busses to exclude from USB host support
     private final String[] mHostBlacklist;
 
     private final Context mContext;
     private final Object mLock = new Object();
-    private final UsbSettingsManager mSettingsManager;
 
-    public UsbHostManager(Context context, UsbSettingsManager settingsManager) {
+    // @GuardedBy("mLock")
+    private UsbSettingsManager mCurrentSettings;
+
+    public UsbHostManager(Context context) {
         mContext = context;
-        mSettingsManager = settingsManager;
         mHostBlacklist = context.getResources().getStringArray(
                 com.android.internal.R.array.config_usbHostBlacklist);
     }
 
+    public void setCurrentSettings(UsbSettingsManager settings) {
+        synchronized (mLock) {
+            mCurrentSettings = settings;
+        }
+    }
+
+    private UsbSettingsManager getCurrentSettings() {
+        synchronized (mLock) {
+            return mCurrentSettings;
+        }
+    }
+
     private boolean isBlackListed(String deviceName) {
         int count = mHostBlacklist.length;
         for (int i = 0; i < count; i++) {
@@ -154,7 +151,7 @@
             UsbDevice device = new UsbDevice(deviceName, vendorID, productID,
                     deviceClass, deviceSubclass, deviceProtocol, interfaces);
             mDevices.put(deviceName, device);
-            mSettingsManager.deviceAttached(device);
+            getCurrentSettings().deviceAttached(device);
         }
     }
 
@@ -163,7 +160,7 @@
         synchronized (mLock) {
             UsbDevice device = mDevices.remove(deviceName);
             if (device != null) {
-                mSettingsManager.deviceDetached(device);
+                getCurrentSettings().deviceDetached(device);
             }
         }
     }
@@ -202,7 +199,7 @@
                 throw new IllegalArgumentException(
                         "device " + deviceName + " does not exist or is restricted");
             }
-            mSettingsManager.checkPermission(device);
+            getCurrentSettings().checkPermission(device);
             return nativeOpenDevice(deviceName);
         }
     }
diff --git a/services/java/com/android/server/usb/UsbService.java b/services/java/com/android/server/usb/UsbService.java
index bebcd56..629f5fa 100644
--- a/services/java/com/android/server/usb/UsbService.java
+++ b/services/java/com/android/server/usb/UsbService.java
@@ -17,15 +17,20 @@
 package com.android.server.usb;
 
 import android.app.PendingIntent;
+import android.content.BroadcastReceiver;
 import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
 import android.content.pm.PackageManager;
 import android.hardware.usb.IUsbManager;
 import android.hardware.usb.UsbAccessory;
 import android.hardware.usb.UsbDevice;
-import android.net.Uri;
-import android.os.Binder;
 import android.os.Bundle;
 import android.os.ParcelFileDescriptor;
+import android.os.UserHandle;
+import android.util.SparseArray;
+
+import com.android.internal.util.IndentingPrintWriter;
 
 import java.io.File;
 import java.io.FileDescriptor;
@@ -37,21 +42,72 @@
  * support is delegated to UsbDeviceManager.
  */
 public class UsbService extends IUsbManager.Stub {
+    private static final String TAG = "UsbService";
+
     private final Context mContext;
+
     private UsbDeviceManager mDeviceManager;
     private UsbHostManager mHostManager;
-    private final UsbSettingsManager mSettingsManager;
 
+    private final Object mLock = new Object();
+
+    /** Map from {@link UserHandle} to {@link UsbSettingsManager} */
+    // @GuardedBy("mLock")
+    private final SparseArray<UsbSettingsManager>
+            mSettingsByUser = new SparseArray<UsbSettingsManager>();
+
+    private UsbSettingsManager getSettingsForUser(int userId) {
+        synchronized (mLock) {
+            UsbSettingsManager settings = mSettingsByUser.get(userId);
+            if (settings == null) {
+                settings = new UsbSettingsManager(mContext, new UserHandle(userId));
+                mSettingsByUser.put(userId, settings);
+            }
+            return settings;
+        }
+    }
 
     public UsbService(Context context) {
         mContext = context;
-        mSettingsManager = new UsbSettingsManager(context);
-        PackageManager pm = mContext.getPackageManager();
+
+        final PackageManager pm = mContext.getPackageManager();
         if (pm.hasSystemFeature(PackageManager.FEATURE_USB_HOST)) {
-            mHostManager = new UsbHostManager(context, mSettingsManager);
+            mHostManager = new UsbHostManager(context);
         }
         if (new File("/sys/class/android_usb").exists()) {
-            mDeviceManager = new UsbDeviceManager(context, mSettingsManager);
+            mDeviceManager = new UsbDeviceManager(context);
+        }
+
+        setCurrentUser(UserHandle.USER_OWNER);
+
+        final IntentFilter userFilter = new IntentFilter();
+        userFilter.addAction(Intent.ACTION_USER_SWITCHED);
+        userFilter.addAction(Intent.ACTION_USER_STOPPED);
+        mContext.registerReceiver(mUserReceiver, userFilter, null, null);
+    }
+
+    private BroadcastReceiver mUserReceiver = new BroadcastReceiver() {
+        @Override
+        public void onReceive(Context context, Intent intent) {
+            final int userId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, -1);
+            final String action = intent.getAction();
+            if (Intent.ACTION_USER_SWITCHED.equals(action)) {
+                setCurrentUser(userId);
+            } else if (Intent.ACTION_USER_STOPPED.equals(action)) {
+                synchronized (mLock) {
+                    mSettingsByUser.remove(userId);
+                }
+            }
+        }
+    };
+
+    private void setCurrentUser(int userId) {
+        final UsbSettingsManager userSettings = getSettingsForUser(userId);
+        if (mHostManager != null) {
+            mHostManager.setCurrentSettings(userSettings);
+        }
+        if (mDeviceManager != null) {
+            mDeviceManager.setCurrentSettings(userSettings);
         }
     }
 
@@ -65,6 +121,7 @@
     }
 
     /* Returns a list of all currently attached USB devices (host mdoe) */
+    @Override
     public void getDeviceList(Bundle devices) {
         if (mHostManager != null) {
             mHostManager.getDeviceList(devices);
@@ -72,6 +129,7 @@
     }
 
     /* Opens the specified USB device (host mode) */
+    @Override
     public ParcelFileDescriptor openDevice(String deviceName) {
         if (mHostManager != null) {
             return mHostManager.openDevice(deviceName);
@@ -81,6 +139,7 @@
     }
 
     /* returns the currently attached USB accessory (device mode) */
+    @Override
     public UsbAccessory getCurrentAccessory() {
         if (mDeviceManager != null) {
             return mDeviceManager.getCurrentAccessory();
@@ -90,6 +149,7 @@
     }
 
     /* opens the currently attached USB accessory (device mode) */
+    @Override
     public ParcelFileDescriptor openAccessory(UsbAccessory accessory) {
         if (mDeviceManager != null) {
             return mDeviceManager.openAccessory(accessory);
@@ -98,54 +158,70 @@
         }
     }
 
-    public void setDevicePackage(UsbDevice device, String packageName) {
+    @Override
+    public void setDevicePackage(UsbDevice device, String packageName, int userId) {
         mContext.enforceCallingOrSelfPermission(android.Manifest.permission.MANAGE_USB, null);
-        mSettingsManager.setDevicePackage(device, packageName);
+        getSettingsForUser(userId).setDevicePackage(device, packageName);
     }
 
-    public void setAccessoryPackage(UsbAccessory accessory, String packageName) {
+    @Override
+    public void setAccessoryPackage(UsbAccessory accessory, String packageName, int userId) {
         mContext.enforceCallingOrSelfPermission(android.Manifest.permission.MANAGE_USB, null);
-        mSettingsManager.setAccessoryPackage(accessory, packageName);
+        getSettingsForUser(userId).setAccessoryPackage(accessory, packageName);
     }
 
+    @Override
     public boolean hasDevicePermission(UsbDevice device) {
-        return mSettingsManager.hasPermission(device);
+        final int userId = UserHandle.getCallingUserId();
+        return getSettingsForUser(userId).hasPermission(device);
     }
 
+    @Override
     public boolean hasAccessoryPermission(UsbAccessory accessory) {
-        return mSettingsManager.hasPermission(accessory);
+        final int userId = UserHandle.getCallingUserId();
+        return getSettingsForUser(userId).hasPermission(accessory);
     }
 
-    public void requestDevicePermission(UsbDevice device, String packageName,
-            PendingIntent pi) {
-        mSettingsManager.requestPermission(device, packageName, pi);
+    @Override
+    public void requestDevicePermission(UsbDevice device, String packageName, PendingIntent pi) {
+        final int userId = UserHandle.getCallingUserId();
+        getSettingsForUser(userId).requestPermission(device, packageName, pi);
     }
 
-    public void requestAccessoryPermission(UsbAccessory accessory, String packageName,
-            PendingIntent pi) {
-        mSettingsManager.requestPermission(accessory, packageName, pi);
+    @Override
+    public void requestAccessoryPermission(
+            UsbAccessory accessory, String packageName, PendingIntent pi) {
+        final int userId = UserHandle.getCallingUserId();
+        getSettingsForUser(userId).requestPermission(accessory, packageName, pi);
     }
 
+    @Override
     public void grantDevicePermission(UsbDevice device, int uid) {
         mContext.enforceCallingOrSelfPermission(android.Manifest.permission.MANAGE_USB, null);
-        mSettingsManager.grantDevicePermission(device, uid);
+        final int userId = UserHandle.getUserId(uid);
+        getSettingsForUser(userId).grantDevicePermission(device, uid);
     }
 
+    @Override
     public void grantAccessoryPermission(UsbAccessory accessory, int uid) {
         mContext.enforceCallingOrSelfPermission(android.Manifest.permission.MANAGE_USB, null);
-        mSettingsManager.grantAccessoryPermission(accessory, uid);
+        final int userId = UserHandle.getUserId(uid);
+        getSettingsForUser(userId).grantAccessoryPermission(accessory, uid);
     }
 
-    public boolean hasDefaults(String packageName) {
+    @Override
+    public boolean hasDefaults(String packageName, int userId) {
         mContext.enforceCallingOrSelfPermission(android.Manifest.permission.MANAGE_USB, null);
-        return mSettingsManager.hasDefaults(packageName);
+        return getSettingsForUser(userId).hasDefaults(packageName);
     }
 
-    public void clearDefaults(String packageName) {
+    @Override
+    public void clearDefaults(String packageName, int userId) {
         mContext.enforceCallingOrSelfPermission(android.Manifest.permission.MANAGE_USB, null);
-        mSettingsManager.clearDefaults(packageName);
+        getSettingsForUser(userId).clearDefaults(packageName);
     }
 
+    @Override
     public void setCurrentFunction(String function, boolean makeDefault) {
         mContext.enforceCallingOrSelfPermission(android.Manifest.permission.MANAGE_USB, null);
         if (mDeviceManager != null) {
@@ -155,6 +231,7 @@
         }
     }
 
+    @Override
     public void setMassStorageBackingFile(String path) {
         mContext.enforceCallingOrSelfPermission(android.Manifest.permission.MANAGE_USB, null);
         if (mDeviceManager != null) {
@@ -164,34 +241,41 @@
         }
     }
 
+    @Override
     public void allowUsbDebugging(boolean alwaysAllow, String publicKey) {
         mContext.enforceCallingOrSelfPermission(android.Manifest.permission.MANAGE_USB, null);
         mDeviceManager.allowUsbDebugging(alwaysAllow, publicKey);
     }
 
+    @Override
     public void denyUsbDebugging() {
         mContext.enforceCallingOrSelfPermission(android.Manifest.permission.MANAGE_USB, null);
         mDeviceManager.denyUsbDebugging();
     }
 
     @Override
-    public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
-        if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DUMP)
-                != PackageManager.PERMISSION_GRANTED) {
-            pw.println("Permission Denial: can't dump UsbManager from from pid="
-                    + Binder.getCallingPid()
-                    + ", uid=" + Binder.getCallingUid());
-            return;
-        }
+    public void dump(FileDescriptor fd, PrintWriter writer, String[] args) {
+        mContext.enforceCallingOrSelfPermission(android.Manifest.permission.DUMP, TAG);
+        final IndentingPrintWriter pw = new IndentingPrintWriter(writer, "  ");
 
         pw.println("USB Manager State:");
-
         if (mDeviceManager != null) {
             mDeviceManager.dump(fd, pw);
         }
         if (mHostManager != null) {
             mHostManager.dump(fd, pw);
         }
-        mSettingsManager.dump(fd, pw);
+
+        synchronized (mLock) {
+            for (int i = 0; i < mSettingsByUser.size(); i++) {
+                final int userId = mSettingsByUser.keyAt(i);
+                final UsbSettingsManager settings = mSettingsByUser.valueAt(i);
+                pw.increaseIndent();
+                pw.println("Settings for user " + userId + ":");
+                settings.dump(fd, pw);
+                pw.decreaseIndent();
+            }
+        }
+        pw.decreaseIndent();
     }
 }
diff --git a/services/java/com/android/server/usb/UsbSettingsManager.java b/services/java/com/android/server/usb/UsbSettingsManager.java
index a8453d3..4b2bbfe 100644
--- a/services/java/com/android/server/usb/UsbSettingsManager.java
+++ b/services/java/com/android/server/usb/UsbSettingsManager.java
@@ -33,9 +33,10 @@
 import android.hardware.usb.UsbInterface;
 import android.hardware.usb.UsbManager;
 import android.os.Binder;
-import android.os.FileUtils;
-import android.os.Process;
+import android.os.Environment;
 import android.os.UserHandle;
+import android.util.AtomicFile;
+import android.util.Log;
 import android.util.Slog;
 import android.util.SparseBooleanArray;
 import android.util.Xml;
@@ -48,7 +49,6 @@
 import org.xmlpull.v1.XmlPullParserException;
 import org.xmlpull.v1.XmlSerializer;
 
-import java.io.BufferedOutputStream;
 import java.io.File;
 import java.io.FileDescriptor;
 import java.io.FileInputStream;
@@ -60,13 +60,21 @@
 import java.util.HashMap;
 import java.util.List;
 
-class UsbSettingsManager {
+import libcore.io.IoUtils;
 
+class UsbSettingsManager {
     private static final String TAG = "UsbSettingsManager";
     private static final boolean DEBUG = false;
-    private static final File sSettingsFile = new File("/data/system/usb_device_manager.xml");
+
+    /** Legacy settings file, before multi-user */
+    private static final File sSingleUserSettingsFile = new File(
+            "/data/system/usb_device_manager.xml");
+
+    private final UserHandle mUser;
+    private final AtomicFile mSettingsFile;
 
     private final Context mContext;
+    private final Context mUserContext;
     private final PackageManager mPackageManager;
 
     // Temporary mapping USB device name to list of UIDs with permissions for the device
@@ -350,28 +358,49 @@
     }
 
     private class MyPackageMonitor extends PackageMonitor {
-
+        @Override
         public void onPackageAdded(String packageName, int uid) {
             handlePackageUpdate(packageName);
         }
 
+        @Override
         public void onPackageChanged(String packageName, int uid, String[] components) {
             handlePackageUpdate(packageName);
         }
 
+        @Override
         public void onPackageRemoved(String packageName, int uid) {
             clearDefaults(packageName);
         }
     }
+
     MyPackageMonitor mPackageMonitor = new MyPackageMonitor();
 
-    public UsbSettingsManager(Context context) {
+    public UsbSettingsManager(Context context, UserHandle user) {
+        if (DEBUG) Slog.v(TAG, "Creating settings for " + user);
+
+        try {
+            mUserContext = context.createPackageContextAsUser("android", 0, user);
+        } catch (NameNotFoundException e) {
+            throw new RuntimeException("Missing android package");
+        }
+
         mContext = context;
-        mPackageManager = context.getPackageManager();
+        mPackageManager = mUserContext.getPackageManager();
+
+        mUser = user;
+        mSettingsFile = new AtomicFile(new File(
+                Environment.getUserSystemDirectory(user.getIdentifier()),
+                "usb_device_manager.xml"));
+
         synchronized (mLock) {
+            if (UserHandle.OWNER.equals(user)) {
+                upgradeSingleUserLocked();
+            }
             readSettingsLocked();
         }
-        mPackageMonitor.register(context, null, true);
+
+        mPackageMonitor.register(mUserContext, null, true);
     }
 
     private void readPreference(XmlPullParser parser)
@@ -395,10 +424,54 @@
         XmlUtils.nextElement(parser);
     }
 
+    /**
+     * Upgrade any single-user settings from {@link #sSingleUserSettingsFile}.
+     * Should only by called by owner.
+     */
+    private void upgradeSingleUserLocked() {
+        if (sSingleUserSettingsFile.exists()) {
+            mDevicePreferenceMap.clear();
+            mAccessoryPreferenceMap.clear();
+
+            FileInputStream fis = null;
+            try {
+                fis = new FileInputStream(sSingleUserSettingsFile);
+                XmlPullParser parser = Xml.newPullParser();
+                parser.setInput(fis, null);
+
+                XmlUtils.nextElement(parser);
+                while (parser.getEventType() != XmlPullParser.END_DOCUMENT) {
+                    final String tagName = parser.getName();
+                    if ("preference".equals(tagName)) {
+                        readPreference(parser);
+                    } else {
+                        XmlUtils.nextElement(parser);
+                    }
+                }
+            } catch (IOException e) {
+                Log.wtf(TAG, "Failed to read single-user settings", e);
+            } catch (XmlPullParserException e) {
+                Log.wtf(TAG, "Failed to read single-user settings", e);
+            } finally {
+                IoUtils.closeQuietly(fis);
+            }
+
+            writeSettingsLocked();
+
+            // Success or failure, we delete single-user file
+            sSingleUserSettingsFile.delete();
+        }
+    }
+
     private void readSettingsLocked() {
+        if (DEBUG) Slog.v(TAG, "readSettingsLocked()");
+
+        mDevicePreferenceMap.clear();
+        mAccessoryPreferenceMap.clear();
+
         FileInputStream stream = null;
         try {
-            stream = new FileInputStream(sSettingsFile);
+            stream = mSettingsFile.openRead();
             XmlPullParser parser = Xml.newPullParser();
             parser.setInput(stream, null);
 
@@ -407,7 +480,7 @@
                 String tagName = parser.getName();
                 if ("preference".equals(tagName)) {
                     readPreference(parser);
-                 } else {
+                } else {
                     XmlUtils.nextElement(parser);
                 }
             }
@@ -415,25 +488,21 @@
             if (DEBUG) Slog.d(TAG, "settings file not found");
         } catch (Exception e) {
             Slog.e(TAG, "error reading settings file, deleting to start fresh", e);
-            sSettingsFile.delete();
+            mSettingsFile.delete();
         } finally {
-            if (stream != null) {
-                try {
-                    stream.close();
-                } catch (IOException e) {
-                }
-            }
+            IoUtils.closeQuietly(stream);
         }
     }
 
     private void writeSettingsLocked() {
+        if (DEBUG) Slog.v(TAG, "writeSettingsLocked()");
+
         FileOutputStream fos = null;
         try {
-            FileOutputStream fstr = new FileOutputStream(sSettingsFile);
-            if (DEBUG) Slog.d(TAG, "writing settings to " + fstr);
-            BufferedOutputStream str = new BufferedOutputStream(fstr);
+            fos = mSettingsFile.startWrite();
+
             FastXmlSerializer serializer = new FastXmlSerializer();
-            serializer.setOutput(str, "utf-8");
+            serializer.setOutput(fos, "utf-8");
             serializer.startDocument(null, true);
             serializer.setFeature("http://xmlpull.org/v1/doc/features.html#indent-output", true);
             serializer.startTag(null, "settings");
@@ -455,12 +524,12 @@
             serializer.endTag(null, "settings");
             serializer.endDocument();
 
-            str.flush();
-            FileUtils.sync(fstr);
-            str.close();
-        } catch (Exception e) {
-            Slog.e(TAG, "error writing settings file, deleting to start fresh", e);
-            sSettingsFile.delete();
+            mSettingsFile.finishWrite(fos);
+        } catch (IOException e) {
+            Slog.e(TAG, "Failed to write settings", e);
+            if (fos != null) {
+                mSettingsFile.failWrite(fos);
+            }
         }
     }
 
@@ -547,7 +616,7 @@
         }
 
         // Send broadcast to running activity with registered intent
-        mContext.sendBroadcastAsUser(intent, UserHandle.ALL);
+        mUserContext.sendBroadcast(intent);
 
         // Start activity with registered intent
         resolveActivity(intent, matches, defaultPackage, device, null);
@@ -608,7 +677,7 @@
                     dialogIntent.putExtra(UsbManager.EXTRA_ACCESSORY, accessory);
                     dialogIntent.putExtra("uri", uri);
                     try {
-                        mContext.startActivity(dialogIntent);
+                        mUserContext.startActivityAsUser(dialogIntent, mUser);
                     } catch (ActivityNotFoundException e) {
                         Slog.e(TAG, "unable to start UsbAccessoryUriActivity");
                     }
@@ -656,7 +725,7 @@
                 intent.setComponent(
                         new ComponentName(defaultRI.activityInfo.packageName,
                                 defaultRI.activityInfo.name));
-                mContext.startActivity(intent);
+                mUserContext.startActivityAsUser(intent, mUser);
             } catch (ActivityNotFoundException e) {
                 Slog.e(TAG, "startActivity failed", e);
             }
@@ -683,7 +752,7 @@
                 resolverIntent.putExtra(Intent.EXTRA_INTENT, intent);
             }
             try {
-                mContext.startActivity(resolverIntent);
+                mUserContext.startActivityAsUser(resolverIntent, mUser);
             } catch (ActivityNotFoundException e) {
                 Slog.e(TAG, "unable to start activity " + resolverIntent);
             }
@@ -814,7 +883,7 @@
     }
 
     private void requestPermissionDialog(Intent intent, String packageName, PendingIntent pi) {
-        int uid = Binder.getCallingUid();
+        final int uid = Binder.getCallingUid();
 
         // compare uid with packageName to foil apps pretending to be someone else
         try {
@@ -833,9 +902,9 @@
         intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
         intent.putExtra(Intent.EXTRA_INTENT, pi);
         intent.putExtra("package", packageName);
-        intent.putExtra("uid", uid);
+        intent.putExtra(Intent.EXTRA_UID, uid);
         try {
-            mContext.startActivity(intent);
+            mUserContext.startActivityAsUser(intent, mUser);
         } catch (ActivityNotFoundException e) {
             Slog.e(TAG, "unable to start UsbPermissionActivity");
         } finally {
@@ -851,7 +920,7 @@
             intent.putExtra(UsbManager.EXTRA_DEVICE, device);
             intent.putExtra(UsbManager.EXTRA_PERMISSION_GRANTED, true);
             try {
-                pi.send(mContext, 0, intent);
+                pi.send(mUserContext, 0, intent);
             } catch (PendingIntent.CanceledException e) {
                 if (DEBUG) Slog.d(TAG, "requestPermission PendingIntent was cancelled");
             }
@@ -864,14 +933,14 @@
     }
 
     public void requestPermission(UsbAccessory accessory, String packageName, PendingIntent pi) {
-      Intent intent = new Intent();
+        Intent intent = new Intent();
 
         // respond immediately if permission has already been granted
         if (hasPermission(accessory)) {
             intent.putExtra(UsbManager.EXTRA_ACCESSORY, accessory);
             intent.putExtra(UsbManager.EXTRA_PERMISSION_GRANTED, true);
-           try {
-                pi.send(mContext, 0, intent);
+            try {
+                pi.send(mUserContext, 0, intent);
             } catch (PendingIntent.CanceledException e) {
                 if (DEBUG) Slog.d(TAG, "requestPermission PendingIntent was cancelled");
             }
diff --git a/services/java/com/android/server/wm/DimAnimator.java b/services/java/com/android/server/wm/DimAnimator.java
index 9bca834..5874202 100644
--- a/services/java/com/android/server/wm/DimAnimator.java
+++ b/services/java/com/android/server/wm/DimAnimator.java
@@ -30,37 +30,37 @@
  * all state used for dim animation.
  */
 class DimAnimator {
+    static final String TAG = "DimAnimator";
+
     Surface mDimSurface;
     boolean mDimShown = false;
     float mDimCurrentAlpha;
     float mDimTargetAlpha;
     float mDimDeltaPerMs;
     long mLastDimAnimTime;
-    
+
     int mLastDimWidth, mLastDimHeight;
 
     DimAnimator (SurfaceSession session, final int layerStack) {
-        if (mDimSurface == null) {
-            try {
-                if (WindowManagerService.DEBUG_SURFACE_TRACE) {
-                    mDimSurface = new WindowStateAnimator.SurfaceTrace(session,
-                        "DimAnimator",
-                        16, 16, PixelFormat.OPAQUE,
-                        Surface.FX_SURFACE_DIM | Surface.HIDDEN);
-                } else {
-                    mDimSurface = new Surface(session, "DimAnimator",
-                        16, 16, PixelFormat.OPAQUE,
-                        Surface.FX_SURFACE_DIM | Surface.HIDDEN);
-                }
-                if (WindowManagerService.SHOW_TRANSACTIONS ||
-                        WindowManagerService.SHOW_SURFACE_ALLOC) Slog.i(WindowManagerService.TAG,
-                                "  DIM " + mDimSurface + ": CREATE");
-                mDimSurface.setLayerStack(layerStack);
-                mDimSurface.setAlpha(0.0f);
-                mDimSurface.show();
-            } catch (Exception e) {
-                Slog.e(WindowManagerService.TAG, "Exception creating Dim surface", e);
+        try {
+            if (WindowManagerService.DEBUG_SURFACE_TRACE) {
+                mDimSurface = new WindowStateAnimator.SurfaceTrace(session,
+                    "DimAnimator",
+                    16, 16, PixelFormat.OPAQUE,
+                    Surface.FX_SURFACE_DIM | Surface.HIDDEN);
+            } else {
+                mDimSurface = new Surface(session, "DimAnimator",
+                    16, 16, PixelFormat.OPAQUE,
+                    Surface.FX_SURFACE_DIM | Surface.HIDDEN);
             }
+            if (WindowManagerService.SHOW_TRANSACTIONS ||
+                    WindowManagerService.SHOW_SURFACE_ALLOC) Slog.i(WindowManagerService.TAG,
+                            "  DIM " + mDimSurface + ": CREATE");
+            mDimSurface.setLayerStack(layerStack);
+            mDimSurface.setAlpha(0.0f);
+            mDimSurface.show();
+        } catch (Exception e) {
+            Slog.e(WindowManagerService.TAG, "Exception creating Dim surface", e);
         }
     }
 
@@ -69,6 +69,11 @@
      * {@link #updateSurface} after all windows are examined.
      */
     void updateParameters(final Resources res, final Parameters params, final long currentTime) {
+        if (mDimSurface == null) {
+            Slog.e(TAG, "updateParameters: no Surface");
+            return;
+        }
+
         // Multiply by 1.5 so that rotating a frozen surface that includes this does not expose a
         // corner.
         final int dw = (int) (params.mDimWidth * 1.5);
@@ -133,6 +138,11 @@
      * false when the animation is finished and the dim surface is hidden.
      */
     boolean updateSurface(boolean dimming, long currentTime, boolean displayFrozen) {
+        if (mDimSurface == null) {
+            Slog.e(TAG, "updateSurface: no Surface");
+            return false;
+        }
+
         if (!dimming) {
             if (mDimTargetAlpha != 0) {
                 mLastDimAnimTime = currentTime;
@@ -187,6 +197,13 @@
         return animating;
     }
 
+    public void kill() {
+        if (mDimSurface != null) {
+            mDimSurface.destroy();
+            mDimSurface = null;
+        }
+    }
+
     public void printTo(String prefix, PrintWriter pw) {
         pw.print(prefix);
         pw.print("mDimSurface="); pw.print(mDimSurface);
diff --git a/services/java/com/android/server/wm/DimSurface.java b/services/java/com/android/server/wm/DimSurface.java
index ddbd70d..4225868 100644
--- a/services/java/com/android/server/wm/DimSurface.java
+++ b/services/java/com/android/server/wm/DimSurface.java
@@ -24,6 +24,8 @@
 import java.io.PrintWriter;
 
 class DimSurface {
+    static final String TAG = "DimSurface";
+
     Surface mDimSurface;
     boolean mDimShown = false;
     int mDimColor = 0;
@@ -31,27 +33,25 @@
     int mLastDimWidth, mLastDimHeight;
 
     DimSurface(SurfaceSession session, final int layerStack) {
-        if (mDimSurface == null) {
-            try {
-                if (WindowManagerService.DEBUG_SURFACE_TRACE) {
-                    mDimSurface = new WindowStateAnimator.SurfaceTrace(session,
-                        "DimSurface",
-                        16, 16, PixelFormat.OPAQUE,
-                        Surface.FX_SURFACE_DIM | Surface.HIDDEN);
-                } else {
-                    mDimSurface = new Surface(session, "DimSurface",
-                        16, 16, PixelFormat.OPAQUE,
-                        Surface.FX_SURFACE_DIM | Surface.HIDDEN);
-                }
-                if (WindowManagerService.SHOW_TRANSACTIONS ||
-                        WindowManagerService.SHOW_SURFACE_ALLOC) Slog.i(WindowManagerService.TAG,
-                                "  DIM " + mDimSurface + ": CREATE");
-                mDimSurface.setLayerStack(layerStack);
-                mDimSurface.setAlpha(0.0f);
-                mDimSurface.show();
-            } catch (Exception e) {
-                Slog.e(WindowManagerService.TAG, "Exception creating Dim surface", e);
+        try {
+            if (WindowManagerService.DEBUG_SURFACE_TRACE) {
+                mDimSurface = new WindowStateAnimator.SurfaceTrace(session,
+                    "DimSurface",
+                    16, 16, PixelFormat.OPAQUE,
+                    Surface.FX_SURFACE_DIM | Surface.HIDDEN);
+            } else {
+                mDimSurface = new Surface(session, "DimSurface",
+                    16, 16, PixelFormat.OPAQUE,
+                    Surface.FX_SURFACE_DIM | Surface.HIDDEN);
             }
+            if (WindowManagerService.SHOW_TRANSACTIONS ||
+                    WindowManagerService.SHOW_SURFACE_ALLOC) Slog.i(WindowManagerService.TAG,
+                            "  DIM " + mDimSurface + ": CREATE");
+            mDimSurface.setLayerStack(layerStack);
+            mDimSurface.setAlpha(0.0f);
+            mDimSurface.show();
+        } catch (Exception e) {
+            Slog.e(WindowManagerService.TAG, "Exception creating Dim surface", e);
         }
     }
 
@@ -59,6 +59,11 @@
      * Show the dim surface.
      */
     void show(int dw, int dh, int layer, int color) {
+        if (mDimSurface == null) {
+            Slog.e(TAG, "show: no Surface");
+            return;
+        }
+
         if (!mDimShown) {
             if (WindowManagerService.SHOW_TRANSACTIONS) Slog.i(WindowManagerService.TAG, "  DIM " + mDimSurface + ": SHOW pos=(0,0) (" +
                     dw + "x" + dh + " layer=" + layer + ")");
@@ -88,6 +93,11 @@
     }
 
     void hide() {
+        if (mDimSurface == null) {
+            Slog.e(TAG, "hide: no Surface");
+            return;
+        }
+
         if (mDimShown) {
             mDimShown = false;
             try {
@@ -99,6 +109,13 @@
         }
     }
 
+    void kill() {
+        if (mDimSurface != null) {
+            mDimSurface.destroy();
+            mDimSurface = null;
+        }
+    }
+
     public void printTo(String prefix, PrintWriter pw) {
         pw.print(prefix); pw.print("mDimSurface="); pw.println(mDimSurface);
         pw.print(prefix); pw.print("mDimShown="); pw.print(mDimShown);
diff --git a/services/java/com/android/server/wm/WindowAnimator.java b/services/java/com/android/server/wm/WindowAnimator.java
index 377e89c..b67fb51 100644
--- a/services/java/com/android/server/wm/WindowAnimator.java
+++ b/services/java/com/android/server/wm/WindowAnimator.java
@@ -147,6 +147,22 @@
     }
 
     void removeDisplayLocked(final int displayId) {
+        final DisplayContentsAnimator displayAnimator = mDisplayContentsAnimators.get(displayId);
+        if (displayAnimator != null) {
+            if (displayAnimator.mWindowAnimationBackgroundSurface != null) {
+                displayAnimator.mWindowAnimationBackgroundSurface.kill();
+                displayAnimator.mWindowAnimationBackgroundSurface = null;
+            }
+            if (displayAnimator.mScreenRotationAnimation != null) {
+                displayAnimator.mScreenRotationAnimation.kill();
+                displayAnimator.mScreenRotationAnimation = null;
+            }
+            if (displayAnimator.mDimAnimator != null) {
+                displayAnimator.mDimAnimator.kill();
+                displayAnimator.mDimAnimator = null;
+            }
+        }
+
         mDisplayContentsAnimators.delete(displayId);
     }
 
@@ -527,11 +543,15 @@
                 }
             }
 
-            windowAnimationBackgroundSurface.show(mDw, mDh,
-                    animLayer - WindowManagerService.LAYER_OFFSET_DIM,
-                    windowAnimationBackgroundColor);
+            if (windowAnimationBackgroundSurface != null) {
+                windowAnimationBackgroundSurface.show(mDw, mDh,
+                        animLayer - WindowManagerService.LAYER_OFFSET_DIM,
+                        windowAnimationBackgroundColor);
+            }
         } else {
-            windowAnimationBackgroundSurface.hide();
+            if (windowAnimationBackgroundSurface != null) {
+                windowAnimationBackgroundSurface.hide();
+            }
         }
     }
 
@@ -643,9 +663,8 @@
 
                 final DimAnimator.Parameters dimParams = displayAnimator.mDimParams;
                 final DimAnimator dimAnimator = displayAnimator.mDimAnimator;
-                if (dimParams != null) {
-                    dimAnimator.updateParameters(
-                            mContext.getResources(), dimParams, mCurrentTime);
+                if (dimAnimator != null && dimParams != null) {
+                    dimAnimator.updateParameters(mContext.getResources(), dimParams, mCurrentTime);
                 }
                 if (dimAnimator != null && dimAnimator.mDimShown) {
                     mAnimating |= dimAnimator.updateSurface(isDimmingLocked(displayId),
@@ -801,9 +820,9 @@
 
     private class DisplayContentsAnimator {
         WinAnimatorList mWinAnimators = new WinAnimatorList();
-        final DimAnimator mDimAnimator;
+        DimAnimator mDimAnimator = null;
         DimAnimator.Parameters mDimParams = null;
-        final DimSurface mWindowAnimationBackgroundSurface;
+        DimSurface mWindowAnimationBackgroundSurface = null;
         ScreenRotationAnimation mScreenRotationAnimation = null;
 
         public DisplayContentsAnimator(int displayId) {
diff --git a/services/java/com/android/server/wm/WindowManagerService.java b/services/java/com/android/server/wm/WindowManagerService.java
index 3f7b67b..8fb1459 100755
--- a/services/java/com/android/server/wm/WindowManagerService.java
+++ b/services/java/com/android/server/wm/WindowManagerService.java
@@ -811,12 +811,12 @@
         mBatteryStats = BatteryStatsService.getService();
 
         // Get persisted window scale setting
-        mWindowAnimationScale = Settings.System.getFloat(context.getContentResolver(),
-                Settings.System.WINDOW_ANIMATION_SCALE, mWindowAnimationScale);
-        mTransitionAnimationScale = Settings.System.getFloat(context.getContentResolver(),
-                Settings.System.TRANSITION_ANIMATION_SCALE, mTransitionAnimationScale);
-        setAnimatorDurationScale(Settings.System.getFloat(context.getContentResolver(),
-                Settings.System.ANIMATOR_DURATION_SCALE, mTransitionAnimationScale));
+        mWindowAnimationScale = Settings.Global.getFloat(context.getContentResolver(),
+                Settings.Global.WINDOW_ANIMATION_SCALE, mWindowAnimationScale);
+        mTransitionAnimationScale = Settings.Global.getFloat(context.getContentResolver(),
+                Settings.Global.TRANSITION_ANIMATION_SCALE, mTransitionAnimationScale);
+        setAnimatorDurationScale(Settings.Global.getFloat(context.getContentResolver(),
+                Settings.Global.ANIMATOR_DURATION_SCALE, mTransitionAnimationScale));
 
         // Track changes to DevicePolicyManager state so we can enable/disable keyguard.
         IntentFilter filter = new IntentFilter();
@@ -7480,12 +7480,12 @@
                 }
 
                 case PERSIST_ANIMATION_SCALE: {
-                    Settings.System.putFloat(mContext.getContentResolver(),
-                            Settings.System.WINDOW_ANIMATION_SCALE, mWindowAnimationScale);
-                    Settings.System.putFloat(mContext.getContentResolver(),
-                            Settings.System.TRANSITION_ANIMATION_SCALE, mTransitionAnimationScale);
-                    Settings.System.putFloat(mContext.getContentResolver(),
-                            Settings.System.ANIMATOR_DURATION_SCALE, mAnimatorDurationScale);
+                    Settings.Global.putFloat(mContext.getContentResolver(),
+                            Settings.Global.WINDOW_ANIMATION_SCALE, mWindowAnimationScale);
+                    Settings.Global.putFloat(mContext.getContentResolver(),
+                            Settings.Global.TRANSITION_ANIMATION_SCALE, mTransitionAnimationScale);
+                    Settings.Global.putFloat(mContext.getContentResolver(),
+                            Settings.Global.ANIMATOR_DURATION_SCALE, mAnimatorDurationScale);
                     break;
                 }
 
@@ -10870,8 +10870,8 @@
         final DisplayContent displayContent = getDisplayContentLocked(displayId);
         mDisplayContents.delete(displayId);
         WindowList windows = displayContent.getWindowList();
-        for (int i = windows.size() - 1; i >= 0; --i) {
-            final WindowState win = windows.get(i);
+        while (!windows.isEmpty()) {
+            final WindowState win = windows.get(windows.size() - 1);
             removeWindowLocked(win.mSession, win);
         }
         mAnimator.removeDisplayLocked(displayId);