Merge "Layer changes" into lmp-mr1-dev
diff --git a/api/current.txt b/api/current.txt
index 4cfab54..8d71375 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -239,6 +239,8 @@
     field public static final int accessibilityFeedbackType = 16843650; // 0x1010382
     field public static final int accessibilityFlags = 16843652; // 0x1010384
     field public static final int accessibilityLiveRegion = 16843758; // 0x10103ee
+    field public static final int accessibilityTraversalAfter = 16844036; // 0x1010504
+    field public static final int accessibilityTraversalBefore = 16844035; // 0x1010503
     field public static final int accountPreferences = 16843423; // 0x101029f
     field public static final int accountType = 16843407; // 0x101028f
     field public static final int action = 16842797; // 0x101002d
@@ -402,6 +404,7 @@
     field public static final int closeIcon = 16843905; // 0x1010481
     field public static final int codes = 16843330; // 0x1010242
     field public static final int collapseColumns = 16843083; // 0x101014b
+    field public static final int collapseContentDescription = 16844034; // 0x1010502
     field public static final int color = 16843173; // 0x10101a5
     field public static final int colorAccent = 16843829; // 0x1010435
     field public static final int colorActivatedHighlight = 16843664; // 0x1010390
@@ -9259,6 +9262,7 @@
     method public int getType(int);
     method public boolean getValue(int, android.util.TypedValue);
     method public boolean hasValue(int);
+    method public boolean hasValueOrEmpty(int);
     method public int length();
     method public android.util.TypedValue peekValue(int);
     method public void recycle();
@@ -25144,6 +25148,7 @@
     field public static final java.lang.String ACTION_APPLICATION_DETAILS_SETTINGS = "android.settings.APPLICATION_DETAILS_SETTINGS";
     field public static final java.lang.String ACTION_APPLICATION_DEVELOPMENT_SETTINGS = "android.settings.APPLICATION_DEVELOPMENT_SETTINGS";
     field public static final java.lang.String ACTION_APPLICATION_SETTINGS = "android.settings.APPLICATION_SETTINGS";
+    field public static final java.lang.String ACTION_BATTERY_SAVER_SETTINGS = "android.settings.BATTERY_SAVER_SETTINGS";
     field public static final java.lang.String ACTION_BLUETOOTH_SETTINGS = "android.settings.BLUETOOTH_SETTINGS";
     field public static final java.lang.String ACTION_CAPTIONING_SETTINGS = "android.settings.CAPTIONING_SETTINGS";
     field public static final java.lang.String ACTION_CAST_SETTINGS = "android.settings.CAST_SETTINGS";
@@ -25165,6 +25170,7 @@
     field public static final java.lang.String ACTION_NFCSHARING_SETTINGS = "android.settings.NFCSHARING_SETTINGS";
     field public static final java.lang.String ACTION_NFC_PAYMENT_SETTINGS = "android.settings.NFC_PAYMENT_SETTINGS";
     field public static final java.lang.String ACTION_NFC_SETTINGS = "android.settings.NFC_SETTINGS";
+    field public static final java.lang.String ACTION_NOTIFICATION_LISTENER_SETTINGS = "android.settings.ACTION_NOTIFICATION_LISTENER_SETTINGS";
     field public static final java.lang.String ACTION_PRINT_SETTINGS = "android.settings.ACTION_PRINT_SETTINGS";
     field public static final java.lang.String ACTION_PRIVACY_SETTINGS = "android.settings.PRIVACY_SETTINGS";
     field public static final java.lang.String ACTION_QUICK_LAUNCH_SETTINGS = "android.settings.QUICK_LAUNCH_SETTINGS";
@@ -28089,6 +28095,7 @@
     method public final java.util.List<android.telecom.Connection> getConferenceableConnections();
     method public final java.util.List<android.telecom.Connection> getConnections();
     method public final android.telecom.PhoneAccountHandle getPhoneAccountHandle();
+    method public android.telecom.Connection getPrimaryConnection();
     method public final int getState();
     method public void onAudioStateChanged(android.telecom.AudioState);
     method public void onDisconnect();
@@ -28178,6 +28185,7 @@
   public abstract class ConnectionService extends android.app.Service {
     ctor public ConnectionService();
     method public final void addConference(android.telecom.Conference);
+    method public final void addExistingConnection(android.telecom.PhoneAccountHandle, android.telecom.Connection);
     method public final void conferenceRemoteConnections(android.telecom.RemoteConnection, android.telecom.RemoteConnection);
     method public final android.telecom.RemoteConnection createRemoteIncomingConnection(android.telecom.PhoneAccountHandle, android.telecom.ConnectionRequest);
     method public final android.telecom.RemoteConnection createRemoteOutgoingConnection(android.telecom.PhoneAccountHandle, android.telecom.ConnectionRequest);
@@ -28187,6 +28195,7 @@
     method public android.telecom.Connection onCreateIncomingConnection(android.telecom.PhoneAccountHandle, android.telecom.ConnectionRequest);
     method public android.telecom.Connection onCreateOutgoingConnection(android.telecom.PhoneAccountHandle, android.telecom.ConnectionRequest);
     method public void onRemoteConferenceAdded(android.telecom.RemoteConference);
+    method public void onRemoteExistingConnectionAdded(android.telecom.RemoteConnection);
     field public static final java.lang.String SERVICE_INTERFACE = "android.telecom.ConnectionService";
   }
 
@@ -28385,6 +28394,7 @@
     method public android.telecom.PhoneAccount getPhoneAccount(android.telecom.PhoneAccountHandle);
     method public java.util.List<android.telecom.PhoneAccountHandle> getPhoneAccountsForPackage();
     method public boolean handleMmi(java.lang.String);
+    method public boolean handleMmi(android.telecom.PhoneAccountHandle, java.lang.String);
     method public boolean hasMultipleCallCapableAccounts();
     method public boolean isInCall();
     method public void registerPhoneAccount(android.telecom.PhoneAccount);
@@ -28767,6 +28777,7 @@
     field public static final int MMS_ERROR_RETRY = 6; // 0x6
     field public static final int MMS_ERROR_UNABLE_CONNECT_MMS = 3; // 0x3
     field public static final int MMS_ERROR_UNSPECIFIED = 1; // 0x1
+    field public static final java.lang.String MMS_SHOW_CELL_BROADCAST_APP_LINKS = "config_cellBroadcastAppLinks";
     field public static final int RESULT_ERROR_GENERIC_FAILURE = 1; // 0x1
     field public static final int RESULT_ERROR_NO_SERVICE = 4; // 0x4
     field public static final int RESULT_ERROR_NULL_PDU = 3; // 0x3
@@ -32147,6 +32158,7 @@
     method public static int complexToDimensionPixelSize(int, android.util.DisplayMetrics);
     method public static float complexToFloat(int);
     method public static float complexToFraction(int, float, float);
+    method public int getComplexUnit();
     method public float getDimension(android.util.DisplayMetrics);
     method public final float getFloat();
     method public float getFraction(float, float);
@@ -32169,6 +32181,8 @@
     field public static final int COMPLEX_UNIT_PX = 0; // 0x0
     field public static final int COMPLEX_UNIT_SHIFT = 0; // 0x0
     field public static final int COMPLEX_UNIT_SP = 2; // 0x2
+    field public static final int DATA_NULL_EMPTY = 1; // 0x1
+    field public static final int DATA_NULL_UNDEFINED = 0; // 0x0
     field public static final int DENSITY_DEFAULT = 0; // 0x0
     field public static final int DENSITY_NONE = 65535; // 0xffff
     field public static final int TYPE_ATTRIBUTE = 2; // 0x2
@@ -33600,6 +33614,8 @@
     method public static int generateViewId();
     method public int getAccessibilityLiveRegion();
     method public android.view.accessibility.AccessibilityNodeProvider getAccessibilityNodeProvider();
+    method public int getAccessibilityTraversalAfter();
+    method public int getAccessibilityTraversalBefore();
     method public float getAlpha();
     method public android.view.animation.Animation getAnimation();
     method public android.os.IBinder getApplicationWindowToken();
@@ -33876,6 +33892,8 @@
     method public void sendAccessibilityEventUnchecked(android.view.accessibility.AccessibilityEvent);
     method public void setAccessibilityDelegate(android.view.View.AccessibilityDelegate);
     method public void setAccessibilityLiveRegion(int);
+    method public void setAccessibilityTraversalAfter(int);
+    method public void setAccessibilityTraversalBefore(int);
     method public void setActivated(boolean);
     method public void setAlpha(float);
     method public void setAnimation(android.view.animation.Animation);
@@ -34726,12 +34744,14 @@
     method public void setCallback(android.view.Window.Callback);
     method public abstract void setChildDrawable(int, android.graphics.drawable.Drawable);
     method public abstract void setChildInt(int, int);
+    method public void setClipToOutline(boolean);
     method public void setContainer(android.view.Window);
     method public abstract void setContentView(int);
     method public abstract void setContentView(android.view.View);
     method public abstract void setContentView(android.view.View, android.view.ViewGroup.LayoutParams);
     method protected void setDefaultWindowFormat(int);
     method public void setDimAmount(float);
+    method public void setElevation(float);
     method public void setEnterTransition(android.transition.Transition);
     method public void setExitTransition(android.transition.Transition);
     method public abstract void setFeatureDrawable(int, android.graphics.drawable.Drawable);
@@ -35153,6 +35173,8 @@
     method public java.lang.CharSequence getText();
     method public int getTextSelectionEnd();
     method public int getTextSelectionStart();
+    method public android.view.accessibility.AccessibilityNodeInfo getTraversalAfter();
+    method public android.view.accessibility.AccessibilityNodeInfo getTraversalBefore();
     method public java.lang.String getViewIdResourceName();
     method public android.view.accessibility.AccessibilityWindowInfo getWindow();
     method public int getWindowId();
@@ -35223,6 +35245,10 @@
     method public void setSource(android.view.View, int);
     method public void setText(java.lang.CharSequence);
     method public void setTextSelection(int, int);
+    method public void setTraversalAfter(android.view.View);
+    method public void setTraversalAfter(android.view.View, int);
+    method public void setTraversalBefore(android.view.View);
+    method public void setTraversalBefore(android.view.View, int);
     method public void setViewIdResourceName(java.lang.String);
     method public void setVisibleToUser(boolean);
     method public void writeToParcel(android.os.Parcel, int);
@@ -38420,6 +38446,8 @@
     method public boolean onLoadClass(java.lang.Class);
     method public void reapply(android.content.Context, android.view.View);
     method public void removeAllViews(int);
+    method public void setAccessibilityTraversalAfter(int, int);
+    method public void setAccessibilityTraversalBefore(int, int);
     method public void setBitmap(int, java.lang.String, android.graphics.Bitmap);
     method public void setBoolean(int, java.lang.String, boolean);
     method public void setBundle(int, java.lang.String, android.os.Bundle);
diff --git a/cmds/pm/src/com/android/commands/pm/Pm.java b/cmds/pm/src/com/android/commands/pm/Pm.java
index 5e9d8f7..7fd586f 100644
--- a/cmds/pm/src/com/android/commands/pm/Pm.java
+++ b/cmds/pm/src/com/android/commands/pm/Pm.java
@@ -96,8 +96,9 @@
         "Error: Could not access the Package Manager.  Is the system running?";
 
     public static void main(String[] args) {
+        int exitCode = 1;
         try {
-            new Pm().run(args);
+            exitCode = new Pm().run(args);
         } catch (Exception e) {
             Log.e(TAG, "Error", e);
             System.err.println("Error: " + e);
@@ -105,20 +106,20 @@
                 System.err.println(PM_NOT_RUNNING_ERR);
             }
         }
+        System.exit(exitCode);
     }
 
-    public void run(String[] args) throws IOException, RemoteException {
+    public int run(String[] args) throws IOException, RemoteException {
         boolean validCommand = false;
         if (args.length < 1) {
-            showUsage();
-            return;
+            return showUsage();
         }
 
         mUm = IUserManager.Stub.asInterface(ServiceManager.getService("user"));
         mPm = IPackageManager.Stub.asInterface(ServiceManager.getService("package"));
         if (mPm == null) {
             System.err.println(PM_NOT_RUNNING_ERR);
-            return;
+            return 1;
         }
         mInstaller = mPm.getPackageInstaller();
 
@@ -127,155 +128,129 @@
         mNextArg = 1;
 
         if ("list".equals(op)) {
-            runList();
-            return;
+            return runList();
         }
 
         if ("path".equals(op)) {
-            runPath();
-            return;
+            return runPath();
         }
 
         if ("dump".equals(op)) {
-            runDump();
-            return;
+            return runDump();
         }
 
         if ("install".equals(op)) {
-            runInstall();
-            return;
+            return runInstall();
         }
 
         if ("install-create".equals(op)) {
-            runInstallCreate();
-            return;
+            return runInstallCreate();
         }
 
         if ("install-write".equals(op)) {
-            runInstallWrite();
-            return;
+            return runInstallWrite();
         }
 
         if ("install-commit".equals(op)) {
-            runInstallCommit();
-            return;
+            return runInstallCommit();
         }
 
         if ("install-abandon".equals(op) || "install-destroy".equals(op)) {
-            runInstallAbandon();
-            return;
+            return runInstallAbandon();
         }
 
         if ("set-installer".equals(op)) {
-            runSetInstaller();
-            return;
+            return runSetInstaller();
         }
 
         if ("uninstall".equals(op)) {
-            runUninstall();
-            return;
+            return runUninstall();
         }
 
         if ("clear".equals(op)) {
-            runClear();
-            return;
+            return runClear();
         }
 
         if ("enable".equals(op)) {
-            runSetEnabledSetting(PackageManager.COMPONENT_ENABLED_STATE_ENABLED);
-            return;
+            return runSetEnabledSetting(PackageManager.COMPONENT_ENABLED_STATE_ENABLED);
         }
 
         if ("disable".equals(op)) {
-            runSetEnabledSetting(PackageManager.COMPONENT_ENABLED_STATE_DISABLED);
-            return;
+            return runSetEnabledSetting(PackageManager.COMPONENT_ENABLED_STATE_DISABLED);
         }
 
         if ("disable-user".equals(op)) {
-            runSetEnabledSetting(PackageManager.COMPONENT_ENABLED_STATE_DISABLED_USER);
-            return;
+            return runSetEnabledSetting(PackageManager.COMPONENT_ENABLED_STATE_DISABLED_USER);
         }
 
         if ("disable-until-used".equals(op)) {
-            runSetEnabledSetting(PackageManager.COMPONENT_ENABLED_STATE_DISABLED_UNTIL_USED);
-            return;
+            return runSetEnabledSetting(PackageManager.COMPONENT_ENABLED_STATE_DISABLED_UNTIL_USED);
         }
 
         if ("hide".equals(op)) {
-            runSetHiddenSetting(true);
-            return;
+            return runSetHiddenSetting(true);
         }
 
         if ("unhide".equals(op)) {
-            runSetHiddenSetting(false);
-            return;
+            return runSetHiddenSetting(false);
         }
 
         if ("grant".equals(op)) {
-            runGrantRevokePermission(true);
-            return;
+            return runGrantRevokePermission(true);
         }
 
         if ("revoke".equals(op)) {
-            runGrantRevokePermission(false);
-            return;
+            return runGrantRevokePermission(false);
         }
 
         if ("set-permission-enforced".equals(op)) {
-            runSetPermissionEnforced();
-            return;
+            return runSetPermissionEnforced();
         }
 
         if ("set-install-location".equals(op)) {
-            runSetInstallLocation();
-            return;
+            return runSetInstallLocation();
         }
 
         if ("get-install-location".equals(op)) {
-            runGetInstallLocation();
-            return;
+            return runGetInstallLocation();
         }
 
         if ("trim-caches".equals(op)) {
-            runTrimCaches();
-            return;
+            return runTrimCaches();
         }
 
         if ("create-user".equals(op)) {
-            runCreateUser();
-            return;
+            return runCreateUser();
         }
 
         if ("remove-user".equals(op)) {
-            runRemoveUser();
-            return;
+            return runRemoveUser();
         }
 
         if ("get-max-users".equals(op)) {
-            runGetMaxUsers();
-            return;
+            return runGetMaxUsers();
         }
 
         if ("force-dex-opt".equals(op)) {
-            runForceDexOpt();
-            return;
+            return runForceDexOpt();
         }
 
         try {
             if (args.length == 1) {
                 if (args[0].equalsIgnoreCase("-l")) {
                     validCommand = true;
-                    runListPackages(false);
+                    return runListPackages(false);
                 } else if (args[0].equalsIgnoreCase("-lf")){
                     validCommand = true;
-                    runListPackages(true);
+                    return runListPackages(true);
                 }
             } else if (args.length == 2) {
                 if (args[0].equalsIgnoreCase("-p")) {
                     validCommand = true;
-                    displayPackageFilePath(args[1]);
+                    return displayPackageFilePath(args[1]);
                 }
             }
+            return 1;
         } finally {
             if (validCommand == false) {
                 if (op != null) {
@@ -296,35 +271,36 @@
      * pm list libraries
      * pm list instrumentation
      */
-    private void runList() {
+    private int runList() {
         String type = nextArg();
         if (type == null) {
             System.err.println("Error: didn't specify type of data to list");
-            return;
+            return 1;
         }
         if ("package".equals(type) || "packages".equals(type)) {
-            runListPackages(false);
+            return runListPackages(false);
         } else if ("permission-groups".equals(type)) {
-            runListPermissionGroups();
+            return runListPermissionGroups();
         } else if ("permissions".equals(type)) {
-            runListPermissions();
+            return runListPermissions();
         } else if ("features".equals(type)) {
-            runListFeatures();
+            return runListFeatures();
         } else if ("libraries".equals(type)) {
-            runListLibraries();
+            return runListLibraries();
         } else if ("instrumentation".equals(type)) {
-            runListInstrumentation();
+            return runListInstrumentation();
         } else if ("users".equals(type)) {
-            runListUsers();
+            return runListUsers();
         } else {
             System.err.println("Error: unknown list type '" + type + "'");
+            return 1;
         }
     }
 
     /**
      * Lists all the installed packages.
      */
-    private void runListPackages(boolean showApplicationPackage) {
+    private int runListPackages(boolean showApplicationPackage) {
         int getFlags = 0;
         boolean listDisabled = false, listEnabled = false;
         boolean listSystem = false, listThirdParty = false;
@@ -355,12 +331,12 @@
                     getFlags |= PackageManager.GET_UNINSTALLED_PACKAGES;
                 } else {
                     System.err.println("Error: Unknown option: " + opt);
-                    return;
+                    return 1;
                 }
             }
         } catch (RuntimeException ex) {
             System.err.println("Error: " + ex.toString());
-            return;
+            return 1;
         }
 
         String filter = nextArg();
@@ -393,9 +369,11 @@
                     System.out.println();
                 }
             }
+            return 0;
         } catch (RemoteException e) {
             System.err.println(e.toString());
             System.err.println(PM_NOT_RUNNING_ERR);
+            return 1;
         }
     }
 
@@ -411,7 +389,7 @@
      *
      * pm list features
      */
-    private void runListFeatures() {
+    private int runListFeatures() {
         try {
             List<FeatureInfo> list = new ArrayList<FeatureInfo>();
             FeatureInfo[] rawList = mPm.getSystemAvailableFeatures();
@@ -438,9 +416,11 @@
                 else System.out.println("reqGlEsVersion=0x"
                         + Integer.toHexString(fi.reqGlEsVersion));
             }
+            return 0;
         } catch (RemoteException e) {
             System.err.println(e.toString());
             System.err.println(PM_NOT_RUNNING_ERR);
+            return 1;
         }
     }
 
@@ -449,7 +429,7 @@
      *
      * pm list libraries
      */
-    private void runListLibraries() {
+    private int runListLibraries() {
         try {
             List<String> list = new ArrayList<String>();
             String[] rawList = mPm.getSystemSharedLibraryNames();
@@ -474,9 +454,11 @@
                 System.out.print("library:");
                 System.out.println(lib);
             }
+            return 0;
         } catch (RemoteException e) {
             System.err.println(e.toString());
             System.err.println(PM_NOT_RUNNING_ERR);
+            return 1;
         }
     }
 
@@ -485,7 +467,7 @@
      *
      * pm list instrumentation [package] [-f]
      */
-    private void runListInstrumentation() {
+    private int runListInstrumentation() {
         int flags = 0;      // flags != 0 is only used to request meta-data
         boolean showPackage = false;
         String targetPackage = null;
@@ -499,12 +481,12 @@
                     targetPackage = opt;
                 } else {
                     System.err.println("Error: Unknown option: " + opt);
-                    return;
+                    return 1;
                 }
             }
         } catch (RuntimeException ex) {
             System.err.println("Error: " + ex.toString());
-            return;
+            return 1;
         }
 
         try {
@@ -531,16 +513,18 @@
                 System.out.print(ii.targetPackage);
                 System.out.println(")");
             }
+            return 0;
         } catch (RemoteException e) {
             System.err.println(e.toString());
             System.err.println(PM_NOT_RUNNING_ERR);
+            return 1;
         }
     }
 
     /**
      * Lists all the known permission groups.
      */
-    private void runListPermissionGroups() {
+    private int runListPermissionGroups() {
         try {
             List<PermissionGroupInfo> pgs = mPm.getAllPermissionGroups(0);
 
@@ -550,9 +534,11 @@
                 System.out.print("permission group:");
                 System.out.println(pgi.name);
             }
+            return 0;
         } catch (RemoteException e) {
             System.err.println(e.toString());
             System.err.println(PM_NOT_RUNNING_ERR);
+            return 1;
         }
     }
 
@@ -572,7 +558,7 @@
     /**
      * Lists all the permissions in a group.
      */
-    private void runListPermissions() {
+    private int runListPermissions() {
         try {
             boolean labels = false;
             boolean groups = false;
@@ -595,7 +581,7 @@
                     dangerousOnly = true;
                 } else {
                     System.err.println("Error: Unknown option: " + opt);
-                    return;
+                    return 1;
                 }
             }
 
@@ -637,9 +623,11 @@
                 doListPermissions(groupList, groups, labels, summary,
                         -10000, 10000);
             }
+            return 0;
         } catch (RemoteException e) {
             System.err.println(e.toString());
             System.err.println(PM_NOT_RUNNING_ERR);
+            return 1;
         }
     }
 
@@ -739,22 +727,23 @@
         }
     }
 
-    private void runPath() {
+    private int runPath() {
         String pkg = nextArg();
         if (pkg == null) {
             System.err.println("Error: no package specified");
-            return;
+            return 1;
         }
-        displayPackageFilePath(pkg);
+        return displayPackageFilePath(pkg);
     }
 
-    private void runDump() {
+    private int runDump() {
         String pkg = nextArg();
         if (pkg == null) {
             System.err.println("Error: no package specified");
-            return;
+            return 1;
         }
         ActivityManager.dumpPackageStateStatic(FileDescriptor.out, pkg);
+        return 0;
     }
 
     class LocalPackageInstallObserver extends PackageInstallObserver {
@@ -822,31 +811,34 @@
         return Integer.toString(result);
     }
 
-    private void runSetInstallLocation() {
+    private int runSetInstallLocation() {
         int loc;
 
         String arg = nextArg();
         if (arg == null) {
             System.err.println("Error: no install location specified.");
-            return;
+            return 1;
         }
         try {
             loc = Integer.parseInt(arg);
         } catch (NumberFormatException e) {
             System.err.println("Error: install location has to be a number.");
-            return;
+            return 1;
         }
         try {
             if (!mPm.setInstallLocation(loc)) {
                 System.err.println("Error: install location has to be a number.");
+                return 1;
             }
+            return 0;
         } catch (RemoteException e) {
             System.err.println(e.toString());
             System.err.println(PM_NOT_RUNNING_ERR);
+            return 1;
         }
     }
 
-    private void runGetInstallLocation() {
+    private int runGetInstallLocation() {
         try {
             int loc = mPm.getInstallLocation();
             String locStr = "invalid";
@@ -858,13 +850,15 @@
                 locStr = "external";
             }
             System.out.println(loc + "[" + locStr + "]");
+            return 0;
         } catch (RemoteException e) {
             System.err.println(e.toString());
             System.err.println(PM_NOT_RUNNING_ERR);
+            return 1;
         }
     }
 
-    private void runInstall() {
+    private int runInstall() {
         int installFlags = 0;
         int userId = UserHandle.USER_ALL;
         String installerPackageName = null;
@@ -884,7 +878,7 @@
                 installerPackageName = nextOptionData();
                 if (installerPackageName == null) {
                     System.err.println("Error: no value specified for -i");
-                    return;
+                    return 1;
                 }
             } else if (opt.equals("-t")) {
                 installFlags |= PackageManager.INSTALL_ALLOW_TEST;
@@ -900,13 +894,13 @@
                 originatingUriString = nextOptionData();
                 if (originatingUriString == null) {
                     System.err.println("Error: must supply argument for --originating-uri");
-                    return;
+                    return 1;
                 }
             } else if (opt.equals("--referrer")) {
                 referrer = nextOptionData();
                 if (referrer == null) {
                     System.err.println("Error: must supply argument for --referrer");
-                    return;
+                    return 1;
                 }
             } else if (opt.equals("--abi")) {
                 abi = checkAbiArgument(nextOptionData());
@@ -914,7 +908,7 @@
                 userId = Integer.parseInt(nextOptionData());
             } else {
                 System.err.println("Error: Unknown option: " + opt);
-                return;
+                return 1;
             }
         }
 
@@ -944,7 +938,7 @@
         System.err.println("\tpkg: " + apkFilePath);
         if (apkFilePath == null) {
             System.err.println("Error: no package specified");
-            return;
+            return 1;
         }
 
         // Populate verificationURI, optionally present
@@ -973,19 +967,22 @@
                 }
                 if (obs.result == PackageManager.INSTALL_SUCCEEDED) {
                     System.out.println("Success");
+                    return 0;
                 } else {
                     System.err.println("Failure ["
                             + installFailureToString(obs)
                             + "]");
+                    return 1;
                 }
             }
         } catch (RemoteException e) {
             System.err.println(e.toString());
             System.err.println(PM_NOT_RUNNING_ERR);
+            return 1;
         }
     }
 
-    private void runInstallCreate() throws RemoteException {
+    private int runInstallCreate() throws RemoteException {
         int userId = UserHandle.USER_ALL;
         String installerPackageName = null;
 
@@ -1040,9 +1037,10 @@
 
         // NOTE: adb depends on parsing this string
         System.out.println("Success: created install session [" + sessionId + "]");
+        return 0;
     }
 
-    private void runInstallWrite() throws IOException, RemoteException {
+    private int runInstallWrite() throws IOException, RemoteException {
         long sizeBytes = -1;
 
         String opt;
@@ -1097,6 +1095,7 @@
             session.fsync(out);
 
             System.out.println("Success: streamed " + total + " bytes");
+            return 0;
         } finally {
             IoUtils.closeQuietly(out);
             IoUtils.closeQuietly(in);
@@ -1104,7 +1103,7 @@
         }
     }
 
-    private void runInstallCommit() throws RemoteException {
+    private int runInstallCommit() throws RemoteException {
         final int sessionId = Integer.parseInt(nextArg());
 
         PackageInstaller.Session session = null;
@@ -1119,18 +1118,19 @@
                     PackageInstaller.STATUS_FAILURE);
             if (status == PackageInstaller.STATUS_SUCCESS) {
                 System.out.println("Success");
+                return 0;
             } else {
                 Log.e(TAG, "Failure details: " + result.getExtras());
-                System.out.println("Failure ["
+                System.err.println("Failure ["
                         + result.getStringExtra(PackageInstaller.EXTRA_STATUS_MESSAGE) + "]");
-                return;
+                return 1;
             }
         } finally {
             IoUtils.closeQuietly(session);
         }
     }
 
-    private void runInstallAbandon() throws RemoteException {
+    private int runInstallAbandon() throws RemoteException {
         final int sessionId = Integer.parseInt(nextArg());
 
         PackageInstaller.Session session = null;
@@ -1138,12 +1138,13 @@
             session = new PackageInstaller.Session(mInstaller.openSession(sessionId));
             session.abandon();
             System.out.println("Success");
+            return 0;
         } finally {
             IoUtils.closeQuietly(session);
         }
     }
 
-    private void runSetInstaller() throws RemoteException {
+    private int runSetInstaller() throws RemoteException {
         final String targetPackage = nextArg();
         final String installerPackageName = nextArg();
 
@@ -1154,9 +1155,10 @@
 
         mPm.setInstallerPackageName(targetPackage, installerPackageName);
         System.out.println("Success");
+        return 0;
     }
 
-    public void runCreateUser() {
+    public int runCreateUser() {
         String name;
         int userId = -1;
         int flags = 0;
@@ -1167,7 +1169,7 @@
                 if (optionData == null || !isNumber(optionData)) {
                     System.err.println("Error: no USER_ID specified");
                     showUsage();
-                    return;
+                    return 1;
                 } else {
                     userId = Integer.parseInt(optionData);
                 }
@@ -1176,13 +1178,13 @@
             } else {
                 System.err.println("Error: unknown option " + opt);
                 showUsage();
-                return;
+                return 1;
             }
         }
         String arg = nextArg();
         if (arg == null) {
             System.err.println("Error: no user name specified.");
-            return;
+            return 1;
         }
         name = arg;
         try {
@@ -1194,75 +1196,85 @@
             }
             if (info != null) {
                 System.out.println("Success: created user id " + info.id);
+                return 1;
             } else {
                 System.err.println("Error: couldn't create User.");
+                return 1;
             }
         } catch (RemoteException e) {
             System.err.println(e.toString());
             System.err.println(PM_NOT_RUNNING_ERR);
+            return 1;
         }
-
     }
 
-    public void runRemoveUser() {
+    public int runRemoveUser() {
         int userId;
         String arg = nextArg();
         if (arg == null) {
             System.err.println("Error: no user id specified.");
-            return;
+            return 1;
         }
         try {
             userId = Integer.parseInt(arg);
         } catch (NumberFormatException e) {
             System.err.println("Error: user id '" + arg + "' is not a number.");
-            return;
+            return 1;
         }
         try {
             if (mUm.removeUser(userId)) {
                 System.out.println("Success: removed user");
+                return 0;
             } else {
                 System.err.println("Error: couldn't remove user id " + userId);
+                return 1;
             }
         } catch (RemoteException e) {
             System.err.println(e.toString());
             System.err.println(PM_NOT_RUNNING_ERR);
+            return 1;
         }
     }
 
-    public void runListUsers() {
+    public int runListUsers() {
         try {
             IActivityManager am = ActivityManagerNative.getDefault();
 
             List<UserInfo> users = mUm.getUsers(false);
             if (users == null) {
                 System.err.println("Error: couldn't get users");
+                return 1;
             } else {
                 System.out.println("Users:");
                 for (int i = 0; i < users.size(); i++) {
                     String running = am.isUserRunning(users.get(i).id, false) ? " running" : "";
                     System.out.println("\t" + users.get(i).toString() + running);
                 }
+                return 0;
             }
         } catch (RemoteException e) {
             System.err.println(e.toString());
             System.err.println(PM_NOT_RUNNING_ERR);
+            return 1;
         }
     }
 
-    public void runGetMaxUsers() {
+    public int runGetMaxUsers() {
         System.out.println("Maximum supported users: " + UserManager.getMaxSupportedUsers());
+        return 0;
     }
 
-    public void runForceDexOpt() {
+    public int runForceDexOpt() {
         final String packageName = nextArg();
         try {
             mPm.forceDexOpt(packageName);
+            return 0;
         } catch (RemoteException e) {
             throw e.rethrowAsRuntimeException();
         }
     }
 
-    private void runUninstall() throws RemoteException {
+    private int runUninstall() throws RemoteException {
         int flags = 0;
         int userId = UserHandle.USER_ALL;
 
@@ -1277,11 +1289,11 @@
                 } else {
                     showUsage();
                     System.err.println("Error: Invalid user: " + param);
-                    return;
+                    return 1;
                 }
             } else {
                 System.err.println("Error: Unknown option: " + opt);
-                return;
+                return 1;
             }
         }
 
@@ -1289,7 +1301,7 @@
         if (pkg == null) {
             System.err.println("Error: no package specified");
             showUsage();
-            return;
+            return 1;
         }
 
         if (userId == UserHandle.USER_ALL) {
@@ -1302,11 +1314,11 @@
             } catch (RemoteException e) {
                 System.err.println(e.toString());
                 System.err.println(PM_NOT_RUNNING_ERR);
-                return;
+                return 1;
             }
             if (info == null) {
                 System.err.println("Failure - not installed for " + userId);
-                return;
+                return 1;
             }
             final boolean isSystem =
                     (info.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) != 0;
@@ -1326,10 +1338,12 @@
                 PackageInstaller.STATUS_FAILURE);
         if (status == PackageInstaller.STATUS_SUCCESS) {
             System.out.println("Success");
+            return 0;
         } else {
             Log.e(TAG, "Failure details: " + result.getExtras());
-            System.out.println("Failure ["
+            System.err.println("Failure ["
                     + result.getStringExtra(PackageInstaller.EXTRA_STATUS_MESSAGE) + "]");
+            return 1;
         }
     }
 
@@ -1347,7 +1361,7 @@
         }
     }
 
-    private void runClear() {
+    private int runClear() {
         int userId = 0;
         String option = nextOption();
         if (option != null && option.equals("--user")) {
@@ -1355,7 +1369,7 @@
             if (optionData == null || !isNumber(optionData)) {
                 System.err.println("Error: no USER_ID specified");
                 showUsage();
-                return;
+                return 1;
             } else {
                 userId = Integer.parseInt(optionData);
             }
@@ -1365,7 +1379,7 @@
         if (pkg == null) {
             System.err.println("Error: no package specified");
             showUsage();
-            return;
+            return 1;
         }
 
         ClearDataObserver obs = new ClearDataObserver();
@@ -1381,13 +1395,16 @@
             }
 
             if (obs.result) {
-                System.err.println("Success");
+                System.out.println("Success");
+                return 0;
             } else {
                 System.err.println("Failed");
+                return 1;
             }
         } catch (RemoteException e) {
             System.err.println(e.toString());
             System.err.println(PM_NOT_RUNNING_ERR);
+            return 1;
         }
     }
 
@@ -1416,7 +1433,7 @@
         return true;
     }
 
-    private void runSetEnabledSetting(int state) {
+    private int runSetEnabledSetting(int state) {
         int userId = 0;
         String option = nextOption();
         if (option != null && option.equals("--user")) {
@@ -1424,7 +1441,7 @@
             if (optionData == null || !isNumber(optionData)) {
                 System.err.println("Error: no USER_ID specified");
                 showUsage();
-                return;
+                return 1;
             } else {
                 userId = Integer.parseInt(optionData);
             }
@@ -1434,34 +1451,38 @@
         if (pkg == null) {
             System.err.println("Error: no package or component specified");
             showUsage();
-            return;
+            return 1;
         }
         ComponentName cn = ComponentName.unflattenFromString(pkg);
         if (cn == null) {
             try {
                 mPm.setApplicationEnabledSetting(pkg, state, 0, userId,
                         "shell:" + android.os.Process.myUid());
-                System.err.println("Package " + pkg + " new state: "
+                System.out.println("Package " + pkg + " new state: "
                         + enabledSettingToString(
                         mPm.getApplicationEnabledSetting(pkg, userId)));
+                return 0;
             } catch (RemoteException e) {
                 System.err.println(e.toString());
                 System.err.println(PM_NOT_RUNNING_ERR);
+                return 1;
             }
         } else {
             try {
                 mPm.setComponentEnabledSetting(cn, state, 0, userId);
-                System.err.println("Component " + cn.toShortString() + " new state: "
+                System.out.println("Component " + cn.toShortString() + " new state: "
                         + enabledSettingToString(
                         mPm.getComponentEnabledSetting(cn, userId)));
+                return 0;
             } catch (RemoteException e) {
                 System.err.println(e.toString());
                 System.err.println(PM_NOT_RUNNING_ERR);
+                return 1;
             }
         }
     }
 
-    private void runSetHiddenSetting(boolean state) {
+    private int runSetHiddenSetting(boolean state) {
         int userId = 0;
         String option = nextOption();
         if (option != null && option.equals("--user")) {
@@ -1469,7 +1490,7 @@
             if (optionData == null || !isNumber(optionData)) {
                 System.err.println("Error: no USER_ID specified");
                 showUsage();
-                return;
+                return 1;
             } else {
                 userId = Integer.parseInt(optionData);
             }
@@ -1479,30 +1500,32 @@
         if (pkg == null) {
             System.err.println("Error: no package or component specified");
             showUsage();
-            return;
+            return 1;
         }
         try {
             mPm.setApplicationHiddenSettingAsUser(pkg, state, userId);
-            System.err.println("Package " + pkg + " new hidden state: "
+            System.out.println("Package " + pkg + " new hidden state: "
                     + mPm.getApplicationHiddenSettingAsUser(pkg, userId));
+            return 0;
         } catch (RemoteException e) {
             System.err.println(e.toString());
             System.err.println(PM_NOT_RUNNING_ERR);
+            return 1;
         }
     }
 
-    private void runGrantRevokePermission(boolean grant) {
+    private int runGrantRevokePermission(boolean grant) {
         String pkg = nextArg();
         if (pkg == null) {
             System.err.println("Error: no package specified");
             showUsage();
-            return;
+            return 1;
         }
         String perm = nextArg();
         if (perm == null) {
             System.err.println("Error: no permission specified");
             showUsage();
-            return;
+            return 1;
         }
         try {
             if (grant) {
@@ -1510,41 +1533,49 @@
             } else {
                 mPm.revokePermission(pkg, perm);
             }
+            return 0;
         } catch (RemoteException e) {
             System.err.println(e.toString());
             System.err.println(PM_NOT_RUNNING_ERR);
+            return 1;
         } catch (IllegalArgumentException e) {
             System.err.println("Bad argument: " + e.toString());
             showUsage();
+            return 1;
         } catch (SecurityException e) {
             System.err.println("Operation not allowed: " + e.toString());
+            return 1;
         }
     }
 
-    private void runSetPermissionEnforced() {
+    private int runSetPermissionEnforced() {
         final String permission = nextArg();
         if (permission == null) {
             System.err.println("Error: no permission specified");
             showUsage();
-            return;
+            return 1;
         }
         final String enforcedRaw = nextArg();
         if (enforcedRaw == null) {
             System.err.println("Error: no enforcement specified");
             showUsage();
-            return;
+            return 1;
         }
         final boolean enforced = Boolean.parseBoolean(enforcedRaw);
         try {
             mPm.setPermissionEnforced(permission, enforced);
+            return 0;
         } catch (RemoteException e) {
             System.err.println(e.toString());
             System.err.println(PM_NOT_RUNNING_ERR);
+            return 1;
         } catch (IllegalArgumentException e) {
             System.err.println("Bad argument: " + e.toString());
             showUsage();
+            return 1;
         } catch (SecurityException e) {
             System.err.println("Operation not allowed: " + e.toString());
+            return 1;
         }
     }
 
@@ -1563,12 +1594,12 @@
 
     }
 
-    private void runTrimCaches() {
+    private int runTrimCaches() {
         String size = nextArg();
         if (size == null) {
             System.err.println("Error: no size specified");
             showUsage();
-            return;
+            return 1;
         }
         int len = size.length();
         long multiplier = 1;
@@ -1583,7 +1614,7 @@
             } else {
                 System.err.println("Invalid suffix: " + c);
                 showUsage();
-                return;
+                return 1;
             }
             size = size.substring(0, len-1);
         }
@@ -1593,7 +1624,7 @@
         } catch (NumberFormatException e) {
             System.err.println("Error: expected number at: " + size);
             showUsage();
-            return;
+            return 1;
         }
         ClearDataObserver obs = new ClearDataObserver();
         try {
@@ -1606,14 +1637,18 @@
                     }
                 }
             }
+            return 0;
         } catch (RemoteException e) {
             System.err.println(e.toString());
             System.err.println(PM_NOT_RUNNING_ERR);
+            return 1;
         } catch (IllegalArgumentException e) {
             System.err.println("Bad argument: " + e.toString());
             showUsage();
+            return 1;
         } catch (SecurityException e) {
             System.err.println("Operation not allowed: " + e.toString());
+            return 1;
         }
     }
 
@@ -1621,7 +1656,7 @@
      * Displays the package file for a package.
      * @param pckg
      */
-    private void displayPackageFilePath(String pckg) {
+    private int displayPackageFilePath(String pckg) {
         try {
             PackageInfo info = mPm.getPackageInfo(pckg, 0, 0);
             if (info != null && info.applicationInfo != null) {
@@ -1632,12 +1667,14 @@
                         System.out.print("package:");
                         System.out.println(splitSourceDir);
                     }
+                    return 0;
                 }
             }
         } catch (RemoteException e) {
             System.err.println(e.toString());
             System.err.println(PM_NOT_RUNNING_ERR);
         }
+        return 1;
     }
 
     private Resources getResources(PackageItemInfo pii) {
@@ -1752,7 +1789,7 @@
         return arg;
     }
 
-    private static void showUsage() {
+    private static int showUsage() {
         System.err.println("usage: pm list packages [-f] [-d] [-e] [-s] [-3] [-i] [-u] [--user USER_ID] [FILTER]");
         System.err.println("       pm list permission-groups");
         System.err.println("       pm list permissions [-g] [-f] [-d] [-u] [GROUP]");
@@ -1873,5 +1910,6 @@
         System.err.println("pm remove-user: remove the user with the given USER_IDENTIFIER,");
         System.err.println("  deleting all data associated with that user");
         System.err.println("");
+        return 1;
     }
 }
diff --git a/core/java/android/app/ActivityTransitionCoordinator.java b/core/java/android/app/ActivityTransitionCoordinator.java
index 82b6e35..9062892 100644
--- a/core/java/android/app/ActivityTransitionCoordinator.java
+++ b/core/java/android/app/ActivityTransitionCoordinator.java
@@ -638,6 +638,7 @@
         if (decorView != null) {
             decorView.getLocationOnScreen(decorLoc);
         }
+        Matrix tempMatrix = new Matrix();
         for (String name: names) {
             Bundle sharedElementBundle = state.getBundle(name);
             if (sharedElementBundle != null) {
@@ -647,7 +648,7 @@
                     snapshot = mListener.onCreateSnapshotView(context, parcelable);
                 }
                 if (snapshot != null) {
-                    setSharedElementState(snapshot, name, state, null, null, decorLoc);
+                    setSharedElementState(snapshot, name, state, tempMatrix, null, decorLoc);
                 }
                 snapshots.add(snapshot);
             }
diff --git a/core/java/android/app/ApplicationPackageManager.java b/core/java/android/app/ApplicationPackageManager.java
index 854719d..967e97e 100644
--- a/core/java/android/app/ApplicationPackageManager.java
+++ b/core/java/android/app/ApplicationPackageManager.java
@@ -1609,6 +1609,18 @@
         return null;
     }
 
+    /**
+     * @hide
+     */
+    @Override
+    public boolean isUpgrade() {
+        try {
+            return mPM.isUpgrade();
+        } catch (RemoteException e) {
+            return false;
+        }
+    }
+
     @Override
     public PackageInstaller getPackageInstaller() {
         synchronized (mLock) {
diff --git a/core/java/android/app/EnterTransitionCoordinator.java b/core/java/android/app/EnterTransitionCoordinator.java
index 7894887..ecf19c7 100644
--- a/core/java/android/app/EnterTransitionCoordinator.java
+++ b/core/java/android/app/EnterTransitionCoordinator.java
@@ -133,16 +133,17 @@
             return;
         }
         mAreViewsReady = true;
+        final ViewGroup decor = getDecor();
         // Ensure the views have been laid out before capturing the views -- we need the epicenter.
-        if (sharedElements.isEmpty() || !sharedElements.valueAt(0).isLayoutRequested()) {
+        if (decor == null || (decor.isAttachedToWindow() &&
+                (sharedElements.isEmpty() || !sharedElements.valueAt(0).isLayoutRequested()))) {
             viewsReady(sharedElements);
         } else {
-            final View sharedElement = sharedElements.valueAt(0);
-            sharedElement.getViewTreeObserver()
+            decor.getViewTreeObserver()
                     .addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener() {
                 @Override
                 public boolean onPreDraw() {
-                    sharedElement.getViewTreeObserver().removeOnPreDrawListener(this);
+                    decor.getViewTreeObserver().removeOnPreDrawListener(this);
                     viewsReady(sharedElements);
                     return true;
                 }
diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java
index a30ae57..74502fc 100644
--- a/core/java/android/app/admin/DevicePolicyManager.java
+++ b/core/java/android/app/admin/DevicePolicyManager.java
@@ -3133,9 +3133,10 @@
     }
 
     /**
-     * Called by a profile owner to disable account management for a specific type of account.
+     * Called by a device owner or profile owner to disable account management for a specific type
+     * of account.
      *
-     * <p>The calling device admin must be a profile owner. If it is not, a
+     * <p>The calling device admin must be a device owner or profile owner. If it is not, a
      * security exception will be thrown.
      *
      * <p>When account management is disabled for an account type, adding or removing an account
diff --git a/core/java/android/bluetooth/BluetoothAdapter.java b/core/java/android/bluetooth/BluetoothAdapter.java
index f2e03cf..c262bae 100644
--- a/core/java/android/bluetooth/BluetoothAdapter.java
+++ b/core/java/android/bluetooth/BluetoothAdapter.java
@@ -1445,7 +1445,7 @@
                 if (VDBG) Log.d(TAG, "onBluetoothServiceDown: " + mService);
                 synchronized (mManagerCallback) {
                     mService = null;
-                    mLeScanClients.clear();
+                    if (mLeScanClients != null) mLeScanClients.clear();
                     if (sBluetoothLeAdvertiser != null) sBluetoothLeAdvertiser.cleanup();
                     if (sBluetoothLeScanner != null) sBluetoothLeScanner.cleanup();
                     for (IBluetoothManagerCallback cb : mProxyServiceStateCallbacks ){
diff --git a/core/java/android/content/pm/IPackageManager.aidl b/core/java/android/content/pm/IPackageManager.aidl
index c37534a..0dc86ad 100644
--- a/core/java/android/content/pm/IPackageManager.aidl
+++ b/core/java/android/content/pm/IPackageManager.aidl
@@ -436,6 +436,7 @@
 
     boolean isFirstBoot();
     boolean isOnlyCoreApps();
+    boolean isUpgrade();
 
     void setPermissionEnforced(String permission, boolean enforced);
     boolean isPermissionEnforced(String permission);
diff --git a/core/java/android/content/pm/LauncherApps.java b/core/java/android/content/pm/LauncherApps.java
index 5ee0b67..c164340 100644
--- a/core/java/android/content/pm/LauncherApps.java
+++ b/core/java/android/content/pm/LauncherApps.java
@@ -499,20 +499,4 @@
             obtainMessage(MSG_UNAVAILABLE, info).sendToTarget();
         }
     }
-
-    /**
-     * TODO Remove after 2014-09-22
-     * @hide
-     */
-    public void addCallback(Callback callback) {
-        registerCallback(callback);
-    }
-
-    /**
-     * TODO Remove after 2014-09-22
-     * @hide
-     */
-    public void removeCallback(Callback callback) {
-        unregisterCallback(callback);
-    }
 }
diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java
index ab90b66..e9f7c50 100644
--- a/core/java/android/content/pm/PackageManager.java
+++ b/core/java/android/content/pm/PackageManager.java
@@ -3867,6 +3867,13 @@
     public abstract VerifierDeviceIdentity getVerifierDeviceIdentity();
 
     /**
+     * Returns true if the device is upgrading, such as first boot after OTA.
+     *
+     * @hide
+     */
+    public abstract boolean isUpgrade();
+
+    /**
      * Return interface that offers the ability to install, upgrade, and remove
      * applications on the device.
      */
diff --git a/core/java/android/content/res/Configuration.java b/core/java/android/content/res/Configuration.java
index acdd87e..14af584 100644
--- a/core/java/android/content/res/Configuration.java
+++ b/core/java/android/content/res/Configuration.java
@@ -1371,7 +1371,7 @@
             }
         }
 
-        if (!config.locale.getLanguage().isEmpty()) {
+        if (config.locale != null && !config.locale.getLanguage().isEmpty()) {
             parts.add(localeToResourceQualifier(config.locale));
         }
 
diff --git a/core/java/android/content/res/Resources.java b/core/java/android/content/res/Resources.java
index 6e9efe1..0145e05 100644
--- a/core/java/android/content/res/Resources.java
+++ b/core/java/android/content/res/Resources.java
@@ -18,6 +18,7 @@
 
 import android.animation.Animator;
 import android.animation.StateListAnimator;
+import android.annotation.NonNull;
 import android.util.Pools.SynchronizedPool;
 import android.view.ViewDebug;
 import com.android.internal.util.XmlUtils;
@@ -1548,20 +1549,21 @@
          * contents of the typed array are ultimately filled in by
          * {@link Resources#getValue}.
          *
-         * @param values The base set of attribute values, must be equal
-         *               in length to {@code attrs} or {@code null}. All values
-         *               must be of type {@link TypedValue#TYPE_ATTRIBUTE}.
+         * @param values The base set of attribute values, must be equal in
+         *               length to {@code attrs}. All values must be of type
+         *               {@link TypedValue#TYPE_ATTRIBUTE}.
          * @param attrs The desired attributes to be retrieved.
          * @return Returns a TypedArray holding an array of the attribute
          *         values. Be sure to call {@link TypedArray#recycle()}
          *         when done with it.
          * @hide
          */
-        public TypedArray resolveAttributes(int[] values, int[] attrs) {
+        @NonNull
+        public TypedArray resolveAttributes(@NonNull int[] values, @NonNull int[] attrs) {
             final int len = attrs.length;
-            if (values != null && len != values.length) {
+            if (values == null || len != values.length) {
                 throw new IllegalArgumentException(
-                        "Base attribute values must be null or the same length as attrs");
+                        "Base attribute values must the same length as attrs");
             }
 
             final TypedArray array = TypedArray.obtain(Resources.this, len);
diff --git a/core/java/android/content/res/TypedArray.java b/core/java/android/content/res/TypedArray.java
index 73b93c6..02602fb 100644
--- a/core/java/android/content/res/TypedArray.java
+++ b/core/java/android/content/res/TypedArray.java
@@ -807,6 +807,9 @@
 
     /**
      * Determines whether there is an attribute at <var>index</var>.
+     * <p>
+     * <strong>Note:</strong> If the attribute was set to {@code @empty} or
+     * {@code @undefined}, this method returns {@code false}.
      *
      * @param index Index of attribute to retrieve.
      *
@@ -824,6 +827,27 @@
     }
 
     /**
+     * Determines whether there is an attribute at <var>index</var>, returning
+     * {@code true} if the attribute was explicitly set to {@code @empty} and
+     * {@code false} only if the attribute was undefined.
+     *
+     * @param index Index of attribute to retrieve.
+     *
+     * @return True if the attribute has a value or is empty, false otherwise.
+     */
+    public boolean hasValueOrEmpty(int index) {
+        if (mRecycled) {
+            throw new RuntimeException("Cannot make calls to a recycled instance!");
+        }
+
+        index *= AssetManager.STYLE_NUM_ENTRIES;
+        final int[] data = mData;
+        final int type = data[index+AssetManager.STYLE_TYPE];
+        return type != TypedValue.TYPE_NULL
+                || data[index+AssetManager.STYLE_DATA] == TypedValue.DATA_NULL_EMPTY;
+    }
+
+    /**
      * Retrieve the raw TypedValue for the attribute at <var>index</var>
      * and return a temporary object holding its data.  This object is only
      * valid until the next call on to {@link TypedArray}.
diff --git a/core/java/android/os/INetworkManagementService.aidl b/core/java/android/os/INetworkManagementService.aidl
index d0ba4b8..5d5d2b3 100644
--- a/core/java/android/os/INetworkManagementService.aidl
+++ b/core/java/android/os/INetworkManagementService.aidl
@@ -92,6 +92,11 @@
     void enableIpv6(String iface);
 
     /**
+     * Enables or enables IPv6 ND offload.
+     */
+    void setInterfaceIpv6NdOffload(String iface, boolean enable);
+
+    /**
      * Retrieves the network routes currently configured on the specified
      * interface
      */
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index a165279..c54a5ba 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -787,11 +787,10 @@
      * <p>
      * Output: Nothing.
      * @see android.service.notification.NotificationListenerService
-     * @hide
      */
     @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
     public static final String ACTION_NOTIFICATION_LISTENER_SETTINGS
-            = "android.settings.NOTIFICATION_LISTENER_SETTINGS";
+            = "android.settings.ACTION_NOTIFICATION_LISTENER_SETTINGS";
 
     /**
      * @hide
@@ -873,8 +872,9 @@
 
     /**
      * Activity Action: Show battery saver settings.
-     *
-     * @hide
+     * <p>
+     * In some cases, a matching Activity may not exist, so ensure you safeguard
+     * against this.
      */
     @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
     public static final String ACTION_BATTERY_SAVER_SETTINGS
@@ -4738,8 +4738,8 @@
         public static final String SMS_DEFAULT_APPLICATION = "sms_default_application";
 
         /**
-         * Name of a package that the current user has explicitly allowed to see all of that
-         * user's notifications.
+         * Names of the packages that the current user has explicitly allowed to
+         * see all of the user's notifications, separated by ':'.
          *
          * @hide
          */
@@ -6629,7 +6629,8 @@
             WIFI_NUM_OPEN_NETWORKS_KEPT,
             EMERGENCY_TONE,
             CALL_AUTO_RETRY,
-            DOCK_AUDIO_MEDIA_ENABLED
+            DOCK_AUDIO_MEDIA_ENABLED,
+            LOW_POWER_MODE_TRIGGER_LEVEL
         };
 
         // Populated lazily, guarded by class object:
diff --git a/core/java/android/util/TypedValue.java b/core/java/android/util/TypedValue.java
index 931fb81..74d4245 100644
--- a/core/java/android/util/TypedValue.java
+++ b/core/java/android/util/TypedValue.java
@@ -139,6 +139,17 @@
     /* ------------------------------------------------------------ */
 
     /**
+     * {@link #TYPE_NULL} data indicating the value was not specified.
+     */
+    public static final int DATA_NULL_UNDEFINED = 0;
+    /**
+     * {@link #TYPE_NULL} data indicating the value was explicitly set to null.
+     */
+    public static final int DATA_NULL_EMPTY = 1;
+
+    /* ------------------------------------------------------------ */
+
+    /**
      * If {@link #density} is equal to this value, then the density should be
      * treated as the system's default density value: {@link DisplayMetrics#DENSITY_DEFAULT}.
      */
@@ -301,6 +312,18 @@
     }
 
     /**
+     * Return the complex unit type for this value. For example, a dimen type
+     * with value 12sp will return {@link #COMPLEX_UNIT_SP}. Only use for values
+     * whose type is {@link #TYPE_DIMENSION}.
+     *
+     * @return The complex unit type.
+     */
+     public int getComplexUnit()
+     {
+         return COMPLEX_UNIT_MASK & (data>>TypedValue.COMPLEX_UNIT_SHIFT);
+     }
+
+    /**
      * Converts an unpacked complex data value holding a dimension to its final floating 
      * point value. The two parameters <var>unit</var> and <var>value</var>
      * are as in {@link #TYPE_DIMENSION}.
diff --git a/core/java/android/view/IWindow.aidl b/core/java/android/view/IWindow.aidl
index 3e7aae0..9fc80fc 100644
--- a/core/java/android/view/IWindow.aidl
+++ b/core/java/android/view/IWindow.aidl
@@ -85,4 +85,9 @@
      * is done.
      */
     void doneAnimating();
+
+    /**
+     * Called for non-application windows when the enter animation has completed.
+     */
+    void dispatchWindowShown();
 }
diff --git a/core/java/android/view/ThreadedRenderer.java b/core/java/android/view/ThreadedRenderer.java
index 0711aed..00a8884 100644
--- a/core/java/android/view/ThreadedRenderer.java
+++ b/core/java/android/view/ThreadedRenderer.java
@@ -191,7 +191,8 @@
         final float lightX = width / 2.0f;
         mWidth = width;
         mHeight = height;
-        if (surfaceInsets != null && !surfaceInsets.isEmpty()) {
+        if (surfaceInsets != null && (surfaceInsets.left != 0 || surfaceInsets.right != 0
+                || surfaceInsets.top != 0 || surfaceInsets.bottom != 0)) {
             mHasInsets = true;
             mInsetLeft = surfaceInsets.left;
             mInsetTop = surfaceInsets.top;
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index e7b98ca..1d09696 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -3109,6 +3109,16 @@
     private MatchLabelForPredicate mMatchLabelForPredicate;
 
     /**
+     * Specifies a view before which this one is visited in accessibility traversal.
+     */
+    private int mAccessibilityTraversalBeforeId = NO_ID;
+
+    /**
+     * Specifies a view after which this one is visited in accessibility traversal.
+     */
+    private int mAccessibilityTraversalAfterId = NO_ID;
+
+    /**
      * Predicate for matching a view by its id.
      */
     private MatchIdPredicate mMatchIdPredicate;
@@ -3229,6 +3239,8 @@
          */
         private ArrayList<OnLayoutChangeListener> mOnLayoutChangeListeners;
 
+        protected OnScrollChangeListener mOnScrollChangeListener;
+
         /**
          * Listeners for attach events.
          */
@@ -3886,6 +3898,12 @@
                 case com.android.internal.R.styleable.View_contentDescription:
                     setContentDescription(a.getString(attr));
                     break;
+                case com.android.internal.R.styleable.View_accessibilityTraversalBefore:
+                    setAccessibilityTraversalBefore(a.getResourceId(attr, NO_ID));
+                    break;
+                case com.android.internal.R.styleable.View_accessibilityTraversalAfter:
+                    setAccessibilityTraversalAfter(a.getResourceId(attr, NO_ID));
+                    break;
                 case com.android.internal.R.styleable.View_labelFor:
                     setLabelFor(a.getResourceId(attr, NO_ID));
                     break;
@@ -4606,6 +4624,17 @@
     }
 
     /**
+     * Register a callback to be invoked when the scroll position of this view
+     * changed.
+     *
+     * @param l The callback that will run.
+     * @hide Only used internally.
+     */
+    public void setOnScrollChangeListener(OnScrollChangeListener l) {
+        getListenerInfo().mOnScrollChangeListener = l;
+    }
+
+    /**
      * Register a callback to be invoked when focus of this view changed.
      *
      * @param l The callback that will run.
@@ -5598,6 +5627,7 @@
             if (rootView == null) {
                 rootView = this;
             }
+
             View label = rootView.findLabelForView(this, mID);
             if (label != null) {
                 info.setLabeledBy(label);
@@ -5626,6 +5656,30 @@
             }
         }
 
+        if (mAccessibilityTraversalBeforeId != View.NO_ID) {
+            View rootView = getRootView();
+            if (rootView == null) {
+                rootView = this;
+            }
+            View next = rootView.findViewInsideOutShouldExist(this,
+                    mAccessibilityTraversalBeforeId);
+            if (next != null) {
+                info.setTraversalBefore(next);
+            }
+        }
+
+        if (mAccessibilityTraversalAfterId != View.NO_ID) {
+            View rootView = getRootView();
+            if (rootView == null) {
+                rootView = this;
+            }
+            View next = rootView.findViewInsideOutShouldExist(this,
+                    mAccessibilityTraversalAfterId);
+            if (next != null) {
+                info.setTraversalAfter(next);
+            }
+        }
+
         info.setVisibleToUser(isVisibleToUser());
 
         info.setPackageName(mContext.getPackageName());
@@ -6030,6 +6084,94 @@
     }
 
     /**
+     * Sets the id of a view before which this one is visited in accessibility traversal.
+     * A screen-reader must visit the content of this view before the content of the one
+     * it precedes. For example, if view B is set to be before view A, then a screen-reader
+     * will traverse the entire content of B before traversing the entire content of A,
+     * regardles of what traversal strategy it is using.
+     * <p>
+     * Views that do not have specified before/after relationships are traversed in order
+     * determined by the screen-reader.
+     * </p>
+     * <p>
+     * Setting that this view is before a view that is not important for accessibility
+     * or if this view is not important for accessibility will have no effect as the
+     * screen-reader is not aware of unimportant views.
+     * </p>
+     *
+     * @param beforeId The id of a view this one precedes in accessibility traversal.
+     *
+     * @attr ref android.R.styleable#View_accessibilityTraversalBefore
+     *
+     * @see #setImportantForAccessibility(int)
+     */
+    @RemotableViewMethod
+    public void setAccessibilityTraversalBefore(int beforeId) {
+        if (mAccessibilityTraversalBeforeId == beforeId) {
+            return;
+        }
+        mAccessibilityTraversalBeforeId = beforeId;
+        notifyViewAccessibilityStateChangedIfNeeded(
+                AccessibilityEvent.CONTENT_CHANGE_TYPE_UNDEFINED);
+    }
+
+    /**
+     * Gets the id of a view before which this one is visited in accessibility traversal.
+     *
+     * @return The id of a view this one precedes in accessibility traversal if
+     *         specified, otherwise {@link #NO_ID}.
+     *
+     * @see #setAccessibilityTraversalBefore(int)
+     */
+    public int getAccessibilityTraversalBefore() {
+        return mAccessibilityTraversalBeforeId;
+    }
+
+    /**
+     * Sets the id of a view after which this one is visited in accessibility traversal.
+     * A screen-reader must visit the content of the other view before the content of this
+     * one. For example, if view B is set to be after view A, then a screen-reader
+     * will traverse the entire content of A before traversing the entire content of B,
+     * regardles of what traversal strategy it is using.
+     * <p>
+     * Views that do not have specified before/after relationships are traversed in order
+     * determined by the screen-reader.
+     * </p>
+     * <p>
+     * Setting that this view is after a view that is not important for accessibility
+     * or if this view is not important for accessibility will have no effect as the
+     * screen-reader is not aware of unimportant views.
+     * </p>
+     *
+     * @param afterId The id of a view this one succedees in accessibility traversal.
+     *
+     * @attr ref android.R.styleable#View_accessibilityTraversalAfter
+     *
+     * @see #setImportantForAccessibility(int)
+     */
+    @RemotableViewMethod
+    public void setAccessibilityTraversalAfter(int afterId) {
+        if (mAccessibilityTraversalAfterId == afterId) {
+            return;
+        }
+        mAccessibilityTraversalAfterId = afterId;
+        notifyViewAccessibilityStateChangedIfNeeded(
+                AccessibilityEvent.CONTENT_CHANGE_TYPE_UNDEFINED);
+    }
+
+    /**
+     * Gets the id of a view after which this one is visited in accessibility traversal.
+     *
+     * @return The id of a view this one succeedes in accessibility traversal if
+     *         specified, otherwise {@link #NO_ID}.
+     *
+     * @see #setAccessibilityTraversalAfter(int)
+     */
+    public int getAccessibilityTraversalAfter() {
+        return mAccessibilityTraversalAfterId;
+    }
+
+    /**
      * Gets the id of a view for which this view serves as a label for
      * accessibility purposes.
      *
@@ -6048,11 +6190,16 @@
      */
     @RemotableViewMethod
     public void setLabelFor(int id) {
+        if (mLabelForId == id) {
+            return;
+        }
         mLabelForId = id;
         if (mLabelForId != View.NO_ID
                 && mID == View.NO_ID) {
             mID = generateViewId();
         }
+        notifyViewAccessibilityStateChangedIfNeeded(
+                AccessibilityEvent.CONTENT_CHANGE_TYPE_UNDEFINED);
     }
 
     /**
@@ -9794,6 +9941,29 @@
         if (ai != null) {
             ai.mViewScrollChanged = true;
         }
+
+        if (mListenerInfo != null && mListenerInfo.mOnScrollChangeListener != null) {
+            mListenerInfo.mOnScrollChangeListener.onScrollChange(this, l, t, oldl, oldt);
+        }
+    }
+
+    /**
+     * Interface definition for a callback to be invoked when the scroll
+     * position of a view changes.
+     *
+     * @hide Only used internally.
+     */
+    public interface OnScrollChangeListener {
+        /**
+         * Called when the scroll position of a view changes.
+         *
+         * @param v The view whose scroll position has changed.
+         * @param scrollX Current horizontal scroll origin.
+         * @param scrollY Current vertical scroll origin.
+         * @param oldScrollX Previous horizontal scroll origin.
+         * @param oldScrollY Previous vertical scroll origin.
+         */
+        void onScrollChange(View v, int scrollX, int scrollY, int oldScrollX, int oldScrollY);
     }
 
     /**
@@ -14062,7 +14232,6 @@
                     } else {
                         draw(canvas);
                     }
-                    drawAccessibilityFocus(canvas);
                 }
             } finally {
                 renderNode.end(canvas);
@@ -14357,7 +14526,6 @@
             } else {
                 draw(canvas);
             }
-            drawAccessibilityFocus(canvas);
 
             canvas.restoreToCount(restoreCount);
             canvas.setBitmap(null);
@@ -14432,7 +14600,6 @@
         } else {
             draw(canvas);
         }
-        drawAccessibilityFocus(canvas);
 
         mPrivateFlags = flags;
 
@@ -15030,13 +15197,9 @@
                     if ((mPrivateFlags & PFLAG_SKIP_DRAW) == PFLAG_SKIP_DRAW) {
                         mPrivateFlags &= ~PFLAG_DIRTY_MASK;
                         dispatchDraw(canvas);
-                        if (mOverlay != null && !mOverlay.isEmpty()) {
-                            mOverlay.getOverlayView().draw(canvas);
-                        }
                     } else {
                         draw(canvas);
                     }
-                    drawAccessibilityFocus(canvas);
                 } else {
                     mPrivateFlags &= ~PFLAG_DIRTY_MASK;
                     ((HardwareCanvas) canvas).drawRenderNode(renderNode, null, flags);
@@ -15288,50 +15451,6 @@
     }
 
     /**
-     * Draws the accessibility focus rect onto the specified canvas.
-     *
-     * @param canvas Canvas on which to draw the focus rect
-     */
-    private void drawAccessibilityFocus(Canvas canvas) {
-        if (mAttachInfo == null) {
-            return;
-        }
-
-        final Rect bounds = mAttachInfo.mTmpInvalRect;
-        final ViewRootImpl viewRoot = getViewRootImpl();
-        if (viewRoot == null || viewRoot.getAccessibilityFocusedHost() != this) {
-            return;
-        }
-
-        final AccessibilityManager manager = AccessibilityManager.getInstance(mContext);
-        if (!manager.isEnabled() || !manager.isTouchExplorationEnabled()) {
-            return;
-        }
-
-        final Drawable drawable = viewRoot.getAccessibilityFocusedDrawable();
-        if (drawable == null) {
-            return;
-        }
-
-        final AccessibilityNodeInfo virtualView = viewRoot.getAccessibilityFocusedVirtualView();
-        if (virtualView != null) {
-            virtualView.getBoundsInScreen(bounds);
-            final int[] offset = mAttachInfo.mTmpLocation;
-            getLocationOnScreen(offset);
-            bounds.offset(-offset[0], -offset[1]);
-        } else {
-            bounds.set(0, 0, mRight - mLeft, mBottom - mTop);
-        }
-
-        canvas.save();
-        canvas.translate(mScrollX, mScrollY);
-        canvas.clipRect(bounds, Region.Op.REPLACE);
-        drawable.setBounds(bounds);
-        drawable.draw(canvas);
-        canvas.restore();
-    }
-
-    /**
      * Draws the background onto the specified canvas.
      *
      * @param canvas Canvas on which to draw the background
@@ -16353,6 +16472,12 @@
                 if (tintInfo.mHasTintMode) {
                     mBackground.setTintMode(tintInfo.mTintMode);
                 }
+
+                // The drawable (or one of its children) may not have been
+                // stateful before applying the tint, so let's try again.
+                if (mBackground.isStateful()) {
+                    mBackground.setState(getDrawableState());
+                }
             }
         }
     }
diff --git a/core/java/android/view/ViewGroup.java b/core/java/android/view/ViewGroup.java
index 7c7e3e7..654a8ed 100644
--- a/core/java/android/view/ViewGroup.java
+++ b/core/java/android/view/ViewGroup.java
@@ -4250,9 +4250,7 @@
             clearChildFocus = true;
         }
 
-        if (view.isAccessibilityFocused()) {
-            view.clearAccessibilityFocus();
-        }
+        view.clearAccessibilityFocus();
 
         cancelTouchTarget(view);
         cancelHoverTarget(view);
@@ -4345,9 +4343,7 @@
                 clearChildFocus = true;
             }
 
-            if (view.isAccessibilityFocused()) {
-                view.clearAccessibilityFocus();
-            }
+            view.clearAccessibilityFocus();
 
             cancelTouchTarget(view);
             cancelHoverTarget(view);
@@ -4432,9 +4428,7 @@
                 clearChildFocus = true;
             }
 
-            if (view.isAccessibilityFocused()) {
-                view.clearAccessibilityFocus();
-            }
+            view.clearAccessibilityFocus();
 
             cancelTouchTarget(view);
             cancelHoverTarget(view);
diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java
index 81fc966..f0d5252 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -727,7 +727,10 @@
                     mAttachInfo.mHardwareRenderer.destroy();
                 }
 
-                final boolean translucent = attrs.format != PixelFormat.OPAQUE;
+                final Rect insets = attrs.surfaceInsets;
+                final boolean hasSurfaceInsets = insets.left == 0 || insets.right == 0
+                        || insets.top == 0 || insets.bottom == 0;
+                final boolean translucent = attrs.format != PixelFormat.OPAQUE || hasSurfaceInsets;
                 mAttachInfo.mHardwareRenderer = HardwareRenderer.create(mContext, translucent);
                 if (mAttachInfo.mHardwareRenderer != null) {
                     mAttachInfo.mHardwareRenderer.setName(attrs.getTitle().toString());
@@ -2255,6 +2258,7 @@
             canvas.drawHardwareLayer(mResizeBuffer, mHardwareXOffset, mHardwareYOffset,
                     mResizePaint);
         }
+        drawAccessibilityFocusedDrawableIfNeeded(canvas);
     }
 
     /**
@@ -2474,18 +2478,38 @@
             dirty.offset(surfaceInsets.left, surfaceInsets.right);
         }
 
-        if (!dirty.isEmpty() || mIsAnimating) {
+        boolean accessibilityFocusDirty = false;
+        final Drawable drawable = mAttachInfo.mAccessibilityFocusDrawable;
+        if (drawable != null) {
+            final Rect bounds = mAttachInfo.mTmpInvalRect;
+            final boolean hasFocus = getAccessibilityFocusedRect(bounds);
+            if (!hasFocus) {
+                bounds.setEmpty();
+            }
+            if (!bounds.equals(drawable.getBounds())) {
+                accessibilityFocusDirty = true;
+            }
+        }
+
+        if (!dirty.isEmpty() || mIsAnimating || accessibilityFocusDirty) {
             if (mAttachInfo.mHardwareRenderer != null && mAttachInfo.mHardwareRenderer.isEnabled()) {
+                // If accessibility focus moved, always invalidate the root.
+                boolean invalidateRoot = accessibilityFocusDirty;
+
                 // Draw with hardware renderer.
                 mIsAnimating = false;
-                boolean invalidateRoot = false;
+
                 if (mHardwareYOffset != yOffset || mHardwareXOffset != xOffset) {
                     mHardwareYOffset = yOffset;
                     mHardwareXOffset = xOffset;
-                    mAttachInfo.mHardwareRenderer.invalidateRoot();
+                    invalidateRoot = true;
                 }
                 mResizeAlpha = resizeAlpha;
 
+                if (invalidateRoot) {
+                    mAttachInfo.mHardwareRenderer.invalidateRoot();
+                }
+
                 dirty.setEmpty();
 
                 mBlockResizeBuffer = false;
@@ -2604,6 +2628,8 @@
                 attachInfo.mSetIgnoreDirtyState = false;
 
                 mView.draw(canvas);
+
+                drawAccessibilityFocusedDrawableIfNeeded(canvas);
             } finally {
                 if (!attachInfo.mSetIgnoreDirtyState) {
                     // Only clear the flag if it was not set during the mView.draw() call
@@ -2627,7 +2653,56 @@
         return true;
     }
 
-    Drawable getAccessibilityFocusedDrawable() {
+    /**
+     * We want to draw a highlight around the current accessibility focused.
+     * Since adding a style for all possible view is not a viable option we
+     * have this specialized drawing method.
+     *
+     * Note: We are doing this here to be able to draw the highlight for
+     *       virtual views in addition to real ones.
+     *
+     * @param canvas The canvas on which to draw.
+     */
+    private void drawAccessibilityFocusedDrawableIfNeeded(Canvas canvas) {
+        final Rect bounds = mAttachInfo.mTmpInvalRect;
+        if (getAccessibilityFocusedRect(bounds)) {
+            final Drawable drawable = getAccessibilityFocusedDrawable();
+            if (drawable != null) {
+                drawable.setBounds(bounds);
+                drawable.draw(canvas);
+            }
+        } else if (mAttachInfo.mAccessibilityFocusDrawable != null) {
+            mAttachInfo.mAccessibilityFocusDrawable.setBounds(0, 0, 0, 0);
+        }
+    }
+
+    private boolean getAccessibilityFocusedRect(Rect bounds) {
+        final AccessibilityManager manager = AccessibilityManager.getInstance(mView.mContext);
+        if (!manager.isEnabled() || !manager.isTouchExplorationEnabled()) {
+            return false;
+        }
+
+        final View host = mAccessibilityFocusedHost;
+        if (host == null || host.mAttachInfo == null) {
+            return false;
+        }
+
+        final AccessibilityNodeProvider provider = host.getAccessibilityNodeProvider();
+        if (provider == null) {
+            host.getBoundsOnScreen(bounds);
+        } else if (mAccessibilityFocusedVirtualView != null) {
+            mAccessibilityFocusedVirtualView.getBoundsInScreen(bounds);
+        } else {
+            return false;
+        }
+
+        final AttachInfo attachInfo = mAttachInfo;
+        bounds.offset(-attachInfo.mWindowLeft, -attachInfo.mWindowTop);
+        bounds.intersect(0, 0, attachInfo.mViewRootImpl.mWidth, attachInfo.mViewRootImpl.mHeight);
+        return !bounds.isEmpty();
+    }
+
+    private Drawable getAccessibilityFocusedDrawable() {
         // Lazily load the accessibility focus drawable.
         if (mAttachInfo.mAccessibilityFocusDrawable == null) {
             final TypedValue value = new TypedValue();
@@ -3014,6 +3089,7 @@
     private final static int MSG_INVALIDATE_WORLD = 23;
     private final static int MSG_WINDOW_MOVED = 24;
     private final static int MSG_SYNTHESIZE_INPUT_EVENT = 25;
+    private final static int MSG_DISPATCH_WINDOW_SHOWN = 26;
 
     final class ViewRootHandler extends Handler {
         @Override
@@ -3063,6 +3139,8 @@
                     return "MSG_WINDOW_MOVED";
                 case MSG_SYNTHESIZE_INPUT_EVENT:
                     return "MSG_SYNTHESIZE_INPUT_EVENT";
+                case MSG_DISPATCH_WINDOW_SHOWN:
+                    return "MSG_DISPATCH_WINDOW_SHOWN";
             }
             return super.getMessageName(message);
         }
@@ -3291,6 +3369,9 @@
                     invalidateWorld(mView);
                 }
             } break;
+            case MSG_DISPATCH_WINDOW_SHOWN: {
+                handleDispatchWindowShown();
+            }
             }
         }
     }
@@ -5137,6 +5218,10 @@
         }
     }
 
+    public void handleDispatchWindowShown() {
+        mAttachInfo.mTreeObserver.dispatchOnWindowShown();
+    }
+
     public void getLastTouchPoint(Point outLocation) {
         outLocation.x = (int) mLastTouchPoint.x;
         outLocation.y = (int) mLastTouchPoint.y;
@@ -5997,6 +6082,10 @@
         mHandler.sendMessage(msg);
     }
 
+    public void dispatchWindowShown() {
+        mHandler.sendEmptyMessage(MSG_DISPATCH_WINDOW_SHOWN);
+    }
+
     public void dispatchCloseSystemDialogs(String reason) {
         Message msg = Message.obtain();
         msg.what = MSG_CLOSE_SYSTEM_DIALOGS;
@@ -6507,6 +6596,14 @@
                 viewAncestor.dispatchDoneAnimating();
             }
         }
+
+        @Override
+        public void dispatchWindowShown() {
+            final ViewRootImpl viewAncestor = mViewAncestor.get();
+            if (viewAncestor != null) {
+                viewAncestor.dispatchWindowShown();
+            }
+        }
     }
 
     public static final class CalledFromWrongThreadException extends AndroidRuntimeException {
diff --git a/core/java/android/view/ViewTreeObserver.java b/core/java/android/view/ViewTreeObserver.java
index a9444b4..b85fec8 100644
--- a/core/java/android/view/ViewTreeObserver.java
+++ b/core/java/android/view/ViewTreeObserver.java
@@ -44,10 +44,15 @@
     private CopyOnWriteArray<OnComputeInternalInsetsListener> mOnComputeInternalInsetsListeners;
     private CopyOnWriteArray<OnScrollChangedListener> mOnScrollChangedListeners;
     private CopyOnWriteArray<OnPreDrawListener> mOnPreDrawListeners;
+    private CopyOnWriteArray<OnWindowShownListener> mOnWindowShownListeners;
 
     // These listeners cannot be mutated during dispatch
     private ArrayList<OnDrawListener> mOnDrawListeners;
 
+    /** Remains false until #dispatchOnWindowShown() is called. If a listener registers after
+     * that the listener will be immediately called. */
+    private boolean mWindowShown;
+
     private boolean mAlive = true;
 
     /**
@@ -174,6 +179,19 @@
     }
 
     /**
+     * Interface definition for a callback noting when a system window has been displayed.
+     * This is only used for non-Activity windows. Activity windows can use
+     * Activity.onEnterAnimationComplete() to get the same signal.
+     * @hide
+     */
+    public interface OnWindowShownListener {
+        /**
+         * Callback method to be invoked when a non-activity window is fully shown.
+         */
+        void onWindowShown();
+    }
+
+    /**
      * Parameters used with OnComputeInternalInsetsListener.
      * 
      * We are not yet ready to commit to this API and support it, so
@@ -375,6 +393,14 @@
             }
         }
 
+        if (observer.mOnWindowShownListeners != null) {
+            if (mOnWindowShownListeners != null) {
+                mOnWindowShownListeners.addAll(observer.mOnWindowShownListeners);
+            } else {
+                mOnWindowShownListeners = observer.mOnWindowShownListeners;
+            }
+        }
+
         observer.kill();
     }
 
@@ -568,6 +594,45 @@
     }
 
     /**
+     * Register a callback to be invoked when the view tree window has been shown
+     *
+     * @param listener The callback to add
+     *
+     * @throws IllegalStateException If {@link #isAlive()} returns false
+     * @hide
+     */
+    public void addOnWindowShownListener(OnWindowShownListener listener) {
+        checkIsAlive();
+
+        if (mOnWindowShownListeners == null) {
+            mOnWindowShownListeners = new CopyOnWriteArray<OnWindowShownListener>();
+        }
+
+        mOnWindowShownListeners.add(listener);
+        if (mWindowShown) {
+            listener.onWindowShown();
+        }
+    }
+
+    /**
+     * Remove a previously installed window shown callback
+     *
+     * @param victim The callback to remove
+     *
+     * @throws IllegalStateException If {@link #isAlive()} returns false
+     *
+     * @see #addOnWindowShownListener(OnWindowShownListener)
+     * @hide
+     */
+    public void removeOnWindowShownListener(OnWindowShownListener victim) {
+        checkIsAlive();
+        if (mOnWindowShownListeners == null) {
+            return;
+        }
+        mOnWindowShownListeners.remove(victim);
+    }
+
+    /**
      * <p>Register a callback to be invoked when the view tree is about to be drawn.</p>
      * <p><strong>Note:</strong> this method <strong>cannot</strong> be invoked from
      * {@link android.view.ViewTreeObserver.OnDrawListener#onDraw()}.</p>
@@ -854,6 +919,27 @@
     }
 
     /**
+     * Notifies registered listeners that the window is now shown
+     * @hide
+     */
+    @SuppressWarnings("unchecked")
+    public final void dispatchOnWindowShown() {
+        mWindowShown = true;
+        final CopyOnWriteArray<OnWindowShownListener> listeners = mOnWindowShownListeners;
+        if (listeners != null && listeners.size() > 0) {
+            CopyOnWriteArray.Access<OnWindowShownListener> access = listeners.start();
+            try {
+                int count = access.size();
+                for (int i = 0; i < count; i++) {
+                    access.get(i).onWindowShown();
+                }
+            } finally {
+                listeners.end();
+            }
+        }
+    }
+
+    /**
      * Notifies registered listeners that the drawing pass is about to start.
      */
     public final void dispatchOnDraw() {
diff --git a/core/java/android/view/Window.java b/core/java/android/view/Window.java
index 20edeb8..0076abf 100644
--- a/core/java/android/view/Window.java
+++ b/core/java/android/view/Window.java
@@ -1074,17 +1074,36 @@
     public abstract void onConfigurationChanged(Configuration newConfig);
 
     /**
+     * Sets the window elevation.
+     *
+     * @param elevation The window elevation.
+     * @see View#setElevation(float)
+     * @see android.R.styleable#Window_windowElevation
+     */
+    public void setElevation(float elevation) {}
+
+    /**
+     * Sets whether window content should be clipped to the outline of the
+     * window background.
+     *
+     * @param clipToOutline Whether window content should be clipped to the
+     *                      outline of the window background.
+     * @see View#setClipToOutline(boolean)
+     * @see android.R.styleable#Window_windowClipToOutline
+     */
+    public void setClipToOutline(boolean clipToOutline) {}
+
+    /**
      * Change the background of this window to a Drawable resource. Setting the
      * background to null will make the window be opaque. To make the window
      * transparent, you can use an empty drawable (for instance a ColorDrawable
      * with the color 0 or the system drawable android:drawable/empty.)
      *
-     * @param resid The resource identifier of a drawable resource which will be
-     *              installed as the new background.
+     * @param resId The resource identifier of a drawable resource which will
+     *              be installed as the new background.
      */
-    public void setBackgroundDrawableResource(int resid)
-    {
-        setBackgroundDrawable(mContext.getDrawable(resid));
+    public void setBackgroundDrawableResource(int resId) {
+        setBackgroundDrawable(mContext.getDrawable(resId));
     }
 
     /**
diff --git a/core/java/android/view/WindowManager.java b/core/java/android/view/WindowManager.java
index 5b48c0d..f4f047e 100644
--- a/core/java/android/view/WindowManager.java
+++ b/core/java/android/view/WindowManager.java
@@ -1324,7 +1324,7 @@
          *
          * @hide
          */
-        public Rect surfaceInsets = new Rect();
+        public final Rect surfaceInsets = new Rect();
     
         /**
          * The desired bitmap format.  May be one of the constants in
diff --git a/core/java/android/view/accessibility/AccessibilityNodeInfo.java b/core/java/android/view/accessibility/AccessibilityNodeInfo.java
index 3987fbc..b5afdf7 100644
--- a/core/java/android/view/accessibility/AccessibilityNodeInfo.java
+++ b/core/java/android/view/accessibility/AccessibilityNodeInfo.java
@@ -547,6 +547,8 @@
     private long mParentNodeId = ROOT_NODE_ID;
     private long mLabelForId = ROOT_NODE_ID;
     private long mLabeledById = ROOT_NODE_ID;
+    private long mTraversalBefore = ROOT_NODE_ID;
+    private long mTraversalAfter = ROOT_NODE_ID;
 
     private int mBooleanProperties;
     private final Rect mBoundsInParent = new Rect();
@@ -1046,6 +1048,126 @@
     }
 
     /**
+     * Gets the node before which this one is visited during traversal. A screen-reader
+     * must visit the content of this node before the content of the one it precedes.
+     *
+     * @return The succeeding node if such or <code>null</code>.
+     *
+     * @see #setTraversalBefore(android.view.View)
+     * @see #setTraversalBefore(android.view.View, int)
+     */
+    public AccessibilityNodeInfo getTraversalBefore() {
+        enforceSealed();
+        return getNodeForAccessibilityId(mTraversalBefore);
+    }
+
+    /**
+     * Sets the view before whose node this one should be visited during traversal. A
+     * screen-reader must visit the content of this node before the content of the one
+     * it precedes.
+     * <p>
+     *   <strong>Note:</strong> Cannot be called from an
+     *   {@link android.accessibilityservice.AccessibilityService}.
+     *   This class is made immutable before being delivered to an AccessibilityService.
+     * </p>
+     *
+     * @param view The view providing the preceding node.
+     *
+     * @see #getTraversalBefore()
+     */
+    public void setTraversalBefore(View view) {
+        setTraversalBefore(view, UNDEFINED_ITEM_ID);
+    }
+
+    /**
+     * Sets the node before which this one is visited during traversal. A screen-reader
+     * must visit the content of this node before the content of the one it precedes.
+     * The successor is a virtual descendant of the given <code>root</code>. If
+     * <code>virtualDescendantId</code> equals to {@link View#NO_ID} the root is set
+     * as the successor.
+     * <p>
+     * A virtual descendant is an imaginary View that is reported as a part of the view
+     * hierarchy for accessibility purposes. This enables custom views that draw complex
+     * content to report them selves as a tree of virtual views, thus conveying their
+     * logical structure.
+     * </p>
+     * <p>
+     *   <strong>Note:</strong> Cannot be called from an
+     *   {@link android.accessibilityservice.AccessibilityService}.
+     *   This class is made immutable before being delivered to an AccessibilityService.
+     * </p>
+     *
+     * @param root The root of the virtual subtree.
+     * @param virtualDescendantId The id of the virtual descendant.
+     */
+    public void setTraversalBefore(View root, int virtualDescendantId) {
+        enforceNotSealed();
+        final int rootAccessibilityViewId = (root != null)
+                ? root.getAccessibilityViewId() : UNDEFINED_ITEM_ID;
+        mTraversalBefore = makeNodeId(rootAccessibilityViewId, virtualDescendantId);
+    }
+
+    /**
+     * Gets the node after which this one is visited in accessibility traversal.
+     * A screen-reader must visit the content of the other node before the content
+     * of this one.
+     *
+     * @return The succeeding node if such or <code>null</code>.
+     *
+     * @see #setTraversalAfter(android.view.View)
+     * @see #setTraversalAfter(android.view.View, int)
+     */
+    public AccessibilityNodeInfo getTraversalAfter() {
+        enforceSealed();
+        return getNodeForAccessibilityId(mTraversalAfter);
+    }
+
+    /**
+     * Sets the view whose node is visited after this one in accessibility traversal.
+     * A screen-reader must visit the content of the other node before the content
+     * of this one.
+     * <p>
+     *   <strong>Note:</strong> Cannot be called from an
+     *   {@link android.accessibilityservice.AccessibilityService}.
+     *   This class is made immutable before being delivered to an AccessibilityService.
+     * </p>
+     *
+     * @param view The previous view.
+     *
+     * @see #getTraversalAfter()
+     */
+    public void setTraversalAfter(View view) {
+        setTraversalAfter(view, UNDEFINED_ITEM_ID);
+    }
+
+    /**
+     * Sets the node after which this one is visited in accessibility traversal.
+     * A screen-reader must visit the content of the other node before the content
+     * of this one. If <code>virtualDescendantId</code> equals to {@link View#NO_ID}
+     * the root is set as the predecessor.
+     * <p>
+     * A virtual descendant is an imaginary View that is reported as a part of the view
+     * hierarchy for accessibility purposes. This enables custom views that draw complex
+     * content to report them selves as a tree of virtual views, thus conveying their
+     * logical structure.
+     * </p>
+     * <p>
+     *   <strong>Note:</strong> Cannot be called from an
+     *   {@link android.accessibilityservice.AccessibilityService}.
+     *   This class is made immutable before being delivered to an AccessibilityService.
+     * </p>
+     *
+     * @param root The root of the virtual subtree.
+     * @param virtualDescendantId The id of the virtual descendant.
+     */
+    public void setTraversalAfter(View root, int virtualDescendantId) {
+        enforceNotSealed();
+        final int rootAccessibilityViewId = (root != null)
+                ? root.getAccessibilityViewId() : UNDEFINED_ITEM_ID;
+        mTraversalAfter = makeNodeId(rootAccessibilityViewId, virtualDescendantId);
+    }
+
+    /**
      * Sets the maximum text length, or -1 for no limit.
      * <p>
      * Typically used to indicate that an editable text field has a limit on
@@ -1229,13 +1351,7 @@
      */
     public AccessibilityNodeInfo getParent() {
         enforceSealed();
-        if (!canPerformRequestOverConnection(mParentNodeId)) {
-            return null;
-        }
-        AccessibilityInteractionClient client = AccessibilityInteractionClient.getInstance();
-        return client.findAccessibilityNodeInfoByAccessibilityId(mConnectionId,
-                mWindowId, mParentNodeId, false, FLAG_PREFETCH_PREDECESSORS
-                        | FLAG_PREFETCH_DESCENDANTS | FLAG_PREFETCH_SIBLINGS);
+        return getNodeForAccessibilityId(mParentNodeId);
     }
 
     /**
@@ -2055,13 +2171,7 @@
      */
     public AccessibilityNodeInfo getLabelFor() {
         enforceSealed();
-        if (!canPerformRequestOverConnection(mLabelForId)) {
-            return null;
-        }
-        AccessibilityInteractionClient client = AccessibilityInteractionClient.getInstance();
-        return client.findAccessibilityNodeInfoByAccessibilityId(mConnectionId,
-                mWindowId, mLabelForId, false, FLAG_PREFETCH_PREDECESSORS
-                        | FLAG_PREFETCH_DESCENDANTS | FLAG_PREFETCH_SIBLINGS);
+        return getNodeForAccessibilityId(mLabelForId);
     }
 
     /**
@@ -2113,13 +2223,7 @@
      */
     public AccessibilityNodeInfo getLabeledBy() {
         enforceSealed();
-        if (!canPerformRequestOverConnection(mLabeledById)) {
-            return null;
-        }
-        AccessibilityInteractionClient client = AccessibilityInteractionClient.getInstance();
-        return client.findAccessibilityNodeInfoByAccessibilityId(mConnectionId,
-                mWindowId, mLabeledById, false, FLAG_PREFETCH_PREDECESSORS
-                        | FLAG_PREFETCH_DESCENDANTS | FLAG_PREFETCH_SIBLINGS);
+        return getNodeForAccessibilityId(mLabeledById);
     }
 
     /**
@@ -2453,6 +2557,9 @@
         parcel.writeLong(mParentNodeId);
         parcel.writeLong(mLabelForId);
         parcel.writeLong(mLabeledById);
+        parcel.writeLong(mTraversalBefore);
+        parcel.writeLong(mTraversalAfter);
+
         parcel.writeInt(mConnectionId);
 
         final LongArray childIds = mChildNodeIds;
@@ -2571,6 +2678,8 @@
         mParentNodeId = other.mParentNodeId;
         mLabelForId = other.mLabelForId;
         mLabeledById = other.mLabeledById;
+        mTraversalBefore = other.mTraversalBefore;
+        mTraversalAfter = other.mTraversalAfter;
         mWindowId = other.mWindowId;
         mConnectionId = other.mConnectionId;
         mBoundsInParent.set(other.mBoundsInParent);
@@ -2633,6 +2742,9 @@
         mParentNodeId = parcel.readLong();
         mLabelForId = parcel.readLong();
         mLabeledById = parcel.readLong();
+        mTraversalBefore = parcel.readLong();
+        mTraversalAfter = parcel.readLong();
+
         mConnectionId = parcel.readInt();
 
         final int childrenSize = parcel.readInt();
@@ -2725,6 +2837,8 @@
         mParentNodeId = ROOT_NODE_ID;
         mLabelForId = ROOT_NODE_ID;
         mLabeledById = ROOT_NODE_ID;
+        mTraversalBefore = ROOT_NODE_ID;
+        mTraversalAfter = ROOT_NODE_ID;
         mWindowId = UNDEFINED_ITEM_ID;
         mConnectionId = UNDEFINED_CONNECTION_ID;
         mMaxTextLength = -1;
@@ -2911,6 +3025,8 @@
             builder.append("; accessibilityViewId: " + getAccessibilityViewId(mSourceNodeId));
             builder.append("; virtualDescendantId: " + getVirtualDescendantId(mSourceNodeId));
             builder.append("; mParentNodeId: " + mParentNodeId);
+            builder.append("; traversalBefore: ").append(mTraversalBefore);
+            builder.append("; traversalAfter: ").append(mTraversalAfter);
 
             int granularities = mMovementGranularities;
             builder.append("; MovementGranularities: [");
@@ -2963,6 +3079,16 @@
         return builder.toString();
     }
 
+    private AccessibilityNodeInfo getNodeForAccessibilityId(long accessibilityId) {
+        if (!canPerformRequestOverConnection(accessibilityId)) {
+            return null;
+        }
+        AccessibilityInteractionClient client = AccessibilityInteractionClient.getInstance();
+        return client.findAccessibilityNodeInfoByAccessibilityId(mConnectionId,
+                mWindowId, accessibilityId, false, FLAG_PREFETCH_PREDECESSORS
+                        | FLAG_PREFETCH_DESCENDANTS | FLAG_PREFETCH_SIBLINGS);
+    }
+
     /**
      * A class defining an action that can be performed on an {@link AccessibilityNodeInfo}.
      * Each action has a unique id that is mandatory and optional data.
diff --git a/core/java/android/widget/AbsListView.java b/core/java/android/widget/AbsListView.java
index 4aebaae..6927660 100644
--- a/core/java/android/widget/AbsListView.java
+++ b/core/java/android/widget/AbsListView.java
@@ -2663,7 +2663,7 @@
      * @return True if the selector should be shown
      */
     boolean shouldShowSelector() {
-        return (!isInTouchMode()) || (touchModeDrawsInPressedState() && isPressed());
+        return (isFocused() && !isInTouchMode()) || (touchModeDrawsInPressedState() && isPressed());
     }
 
     private void drawSelector(Canvas canvas) {
@@ -4910,9 +4910,7 @@
                     if (position >= headerViewsCount && position < footerViewsStart) {
                         // The view will be rebound to new data, clear any
                         // system-managed transient state.
-                        if (child.isAccessibilityFocused()) {
-                            child.clearAccessibilityFocus();
-                        }
+                        child.clearAccessibilityFocus();
                         mRecycler.addScrapView(child, position);
                     }
                 }
@@ -4933,9 +4931,7 @@
                     if (position >= headerViewsCount && position < footerViewsStart) {
                         // The view will be rebound to new data, clear any
                         // system-managed transient state.
-                        if (child.isAccessibilityFocused()) {
-                            child.clearAccessibilityFocus();
-                        }
+                        child.clearAccessibilityFocus();
                         mRecycler.addScrapView(child, position);
                     }
                 }
@@ -6776,9 +6772,7 @@
         }
 
         private void clearAccessibilityFromScrap(View view) {
-            if (view.isAccessibilityFocused()) {
-                view.clearAccessibilityFocus();
-            }
+            view.clearAccessibilityFocus();
             view.setAccessibilityDelegate(null);
         }
 
diff --git a/core/java/android/widget/AbsSeekBar.java b/core/java/android/widget/AbsSeekBar.java
index b2cfdf7..d39960f 100644
--- a/core/java/android/widget/AbsSeekBar.java
+++ b/core/java/android/widget/AbsSeekBar.java
@@ -267,6 +267,12 @@
             if (mHasThumbTintMode) {
                 mThumb.setTintMode(mThumbTintMode);
             }
+
+            // The drawable (or one of its children) may not have been
+            // stateful before applying the tint, so let's try again.
+            if (mThumb.isStateful()) {
+                mThumb.setState(getDrawableState());
+            }
         }
     }
 
diff --git a/core/java/android/widget/ActionMenuView.java b/core/java/android/widget/ActionMenuView.java
index 7198e52..0a8a01f 100644
--- a/core/java/android/widget/ActionMenuView.java
+++ b/core/java/android/widget/ActionMenuView.java
@@ -429,7 +429,7 @@
         }
 
         final int childCount = getChildCount();
-        final int midVertical = (top + bottom) / 2;
+        final int midVertical = (bottom - top) / 2;
         final int dividerWidth = getDividerWidth();
         int overflowWidth = 0;
         int nonOverflowWidth = 0;
diff --git a/core/java/android/widget/CheckedTextView.java b/core/java/android/widget/CheckedTextView.java
index eb8e8aa..69969a9 100644
--- a/core/java/android/widget/CheckedTextView.java
+++ b/core/java/android/widget/CheckedTextView.java
@@ -267,6 +267,12 @@
             if (mHasCheckMarkTintMode) {
                 mCheckMarkDrawable.setTintMode(mCheckMarkTintMode);
             }
+
+            // The drawable (or one of its children) may not have been
+            // stateful before applying the tint, so let's try again.
+            if (mCheckMarkDrawable.isStateful()) {
+                mCheckMarkDrawable.setState(getDrawableState());
+            }
         }
     }
 
diff --git a/core/java/android/widget/CompoundButton.java b/core/java/android/widget/CompoundButton.java
index 092e31c..447ccc2 100644
--- a/core/java/android/widget/CompoundButton.java
+++ b/core/java/android/widget/CompoundButton.java
@@ -315,6 +315,12 @@
             if (mHasButtonTintMode) {
                 mButtonDrawable.setTintMode(mButtonTintMode);
             }
+
+            // The drawable (or one of its children) may not have been
+            // stateful before applying the tint, so let's try again.
+            if (mButtonDrawable.isStateful()) {
+                mButtonDrawable.setState(getDrawableState());
+            }
         }
     }
 
diff --git a/core/java/android/widget/FrameLayout.java b/core/java/android/widget/FrameLayout.java
index e317524..d974c29 100644
--- a/core/java/android/widget/FrameLayout.java
+++ b/core/java/android/widget/FrameLayout.java
@@ -384,6 +384,12 @@
             if (mHasForegroundTintMode) {
                 mForeground.setTintMode(mForegroundTintMode);
             }
+
+            // The drawable (or one of its children) may not have been
+            // stateful before applying the tint, so let's try again.
+            if (mForeground.isStateful()) {
+                mForeground.setState(getDrawableState());
+            }
         }
     }
 
diff --git a/core/java/android/widget/ImageView.java b/core/java/android/widget/ImageView.java
index 75dfcca..c68bfca 100644
--- a/core/java/android/widget/ImageView.java
+++ b/core/java/android/widget/ImageView.java
@@ -386,21 +386,21 @@
      */
     @android.view.RemotableViewMethod
     public void setImageResource(int resId) {
-        if (mUri != null || mResource != resId) {
-            final int oldWidth = mDrawableWidth;
-            final int oldHeight = mDrawableHeight;
+        // The resource configuration may have changed, so we should always
+        // try to load the resource even if the resId hasn't changed.
+        final int oldWidth = mDrawableWidth;
+        final int oldHeight = mDrawableHeight;
 
-            updateDrawable(null);
-            mResource = resId;
-            mUri = null;
+        updateDrawable(null);
+        mResource = resId;
+        mUri = null;
 
-            resolveUri();
+        resolveUri();
 
-            if (oldWidth != mDrawableWidth || oldHeight != mDrawableHeight) {
-                requestLayout();
-            }
-            invalidate();
+        if (oldWidth != mDrawableWidth || oldHeight != mDrawableHeight) {
+            requestLayout();
         }
+        invalidate();
     }
 
     /**
@@ -527,6 +527,12 @@
             if (mHasDrawableTintMode) {
                 mDrawable.setTintMode(mDrawableTintMode);
             }
+
+            // The drawable (or one of its children) may not have been
+            // stateful before applying the tint, so let's try again.
+            if (mDrawable.isStateful()) {
+                mDrawable.setState(getDrawableState());
+            }
         }
     }
 
@@ -820,6 +826,7 @@
             mDrawableHeight = d.getIntrinsicHeight();
             applyImageTint();
             applyColorMod();
+
             configureBounds();
         } else {
             mDrawableWidth = mDrawableHeight = -1;
diff --git a/core/java/android/widget/ProgressBar.java b/core/java/android/widget/ProgressBar.java
index 1c190c3..887a93b 100644
--- a/core/java/android/widget/ProgressBar.java
+++ b/core/java/android/widget/ProgressBar.java
@@ -673,6 +673,12 @@
                 if (tintInfo.mHasIndeterminateTintMode) {
                     mIndeterminateDrawable.setTintMode(tintInfo.mIndeterminateTintMode);
                 }
+
+                // The drawable (or one of its children) may not have been
+                // stateful before applying the tint, so let's try again.
+                if (mIndeterminateDrawable.isStateful()) {
+                    mIndeterminateDrawable.setState(getDrawableState());
+                }
             }
         }
     }
@@ -781,6 +787,12 @@
                 if (mProgressTintInfo.mHasProgressTintMode) {
                     target.setTintMode(mProgressTintInfo.mProgressTintMode);
                 }
+
+                // The drawable (or one of its children) may not have been
+                // stateful before applying the tint, so let's try again.
+                if (target.isStateful()) {
+                    target.setState(getDrawableState());
+                }
             }
         }
     }
@@ -800,6 +812,12 @@
                 if (mProgressTintInfo.mHasProgressBackgroundTintMode) {
                     target.setTintMode(mProgressTintInfo.mProgressBackgroundTintMode);
                 }
+
+                // The drawable (or one of its children) may not have been
+                // stateful before applying the tint, so let's try again.
+                if (target.isStateful()) {
+                    target.setState(getDrawableState());
+                }
             }
         }
     }
@@ -819,6 +837,12 @@
                 if (mProgressTintInfo.mHasSecondaryProgressTintMode) {
                     target.setTintMode(mProgressTintInfo.mSecondaryProgressTintMode);
                 }
+
+                // The drawable (or one of its children) may not have been
+                // stateful before applying the tint, so let's try again.
+                if (target.isStateful()) {
+                    target.setState(getDrawableState());
+                }
             }
         }
     }
diff --git a/core/java/android/widget/RemoteViews.java b/core/java/android/widget/RemoteViews.java
index 80f364b..dd7fa18 100644
--- a/core/java/android/widget/RemoteViews.java
+++ b/core/java/android/widget/RemoteViews.java
@@ -2528,6 +2528,26 @@
     }
 
     /**
+     * Equivalent to calling {@link android.view.View#setAccessibilityTraversalBefore(int)}.
+     *
+     * @param viewId The id of the view whose before view in accessibility traversal to set.
+     * @param nextId The id of the next in the accessibility traversal.
+     **/
+    public void setAccessibilityTraversalBefore(int viewId, int nextId) {
+        setInt(viewId, "setAccessibilityTraversalBefore", nextId);
+    }
+
+    /**
+     * Equivalent to calling {@link android.view.View#setAccessibilityTraversalAfter(int)}.
+     *
+     * @param viewId The id of the view whose after view in accessibility traversal to set.
+     * @param nextId The id of the next in the accessibility traversal.
+     **/
+    public void setAccessibilityTraversalAfter(int viewId, int nextId) {
+        setInt(viewId, "setAccessibilityTraversalAfter", nextId);
+    }
+
+    /**
      * Equivalent to calling View.setLabelFor(int).
      *
      * @param viewId The id of the view whose property to set.
diff --git a/core/java/android/widget/Toolbar.java b/core/java/android/widget/Toolbar.java
index d8e39e3..d4d186c 100644
--- a/core/java/android/widget/Toolbar.java
+++ b/core/java/android/widget/Toolbar.java
@@ -104,6 +104,7 @@
     private ImageView mLogoView;
 
     private Drawable mCollapseIcon;
+    private CharSequence mCollapseDescription;
     private ImageButton mCollapseButtonView;
     View mExpandedActionView;
 
@@ -238,6 +239,7 @@
         }
 
         mCollapseIcon = a.getDrawable(R.styleable.Toolbar_collapseIcon);
+        mCollapseDescription = a.getText(R.styleable.Toolbar_collapseContentDescription);
 
         final CharSequence title = a.getText(R.styleable.Toolbar_title);
         if (!TextUtils.isEmpty(title)) {
@@ -998,6 +1000,7 @@
         if (mCollapseButtonView == null) {
             mCollapseButtonView = new ImageButton(getContext(), null, 0, mNavButtonStyle);
             mCollapseButtonView.setImageDrawable(mCollapseIcon);
+            mCollapseButtonView.setContentDescription(mCollapseDescription);
             final LayoutParams lp = generateDefaultLayoutParams();
             lp.gravity = Gravity.START | (mButtonGravity & Gravity.VERTICAL_GRAVITY_MASK);
             lp.mViewType = LayoutParams.EXPANDED;
diff --git a/core/java/com/android/internal/app/AlertController.java b/core/java/com/android/internal/app/AlertController.java
index 0183e45..35e03c3 100644
--- a/core/java/com/android/internal/app/AlertController.java
+++ b/core/java/com/android/internal/app/AlertController.java
@@ -26,7 +26,6 @@
 import android.content.res.TypedArray;
 import android.database.Cursor;
 import android.graphics.drawable.Drawable;
-import android.os.Build;
 import android.os.Handler;
 import android.os.Message;
 import android.text.TextUtils;
@@ -38,9 +37,12 @@
 import android.view.View;
 import android.view.ViewGroup;
 import android.view.ViewGroup.LayoutParams;
+import android.view.ViewParent;
+import android.view.ViewTreeObserver;
 import android.view.Window;
 import android.view.WindowInsets;
 import android.view.WindowManager;
+import android.widget.AbsListView;
 import android.widget.AdapterView;
 import android.widget.AdapterView.OnItemClickListener;
 import android.widget.ArrayAdapter;
@@ -449,11 +451,11 @@
     }
 
     private void setupView() {
-        final LinearLayout contentPanel = (LinearLayout) mWindow.findViewById(R.id.contentPanel);
+        final ViewGroup contentPanel = (ViewGroup) mWindow.findViewById(R.id.contentPanel);
         setupContent(contentPanel);
         final boolean hasButtons = setupButtons();
 
-        final LinearLayout topPanel = (LinearLayout) mWindow.findViewById(R.id.topPanel);
+        final ViewGroup topPanel = (ViewGroup) mWindow.findViewById(R.id.topPanel);
         final TypedArray a = mContext.obtainStyledAttributes(
                 null, R.styleable.AlertDialog, R.attr.alertDialogStyle, 0);
         final boolean hasTitle = setupTitle(topPanel);
@@ -521,13 +523,13 @@
         a.recycle();
     }
 
-    private boolean setupTitle(LinearLayout topPanel) {
+    private boolean setupTitle(ViewGroup topPanel) {
         boolean hasTitle = true;
 
         if (mCustomTitleView != null) {
             // Add the custom title view directly to the topPanel layout
-            LinearLayout.LayoutParams lp = new LinearLayout.LayoutParams(
-                    LinearLayout.LayoutParams.MATCH_PARENT, LinearLayout.LayoutParams.WRAP_CONTENT);
+            LayoutParams lp = new LayoutParams(
+                    LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT);
 
             topPanel.addView(mCustomTitleView, 0, lp);
 
@@ -571,7 +573,7 @@
         return hasTitle;
     }
 
-    private void setupContent(LinearLayout contentPanel) {
+    private void setupContent(ViewGroup contentPanel) {
         mScrollView = (ScrollView) mWindow.findViewById(R.id.scrollView);
         mScrollView.setFocusable(false);
 
@@ -588,14 +590,77 @@
             mScrollView.removeView(mMessageView);
 
             if (mListView != null) {
-                contentPanel.removeView(mWindow.findViewById(R.id.scrollView));
-                contentPanel.addView(mListView,
-                        new LinearLayout.LayoutParams(MATCH_PARENT, MATCH_PARENT));
-                contentPanel.setLayoutParams(new LinearLayout.LayoutParams(MATCH_PARENT, 0, 1.0f));
+                final ViewGroup scrollParent = (ViewGroup) mScrollView.getParent();
+                final int childIndex = scrollParent.indexOfChild(mScrollView);
+                scrollParent.removeViewAt(childIndex);
+                scrollParent.addView(mListView, childIndex,
+                        new LayoutParams(MATCH_PARENT, MATCH_PARENT));
             } else {
                 contentPanel.setVisibility(View.GONE);
             }
         }
+
+        // Set up scroll indicators (if present).
+        final View indicatorUp = mWindow.findViewById(R.id.scrollIndicatorUp);
+        final View indicatorDown = mWindow.findViewById(R.id.scrollIndicatorDown);
+        if (indicatorUp != null || indicatorDown != null) {
+            if (mMessage != null) {
+                // We're just showing the ScrollView, set up listener.
+                mScrollView.setOnScrollChangeListener(new View.OnScrollChangeListener() {
+                        @Override
+                        public void onScrollChange(View v, int scrollX, int scrollY,
+                                int oldScrollX, int oldScrollY) {
+                            manageScrollIndicators(v, indicatorUp, indicatorDown);
+                        }
+                    });
+                // Set up the indicators following layout.
+                mScrollView.post(new Runnable() {
+                     @Override
+                     public void run() {
+                             manageScrollIndicators(mScrollView, indicatorUp, indicatorDown);
+                         }
+                     });
+
+            } else if (mListView != null) {
+                // We're just showing the AbsListView, set up listener.
+                mListView.setOnScrollListener(new AbsListView.OnScrollListener() {
+                        @Override
+                        public void onScrollStateChanged(AbsListView view, int scrollState) {
+                            // That's cool, I guess?
+                        }
+
+                        @Override
+                        public void onScroll(AbsListView v, int firstVisibleItem,
+                                int visibleItemCount, int totalItemCount) {
+                            manageScrollIndicators(v, indicatorUp, indicatorDown);
+                        }
+                    });
+                // Set up the indicators following layout.
+                mListView.post(new Runnable() {
+                        @Override
+                        public void run() {
+                            manageScrollIndicators(mListView, indicatorUp, indicatorDown);
+                        }
+                    });
+            } else {
+                // We don't have any content to scroll, remove the indicators.
+                if (indicatorUp != null) {
+                    contentPanel.removeView(indicatorUp);
+                }
+                if (indicatorDown != null) {
+                    contentPanel.removeView(indicatorDown);
+                }
+            }
+        }
+    }
+
+    private static void manageScrollIndicators(View v, View upIndicator, View downIndicator) {
+        if (upIndicator != null) {
+            upIndicator.setVisibility(v.canScrollVertically(-1) ? View.VISIBLE : View.INVISIBLE);
+        }
+        if (downIndicator != null) {
+            downIndicator.setVisibility(v.canScrollVertically(1) ? View.VISIBLE : View.INVISIBLE);
+        }
     }
 
     private boolean setupButtons() {
diff --git a/core/java/com/android/internal/app/ResolverActivity.java b/core/java/com/android/internal/app/ResolverActivity.java
index ccffa19..7df76e5 100644
--- a/core/java/com/android/internal/app/ResolverActivity.java
+++ b/core/java/com/android/internal/app/ResolverActivity.java
@@ -278,9 +278,9 @@
 
         final ResolverDrawerLayout rdl = (ResolverDrawerLayout) findViewById(R.id.contentPanel);
         if (rdl != null) {
-            rdl.setOnClickOutsideListener(new View.OnClickListener() {
+            rdl.setOnDismissedListener(new ResolverDrawerLayout.OnDismissedListener() {
                 @Override
-                public void onClick(View v) {
+                public void onDismissed() {
                     finish();
                 }
             });
diff --git a/core/java/com/android/internal/app/ToolbarActionBar.java b/core/java/com/android/internal/app/ToolbarActionBar.java
index 4410f25..34b9dcb 100644
--- a/core/java/com/android/internal/app/ToolbarActionBar.java
+++ b/core/java/com/android/internal/app/ToolbarActionBar.java
@@ -40,7 +40,6 @@
 import java.util.ArrayList;
 
 public class ToolbarActionBar extends ActionBar {
-    private Toolbar mToolbar;
     private DecorToolbar mDecorToolbar;
     private boolean mToolbarMenuPrepared;
     private Window.Callback mWindowCallback;
@@ -66,7 +65,6 @@
     };
 
     public ToolbarActionBar(Toolbar toolbar, CharSequence title, Window.Callback windowCallback) {
-        mToolbar = toolbar;
         mDecorToolbar = new ToolbarWidgetWrapper(toolbar, false);
         mWindowCallback = new ToolbarCallbackWrapper(windowCallback);
         mDecorToolbar.setWindowCallback(mWindowCallback);
@@ -91,8 +89,8 @@
 
     @Override
     public void setCustomView(int resId) {
-        final LayoutInflater inflater = LayoutInflater.from(mToolbar.getContext());
-        setCustomView(inflater.inflate(resId, mToolbar, false));
+        final LayoutInflater inflater = LayoutInflater.from(mDecorToolbar.getContext());
+        setCustomView(inflater.inflate(resId, mDecorToolbar.getViewGroup(), false));
     }
 
     @Override
@@ -132,17 +130,17 @@
 
     @Override
     public void setElevation(float elevation) {
-        mToolbar.setElevation(elevation);
+        mDecorToolbar.getViewGroup().setElevation(elevation);
     }
 
     @Override
     public float getElevation() {
-        return mToolbar.getElevation();
+        return mDecorToolbar.getViewGroup().getElevation();
     }
 
     @Override
     public Context getThemedContext() {
-        return mToolbar.getContext();
+        return mDecorToolbar.getContext();
     }
 
     @Override
@@ -152,12 +150,12 @@
 
     @Override
     public void setHomeAsUpIndicator(Drawable indicator) {
-        mToolbar.setNavigationIcon(indicator);
+        mDecorToolbar.setNavigationIcon(indicator);
     }
 
     @Override
     public void setHomeAsUpIndicator(int resId) {
-        mToolbar.setNavigationIcon(resId);
+        mDecorToolbar.setNavigationIcon(resId);
     }
 
     @Override
@@ -280,7 +278,7 @@
 
     @Override
     public void setBackgroundDrawable(@Nullable Drawable d) {
-        mToolbar.setBackground(d);
+        mDecorToolbar.setBackgroundDrawable(d);
     }
 
     @Override
@@ -290,12 +288,12 @@
 
     @Override
     public CharSequence getTitle() {
-        return mToolbar.getTitle();
+        return mDecorToolbar.getTitle();
     }
 
     @Override
     public CharSequence getSubtitle() {
-        return mToolbar.getSubtitle();
+        return mDecorToolbar.getSubtitle();
     }
 
     @Override
@@ -389,44 +387,44 @@
 
     @Override
     public int getHeight() {
-        return mToolbar.getHeight();
+        return mDecorToolbar.getHeight();
     }
 
     @Override
     public void show() {
         // TODO: Consider a better transition for this.
         // Right now use no automatic transition so that the app can supply one if desired.
-        mToolbar.setVisibility(View.VISIBLE);
+        mDecorToolbar.setVisibility(View.VISIBLE);
     }
 
     @Override
     public void hide() {
         // TODO: Consider a better transition for this.
         // Right now use no automatic transition so that the app can supply one if desired.
-        mToolbar.setVisibility(View.GONE);
+        mDecorToolbar.setVisibility(View.GONE);
     }
 
     @Override
     public boolean isShowing() {
-        return mToolbar.getVisibility() == View.VISIBLE;
+        return mDecorToolbar.getVisibility() == View.VISIBLE;
     }
 
     @Override
     public boolean openOptionsMenu() {
-        return mToolbar.showOverflowMenu();
+        return mDecorToolbar.showOverflowMenu();
     }
 
     @Override
     public boolean invalidateOptionsMenu() {
-        mToolbar.removeCallbacks(mMenuInvalidator);
-        mToolbar.postOnAnimation(mMenuInvalidator);
+        mDecorToolbar.getViewGroup().removeCallbacks(mMenuInvalidator);
+        mDecorToolbar.getViewGroup().postOnAnimation(mMenuInvalidator);
         return true;
     }
 
     @Override
     public boolean collapseActionView() {
-        if (mToolbar.hasExpandedActionView()) {
-            mToolbar.collapseActionView();
+        if (mDecorToolbar.hasExpandedActionView()) {
+            mDecorToolbar.collapseActionView();
             return true;
         }
         return false;
@@ -434,10 +432,10 @@
 
     void populateOptionsMenu() {
         if (!mMenuCallbackSet) {
-            mToolbar.setMenuCallbacks(new ActionMenuPresenterCallback(), new MenuBuilderCallback());
+            mDecorToolbar.setMenuCallbacks(new ActionMenuPresenterCallback(), new MenuBuilderCallback());
             mMenuCallbackSet = true;
         }
-        final Menu menu = mToolbar.getMenu();
+        final Menu menu = mDecorToolbar.getMenu();
         final MenuBuilder mb = menu instanceof MenuBuilder ? (MenuBuilder) menu : null;
         if (mb != null) {
             mb.stopDispatchingItemsChanged();
@@ -518,7 +516,7 @@
             }
 
             mClosingActionMenu = true;
-            mToolbar.dismissPopupMenus();
+            mDecorToolbar.dismissPopupMenus();
             if (mWindowCallback != null) {
                 mWindowCallback.onPanelClosed(Window.FEATURE_ACTION_BAR, menu);
             }
@@ -536,7 +534,7 @@
         @Override
         public void onMenuModeChange(MenuBuilder menu) {
             if (mWindowCallback != null) {
-                if (mToolbar.isOverflowMenuShowing()) {
+                if (mDecorToolbar.isOverflowMenuShowing()) {
                     mWindowCallback.onPanelClosed(Window.FEATURE_ACTION_BAR, menu);
                 } else if (mWindowCallback.onPreparePanel(Window.FEATURE_OPTIONS_PANEL,
                         null, menu)) {
diff --git a/core/java/com/android/internal/app/WindowDecorActionBar.java b/core/java/com/android/internal/app/WindowDecorActionBar.java
index 785b303..d95f0e5 100644
--- a/core/java/com/android/internal/app/WindowDecorActionBar.java
+++ b/core/java/com/android/internal/app/WindowDecorActionBar.java
@@ -876,7 +876,7 @@
             currentTheme.resolveAttribute(com.android.internal.R.attr.actionBarWidgetTheme,
                     outValue, true);
             final int targetThemeRes = outValue.resourceId;
-            
+
             if (targetThemeRes != 0 && mContext.getThemeResId() != targetThemeRes) {
                 mThemedContext = new ContextThemeWrapper(mContext, targetThemeRes);
             } else {
@@ -885,7 +885,7 @@
         }
         return mThemedContext;
     }
-    
+
     @Override
     public boolean isTitleTruncated() {
         return mDecorToolbar != null && mDecorToolbar.isTitleTruncated();
@@ -933,14 +933,17 @@
     }
 
     /**
-     * @hide 
+     * @hide
      */
     public class ActionModeImpl extends ActionMode implements MenuBuilder.Callback {
+        private final Context mActionModeContext;
+        private final MenuBuilder mMenu;
+
         private ActionMode.Callback mCallback;
-        private MenuBuilder mMenu;
         private WeakReference<View> mCustomView;
-        
+
         public ActionModeImpl(Context context, ActionMode.Callback callback) {
+            mActionModeContext = context;
             mCallback = callback;
             mMenu = new MenuBuilder(context)
                     .setDefaultShowAsAction(MenuItem.SHOW_AS_ACTION_IF_ROOM);
@@ -949,7 +952,7 @@
 
         @Override
         public MenuInflater getMenuInflater() {
-            return new MenuInflater(getThemedContext());
+            return new MenuInflater(mActionModeContext);
         }
 
         @Override
@@ -1042,7 +1045,7 @@
         public CharSequence getSubtitle() {
             return mContextView.getSubtitle();
         }
-        
+
         @Override
         public void setTitleOptionalHint(boolean titleOptional) {
             super.setTitleOptionalHint(titleOptional);
diff --git a/core/java/com/android/internal/util/MemInfoReader.java b/core/java/com/android/internal/util/MemInfoReader.java
index 1dd9464..b71fa06 100644
--- a/core/java/com/android/internal/util/MemInfoReader.java
+++ b/core/java/com/android/internal/util/MemInfoReader.java
@@ -106,4 +106,8 @@
     public long getZramTotalSizeKb() {
         return mInfos[Debug.MEMINFO_ZRAM_TOTAL];
     }
+
+    public long[] getRawInfo() {
+        return mInfos;
+    }
 }
diff --git a/core/java/com/android/internal/view/BaseIWindow.java b/core/java/com/android/internal/view/BaseIWindow.java
index 50a7a5e..993ab58 100644
--- a/core/java/com/android/internal/view/BaseIWindow.java
+++ b/core/java/com/android/internal/view/BaseIWindow.java
@@ -102,4 +102,8 @@
     @Override
     public void doneAnimating() {
     }
+
+    @Override
+    public void dispatchWindowShown() {
+    }
 }
diff --git a/core/java/com/android/internal/widget/ActionBarView.java b/core/java/com/android/internal/widget/ActionBarView.java
index b9a85e5..654d08b 100644
--- a/core/java/com/android/internal/widget/ActionBarView.java
+++ b/core/java/com/android/internal/widget/ActionBarView.java
@@ -1341,6 +1341,22 @@
         updateHomeAccessibility(mUpGoerFive.isEnabled());
     }
 
+    @Override
+    public void setMenuCallbacks(MenuPresenter.Callback presenterCallback,
+            MenuBuilder.Callback menuBuilderCallback) {
+        if (mActionMenuPresenter != null) {
+            mActionMenuPresenter.setCallback(presenterCallback);
+        }
+        if (mOptionsMenu != null) {
+            mOptionsMenu.setCallback(menuBuilderCallback);
+        }
+    }
+
+    @Override
+    public Menu getMenu() {
+        return mOptionsMenu;
+    }
+
     static class SavedState extends BaseSavedState {
         int expandedMenuItemId;
         boolean isOverflowOpen;
diff --git a/core/java/com/android/internal/widget/DecorToolbar.java b/core/java/com/android/internal/widget/DecorToolbar.java
index f89f0b7..fb413b5 100644
--- a/core/java/com/android/internal/widget/DecorToolbar.java
+++ b/core/java/com/android/internal/widget/DecorToolbar.java
@@ -27,6 +27,8 @@
 import android.view.Window;
 import android.widget.AdapterView;
 import android.widget.SpinnerAdapter;
+
+import com.android.internal.view.menu.MenuBuilder;
 import com.android.internal.view.menu.MenuPresenter;
 
 /**
@@ -93,4 +95,11 @@
     void setDefaultNavigationIcon(Drawable icon);
     void saveHierarchyState(SparseArray<Parcelable> toolbarStates);
     void restoreHierarchyState(SparseArray<Parcelable> toolbarStates);
+    void setBackgroundDrawable(Drawable d);
+    int getHeight();
+    void setVisibility(int visible);
+    int getVisibility();
+    void setMenuCallbacks(MenuPresenter.Callback presenterCallback,
+            MenuBuilder.Callback menuBuilderCallback);
+    Menu getMenu();
 }
diff --git a/core/java/com/android/internal/widget/ResolverDrawerLayout.java b/core/java/com/android/internal/widget/ResolverDrawerLayout.java
index 375822f..25b4945 100644
--- a/core/java/com/android/internal/widget/ResolverDrawerLayout.java
+++ b/core/java/com/android/internal/widget/ResolverDrawerLayout.java
@@ -63,18 +63,22 @@
     private float mCollapseOffset;
 
     private int mCollapsibleHeight;
+    private int mUncollapsibleHeight;
 
     private int mTopOffset;
 
     private boolean mIsDragging;
     private boolean mOpenOnClick;
     private boolean mOpenOnLayout;
+    private boolean mDismissOnScrollerFinished;
     private final int mTouchSlop;
     private final float mMinFlingVelocity;
     private final OverScroller mScroller;
     private final VelocityTracker mVelocityTracker;
 
-    private OnClickListener mClickOutsideListener;
+    private OnDismissedListener mOnDismissedListener;
+    private RunOnDismissedListener mRunOnDismissedListener;
+
     private float mInitialTouchX;
     private float mInitialTouchY;
     private float mLastTouchY;
@@ -143,8 +147,8 @@
         return isSmallCollapsed() ? mMaxCollapsedHeightSmall : mMaxCollapsedHeight;
     }
 
-    public void setOnClickOutsideListener(OnClickListener listener) {
-        mClickOutsideListener = listener;
+    public void setOnDismissedListener(OnDismissedListener listener) {
+        mOnDismissedListener = listener;
     }
 
     @Override
@@ -194,7 +198,7 @@
         }
 
         if (mIsDragging) {
-            mScroller.abortAnimation();
+            abortAnimation();
         }
         return mIsDragging || mOpenOnClick;
     }
@@ -213,12 +217,9 @@
                 mInitialTouchX = x;
                 mInitialTouchY = mLastTouchY = y;
                 mActivePointerId = ev.getPointerId(0);
-                if (findChildUnder(mInitialTouchX, mInitialTouchY) == null &&
-                        mClickOutsideListener != null) {
-                    mIsDragging = handled = true;
-                }
-                handled |= mCollapsibleHeight > 0;
-                mScroller.abortAnimation();
+                mIsDragging = findChildUnder(mInitialTouchX, mInitialTouchY) != null;
+                handled = (!mIsDragging && mOnDismissedListener != null) || mCollapsibleHeight > 0;
+                abortAnimation();
             }
             break;
 
@@ -264,11 +265,12 @@
             break;
 
             case MotionEvent.ACTION_UP: {
+                final boolean wasDragging = mIsDragging;
                 mIsDragging = false;
-                if (!mIsDragging && findChildUnder(mInitialTouchX, mInitialTouchY) == null &&
+                if (!wasDragging && findChildUnder(mInitialTouchX, mInitialTouchY) == null &&
                         findChildUnder(ev.getX(), ev.getY()) == null) {
-                    if (mClickOutsideListener != null) {
-                        mClickOutsideListener.onClick(this);
+                    if (mOnDismissedListener != null) {
+                        dispatchOnDismissed();
                         resetTouch();
                         return true;
                     }
@@ -281,7 +283,13 @@
                 mVelocityTracker.computeCurrentVelocity(1000);
                 final float yvel = mVelocityTracker.getYVelocity(mActivePointerId);
                 if (Math.abs(yvel) > mMinFlingVelocity) {
-                    smoothScrollTo(yvel < 0 ? 0 : mCollapsibleHeight, yvel);
+                    if (mOnDismissedListener != null
+                            && yvel > 0 && mCollapseOffset > mCollapsibleHeight) {
+                        smoothScrollTo(mCollapsibleHeight + mUncollapsibleHeight, yvel);
+                        mDismissOnScrollerFinished = true;
+                    } else {
+                        smoothScrollTo(yvel < 0 ? 0 : mCollapsibleHeight, yvel);
+                    }
                 } else {
                     smoothScrollTo(
                             mCollapseOffset < mCollapsibleHeight / 2 ? 0 : mCollapsibleHeight, 0);
@@ -327,17 +335,27 @@
     @Override
     public void computeScroll() {
         super.computeScroll();
-        if (!mScroller.isFinished()) {
-            final boolean keepGoing = mScroller.computeScrollOffset();
+        if (mScroller.computeScrollOffset()) {
+            final boolean keepGoing = !mScroller.isFinished();
             performDrag(mScroller.getCurrY() - mCollapseOffset);
             if (keepGoing) {
                 postInvalidateOnAnimation();
+            } else if (mDismissOnScrollerFinished && mOnDismissedListener != null) {
+                mRunOnDismissedListener = new RunOnDismissedListener();
+                post(mRunOnDismissedListener);
             }
         }
     }
 
+    private void abortAnimation() {
+        mScroller.abortAnimation();
+        mRunOnDismissedListener = null;
+        mDismissOnScrollerFinished = false;
+    }
+
     private float performDrag(float dy) {
-        final float newPos = Math.max(0, Math.min(mCollapseOffset + dy, mCollapsibleHeight));
+        final float newPos = Math.max(0, Math.min(mCollapseOffset + dy,
+                mCollapsibleHeight + mUncollapsibleHeight));
         if (newPos != mCollapseOffset) {
             dy = newPos - mCollapseOffset;
             final int childCount = getChildCount();
@@ -356,11 +374,18 @@
         return 0;
     }
 
-    private void smoothScrollTo(int yOffset, float velocity) {
-        if (getMaxCollapsedHeight() == 0) {
-            return;
+    void dispatchOnDismissed() {
+        if (mOnDismissedListener != null) {
+            mOnDismissedListener.onDismissed();
         }
-        mScroller.abortAnimation();
+        if (mRunOnDismissedListener != null) {
+            removeCallbacks(mRunOnDismissedListener);
+            mRunOnDismissedListener = null;
+        }
+    }
+
+    private void smoothScrollTo(int yOffset, float velocity) {
+        abortAnimation();
         final int sy = (int) mCollapseOffset;
         int dy = yOffset - sy;
         if (dy == 0) {
@@ -490,6 +515,7 @@
     protected void onDetachedFromWindow() {
         super.onDetachedFromWindow();
         getViewTreeObserver().removeOnTouchModeChangeListener(mTouchModeChangeListener);
+        abortAnimation();
     }
 
     @Override
@@ -585,6 +611,7 @@
 
         mCollapsibleHeight = Math.max(0,
                 heightUsed - alwaysShowHeight - getMaxCollapsedHeight());
+        mUncollapsibleHeight = heightUsed - mCollapsibleHeight;
 
         if (isLaidOut()) {
             mCollapseOffset = Math.min(mCollapseOffset, mCollapsibleHeight);
@@ -734,4 +761,15 @@
             }
         };
     }
+
+    public interface OnDismissedListener {
+        public void onDismissed();
+    }
+
+    private class RunOnDismissedListener implements Runnable {
+        @Override
+        public void run() {
+            dispatchOnDismissed();
+        }
+    }
 }
diff --git a/core/java/com/android/internal/widget/ToolbarWidgetWrapper.java b/core/java/com/android/internal/widget/ToolbarWidgetWrapper.java
index 324a6c9..054ca30 100644
--- a/core/java/com/android/internal/widget/ToolbarWidgetWrapper.java
+++ b/core/java/com/android/internal/widget/ToolbarWidgetWrapper.java
@@ -657,4 +657,36 @@
         mToolbar.restoreHierarchyState(toolbarStates);
     }
 
+    @Override
+    public void setBackgroundDrawable(Drawable d) {
+        //noinspection deprecation
+        mToolbar.setBackgroundDrawable(d);
+    }
+
+    @Override
+    public int getHeight() {
+        return mToolbar.getHeight();
+    }
+
+    @Override
+    public void setVisibility(int visible) {
+        mToolbar.setVisibility(visible);
+    }
+
+    @Override
+    public int getVisibility() {
+        return mToolbar.getVisibility();
+    }
+
+    @Override
+    public void setMenuCallbacks(MenuPresenter.Callback presenterCallback,
+            MenuBuilder.Callback menuBuilderCallback) {
+        mToolbar.setMenuCallbacks(presenterCallback, menuBuilderCallback);
+    }
+
+    @Override
+    public Menu getMenu() {
+        return mToolbar.getMenu();
+    }
+
 }
diff --git a/core/jni/AndroidRuntime.cpp b/core/jni/AndroidRuntime.cpp
index 4159792..4d17877 100644
--- a/core/jni/AndroidRuntime.cpp
+++ b/core/jni/AndroidRuntime.cpp
@@ -929,8 +929,8 @@
  */
 void AndroidRuntime::start(const char* className, const Vector<String8>& options)
 {
-    ALOGD("\n>>>>>> AndroidRuntime START %s <<<<<<\n",
-            className != NULL ? className : "(unknown)");
+    ALOGD(">>>>>> START %s uid %d <<<<<<\n",
+            className != NULL ? className : "(unknown)", getuid());
 
     static const String8 startSystemServer("start-system-server");
 
diff --git a/core/jni/android/graphics/pdf/PdfEditor.cpp b/core/jni/android/graphics/pdf/PdfEditor.cpp
index 5f60c9e..2b756e2 100644
--- a/core/jni/android/graphics/pdf/PdfEditor.cpp
+++ b/core/jni/android/graphics/pdf/PdfEditor.cpp
@@ -19,6 +19,9 @@
 #include "fpdfview.h"
 #include "fpdfedit.h"
 #include "fpdfsave.h"
+#include "fsdk_rendercontext.h"
+#include "fpdf_transformpage.h"
+#include "SkMatrix.h"
 
 #include <android_runtime/AndroidRuntime.h>
 #include <vector>
@@ -29,6 +32,20 @@
 
 namespace android {
 
+enum PageBox {PAGE_BOX_MEDIA, PAGE_BOX_CROP};
+
+static struct {
+    jfieldID x;
+    jfieldID y;
+} gPointClassInfo;
+
+static struct {
+    jfieldID left;
+    jfieldID top;
+    jfieldID right;
+    jfieldID bottom;
+} gRectClassInfo;
+
 static Mutex sLock;
 
 static int sUnmatchedInitRequestCount = 0;
@@ -144,18 +161,201 @@
     }
 }
 
+static void nativeSetTransformAndClip(JNIEnv* env, jclass thiz, jlong documentPtr, jint pageIndex,
+        jlong transformPtr, jint clipLeft, jint clipTop, jint clipRight, jint clipBottom) {
+    FPDF_DOCUMENT document = reinterpret_cast<FPDF_DOCUMENT>(documentPtr);
+
+    CPDF_Page* page = (CPDF_Page*) FPDF_LoadPage(document, pageIndex);
+    if (!page) {
+        jniThrowException(env, "java/lang/IllegalStateException",
+                "cannot open page");
+        return;
+    }
+
+    double width = 0;
+    double height = 0;
+
+    const int result = FPDF_GetPageSizeByIndex(document, pageIndex, &width, &height);
+    if (!result) {
+        jniThrowException(env, "java/lang/IllegalStateException",
+                    "cannot get page size");
+        return;
+    }
+
+    CFX_AffineMatrix matrix;
+
+    SkMatrix* skTransform = reinterpret_cast<SkMatrix*>(transformPtr);
+
+    SkScalar transformValues[6];
+    skTransform->asAffine(transformValues);
+
+    // PDF's coordinate system origin is left-bottom while in graphics it
+    // is the top-left. So, translate the PDF coordinates to ours.
+    matrix.Set(1, 0, 0, -1, 0, page->GetPageHeight());
+
+    // Apply the transformation what was created in our coordinates.
+    matrix.Concat(transformValues[SkMatrix::kAScaleX], transformValues[SkMatrix::kASkewY],
+            transformValues[SkMatrix::kASkewX], transformValues[SkMatrix::kAScaleY],
+            transformValues[SkMatrix::kATransX], transformValues[SkMatrix::kATransY]);
+
+    // Translate the result back to PDF coordinates.
+    matrix.Concat(1, 0, 0, -1, 0, page->GetPageHeight());
+
+    FS_MATRIX transform = {matrix.a, matrix.b, matrix.c, matrix.d, matrix.e, matrix.f};
+    FS_RECTF clip = {(float) clipLeft, (float) clipTop, (float) clipRight, (float) clipBottom};
+
+    FPDFPage_TransFormWithClip(page, &transform, &clip);
+
+    FPDF_ClosePage(page);
+}
+
+static void nativeGetPageSize(JNIEnv* env, jclass thiz, jlong documentPtr,
+        jint pageIndex, jobject outSize) {
+    FPDF_DOCUMENT document = reinterpret_cast<FPDF_DOCUMENT>(documentPtr);
+
+    FPDF_PAGE page = FPDF_LoadPage(document, pageIndex);
+    if (!page) {
+        jniThrowException(env, "java/lang/IllegalStateException",
+                "cannot open page");
+        return;
+    }
+
+    double width = 0;
+    double height = 0;
+
+    const int result = FPDF_GetPageSizeByIndex(document, pageIndex, &width, &height);
+    if (!result) {
+        jniThrowException(env, "java/lang/IllegalStateException",
+                    "cannot get page size");
+        return;
+    }
+
+    env->SetIntField(outSize, gPointClassInfo.x, width);
+    env->SetIntField(outSize, gPointClassInfo.y, height);
+
+    FPDF_ClosePage(page);
+}
+
+static jboolean nativeScaleForPrinting(JNIEnv* env, jclass thiz, jlong documentPtr) {
+    FPDF_DOCUMENT document = reinterpret_cast<FPDF_DOCUMENT>(documentPtr);
+    FPDF_BOOL success = FPDF_VIEWERREF_GetPrintScaling(document);
+    return success ? JNI_TRUE : JNI_FALSE;
+}
+
+static bool nativeGetPageBox(JNIEnv* env, jclass thiz, jlong documentPtr, jint pageIndex,
+        PageBox pageBox, jobject outBox) {
+    FPDF_DOCUMENT document = reinterpret_cast<FPDF_DOCUMENT>(documentPtr);
+
+    FPDF_PAGE page = FPDF_LoadPage(document, pageIndex);
+    if (!page) {
+        jniThrowException(env, "java/lang/IllegalStateException",
+                "cannot open page");
+        return false;
+    }
+
+    float left;
+    float top;
+    float right;
+    float bottom;
+
+    const FPDF_BOOL success = (pageBox == PAGE_BOX_MEDIA)
+        ? FPDFPage_GetMediaBox(page, &left, &top, &right, &bottom)
+        : FPDFPage_GetCropBox(page, &left, &top, &right, &bottom);
+
+    FPDF_ClosePage(page);
+
+    if (!success) {
+        return false;
+    }
+
+    env->SetIntField(outBox, gRectClassInfo.left, (int) left);
+    env->SetIntField(outBox, gRectClassInfo.top, (int) top);
+    env->SetIntField(outBox, gRectClassInfo.right, (int) right);
+    env->SetIntField(outBox, gRectClassInfo.bottom, (int) bottom);
+
+    return true;
+}
+
+static jboolean nativeGetPageMediaBox(JNIEnv* env, jclass thiz, jlong documentPtr, jint pageIndex,
+        jobject outMediaBox) {
+    const bool success = nativeGetPageBox(env, thiz, documentPtr, pageIndex, PAGE_BOX_MEDIA,
+            outMediaBox);
+    return success ? JNI_TRUE : JNI_FALSE;
+}
+
+static jboolean nativeGetPageCropBox(JNIEnv* env, jclass thiz, jlong documentPtr, jint pageIndex,
+        jobject outMediaBox) {
+    const bool success = nativeGetPageBox(env, thiz, documentPtr, pageIndex, PAGE_BOX_CROP,
+         outMediaBox);
+    return success ? JNI_TRUE : JNI_FALSE;
+}
+
+static void nativeSetPageBox(JNIEnv* env, jclass thiz, jlong documentPtr, jint pageIndex,
+        PageBox pageBox, jobject box) {
+    FPDF_DOCUMENT document = reinterpret_cast<FPDF_DOCUMENT>(documentPtr);
+
+    FPDF_PAGE page = FPDF_LoadPage(document, pageIndex);
+    if (!page) {
+        jniThrowException(env, "java/lang/IllegalStateException",
+                "cannot open page");
+        return;
+    }
+
+    const int left = env->GetIntField(box, gRectClassInfo.left);
+    const int top = env->GetIntField(box, gRectClassInfo.top);
+    const int right = env->GetIntField(box, gRectClassInfo.right);
+    const int bottom = env->GetIntField(box, gRectClassInfo.bottom);
+
+    if (pageBox == PAGE_BOX_MEDIA) {
+        FPDFPage_SetMediaBox(page, left, top, right, bottom);
+    } else {
+        FPDFPage_SetCropBox(page, left, top, right, bottom);
+    }
+
+    FPDF_ClosePage(page);
+}
+
+static void nativeSetPageMediaBox(JNIEnv* env, jclass thiz, jlong documentPtr, jint pageIndex,
+        jobject mediaBox) {
+    nativeSetPageBox(env, thiz, documentPtr, pageIndex, PAGE_BOX_MEDIA, mediaBox);
+}
+
+static void nativeSetPageCropBox(JNIEnv* env, jclass thiz, jlong documentPtr, jint pageIndex,
+        jobject mediaBox) {
+    nativeSetPageBox(env, thiz, documentPtr, pageIndex, PAGE_BOX_CROP, mediaBox);
+}
+
 static JNINativeMethod gPdfEditor_Methods[] = {
     {"nativeOpen", "(IJ)J", (void*) nativeOpen},
     {"nativeClose", "(J)V", (void*) nativeClose},
     {"nativeGetPageCount", "(J)I", (void*) nativeGetPageCount},
     {"nativeRemovePage", "(JI)I", (void*) nativeRemovePage},
-    {"nativeWrite", "(JI)V", (void*) nativeWrite}
+    {"nativeWrite", "(JI)V", (void*) nativeWrite},
+    {"nativeSetTransformAndClip", "(JIJIIII)V", (void*) nativeSetTransformAndClip},
+    {"nativeGetPageSize", "(JILandroid/graphics/Point;)V", (void*) nativeGetPageSize},
+    {"nativeScaleForPrinting", "(J)Z", (void*) nativeScaleForPrinting},
+    {"nativeGetPageMediaBox", "(JILandroid/graphics/Rect;)Z", (void*) nativeGetPageMediaBox},
+    {"nativeSetPageMediaBox", "(JILandroid/graphics/Rect;)V", (void*) nativeSetPageMediaBox},
+    {"nativeGetPageCropBox", "(JILandroid/graphics/Rect;)Z", (void*) nativeGetPageCropBox},
+    {"nativeSetPageCropBox", "(JILandroid/graphics/Rect;)V", (void*) nativeSetPageCropBox}
 };
 
 int register_android_graphics_pdf_PdfEditor(JNIEnv* env) {
-    return android::AndroidRuntime::registerNativeMethods(
+    const int result = android::AndroidRuntime::registerNativeMethods(
             env, "android/graphics/pdf/PdfEditor", gPdfEditor_Methods,
             NELEM(gPdfEditor_Methods));
+
+    jclass pointClass = env->FindClass("android/graphics/Point");
+    gPointClassInfo.x = env->GetFieldID(pointClass, "x", "I");
+    gPointClassInfo.y = env->GetFieldID(pointClass, "y", "I");
+
+    jclass rectClass = env->FindClass("android/graphics/Rect");
+    gRectClassInfo.left = env->GetFieldID(rectClass, "left", "I");
+    gRectClassInfo.top = env->GetFieldID(rectClass, "top", "I");
+    gRectClassInfo.right = env->GetFieldID(rectClass, "right", "I");
+    gRectClassInfo.bottom = env->GetFieldID(rectClass, "bottom", "I");
+
+    return result;
 };
 
 };
diff --git a/core/jni/android_hardware_SoundTrigger.cpp b/core/jni/android_hardware_SoundTrigger.cpp
index 7b33bc2..2a8e6d6 100644
--- a/core/jni/android_hardware_SoundTrigger.cpp
+++ b/core/jni/android_hardware_SoundTrigger.cpp
@@ -265,18 +265,21 @@
                                 event->capture_session, event->capture_delay_ms,
                                 event->capture_preamble_ms, event->trigger_in_data,
                                 jAudioFormat, jData, jExtras);
-        env->DeleteLocalRef(jAudioFormat);
-        env->DeleteLocalRef(jData);
+        env->DeleteLocalRef(jExtras);
     } else {
         jEvent = env->NewObject(gRecognitionEventClass, gRecognitionEventCstor,
                                 event->status, event->model, event->capture_available,
                                 event->capture_session, event->capture_delay_ms,
                                 event->capture_preamble_ms, event->trigger_in_data,
                                 jAudioFormat, jData);
-        env->DeleteLocalRef(jAudioFormat);
-        env->DeleteLocalRef(jData);
     }
 
+    if (jAudioFormat != NULL) {
+        env->DeleteLocalRef(jAudioFormat);
+    }
+    if (jData != NULL) {
+        env->DeleteLocalRef(jData);
+    }
 
     env->CallStaticVoidMethod(mClass, gPostEventFromNative, mObject,
                               SOUNDTRIGGER_EVENT_RECOGNITION, 0, 0, jEvent);
diff --git a/core/jni/android_media_AudioSystem.cpp b/core/jni/android_media_AudioSystem.cpp
index 33bb90bc..f099289 100644
--- a/core/jni/android_media_AudioSystem.cpp
+++ b/core/jni/android_media_AudioSystem.cpp
@@ -390,7 +390,7 @@
     return (jint) check_AudioSystem_Command(AudioSystem::setMasterMute(mute));
 }
 
-static jfloat
+static jboolean
 android_media_AudioSystem_getMasterMute(JNIEnv *env, jobject thiz)
 {
     bool mute;
diff --git a/core/jni/android_util_AssetManager.cpp b/core/jni/android_util_AssetManager.cpp
index 4859ee6..94098c9 100644
--- a/core/jni/android_util_AssetManager.cpp
+++ b/core/jni/android_util_AssetManager.cpp
@@ -1095,7 +1095,7 @@
         // coming from, first XML attributes, then XML style, then default
         // style, and finally the theme.
         value.dataType = Res_value::TYPE_NULL;
-        value.data = 0;
+        value.data = Res_value::DATA_NULL_UNDEFINED;
         typeSetFlags = 0;
         config.density = 0;
 
@@ -1157,6 +1157,7 @@
         if (value.dataType == Res_value::TYPE_REFERENCE && value.data == 0) {
             DEBUG_STYLES(ALOGI("-> Setting to @null!"));
             value.dataType = Res_value::TYPE_NULL;
+            value.data = Res_value::DATA_NULL_UNDEFINED;
             block = -1;
         }
 
@@ -1319,7 +1320,7 @@
         // coming from, first XML attributes, then XML style, then default
         // style, and finally the theme.
         value.dataType = Res_value::TYPE_NULL;
-        value.data = 0;
+        value.data = Res_value::DATA_NULL_UNDEFINED;
         typeSetFlags = 0;
         config.density = 0;
 
@@ -1403,6 +1404,7 @@
         if (value.dataType == Res_value::TYPE_REFERENCE && value.data == 0) {
             DEBUG_STYLES(ALOGI("-> Setting to @null!"));
             value.dataType = Res_value::TYPE_NULL;
+            value.data = Res_value::DATA_NULL_UNDEFINED;
             block = kXmlBlock;
         }
 
@@ -1512,7 +1514,7 @@
 
         // Try to find a value for this attribute...
         value.dataType = Res_value::TYPE_NULL;
-        value.data = 0;
+        value.data = Res_value::DATA_NULL_UNDEFINED;
         typeSetFlags = 0;
         config.density = 0;
 
@@ -1548,6 +1550,7 @@
         // Deal with the special @null value -- it turns back to TYPE_NULL.
         if (value.dataType == Res_value::TYPE_REFERENCE && value.data == 0) {
             value.dataType = Res_value::TYPE_NULL;
+            value.data = Res_value::DATA_NULL_UNDEFINED;
         }
 
         //printf("Attribute 0x%08x: final type=0x%x, data=0x%08x\n", curIdent, value.dataType, value.data);
@@ -1661,6 +1664,7 @@
         // Deal with the special @null value -- it turns back to TYPE_NULL.
         if (value.dataType == Res_value::TYPE_REFERENCE && value.data == 0) {
             value.dataType = Res_value::TYPE_NULL;
+            value.data = Res_value::DATA_NULL_UNDEFINED;
         }
 
         //printf("Attribute 0x%08x: final type=0x%x, data=0x%08x\n", curIdent, value.dataType, value.data);
diff --git a/core/jni/com_android_internal_os_Zygote.cpp b/core/jni/com_android_internal_os_Zygote.cpp
index 7ca9374..4f5e08b 100644
--- a/core/jni/com_android_internal_os_Zygote.cpp
+++ b/core/jni/com_android_internal_os_Zygote.cpp
@@ -452,14 +452,23 @@
 
     DropCapabilitiesBoundingSet(env);
 
-    bool need_native_bridge = false;
-    if (instructionSet != NULL) {
+    bool use_native_bridge = !is_system_server && (instructionSet != NULL)
+        && android::NativeBridgeAvailable();
+    if (use_native_bridge) {
       ScopedUtfChars isa_string(env, instructionSet);
-      need_native_bridge = android::NeedsNativeBridge(isa_string.c_str());
+      use_native_bridge = android::NeedsNativeBridge(isa_string.c_str());
+    }
+    if (use_native_bridge && dataDir == NULL) {
+      // dataDir should never be null if we need to use a native bridge.
+      // In general, dataDir will never be null for normal applications. It can only happen in
+      // special cases (for isolated processes which are not associated with any app). These are
+      // launched by the framework and should not be emulated anyway.
+      use_native_bridge = false;
+      ALOGW("Native bridge will not be used because dataDir == NULL.");
     }
 
-    if (!MountEmulatedStorage(uid, mount_external, need_native_bridge)) {
-      ALOGW("Failed to mount emulated storage: %d", errno);
+    if (!MountEmulatedStorage(uid, mount_external, use_native_bridge)) {
+      ALOGW("Failed to mount emulated storage: %s", strerror(errno));
       if (errno == ENOTCONN || errno == EROFS) {
         // When device is actively encrypting, we get ENOTCONN here
         // since FUSE was mounted before the framework restarted.
@@ -487,15 +496,10 @@
 
     SetRLimits(env, javaRlimits);
 
-    if (!is_system_server && need_native_bridge) {
-      // Set the environment for the apps running with native bridge.
-      ScopedUtfChars isa_string(env, instructionSet);  // Known non-null because of need_native_...
-      if (dataDir == NULL) {
-        android::PreInitializeNativeBridge(NULL, isa_string.c_str());
-      } else {
-        ScopedUtfChars data_dir(env, dataDir);
-        android::PreInitializeNativeBridge(data_dir.c_str(), isa_string.c_str());
-      }
+    if (use_native_bridge) {
+      ScopedUtfChars isa_string(env, instructionSet);
+      ScopedUtfChars data_dir(env, dataDir);
+      android::PreInitializeNativeBridge(data_dir.c_str(), isa_string.c_str());
     }
 
     int rc = setresgid(gid, gid, gid);
diff --git a/core/res/res/drawable/view_accessibility_focused.xml b/core/res/res/drawable/view_accessibility_focused.xml
index 68e3f1e..025916b 100644
--- a/core/res/res/drawable/view_accessibility_focused.xml
+++ b/core/res/res/drawable/view_accessibility_focused.xml
@@ -18,9 +18,7 @@
 
     <stroke
         android:width="4dp"
-        android:color="@color/accessibility_focus_highlight"
-        android:dashWidth="4dp"
-        android:dashGap="2dp" />
+        android:color="@color/accessibility_focus_highlight" />
 
     <corners android:radius="2dp" />
 
diff --git a/core/res/res/layout/alert_dialog_material.xml b/core/res/res/layout/alert_dialog_material.xml
index c961828..5627a2c 100644
--- a/core/res/res/layout/alert_dialog_material.xml
+++ b/core/res/res/layout/alert_dialog_material.xml
@@ -51,12 +51,17 @@
         <!-- If the client uses a customTitle, it will be added here. -->
     </LinearLayout>
 
-    <LinearLayout android:id="@+id/contentPanel"
+    <FrameLayout android:id="@+id/contentPanel"
         android:layout_width="match_parent"
         android:layout_height="wrap_content"
         android:layout_weight="1"
-        android:orientation="vertical"
         android:minHeight="48dp">
+        <View android:id="@+id/scrollIndicatorUp"
+            android:visibility="gone"
+            android:layout_width="match_parent"
+            android:layout_height="1dp"
+            android:layout_gravity="top"
+            android:background="@drawable/list_divider_material"/>
         <ScrollView android:id="@+id/scrollView"
             android:layout_width="match_parent"
             android:layout_height="wrap_content"
@@ -78,7 +83,13 @@
                        android:layout_height="@dimen/alert_dialog_padding_top_material" />
             </LinearLayout>
         </ScrollView>
-    </LinearLayout>
+        <View android:id="@+id/scrollIndicatorDown"
+            android:visibility="gone"
+            android:layout_width="match_parent"
+            android:layout_height="1dp"
+            android:layout_gravity="bottom"
+            android:background="@drawable/list_divider_material"/>
+    </FrameLayout>
 
     <FrameLayout android:id="@+id/customPanel"
         android:layout_width="match_parent"
@@ -99,7 +110,8 @@
         android:paddingStart="12dp"
         android:paddingEnd="12dp"
         android:paddingTop="8dp"
-        android:paddingBottom="8dp">
+        android:paddingBottom="8dp"
+        android:gravity="bottom">
         <Button android:id="@+id/button3"
             style="?attr/buttonBarNeutralButtonStyle"
             android:layout_width="wrap_content"
diff --git a/core/res/res/layout/select_dialog_item_material.xml b/core/res/res/layout/select_dialog_item_material.xml
index fe326f3..b45edc6 100644
--- a/core/res/res/layout/select_dialog_item_material.xml
+++ b/core/res/res/layout/select_dialog_item_material.xml
@@ -28,6 +28,6 @@
     android:textAppearance="?android:attr/textAppearanceListItemSmall"
     android:textColor="?android:attr/textColorAlertDialogListItem"
     android:gravity="center_vertical"
-    android:paddingStart="@dimen/alert_dialog_padding_material"
-    android:paddingEnd="@dimen/alert_dialog_padding_material"
+    android:paddingStart="?attr/listPreferredItemPaddingStart"
+    android:paddingEnd="?attr/listPreferredItemPaddingEnd"
     android:ellipsize="marquee" />
diff --git a/core/res/res/values-mcc204-mnc04/config.xml b/core/res/res/values-mcc204-mnc04/config.xml
index 3c03814..d7484e1 100644
--- a/core/res/res/values-mcc204-mnc04/config.xml
+++ b/core/res/res/values-mcc204-mnc04/config.xml
@@ -31,4 +31,11 @@
         <item>"*611:+19085594899,BAE0000000000000"</item>
         <item>"*86:+1MDN,BAE0000000000000"</item>
     </string-array>
+
+    <!-- Flag indicating whether strict threshold is used, or lenient threshold is used,
+          when evaluating RSRP for LTE antenna bar display
+           0. Strict threshold
+           1. Lenient threshold
+    -->
+    <integer name="config_LTE_RSRP_threshold_type">0</integer>
 </resources>
diff --git a/core/res/res/values-mcc311-mnc480/config.xml b/core/res/res/values-mcc311-mnc480/config.xml
index d0a57b3..8cb2928 100644
--- a/core/res/res/values-mcc311-mnc480/config.xml
+++ b/core/res/res/values-mcc311-mnc480/config.xml
@@ -49,4 +49,11 @@
         <item>"*611:+19085594899,"</item>
         <item>"*86:+1MDN,"</item>
     </string-array>
+
+    <!-- Flag indicating whether strict threshold is used, or lenient threshold is used,
+          when evaluating RSRP for LTE antenna bar display
+           0. Strict threshold
+           1. Lenient threshold
+    -->
+    <integer name="config_LTE_RSRP_threshold_type">0</integer>
 </resources>
diff --git a/core/res/res/values/attrs.xml b/core/res/res/values/attrs.xml
index 7b4df49..91a8598 100644
--- a/core/res/res/values/attrs.xml
+++ b/core/res/res/values/attrs.xml
@@ -2363,6 +2363,18 @@
              representation this attribute can be used for providing such. -->
         <attr name="contentDescription" format="string" localization="suggested" />
 
+        <!-- Sets the id of a view before which this one is visited in accessibility traversal.
+             A screen-reader must visit the content of this view before the content of the one
+             it precedes.
+             @see android.view.View#setAccessibilityTraversalBefore(int)} -->
+        <attr name="accessibilityTraversalBefore" format="integer" />
+
+        <!-- Sets the id of a view after which this one is visited in accessibility traversal.
+             A screen-reader must visit the content of the other view before the content of
+             this one.
+             @see android.view.View#setAccessibilityTraversalAfter(int)} -->
+        <attr name="accessibilityTraversalAfter" format="integer" />
+
         <!-- Name of the method in this View's context to invoke when the view is
              clicked. This name must correspond to a public method that takes
              exactly one parameter of type View. For instance, if you specify
@@ -7460,7 +7472,10 @@
             <!-- Push object to the bottom of its container, not changing its size. -->
             <flag name="bottom" value="0x50" />
         </attr>
+        <!-- Icon drawable to use for the collapse button. -->
         <attr name="collapseIcon" format="reference" />
+        <!-- Text to set as the content description for the collapse button. -->
+        <attr name="collapseContentDescription" format="string" />
         <!-- Reference to a theme that should be used to inflate popups
              shown by widgets in the toolbar. -->
         <attr name="popupTheme" format="reference" />
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index 9332105d..60d8210 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -1885,4 +1885,11 @@
     <bool name="config_switch_phone_on_voice_reg_state_change">true</bool>
 
     <bool name="config_sms_force_7bit_encoding">false</bool>
+
+    <!-- Flag indicating whether strict threshold is used, or lenient threshold is used,
+          when evaluating RSRP for LTE antenna bar display
+           0. Strict threshold
+           1. Lenient threshold
+    -->
+    <integer name="config_LTE_RSRP_threshold_type">1</integer>
 </resources>
diff --git a/core/res/res/values/public.xml b/core/res/res/values/public.xml
index 45208ab..c0a5ab2 100644
--- a/core/res/res/values/public.xml
+++ b/core/res/res/values/public.xml
@@ -2589,6 +2589,15 @@
 
     <!-- @hide -->
     <public-padding type="attr" name="private_resource_pad" end="0x01010500" />
+
+    <!-- ===============================================================
+         Resources added in version 22 of the platform
+         =============================================================== -->
+    <eat-comment />
+
     <public type="attr" name="resizeClip"/>
+    <public type="attr" name="collapseContentDescription"/>
+    <public type="attr" name="accessibilityTraversalBefore" />
+    <public type="attr" name="accessibilityTraversalAfter" />
 
 </resources>
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index 99d15cc..27616c7 100644
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -3509,6 +3509,9 @@
     <!-- [CHAR LIMIT=40] Title of dialog that is shown when performing a system upgrade. -->
     <string name="android_upgrading_title">Android is upgrading\u2026</string>
 
+    <!-- [CHAR LIMIT=40] Title of dialog that is shown when system is starting. -->
+    <string name="android_start_title">Android is starting\u2026</string>
+
     <!-- [CHAR LIMIT=NONE] Message shown in upgrading dialog for each .apk that is optimized. -->
     <string name="android_upgrading_apk">Optimizing app
         <xliff:g id="number" example="123">%1$d</xliff:g> of
@@ -4902,4 +4905,7 @@
 
     <!-- Zen mode condition: no exit criteria. [CHAR LIMIT=NONE] -->
     <string name="zen_mode_forever">Indefinitely</string>
+
+    <!-- Content description for the Toolbar icon used to collapse an expanded action mode. [CHAR LIMIT=NONE] -->
+    <string name="toolbar_collapse_description">Collapse</string>
 </resources>
diff --git a/core/res/res/values/styles.xml b/core/res/res/values/styles.xml
index ba15e9c..dd87139 100644
--- a/core/res/res/values/styles.xml
+++ b/core/res/res/values/styles.xml
@@ -1218,6 +1218,7 @@
         <item name="buttonGravity">top</item>
         <item name="navigationButtonStyle">@style/Widget.Toolbar.Button.Navigation</item>
         <item name="collapseIcon">?attr/homeAsUpIndicator</item>
+        <item name="collapseContentDescription">@string/toolbar_collapse_description</item>
         <item name="contentInsetStart">16dp</item>
         <item name="touchscreenBlocksFocus">true</item>
     </style>
diff --git a/core/res/res/values/styles_material.xml b/core/res/res/values/styles_material.xml
index 6e03b3d..cc3ded5 100644
--- a/core/res/res/values/styles_material.xml
+++ b/core/res/res/values/styles_material.xml
@@ -1091,16 +1091,16 @@
     <!-- Dialog styles -->
 
     <style name="AlertDialog.Material" parent="AlertDialog">
-        <item name="fullDark">@null</item>
-        <item name="topDark">@null</item>
-        <item name="centerDark">@null</item>
-        <item name="bottomDark">@null</item>
-        <item name="fullBright">@null</item>
-        <item name="topBright">@null</item>
-        <item name="centerBright">@null</item>
-        <item name="bottomBright">@null</item>
-        <item name="bottomMedium">@null</item>
-        <item name="centerMedium">@null</item>
+        <item name="fullDark">@empty</item>
+        <item name="topDark">@empty</item>
+        <item name="centerDark">@empty</item>
+        <item name="bottomDark">@empty</item>
+        <item name="fullBright">@empty</item>
+        <item name="topBright">@empty</item>
+        <item name="centerBright">@empty</item>
+        <item name="bottomBright">@empty</item>
+        <item name="bottomMedium">@empty</item>
+        <item name="centerMedium">@empty</item>
         <item name="layout">@layout/alert_dialog_material</item>
         <item name="listLayout">@layout/select_dialog_material</item>
         <item name="progressLayout">@layout/progress_dialog_material</item>
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index d86413f..afe7c78 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -1491,6 +1491,7 @@
   <java-symbol type="layout" name="screen_title" />
   <java-symbol type="layout" name="screen_title_icons" />
   <java-symbol type="string" name="system_ui_date_pattern" />
+  <java-symbol type="string" name="android_start_title" />
   <java-symbol type="string" name="android_upgrading_title" />
   <java-symbol type="string" name="bugreport_title" />
   <java-symbol type="string" name="bugreport_message" />
@@ -2090,7 +2091,10 @@
   <java-symbol type="bool" name="config_switch_phone_on_voice_reg_state_change" />
   <java-symbol type="string" name="whichHomeApplicationNamed" />
   <java-symbol type="bool" name="config_sms_force_7bit_encoding" />
-
-  <!-- From MSIM Account -->
   <java-symbol type="layout" name="simple_account_item" />
+  <java-symbol type="id" name="scrollIndicatorUp" />
+  <java-symbol type="id" name="scrollIndicatorDown" />
+
+  <!-- From SignalStrength -->
+  <java-symbol type="integer" name="config_LTE_RSRP_threshold_type" />
 </resources>
diff --git a/core/res/res/values/themes_material.xml b/core/res/res/values/themes_material.xml
index 1864f89..5640fc1 100644
--- a/core/res/res/values/themes_material.xml
+++ b/core/res/res/values/themes_material.xml
@@ -1019,10 +1019,10 @@
         <item name="textAppearance">@style/TextAppearance.Material</item>
         <item name="textAppearanceInverse">@style/TextAppearance.Material.Inverse</item>
 
-        <item name="listPreferredItemPaddingLeft">16dip</item>
-        <item name="listPreferredItemPaddingRight">16dip</item>
-        <item name="listPreferredItemPaddingStart">16dip</item>
-        <item name="listPreferredItemPaddingEnd">16dip</item>
+        <item name="listPreferredItemPaddingLeft">24dip</item>
+        <item name="listPreferredItemPaddingRight">24dip</item>
+        <item name="listPreferredItemPaddingStart">24dip</item>
+        <item name="listPreferredItemPaddingEnd">24dip</item>
 
         <item name="listDivider">@null</item>
 
@@ -1135,10 +1135,10 @@
         <item name="textAppearance">@style/TextAppearance.Material</item>
         <item name="textAppearanceInverse">@style/TextAppearance.Material.Inverse</item>
 
-        <item name="listPreferredItemPaddingLeft">16dip</item>
-        <item name="listPreferredItemPaddingRight">16dip</item>
-        <item name="listPreferredItemPaddingStart">16dip</item>
-        <item name="listPreferredItemPaddingEnd">16dip</item>
+        <item name="listPreferredItemPaddingLeft">24dip</item>
+        <item name="listPreferredItemPaddingRight">24dip</item>
+        <item name="listPreferredItemPaddingStart">24dip</item>
+        <item name="listPreferredItemPaddingEnd">24dip</item>
 
         <item name="listDivider">@null</item>
 
diff --git a/docs/html/google/gcm/adv.jd b/docs/html/google/gcm/adv.jd
index 245467f..95497e3 100644
--- a/docs/html/google/gcm/adv.jd
+++ b/docs/html/google/gcm/adv.jd
@@ -261,7 +261,7 @@
 payload&quot; (non-collapsible message). These concepts are described in more
 detail in the following sections.</p>
 
-<h3 id="s2s"><strong>Send-to-sync messages</strong></h3>
+<h3 id="s2s">Send-to-sync messages</h3>
 
 <p>A send-to-sync (collapsible) message is often a &quot;tickle&quot; that tells
 a mobile application to sync data from the server. For example, suppose you have
@@ -288,6 +288,7 @@
 guarantees about which ones they will be.</p>
 
 <h3 id="payload">Messages with payload</h3>
+
 <p>Unlike a send-to-sync message, every &quot;message with payload&quot;
 (non-collapsible message) is delivered. The payload the message contains can be
 up to 4kb. For example, here is a JSON-formatted message in an IM application in
diff --git a/docs/html/google/gcm/ccs.jd b/docs/html/google/gcm/ccs.jd
index 2faf97f..7db7a74 100644
--- a/docs/html/google/gcm/ccs.jd
+++ b/docs/html/google/gcm/ccs.jd
@@ -21,7 +21,7 @@
       </li>
   <li><a href="#upstream">Upstream Messages</a>
     <ol>
-      <li><a href="#receipts">Receive return receipts</a></li>
+      <li><a href="#receipts">Receive delivery receipts</a></li>
     </ol>
   </li>
   <li><a href="#flow">Flow Control</a> </li>
@@ -45,11 +45,15 @@
 </div>
 </div>
 
-<p>The GCM Cloud Connection Server (CCS) is an XMPP endpoint that provides a
+<p>The Google Cloud Messaging (GCM) Cloud Connection Server (CCS) is an XMPP endpoint that provides a
 persistent, asynchronous, bidirectional connection to Google servers. The
 connection can be used to send and receive messages between your server and
 your users' GCM-connected devices.</p>
 
+<p class="note"><strong>Note:</strong> The content in this document
+applies to <a href="http://developer.chrome.com/apps/cloudMessaging">
+GCM with Chrome apps</a> as well as Android.
+
 <p>You can continue to use the HTTP request mechanism to send messages to GCM
 servers, side-by-side with CCS which uses XMPP. Some of the benefits of CCS include:</p>
 
@@ -259,22 +263,6 @@
 &lt;/message&gt;
 </pre>
 
-<p>Quota exceeded:</p>
-
-<pre>&lt;message&gt;
- &lt;gcm xmlns=&quot;google:mobile:data&quot;&gt;
- {
-   &quot;message_type&quot;:&quot;nack&quot;,
-   &quot;message_id&quot;:&quot;msgId1&quot;,
-   &quot;from&quot;:&quot;APA91bHFOtaQGSwupt5l1og&quot;,
-   &quot;error&quot;:&quot;QUOTA_EXCEEDED&quot;,
-   &quot;error_description&quot;:&quot;Short-term downstream quota exceeded for this registration id&quot;
- }
- &lt;/gcm&gt;
-&lt;/message&gt;
-</pre>
-
-
 <p>The following table lists NACK error codes. Unless otherwise
 indicated, a NACKed message should not be retried. Unexpected NACK error codes
 should be treated the same as {@code INTERNAL_SERVER_ERROR}.</p>
@@ -312,11 +300,11 @@
 <td>{@code INVALID_JSON}</td>
 <td>The JSON message payload is not valid.</td>
 </tr>
-<tr>
-<td>{@code QUOTA_EXCEEDED}</td>
-<td>The rate of messages to a particular registration ID (in other words, to a
-sender/device pair) is too high. If you want to retry the message, try using a slower
-rate.</td>
+<td>{@code DEVICE_MESSAGE_RATE_EXCEEDED}</td>
+<td>The rate of messages to a particular device is too high. You should reduce
+the number of messages sent to this device and should not immediately retry
+sending to this device. This error code replaces {@code QUOTA_EXCEEDED},
+which has been deprecated.</td>
 </tr>
 <tr>
   <td>{@code SERVICE_UNAVAILABLE}</td>
@@ -429,15 +417,17 @@
   &lt;/gcm&gt;
 &lt;/message&gt;</pre>
 
-<h3 id="receipts">Receive return receipts</h3>
+<h3 id="receipts">Receive delivery receipts</h3>
 
-<p>You can use upstream messaging to get receipt notifications, confirming
-that a given message was sent to a device. Your 3rd-party app server receives the receipt
-notification from CCS once the message has been sent to the device.</p>
+<p>You can use upstream messaging to get delivery receipts (sent from CCS to
+your 3rd party app server) when
+a device confirms that it received a message sent by CCS.</p>
 
 <p>To enable this feature, the message your 3rd-party app server sends to CCS must include
 a field called <code>&quot;delivery_receipt_requested&quot;</code>. When this field is set to
-<code>true</code>, CCS sends a return receipt. Here is an XMPP stanza containing a JSON
+<code>true</code>, CCS sends a delivery receipt when a device confirms that it received a particular message.</p>
+
+<p>Here is an XMPP stanza containing a JSON
 message with <code>&quot;delivery_receipt_requested&quot;</code> set to <code>true</code>:</p>
 
 <pre>&lt;message id=&quot;&quot;&gt;
@@ -457,8 +447,10 @@
 &lt;/message&gt;
 </pre>
 
-<p>Here is an example of a receipt notification message that CCS sends back to your 3rd-party
-app server:</p>
+
+
+<p>Here is an example of the delivery receipt that CCS sends to tell your 3rd-party
+app server that a device received a message that CCS sent it:</p>
 
 </p>
 <pre>&lt;message id=&quot;&quot;&gt;
@@ -483,12 +475,12 @@
 <ul>
   <li>The {@code &quot;message_type&quot;} is set to {@code &quot;receipt&quot;}.
   <li>The {@code &quot;message_status&quot;} is set to {@code &quot;MESSAGE_SENT_TO_DEVICE&quot;},
-  indicating that the message was delivered. Notice that in this case,
+  indicating that the device received the message. Notice that in this case,
 {@code &quot;message_status&quot;} is not a field but rather part of the data payload.</li>
   <li>The receipt message ID consists of the original message ID, but with a
-<code>dr:</code> prefix. Your 3rd-party app server must send an ACK back with this ID,
+<code>dr2:</code> prefix. Your 3rd-party app server must send an ACK back with this ID,
 which in this example is {@code dr2:m-1366082849205}.</li>
-  <li>The original message ID and status are inside the
+  <li>The original message ID, the device registration ID, and the status are inside the
 {@code &quot;data&quot;} field.</li>
 </ul>
 
diff --git a/docs/html/google/gcm/client.jd b/docs/html/google/gcm/client.jd
index 20bff10..70109c6 100644
--- a/docs/html/google/gcm/client.jd
+++ b/docs/html/google/gcm/client.jd
@@ -34,14 +34,14 @@
 </div>
 </div>
 
-<p>A GCM client is a GCM-enabled app that runs on an Android device. To write your
-client code, we recommend that you use the
-<a href="{@docRoot}reference/com/google/android/gms/gcm/GoogleCloudMessaging.html">
-{@code GoogleCloudMessaging}</a> APIs.
+<p>A Google Cloud Messaging (GCM) client is a GCM-enabled app that runs on an
+Android device. To write your client code, we recommend that you use the
+<a href="{@docRoot}reference/com/google/android/gms/gcm/package-summary.html">
+GCM APIs</a>.
 The client helper library that was offered in previous versions of GCM still works,
 but it has been superseded by the more efficient
-<a href="{@docRoot}reference/com/google/android/gms/gcm/GoogleCloudMessaging.html">
-{@code GoogleCloudMessaging}</a> APIs.</p>
+<a href="{@docRoot}reference/com/google/android/gms/gcm/package-summary.html">
+GCM APIs</a>.</p>
 
 <p>A full GCM implementation requires both a client implementation and a server
 implementation. For more
@@ -57,8 +57,8 @@
 <h2 id="play-services">Step 1: Set Up Google Play Services</h2>
 
 <p>To write your client application, use the
-<a href="{@docRoot}reference/com/google/android/gms/gcm/GoogleCloudMessaging.html">
-{@code GoogleCloudMessaging}</a> API.
+<a href="{@docRoot}reference/com/google/android/gms/gcm/package-summary.html">
+GCM APIs</a>.
 To use this API, you must set up your project to use the Google Play services SDK,
 as described in <a href="/google/play-services/setup.html">Setup Google Play
 Services SDK</a>.</p>
@@ -159,7 +159,7 @@
 <p>Finally, write your application. This section features a sample client
 application that illustrates how to use the
 <a href="{@docRoot}reference/com/google/android/gms/gcm/GoogleCloudMessaging.html">
-{@code GoogleCloudMessaging}</a> APIs. The sample consists of a main activity
+{@code GoogleCloudMessaging}</a> API. The sample consists of a main activity
 ({@code DemoActivity}), a {@link android.support.v4.content.WakefulBroadcastReceiver}
 ({@code GcmBroadcastReceiver}), and an {@link android.app.IntentService}
 ({@code GcmIntentService}). You can find the complete source code for this sample at the
@@ -456,7 +456,7 @@
 <p>When the user clicks the app's <strong>Send</strong> button, the app sends an
 upstream message using the
 <a href="{@docRoot}reference/com/google/android/gms/gcm/GoogleCloudMessaging.html">
-{@code GoogleCloudMessaging}</a> APIs. In order to receive the upstream message,
+{@code GoogleCloudMessaging}</a> API. In order to receive the upstream message,
 your server should be connected to CCS. You can use one of the demo servers in
 <a href="ccs.html#implement">Implementing an XMPP-based App Server</a> to run the sample and connect
 to CCS.</p>
@@ -652,7 +652,7 @@
 
 <p>To view  statistics and any error messages for your GCM applications:</p>
 <ol>
-  <li> Go to the <code><a href="http://play.google.com/apps/publish">Developer Console</a></code>.</li>
+  <li> Go to the <a href="http://play.google.com/apps/publish">Developer Console</a>.</li>
   <li>Login with your developer account.
   <p>You will see a page that has a list of all of your apps.</p></li>
   <li> Click on the &quot;statistics&quot; link next to the app for which you
diff --git a/docs/html/google/gcm/gcm.jd b/docs/html/google/gcm/gcm.jd
index 19151b9..3d6594d 100644
--- a/docs/html/google/gcm/gcm.jd
+++ b/docs/html/google/gcm/gcm.jd
@@ -21,7 +21,7 @@
 </div>
 </div>
 
-<p>Google Cloud Messaging for Android (GCM) is a free service that helps
+<p>Google Cloud Messaging (GCM) for Android is a free service that helps
 developers  send data from servers to their Android applications on  Android
 devices, and upstream messages from the user's device back to the cloud.
 This could be a lightweight message telling the Android application
diff --git a/docs/html/google/gcm/gs.jd b/docs/html/google/gcm/gs.jd
index ae57b6d..a889624 100644
--- a/docs/html/google/gcm/gs.jd
+++ b/docs/html/google/gcm/gs.jd
@@ -25,12 +25,12 @@
 </div>
 </div>
 
-<p>This document tells you how to get started setting up a GCM
-implementation.
+<p>This document tells you how to get started setting up a Google Cloud Messaging
+(GCM) implementation.
 Before you begin, make sure to <a href="/google/play-services/setup.html">set up
 the Google Play Services SDK</a>. You need this SDK to use the
-<a href="{@docRoot}reference/com/google/android/gms/gcm/GoogleCloudMessaging.html">
-{@code GoogleCloudMessaging}</a> methods.</p>
+<a href="{@docRoot}reference/com/google/android/gms/gcm/package-summary.html">
+GCM APIs</a>.</p>
 
 <h2 id="create-proj">Creating a Google API project</h2>
 <p>To create a Google API project:</p>
diff --git a/docs/html/google/gcm/http.jd b/docs/html/google/gcm/http.jd
index b8d8659..773acd1 100644
--- a/docs/html/google/gcm/http.jd
+++ b/docs/html/google/gcm/http.jd
@@ -33,13 +33,16 @@
 </div>
 </div>
 
-<p>This document describes the GCM HTTP connection server. Connection servers
+<p>This document describes the Google Cloud Messaging (GCM) HTTP
+connection server. Connection servers
 are the Google-provided servers that take messages from the 3rd-party
 application server and sending them to the device.</p>
 
+<p class="note"><strong>Note:</strong> The content in this document
+applies to <a href="http://developer.chrome.com/apps/cloudMessaging">
+GCM with Chrome apps</a> as well as Android.</p>
 
-
-<p class="note"><strong>Note:</strong> See
+<p>See
 <a href="server.html#params">Implementing GCM Server</a> for a list of all the message
 parameters and which connection server(s) supports them.</p>
 
@@ -163,7 +166,7 @@
   </tr>
   <tr>
     <td>5xx</td>
-    <td>Errors in the 500-599 range (such as 500 or 503) indicate that there wa
+    <td>Errors in the 500-599 range (such as 500 or 503) indicate that there was
 an internal error in the GCM server while trying to process the request, or that
 the server is temporarily unavailable (for example, because of timeouts). Sender
 must retry later, honoring any <code>Retry-After</code> header included in the
@@ -416,6 +419,12 @@
 the value passed in the request. Happens when error code is
 <code>InvalidPackageName</code>.
 </dd>
+
+<dt id="big_msg"><strong>Device Message Rate Exceeded</strong></dt>
+  <dd>The rate of messages to a particular device is too high. You should reduce the number
+of messages sent to this device and should not retry sending to this device immediately.
+<br/>Happens when error code is <code>DeviceMessageRateExceeded</code>.</dd>
+
 </dl>
 
 <h3 id="example-responses">Example responses</h3>
diff --git a/docs/html/google/gcm/index.jd b/docs/html/google/gcm/index.jd
index 56e0865..af5d741 100644
--- a/docs/html/google/gcm/index.jd
+++ b/docs/html/google/gcm/index.jd
@@ -13,11 +13,11 @@
 
   <h1 itemprop="name" style="margin-bottom:0;">Google Cloud Messaging for Android</h1>
   <p itemprop="description">
-  Google Cloud Messaging for Android (GCM) is a service that allows you to send data
+  Google Cloud Messaging (GCM) for Android is a service that allows you to send data
 from your server to your users' Android-powered device, and also to receive messages from
 devices on the same connection. The GCM service handles all aspects of queueing of messages
-and delivery to the target Android application running on the target device. GCM is
-completely free no matter how big your messaging needs are, and there are no quotas.
+and delivery to the target Android application running on the target device, and it is
+completely free.
 </p>
 
 </div>
diff --git a/docs/html/google/gcm/notifications.jd b/docs/html/google/gcm/notifications.jd
index 2815f3d..147b69c 100644
--- a/docs/html/google/gcm/notifications.jd
+++ b/docs/html/google/gcm/notifications.jd
@@ -83,7 +83,7 @@
 <h2 id="gen-server">Generate a Notification Key on the Server</h2>
 
 <p>To generate a notification key on the server, you create a new
-create a new <code>notification_key</code> and map it to a
+<code>notification_key</code> and map it to a
 <code>notification_key_name</code>.</p>
 
 <p>This example shows how to create a new <code>notification_key</code> for a
@@ -268,7 +268,7 @@
 
 <p>When you make a request to create a {@code notification_key} or to add/remove its
 regIDs, a successful response always returns the <code>notification_key</code>.
-his is the {@code notification_key} you will use for sending messages:</p>
+Use the returned {@code notification_key} for sending messages:</p>
 
 <pre>HTTP status: 200
 { 
diff --git a/docs/html/google/gcm/server.jd b/docs/html/google/gcm/server.jd
index e3a6b252..20e2b2e 100644
--- a/docs/html/google/gcm/server.jd
+++ b/docs/html/google/gcm/server.jd
@@ -37,7 +37,7 @@
 </div>
 
 
-<p>The server side of GCM consists of 2 components:</p>
+<p>The server side of Google Cloud Messaging (GCM) consists of 2 components:</p>
 <ul>
 <li>Google-provided <strong>GCM Connection Servers</strong>
 take messages from a 3rd-party application server and send them to a GCM-enabled
@@ -168,36 +168,37 @@
 parameter.</p>
 
 <p class="table-caption" id="table1">
-  <strong>Table 1.</strong> Message parameters.</p>
+  <strong>Table 1.</strong> Message Parameters JSON (CCS and HTTP).</p>
 
 <table>
   <tr>
-    <th>Field</th>
+    <th>Parameter</th>
     <th>Description</th>
 <th>Where Supported</th>
 </tr>
   <td><code>to</code></td>
-<td>In CCS, used in place of <code>registration_ids</code> to specify the
-recipient of a message. Its value must be a registration ID.
+<td>In CCS, this parameter is used in place of <code>registration_ids</code> to
+specify the recipient of a message. Its value must be a registration ID.
 The value is a string. Required.</td>
 <td>CCS</td>
 </tr>
 <tr>
 <td><code>message_id</code></td>
-<td>In CCS, uniquely identifies a message in an XMPP connection. The value is a
-string that uniquely identifies the associated message. The value is a string. Required.</td>
+<td>In CCS, this parameter uniquely identifies a message in an XMPP connection.
+The value is a string that uniquely identifies the associated message. Required.</td>
 <td>CCS</td>
 </tr>
 <tr>
 <td><code>message_type</code></td>
-<td>In CCS, indicates a special status message, typically sent by the system.
+<td>In CCS, this parameter indicates a special status message, typically sent by the system.
 However, your app server also uses this parameter to send an 'ack' or 'nack'
 message back to the CCS connection server. For more discussion of this topic, see
 <a href="ccs.html">Cloud Connection Server</a>. The value is a string. Optional.</td>
 <td>CCS</td>
 <tr>
   <td><code>registration_ids</code></td>
-  <td>A string array with the list of devices (registration IDs) receiving the
+  <td>This parameter specifies a string array containing the list of devices
+(registration IDs) receiving the
 message. It must contain at least 1 and at most 1000 registration IDs. To send a
 multicast message, you must use JSON. For sending a single message to a single
 device, you could use a JSON object with just 1 registration id, or plain text
@@ -208,12 +209,13 @@
 </tr>
  <tr>
     <td><code>notification_key</code></td>
-    <td>A string that maps a single user to multiple registration IDs associated
+    <td>This parameter specifies a string that maps a single user to multiple
+registration IDs associated
 with that user. This allows a 3rd-party server to send a single message to
 multiple app instances (typically on multiple devices) owned by a single user.
 A 3rd-party server can use {@code notification_key} as the target for a message
 instead of an individual registration ID (or array of registration IDs). The maximum
-number of members allowed for a {@code notification_key} is 10. For more discussion
+number of members allowed for a {@code notification_key} is 20. For more discussion
 of this topic, see <a href="notifications.html">User Notifications</a>. Optional.
 </td>
 <td style="width:100px">HTTP. This feature is supported in CCS, but you use it by
@@ -221,13 +223,14 @@
 </tr>
   <tr>
     <td><code>collapse_key</code></td>
-    <td>An arbitrary string (such as &quot;Updates Available&quot;) that is used
+    <td>This parameter specifies an arbitrary string (such as
+&quot;Updates Available&quot;) that is used
 to collapse a group of like messages
 when the device is offline, so that only the last message gets sent to the
 client. This is intended to avoid sending too many messages to the phone when it
 comes back online. Note that since there is no guarantee of the order in which
 messages get sent, the &quot;last&quot; message may not actually be the last
-message sent by the application server. Collapse keys are also called
+message sent by the application server. Messages with collapse keys are also called
 <a href="#s2s">send-to-sync messages</a>.
 <br>
 <strong>Note:</strong> GCM allows a maximum of 4 different collapse keys to be
@@ -242,8 +245,9 @@
 </tr>
   <tr>
     <td><code>data</code></td>
-    <td>A JSON object whose fields represents the key-value pairs of the message's
-payload data. If present, the payload data it will be
+    <td>This parameter specifies a JSON object whose fields represents the
+key-value pairs of the message's
+payload data. If present, the payload data will be
 included in the Intent as application data, with the key being the extra's name.
 For instance, <code>"data":{"score":"3x1"}</code> would result in an intent extra
 named <code>score</code> whose value is the string <code>3x1</code>.
@@ -253,17 +257,14 @@
 server anyway. If you want to include objects or other non-string data types
 (such as integers or booleans), you have to do the conversion to string yourself.
 Also note that the key cannot be a reserved word (<code>from</code> or any word
-starting with <code>google.</code>). To complicate things slightly, there are
-some reserved words (such as <code>collapse_key</code>) that are technically
-allowed in payload data. However, if the request also contains the word, the
-value in the request will overwrite the value in the payload data. Hence using
-words that are defined as field names in this table is not recommended, even in
-cases where they are technically allowed. Optional.</td>
+starting with <code>google.</code>). Using words defined in this table as field
+names (such as <code>collapse_key</code>) could yield unpredictable outcomes and
+is not recommended. Optional.</td>
 <td>CCS, HTTP</td>
 </tr>
   <tr>
     <td><code>delay_while_idle</code></td>
-    <td>If included, indicates that the message should not be sent immediately
+    <td>This parameter indicates that the message should not be sent immediately
 if the device is idle. The server will wait for the device to become active, and
 then only the last message for each <code>collapse_key</code> value will be
 sent. The default value is <code>false</code>, and must be a JSON boolean. Optional.</td>
@@ -271,26 +272,70 @@
 </tr>
   <tr>
     <td><code>time_to_live</code></td>
-    <td>How long (in seconds) the message should be kept on GCM storage if the
-device is offline. Optional (default time-to-live is 4 weeks, and must be set as
+    <td>This parameter specifies how long (in seconds) the message should be kept on GCM
+storage if the device is offline. Optional (default time-to-live is 4 weeks, and must be set as
 a JSON number).</td>
 <td>CCS, HTTP</td>
 </tr>
 <tr>
   <td><code>restricted_package_name</code></td>
-  <td>A string containing the package name of your application. When set, messages
-will only be sent to registration IDs that match the package name. Optional.
+  <td>This parameter specifies a string containing the package
+name of your application. When set, messages
+are only sent to registration IDs that match the package name. Optional.
   </td>
 <td>HTTP</td>
 </tr>
 <tr>
   <td><code>dry_run</code></td>
-  <td>If included, allows developers to test their request without actually
+  <td>This parameter allows developers to test a request without actually
 sending a message. Optional. The default value is <code>false</code>, and must
 be a JSON boolean.
   </td>
 <td>HTTP</td>
 </tr>
+<tr>
+  <td><code>delivery_receipt_requested</code></td>
+  <td>This parameter lets you request confirmation of message delivery. When
+this parameter is set to <code>true</code>, CCS sends a
+delivery receipt when a device confirms that it received a message sent by CCS.
+The default value is <code>false</code>, and must be a JSON boolean. Optional.<br />
+This parameter relates to <a href="{@docRoot}google/gcm/ccs.html#receipts"}>
+delivery receipts</a>.
+</td>
+  <td>CCS</td>
+</tr>
+<tr>
+  <td><code>message_status</code></td>
+  <td>This parameter specifies the status of the receipt message.
+The parameter appears inside the
+<code>&quot;data&quot;</code> field of a
+delivery receipt message. Currently the only possible value
+is <code>MESSAGE_SENT_TO_DEVICE</code>, which indicates that a device acknowledges
+receiving  a message sent by CCS.<br />
+This parameter relates to <a href="{@docRoot}google/gcm/ccs.html#receipts"}>
+delivery receipts</a>.</td>
+  <td>CCS</td>
+</tr>
+<tr>
+  <td><code>original_message_id</code></td>
+  <td>The value of this parameter is the ID of the original message that the server sent to
+the device. This parameter appears inside the <code>&quot;data&quot;</code> field of a
+delivery receipt message. <br />
+This parameter relates to <a href="{@docRoot}google/gcm/ccs.html#receipts"}>
+delivery receipts</a>.</td>
+  <td>CCS</td>
+</tr>
+<tr>
+  <td><code>device_registration_id</code></td>
+  <td>For the purpose of tracking the delivery receipt, this parameter lists
+the registration ID of the device to which a given message was sent. This parameter
+appears inside the <code>&quot;data&quot;</code> field of a
+delivery receipt message. <br />
+This parameter relates to <a href="{@docRoot}google/gcm/ccs.html#receipts"}>
+delivery receipts</a>.</td>
+  <td>CCS</td>
+</tr>
+
 </table>
 
 <p>If you want to test your request (either JSON or plain text) without delivering
@@ -298,21 +343,23 @@
 <code>dry_run</code> with the value <code>true</code>. The result will be almost
 identical to running the request without this parameter, except that the message
 will not be delivered to the devices. Consequently, the response will contain fake
-IDs for the message and multicast fields.</p>
+IDs for the message and multicast parameters.</p>
 
-<h3 id="plain-text">Plain text (HTTP only)</h3>
-
-<p>If you are using plain text instead of JSON, the message fields must be set as
+<p>If you are using plain text instead of JSON, the message parameters must be set as
 HTTP parameters sent in the body, and their syntax is slightly different, as
-described below:
+described in the following table:
+
+<p class="table-caption" id="table2">
+  <strong>Table 2.</strong> Message Parameters Plain Text (HTTP only).</p>
 <table>
   <tr>
-    <th>Field</th>
+    <th>Parameter</th>
     <th>Description</th>
   </tr>
   <tr>
     <td><code>registration_id</code></td>
-    <td>Must contain the registration ID of the single device receiving the message.
+    <td>This parameter specifies the registration ID of the single device
+receiving the message.
 Required.</td>
   </tr>
   <tr>
@@ -322,24 +369,23 @@
   <tr>
     <td><code>data.&lt;key&gt;</code></td>
 
-    <td>Payload data, expressed as parameters prefixed with <code>data.</code> and
+    <td>This parameter specifies payload data, expressed as parameters
+prefixed with <code>data.</code> and
 suffixed as the key. For instance, a parameter of <code>data.score=3x1</code> would
 result in an intent extra named <code>score</code> whose value is the string
 <code>3x1</code>. There is no limit on the number of key/value parameters, though
 there is a limit on the total size of the  message. Also note that the key cannot
 be a reserved word (<code>from</code> or any word starting with
-<code>google.</code>). To complicate things slightly, there are some reserved words
-(such as <code>collapse_key</code>) that are technically allowed in payload data.
-However, if the request also contains the word, the value in the request will
-overwrite the value in the payload data. Hence using words that are defined as
-field names in this table is not recommended, even in cases where they are
-technically allowed. Optional.</td>
+<code>google.</code>). Using words defined in this table as field
+names (such as <code>collapse_key</code>) could yield unpredictable outcomes and
+is not recommended. Optional.</td>
 
   </tr>
   <tr>
     <td><code>delay_while_idle</code></td>
-    <td>Should be represented as <code>1</code> or <code>true</code> for
-<code>true</code>, anything else for <code>false</code>. Optional. The default
+    <td>This parameter specifies whether messages should be delivered when the device
+is asleep. A value of <code>1</code> or <code>true</code> indicates
+<code>true</code>, and anything else indicates <code>false</code>. Optional. The default
 value is <code>false</code>.</td>
   </tr>
   <tr>
diff --git a/docs/html/guide/topics/text/creating-input-method.jd b/docs/html/guide/topics/text/creating-input-method.jd
index 802b58a..424a21c 100644
--- a/docs/html/guide/topics/text/creating-input-method.jd
+++ b/docs/html/guide/topics/text/creating-input-method.jd
@@ -41,8 +41,8 @@
 <p>
     To add an IME to the Android system, you create an Android application
     containing a class that extends {@link android.inputmethodservice.InputMethodService}. In
-    addition, you usually create a "settings" activity that passes options to the IME
-    service. You can also define a settings UI that's displayed as part of the system settings.
+    addition, you usually create a "settings" activity that passes options to the IME service. You
+    can also define a settings UI that's displayed as part of the system settings.
 </p>
 <p>This guide covers the following:</p>
 <ul>
@@ -70,29 +70,22 @@
     <strong>Figure 1.</strong> The life cycle of an IME.
 </p>
 <p>
-    The following sections describe how to implement the UI and code associated
-with an IME that
+    The following sections describe how to implement the UI and code associated with an IME that
     follows this lifecycle.
 </p>
 <h2 id="DefiningIME">Declaring IME Components in the Manifest</h2>
 <p>
-    In the Android system, an IME is an Android application that contains a
-special IME service.
-    The application's manifest file must declare the service, request the
-necessary permissions,
-    provide an intent filter that matches the action
-<code>action.view.InputMethod</code>, and
-    provide metadata that defines characteristics of the IME. In addition, to
-provide a settings
-    interface that allows the user to modify the behavior of the IME, you can
-define a "settings"
+    In the Android system, an IME is an Android application that contains a special IME service.
+    The application's manifest file must declare the service, request the necessary permissions,
+    provide an intent filter that matches the action <code>action.view.InputMethod</code>, and
+    provide metadata that defines characteristics of the IME. In addition, to provide a settings
+    interface that allows the user to modify the behavior of the IME, you can define a "settings"
     activity that can be launched from System Settings.
 </p>
 <p>
     The following snippet declares an IME service. It requests the permission
-{@link android.Manifest.permission#BIND_INPUT_METHOD} to allow the service to
-connect the IME to
-    the system, sets up an intent filter that matches the action
+    {@link android.Manifest.permission#BIND_INPUT_METHOD} to allow the service to connect the IME
+    to the system, sets up an intent filter that matches the action
     <code>android.view.InputMethod</code>, and defines metadata for the IME:
 </p>
 <pre>
@@ -108,10 +101,8 @@
     &lt;/service&gt;
 </pre>
 <p>
-    This next snippet declares the settings activity for the IME. It has an
-intent filter for
-    {@link android.content.Intent#ACTION_MAIN} that indicates this activity is
-the main entry point
+    This next snippet declares the settings activity for the IME. It has an intent filter for
+    {@link android.content.Intent#ACTION_MAIN} that indicates this activity is the main entry point
     for the IME application:</p>
 <pre>
     &lt;!-- Optional: an activity for controlling the IME settings --&gt;
@@ -127,23 +118,18 @@
 </p>
 <h2 id="IMEAPI">The Input Method API</h2>
 <p>
-    Classes specific to IMEs are found in the {@link android.inputmethodservice} and {@link android.view.inputmethod}
-    packages. The {@link android.view.KeyEvent} class is important for handling keyboard
-    characters.
+    Classes specific to IMEs are found in the {@link android.inputmethodservice} and
+    {@link android.view.inputmethod} packages. The {@link android.view.KeyEvent} class is
+    important for handling keyboard characters.
 </p>
 <p>
     The central part of an IME is a service component, a class that extends
-    {@link android.inputmethodservice.InputMethodService}. In addition to
-implementing the
-    normal service lifecycle, this class has callbacks for providing your IME's
-UI, handling user
-    input, and delivering text to the field that currently has focus. By
-default, the
-    {@link android.inputmethodservice.InputMethodService} class provides most
-of the implementation
-    for managing the state and visibility of the IME and communicating with the
-current
-    input field.
+    {@link android.inputmethodservice.InputMethodService}. In addition to implementing the
+    normal service lifecycle, this class has callbacks for providing your IME's UI, handling user
+    input, and delivering text to the field that currently has focus. By default, the
+    {@link android.inputmethodservice.InputMethodService} class provides most of the implementation
+    for managing the state and visibility of the IME and communicating with the current input
+    field.
 </p>
 <p>
     The following classes are also important:
@@ -152,45 +138,32 @@
     <dt>{@link android.view.inputmethod.BaseInputConnection}</dt>
     <dd>
         Defines the communication channel from an {@link android.view.inputmethod.InputMethod}
-        back to the application that is receiving its input. You use it to read
-text around the
-        cursor, commit text to the text box, and send raw key events to the
-application.
-        Applications should extend this class rather than implementing the base
-interface
+        back to the application that is receiving its input. You use it to read text around the
+        cursor, commit text to the text box, and send raw key events to the application.
+        Applications should extend this class rather than implementing the base interface
         {@link android.view.inputmethod.InputConnection}.
     </dd>
     <dt>{@link android.inputmethodservice.KeyboardView}</dt>
     <dd>
-        An extension of {@link android.view.View} that renders a keyboard and
-responds to user
+        An extension of {@link android.view.View} that renders a keyboard and responds to user
         input events. The keyboard layout is specified by an instance of
-        {@link android.inputmethodservice.Keyboard}, which you can define in an
-XML file.
+        {@link android.inputmethodservice.Keyboard}, which you can define in an XML file.
     </dd>
 </dl>
 <h2 id="IMEUI">Designing the Input Method UI</h2>
 <p>
-    There are two main visual elements for an IME: the <strong>input</strong>
-view and the
-    <strong>candidates</strong> view. You only have to implement the elements
-that are relevant to
+    There are two main visual elements for an IME: the <strong>input</strong> view and the
+    <strong>candidates</strong> view. You only have to implement the elements that are relevant to
     the input method you're designing.
 </p>
 <h3 id="InputView">Input view</h3>
 <p>
-    The input view is the UI where the user inputs text in the form of
-keyclicks, handwriting or
-    gestures. When the IME is displayed for the first time, the system calls
-the
-    {@link android.inputmethodservice.InputMethodService#onCreateInputView()}
-callback. In your
-    implementation of this method, you create the layout you want to display in
-the IME
-    window and return the layout to the system. This snippet is an example of
-implementing the
-    {@link android.inputmethodservice.InputMethodService#onCreateInputView()}
-method:
+    The input view is the UI where the user inputs text in the form of keyclicks, handwriting or
+    gestures. When the IME is displayed for the first time, the system calls the
+    {@link android.inputmethodservice.InputMethodService#onCreateInputView()} callback. In your
+    implementation of this method, you create the layout you want to display in the IME
+    window and return the layout to the system. This snippet is an example of implementing the
+    {@link android.inputmethodservice.InputMethodService#onCreateInputView()} method:
 <pre>
     &#64;Override
     public View onCreateInputView() {
@@ -215,17 +188,12 @@
 </p>
 <h3 id="CandidateView">Candidates view</h3>
 <p>
-    The candidates view is the UI where the IME displays potential word
-corrections or
+    The candidates view is the UI where the IME displays potential word corrections or
     suggestions for the user to select. In the IME lifecycle, the system calls
-    {@link android.inputmethodservice.InputMethodService#onCreateCandidatesView()} when
-it's ready
-    to display the candidates view. In your implementation of this method,
-return a layout that shows
-    word suggestions, or return null if you don’t want to show anything. A
-null response is the
-    default behavior, so you don’t have to implement this if you don’t
-provide suggestions.</p>
+    {@link android.inputmethodservice.InputMethodService#onCreateCandidatesView()} when it's ready
+    to display the candidates view. In your implementation of this method, return a layout that
+    shows word suggestions, or return null if you don’t want to show anything. A null response is
+    the default behavior, so you don’t have to implement this if you don’t provide suggestions.</p>
 <p>
     For an example implementation that provides user suggestions, see the
     <a href="https://android.googlesource.com/platform/development/+/master/samples/SoftKeyboard/">
@@ -237,32 +205,22 @@
 </p>
 <h4>Handling multiple screen sizes</h4>
 <p>
-    The UI for your IME must be able to scale for different screen sizes, and
-it also
-    must handle both landscape and portrait orientations. In non-fullscreen IME
-mode, leave
-    sufficient space for the application to show the text field and any
-associated context, so that
-    no more than half the screen is occupied by the IME. In fullscreen IME mode
-this is not an
+    The UI for your IME must be able to scale for different screen sizes, and it also
+    must handle both landscape and portrait orientations. In non-fullscreen IME mode, leave
+    sufficient space for the application to show the text field and any associated context, so that
+    no more than half the screen is occupied by the IME. In fullscreen IME mode this is not an
     issue.
 </p>
 <h4>Handling different input types</h4>
 <p>
-    Android text fields allow you to set a specific input type, such as free
-form text, numbers,
-    URLs, email addresses, and search strings. When you implement a new IME,
-you need to
-    detect the input type of each field and provide the appropriate interface
-for it. However, you
-    don't have to set up your IME to check that the user entered text
-valid for the
-    input type; that's the responsibility of the application that owns the text
-field.
+    Android text fields allow you to set a specific input type, such as free-form text, numbers,
+    URLs, email addresses, and search strings. When you implement a new IME, you need to detect
+    the input type of each field and provide the appropriate interface for it. However, you
+    don't have to set up your IME to check that the user entered text valid for the input type;
+    that's the responsibility of the application that owns the text field.
 </p>
 <p>
-    For example, here are screenshots of the interfaces that the Latin IME
-provided with the
+    For example, here are screenshots of the interfaces that the Latin IME provided with the
     Android platform provides for text and phone number inputs:
 </p>
 <img src="{@docRoot}resources/articles/images/inputmethod_text_type_screenshot.png" alt="" height="142" id="figure2" />
@@ -273,18 +231,14 @@
 <p>
     When an input field receives focus and your IME starts, the system calls
     {@link android.inputmethodservice.InputMethodService#onStartInputView(EditorInfo, boolean) onStartInputView()},
-    passing in an {@link android.view.inputmethod.EditorInfo} object that
-    contains details about the input type and other attributes of the text
-field. In this object,
-    the {@link android.view.inputmethod.EditorInfo#inputType} field contains
-the text field's input
+    passing in an {@link android.view.inputmethod.EditorInfo} object that contains details about
+    the input type and other attributes of the text field. In this object, the
+    {@link android.view.inputmethod.EditorInfo#inputType} field contains the text field's input
     type.
 </p>
 <p>
-    The {@link android.view.inputmethod.EditorInfo#inputType} field is an
-<code>int</code>
-    that contains bit patterns for various input type settings. To test it for
-the text field's
+    The {@link android.view.inputmethod.EditorInfo#inputType} field is an <code>int</code>
+    that contains bit patterns for various input type settings. To test it for the text field's
     input type, mask it with the constant {@link android.text.InputType#TYPE_MASK_CLASS}, like
     this:
 </p>
@@ -297,8 +251,7 @@
 <dl>
     <dt>{@link android.text.InputType#TYPE_CLASS_NUMBER}</dt>
     <dd>
-        A text field for entering numbers. As illustrated in the previous
-screen shot, the
+        A text field for entering numbers. As illustrated in the previous screen shot, the
         Latin IME displays a number pad for fields of this type.
     </dd>
     <dt>{@link android.text.InputType#TYPE_CLASS_DATETIME}</dt>
@@ -315,103 +268,86 @@
     </dd>
 </dl>
 <p>
-    These constants are described in more detail in the reference documentation
-for
+    These constants are described in more detail in the reference documentation for
     {@link android.text.InputType}.
 </p>
 <p>
-    The {@link android.view.inputmethod.EditorInfo#inputType} field can contain
-other bits that
+    The {@link android.view.inputmethod.EditorInfo#inputType} field can contain other bits that
     indicate a variant of the text field type, such as:
 </p>
 <dl>
     <dt>{@link android.text.InputType#TYPE_TEXT_VARIATION_PASSWORD}</dt>
     <dd>
-        A variant of {@link android.text.InputType#TYPE_CLASS_TEXT} for
-entering passwords. The
+        A variant of {@link android.text.InputType#TYPE_CLASS_TEXT} for entering passwords. The
         input method will display dingbats instead of the actual text.
     </dd>
     <dt>{@link android.text.InputType#TYPE_TEXT_VARIATION_URI}</dt>
     <dd>
-        A variant of {@link android.text.InputType#TYPE_CLASS_TEXT} for
-entering web URLs and
+        A variant of {@link android.text.InputType#TYPE_CLASS_TEXT} for entering web URLs and
         other Uniform Resource Identifiers (URIs).
     </dd>
     <dt>{@link android.text.InputType#TYPE_TEXT_FLAG_AUTO_COMPLETE}</dt>
     <dd>
-        A variant of {@link android.text.InputType#TYPE_CLASS_TEXT} for
-entering text that the
-        application "auto-completes" from a dictionary, search, or other
-facility.
+        A variant of {@link android.text.InputType#TYPE_CLASS_TEXT} for entering text that the
+        application "auto-completes" from a dictionary, search, or other facility.
     </dd>
 </dl>
 <p>
-    Remember to mask {@link android.view.inputmethod.EditorInfo#inputType} with
-the appropriate
-    constant when you test for these variants. The available mask constants are
-listed in the
+    Remember to mask {@link android.view.inputmethod.EditorInfo#inputType} with the appropriate
+    constant when you test for these variants. The available mask constants are listed in the
     reference documentation for {@link android.text.InputType}.
 </p>
 <p class="caution">
-    <strong>Caution:</strong> In your own IME, make sure you handle text
-correctly when you send it
-    to a password field. Hide the password in your UI both in the input view
-and in the candidates
-    view. Also remember that you shouldn't store passwords on a device. To
-learn more, see the <a href="{@docRoot}guide/practices/security.html">Designing for Security</a>
- guide.
+    <strong>Caution:</strong> In your own IME, make sure you handle text correctly when you send it
+    to a password field. Hide the password in your UI both in the input view and in the candidates
+    view. Also remember that you shouldn't store passwords on a device. To learn more, see the
+    <a href="{@docRoot}guide/practices/security.html">Designing for Security</a> guide.
 </p>
 <h2 id="SendText">Sending Text to the Application</h2>
 <p>
-    As the user inputs text with your IME, you can send text to the application
-by
-    sending individual key events or by editing the text around the cursor in
-the application's text
+    As the user inputs text with your IME, you can send text to the application by sending
+    individual key events or by editing the text around the cursor in the application's text
     field. In either case, you use an instance of {@link android.view.inputmethod.InputConnection}
     to deliver the text. To get this instance, call
     {@link android.inputmethodservice.InputMethodService#getCurrentInputConnection InputMethodService.getCurrentInputConnection()}.
 </p>
 <h3 id="EditingCursor">Editing the text around the cursor</h3>
 <p>
-    When you're handling the editing of existing text in a text field, some of
-the more useful
+    When you're handling the editing of existing text in a text field, some of the more useful
     methods in {@link android.view.inputmethod.BaseInputConnection} are:
 </p>
 <dl>
     <dt>
         {@link android.view.inputmethod.BaseInputConnection#getTextBeforeCursor(int, int) getTextBeforeCursor()}</dt>
     <dd>
-        Returns a {@link java.lang.CharSequence} containing the number of
-requested characters
+        Returns a {@link java.lang.CharSequence} containing the number of requested characters
         before the current cursor position.
     </dd>
     <dt>
         {@link android.view.inputmethod.BaseInputConnection#getTextAfterCursor(int, int) getTextAfterCursor()}
     </dt>
     <dd>
-        Returns a {@link java.lang.CharSequence} containing the number of
-requested characters following the current cursor position.
+        Returns a {@link java.lang.CharSequence} containing the number of requested characters
+        following the current cursor position.
     </dd>
     <dt>
         {@link android.view.inputmethod.BaseInputConnection#deleteSurroundingText(int, int) deleteSurroundingText()}
     </dt>
     <dd>
-        Deletes the specified number of characters before and following the
-current cursor
+        Deletes the specified number of characters before and following the current cursor
         position.
     </dd>
     <dt>
         {@link android.view.inputmethod.BaseInputConnection#commitText(CharSequence, int) commitText()}
     </dt>
     <dd>
-        Commit a {@link java.lang.CharSequence} to the text field and set a new
-cursor
+        Commit a {@link java.lang.CharSequence} to the text field and set a new cursor
         position.
     </dd>
 </dl>
 <p>
-    For example, the following snippet shows how to replace the four characters to
-the left of the cursor with the text "Hello!":
+    For example, the following snippet shows how to replace the four characters to the left of the
+    cursor with the text "Hello!":
 </p>
 <pre>
     InputConnection ic = getCurrentInputConnection();
@@ -424,12 +360,9 @@
 </pre>
 <h3 id="ComposeThenCommit">Composing text before committing</h3>
 <p>
-    If your IME does text prediction or requires multiple steps to compose a
-glyph or
-    word, you can show the progress in the text field until the user commits
-the word, and then you
-    can replace the partial composition with the completed text. You may give
-special treatment to
+    If your IME does text prediction or requires multiple steps to compose a glyph or
+    word, you can show the progress in the text field until the user commits the word, and then you
+    can replace the partial composition with the completed text. You may give special treatment to
     the text by adding a "span" to it when you pass it to
 {@link android.view.inputmethod.InputConnection#setComposingText setComposingText()}.
 </p>
@@ -465,14 +398,10 @@
 </p>
 <h3 id="HardwareKeyEvents">Intercepting hardware key events</h3>
 <p>
-    Even though the input method window doesn't have explicit focus, it
-receives hardware key
-    events first and can choose to consume them or forward them along to the
-application. For
-    example, you may want to consume the directional keys to navigate within
-your UI for candidate
-    selection during composition. You may also want to trap the back key to
-dismiss any popups
+    Even though the input method window doesn't have explicit focus, it receives hardware key
+    events first and can choose to consume them or forward them along to the application. For
+    example, you may want to consume the directional keys to navigate within your UI for candidate
+    selection during composition. You may also want to trap the back key to dismiss any popups
     originating from the input method window.</p>
 <p>
     To intercept hardware keys, override
@@ -483,45 +412,36 @@
     SoftKeyboard</a> sample app for an example.
 </p>
 <p>
-    Remember to call the <code>super()</code> method for keys you don't want to
-handle yourself.
+    Remember to call the <code>super()</code> method for keys you don't want to handle yourself.
 </p>
 <h2 id="IMESubTypes">Creating an IME Subtype</h2>
 <p>
-    Subtypes allow the IME to expose multiple input modes and languages
-supported by an IME. A subtype can represent:
+    Subtypes allow the IME to expose multiple input modes and languages supported by an IME. A
+    subtype can represent:
 </p>
 <ul>
     <li>A locale such as en_US or fr_FR</li>
     <li>An input mode such as voice, keyboard, or handwriting</li>
     <li>
-        Other input styles, forms, or properties specific to the IME, such as
-10-key or qwerty
+        Other input styles, forms, or properties specific to the IME, such as 10-key or qwerty
         keyboard layouts.
     </li>
 </ul>
 <p>
-    Basically, the mode can be any text such as "keyboard", "voice", and so
-forth. A subtype can also expose a combination of these.
+    Basically, the mode can be any text such as "keyboard", "voice", and so forth. A subtype can
+    also expose a combination of these.
 </p>
 
 <p>
-    Subtype information is used for an IME switcher dialog that's available
-from the notification
-    bar and also for IME settings. The information also allows the framework to
-bring up a
-    specific subtype of an IME directly. When you build an IME, use the subtype
-facility, because
-    it helps the user identify and switch between different IME languages and
-modes.
+    Subtype information is used for an IME switcher dialog that's available from the notification
+    bar and also for IME settings. The information also allows the framework to bring up a
+    specific subtype of an IME directly. When you build an IME, use the subtype facility, because
+    it helps the user identify and switch between different IME languages and modes.
 </p>
 <p>
-    You define subtypes in one of the input method's XML resource files, using
-the
-    <code>&lt;subtype&gt;</code> element. The following snippet defines an IME
-with two
-    subtypes: a keyboard subtype for the US English locale, and another
-keyboard subtype for the
+    You define subtypes in one of the input method's XML resource files, using the
+    <code>&lt;subtype&gt;</code> element. The following snippet defines an IME with two
+    subtypes: a keyboard subtype for the US English locale, and another keyboard subtype for the
     French language locale for France:
 </p>
 <pre>
@@ -546,10 +466,8 @@
 /&gt;
 </pre>
 <p>
-    To ensure that your subtypes are labeled correctly in the UI, use %s to get
-a subtype label
-    that is the same as the subtype’s locale label. This is demonstrated in
-the next two snippets.
+    To ensure that your subtypes are labeled correctly in the UI, use %s to get a subtype label
+    that is the same as the subtype’s locale label. This is demonstrated in the next two snippets.
     The first snippet shows part of the input method's XML file:
 </p>
 <pre>
@@ -560,10 +478,8 @@
         android:imeSubtypeMode="keyboard" /&gt;
 </pre>
 <p>
-    The next snippet is part of the IME's <code>strings.xml</code> file. The
-string
-    resource <code>label_subtype_generic</code>, which is used by the input
-method UI definition to
+    The next snippet is part of the IME's <code>strings.xml</code> file. The string
+    resource <code>label_subtype_generic</code>, which is used by the input method UI definition to
     set the subtype's label, is defined as:
 </p>
 <pre>
@@ -575,12 +491,9 @@
 </p>
 <h3 id="SubtypeProcessing">Choosing IME subtypes from the notification bar</h3>
 <p>
-    The Android system manages all subtypes exposed by all IMEs. IME subtypes
-are
-    treated as modes of the IME they belong to. In the notification bar, a user
-can select an
-    available subtype for the currently-set IME, as shown in the following
-screenshot:
+    The Android system manages all subtypes exposed by all IMEs. IME subtypes are
+    treated as modes of the IME they belong to. In the notification bar, a user can select an
+    available subtype for the currently-set IME, as shown in the following screenshot:
 </p>
 <img
 src="{@docRoot}resources/articles/images/inputmethod_subtype_notification.png"
@@ -599,9 +512,9 @@
 </p>
 <h3 id="SubtypeSettings">Choosing IME subtypes from System Settings</h3>
 <p>
-    A user can control how subtypes are used in the “Language &amp; input”
-settings panel in the
-    System Settings area. In the <a href="https://android.googlesource.com/platform/development/+/master/samples/SoftKeyboard/">
+    A user can control how subtypes are used in the “Language &amp; input” settings panel in the
+    System Settings area. In the
+    <a href="https://android.googlesource.com/platform/development/+/master/samples/SoftKeyboard/">
     SoftKeyboard</a> sample app, the file <code>InputMethodSettingsFragment.java</code> contains an
     implementation that facilitates a subtype enabler in the IME settings. Refer to the
     <a href="https://android.googlesource.com/platform/development/+/master/samples/SoftKeyboard/">
@@ -617,15 +530,14 @@
 
 <h2 id="Switching">Switching among IME Subtypes</h2>
 
-<p>You can allow users to switch easily among multiple IME subtypes by providing
-a switching key, such as the globe-shaped language icon, as part of the keyboard. Doing so greatly
-improves the keyboard's usability, and can help avoid user frustration.
+<p>You can allow users to switch easily among multiple IME subtypes by providing a switching key,
+such as the globe-shaped language icon, as part of the keyboard. Doing so greatly improves the
+keyboard's usability, and can help avoid user frustration.
 To enable such switching, perform the following steps:</p>
 <p>
 <ol>
-    <li>Declare <code>supportsSwitchingToNextInputMethod = "true"</code> in the
-input method's XML resource files. Your declaration
-    should look similar to the following snippet:
+    <li>Declare <code>supportsSwitchingToNextInputMethod = "true"</code> in the input method's XML
+    resource files. Your declaration should look similar to the following snippet:
     <pre>
 &lt;input-method xmlns:android="http://schemas.android.com/apk/res/android"
         android:settingsActivity="com.example.softkeyboard.Settings"
@@ -646,8 +558,7 @@
     <strong>Caution:</strong> Prior to Android 5.0 (API level 21),
 {@link android.view.inputmethod.InputMethodManager#switchToNextInputMethod switchToNextInputMethod()}
 is not aware of the <code>supportsSwitchingToNextInputMethod</code> attribute. If the user switches
-into an IME without a switching key, he or she may get stuck in that IME, unable to switch out of it
-easily.</p>
+into an IME without a switching key, he or she may get stuck in that IME, unable to switch out of it easily.</p>
 
 <p>
 
@@ -662,31 +573,23 @@
     Provide a way for users to set options directly from the IME's UI.
 </li>
 <li>
-    Because multiple IMEs may be installed on the device, provide a way for the
-user to switch to a
+    Because multiple IMEs may be installed on the device, provide a way for the user to switch to a
     different IME directly from the input method UI.
 </li>
 <li>
-    Bring up the IME's UI quickly. Preload or load on demand any large
-resources so that users
-    see the IME as soon as they tap on a text field. Cache resources and views
-for subsequent
+    Bring up the IME's UI quickly. Preload or load on demand any large resources so that users
+    see the IME as soon as they tap on a text field. Cache resources and views for subsequent
     invocations of the input method.
 </li>
 <li>
-    Conversely, you should release large memory allocations soon after the
-input method window is
-    hidden, so that applications can have sufficient memory to run. Consider
-using a delayed message
-    to release resources if the IME is in a hidden state for a few seconds.
+    Conversely, you should release large memory allocations soon after the input method window is
+    hidden, so that applications can have sufficient memory to run. Consider using a delayed
+    message to release resources if the IME is in a hidden state for a few seconds.
 </li>
 <li>
-    Make sure that users can enter as many characters as possible for the
-language or locale
-    associated with the IME. Remember that users may use punctuation in
-passwords or user
-    names, so your IME has to provide many different characters to allow users
-to enter a
+    Make sure that users can enter as many characters as possible for the language or locale
+    associated with the IME. Remember that users may use punctuation in passwords or user
+    names, so your IME has to provide many different characters to allow users to enter a
     password and get access to the device.
 </li>
 </ul>
\ No newline at end of file
diff --git a/docs/html/tools/testing/activity_testing.jd b/docs/html/tools/testing/activity_testing.jd
index 88ac9b2..8baa35d 100644
--- a/docs/html/tools/testing/activity_testing.jd
+++ b/docs/html/tools/testing/activity_testing.jd
@@ -242,7 +242,7 @@
     This changes when you run tests against the application. With instrumentation-based classes,
     you can invoke methods against the UI of the application under test. The other test classes
     don't allow this. To run an entire test method on the UI thread, you can annotate the thread
-    with <code>@UIThreadTest</code>. Notice that this will run <em>all</em> of the method statements
+    with <code>@UiThreadTest</code>. Notice that this will run <em>all</em> of the method statements
     on the UI thread.  Methods that do not interact with the UI are not allowed; for example, you
     can't invoke <code>Instrumentation.waitForIdleSync()</code>.
 </p>
diff --git a/docs/html/training/wearables/notifications/pages.jd b/docs/html/training/wearables/notifications/pages.jd
index d74c8ea..6315037 100644
--- a/docs/html/training/wearables/notifications/pages.jd
+++ b/docs/html/training/wearables/notifications/pages.jd
@@ -57,15 +57,14 @@
         .setStyle(secondPageStyle)
         .build();
 
-// Add second page with wearable extender and extend the main notification
-Notification twoPageNotification =
-        new WearableExtender()
-                .addPage(secondPageNotification)
-                .extend(notificationBuilder)
-                .build();
+// Extend the notification builder with the second page
+Notification notification = notificationBuilder
+        .extend(new NotificationCompat.WearableExtender()
+                .addPage(secondPageNotification))
+        .build();
 
 // Issue the notification
 notificationManager =
         NotificationManagerCompat.from(this);
-notificationManager.notify(notificationId, twoPageNotification);
+notificationManager.notify(notificationId, notification);
 </pre>
\ No newline at end of file
diff --git a/graphics/java/android/graphics/drawable/AnimatedRotateDrawable.java b/graphics/java/android/graphics/drawable/AnimatedRotateDrawable.java
index c2e93a7..d2799e1 100644
--- a/graphics/java/android/graphics/drawable/AnimatedRotateDrawable.java
+++ b/graphics/java/android/graphics/drawable/AnimatedRotateDrawable.java
@@ -16,6 +16,8 @@
 
 package android.graphics.drawable;
 
+import android.annotation.NonNull;
+import android.annotation.Nullable;
 import android.graphics.Canvas;
 import android.graphics.Rect;
 import android.graphics.ColorFilter;
@@ -41,6 +43,7 @@
  */
 public class AnimatedRotateDrawable extends Drawable implements Drawable.Callback, Runnable,
         Animatable {
+    private static final String TAG = "AnimatedRotateDrawable";
 
     private AnimatedRotateState mState;
     private boolean mMutated;
@@ -186,6 +189,11 @@
     }
 
     @Override
+    public boolean canApplyTheme() {
+        return (mState != null && mState.canApplyTheme()) || super.canApplyTheme();
+    }
+
+    @Override
     public void invalidateDrawable(Drawable who) {
         final Callback callback = getCallback();
         if (callback != null) {
@@ -254,67 +262,21 @@
     }
 
     @Override
-    public void inflate(Resources r, XmlPullParser parser, AttributeSet attrs, Theme theme)
+    public void inflate(@NonNull Resources r, @NonNull XmlPullParser parser,
+            @NonNull AttributeSet attrs, @Nullable Theme theme)
             throws XmlPullParserException, IOException {
-
         final TypedArray a = obtainAttributes(r, theme, attrs, R.styleable.AnimatedRotateDrawable);
-
         super.inflateWithAttributes(r, parser, a, R.styleable.AnimatedRotateDrawable_visible);
-
-        TypedValue tv = a.peekValue(R.styleable.AnimatedRotateDrawable_pivotX);
-        final boolean pivotXRel = tv.type == TypedValue.TYPE_FRACTION;
-        final float pivotX = pivotXRel ? tv.getFraction(1.0f, 1.0f) : tv.getFloat();
-
-        tv = a.peekValue(R.styleable.AnimatedRotateDrawable_pivotY);
-        final boolean pivotYRel = tv.type == TypedValue.TYPE_FRACTION;
-        final float pivotY = pivotYRel ? tv.getFraction(1.0f, 1.0f) : tv.getFloat();
-
-        setFramesCount(a.getInt(R.styleable.AnimatedRotateDrawable_framesCount, 12));
-        setFramesDuration(a.getInt(R.styleable.AnimatedRotateDrawable_frameDuration, 150));
-
-        final int res = a.getResourceId(R.styleable.AnimatedRotateDrawable_drawable, 0);
-        Drawable drawable = null;
-        if (res > 0) {
-            drawable = r.getDrawable(res, theme);
-        }
-
+        updateStateFromTypedArray(a);
         a.recycle();
 
-        int outerDepth = parser.getDepth();
-        int type;
-        while ((type = parser.next()) != XmlPullParser.END_DOCUMENT &&
-               (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {
-
-            if (type != XmlPullParser.START_TAG) {
-                continue;
-            }
-
-            if ((drawable = Drawable.createFromXmlInner(r, parser, attrs, theme)) == null) {
-                Log.w("drawable", "Bad element under <animated-rotate>: "
-                        + parser .getName());
-            }
-        }
-
-        if (drawable == null) {
-            Log.w("drawable", "No drawable specified for <animated-rotate>");
-        }
-
-        final AnimatedRotateState rotateState = mState;
-        rotateState.mDrawable = drawable;
-        rotateState.mPivotXRel = pivotXRel;
-        rotateState.mPivotX = pivotX;
-        rotateState.mPivotYRel = pivotYRel;
-        rotateState.mPivotY = pivotY;
+        inflateChildElements(r, parser, attrs, theme);
 
         init();
-
-        if (drawable != null) {
-            drawable.setCallback(this);
-        }
     }
 
     @Override
-    public void applyTheme(Theme t) {
+    public void applyTheme(@Nullable Theme t) {
         super.applyTheme(t);
 
         final AnimatedRotateState state = mState;
@@ -322,15 +284,91 @@
             return;
         }
 
-        if (state.mDrawable != null) {
+        if (state.mThemeAttrs != null) {
+            final TypedArray a = t.resolveAttributes(
+                    state.mThemeAttrs, R.styleable.AnimatedRotateDrawable);
+            try {
+                updateStateFromTypedArray(a);
+                verifyRequiredAttributes(a);
+            } catch (XmlPullParserException e) {
+                throw new RuntimeException(e);
+            } finally {
+                a.recycle();
+            }
+        }
+
+        if (state.mDrawable != null && state.mDrawable.canApplyTheme()) {
             state.mDrawable.applyTheme(t);
         }
+
+        init();
+    }
+
+    private void updateStateFromTypedArray(TypedArray a) {
+        final AnimatedRotateState state = mState;
+
+        // Account for any configuration changes.
+        state.mChangingConfigurations |= a.getChangingConfigurations();
+
+        // Extract the theme attributes, if any.
+        state.mThemeAttrs = a.extractThemeAttrs();
+
+        if (a.hasValue(R.styleable.AnimatedRotateDrawable_pivotX)) {
+            final TypedValue tv = a.peekValue(R.styleable.AnimatedRotateDrawable_pivotX);
+            state.mPivotXRel = tv.type == TypedValue.TYPE_FRACTION;
+            state.mPivotX = state.mPivotXRel ? tv.getFraction(1.0f, 1.0f) : tv.getFloat();
+        }
+
+        if (a.hasValue(R.styleable.AnimatedRotateDrawable_pivotY)) {
+            final TypedValue tv = a.peekValue(R.styleable.AnimatedRotateDrawable_pivotY);
+            state.mPivotYRel = tv.type == TypedValue.TYPE_FRACTION;
+            state.mPivotY = state.mPivotYRel ? tv.getFraction(1.0f, 1.0f) : tv.getFloat();
+        }
+
+        setFramesCount(a.getInt(
+                R.styleable.AnimatedRotateDrawable_framesCount, state.mFramesCount));
+        setFramesDuration(a.getInt(
+                R.styleable.AnimatedRotateDrawable_frameDuration, state.mFrameDuration));
+
+        final Drawable dr = a.getDrawable(R.styleable.AnimatedRotateDrawable_drawable);
+        if (dr != null) {
+            state.mDrawable = dr;
+            dr.setCallback(this);
+        }
     }
 
-    @Override
-    public boolean canApplyTheme() {
+    private void inflateChildElements(Resources r, XmlPullParser parser, AttributeSet attrs,
+            Theme theme) throws XmlPullParserException, IOException {
         final AnimatedRotateState state = mState;
-        return state != null && state.mDrawable != null && state.mDrawable.canApplyTheme();
+
+        Drawable dr = null;
+        int outerDepth = parser.getDepth();
+        int type;
+        while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
+                && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {
+            if (type != XmlPullParser.START_TAG) {
+                continue;
+            }
+
+            if ((dr = Drawable.createFromXmlInner(r, parser, attrs, theme)) == null) {
+                Log.w(TAG, "Bad element under <animated-rotate>: " + parser.getName());
+            }
+        }
+
+        if (dr != null) {
+            state.mDrawable = dr;
+            dr.setCallback(this);
+        }
+    }
+
+    private void verifyRequiredAttributes(TypedArray a) throws XmlPullParserException {
+        // If we're not waiting on a theme, verify required attributes.
+        if (mState.mDrawable == null && (mState.mThemeAttrs == null
+                || mState.mThemeAttrs[R.styleable.AnimatedRotateDrawable_drawable] == 0)) {
+            throw new XmlPullParserException(a.getPositionDescription()
+                    + ": <animated-rotate> tag requires a 'drawable' attribute or "
+                    + "child tag defining a drawable");
+        }
     }
 
     public void setFramesCount(int framesCount) {
@@ -362,15 +400,16 @@
 
     final static class AnimatedRotateState extends Drawable.ConstantState {
         Drawable mDrawable;
+        int[] mThemeAttrs;
 
         int mChangingConfigurations;
 
-        boolean mPivotXRel;
-        float mPivotX;
-        boolean mPivotYRel;
-        float mPivotY;
-        int mFrameDuration;
-        int mFramesCount;
+        boolean mPivotXRel = false;
+        float mPivotX = 0;
+        boolean mPivotYRel = false;
+        float mPivotY = 0;
+        int mFrameDuration = 150;
+        int mFramesCount = 12;
 
         private boolean mCanConstantState;
         private boolean mCheckedConstantState;
@@ -387,6 +426,7 @@
                 mDrawable.setLayoutDirection(orig.mDrawable.getLayoutDirection());
                 mDrawable.setBounds(orig.mDrawable.getBounds());
                 mDrawable.setLevel(orig.mDrawable.getLevel());
+                mThemeAttrs = orig.mThemeAttrs;
                 mPivotXRel = orig.mPivotXRel;
                 mPivotX = orig.mPivotX;
                 mPivotYRel = orig.mPivotYRel;
@@ -408,6 +448,12 @@
         }
 
         @Override
+        public boolean canApplyTheme() {
+            return mThemeAttrs != null || (mDrawable != null && mDrawable.canApplyTheme())
+                    || super.canApplyTheme();
+        }
+
+        @Override
         public int getChangingConfigurations() {
             return mChangingConfigurations;
         }
diff --git a/graphics/java/android/graphics/drawable/AnimatedStateListDrawable.java b/graphics/java/android/graphics/drawable/AnimatedStateListDrawable.java
index 849faec..5a3a617 100644
--- a/graphics/java/android/graphics/drawable/AnimatedStateListDrawable.java
+++ b/graphics/java/android/graphics/drawable/AnimatedStateListDrawable.java
@@ -347,24 +347,62 @@
             throws XmlPullParserException, IOException {
         final TypedArray a = obtainAttributes(
                 r, theme, attrs, R.styleable.AnimatedStateListDrawable);
-
         super.inflateWithAttributes(r, parser, a, R.styleable.AnimatedStateListDrawable_visible);
-
-        final StateListState stateListState = getStateListState();
-        stateListState.setVariablePadding(a.getBoolean(
-                R.styleable.AnimatedStateListDrawable_variablePadding, false));
-        stateListState.setConstantSize(a.getBoolean(
-                R.styleable.AnimatedStateListDrawable_constantSize, false));
-        stateListState.setEnterFadeDuration(a.getInt(
-                R.styleable.AnimatedStateListDrawable_enterFadeDuration, 0));
-        stateListState.setExitFadeDuration(a.getInt(
-                R.styleable.AnimatedStateListDrawable_exitFadeDuration, 0));
-
-        setDither(a.getBoolean(R.styleable.AnimatedStateListDrawable_dither, true));
-        setAutoMirrored(a.getBoolean(R.styleable.AnimatedStateListDrawable_autoMirrored, false));
-
+        updateStateFromTypedArray(a);
         a.recycle();
 
+        inflateChildElements(r, parser, attrs, theme);
+
+        init();
+    }
+
+    @Override
+    public void applyTheme(@Nullable Theme theme) {
+        super.applyTheme(theme);
+
+        final AnimatedStateListState state = mState;
+        if (state == null || state.mAnimThemeAttrs == null) {
+            return;
+        }
+
+        final TypedArray a = theme.resolveAttributes(
+                state.mAnimThemeAttrs, R.styleable.AnimatedRotateDrawable);
+        updateStateFromTypedArray(a);
+        a.recycle();
+
+        init();
+    }
+
+    private void updateStateFromTypedArray(TypedArray a) {
+        final AnimatedStateListState state = mState;
+
+        // Account for any configuration changes.
+        state.mChangingConfigurations |= a.getChangingConfigurations();
+
+        // Extract the theme attributes, if any.
+        state.mAnimThemeAttrs = a.extractThemeAttrs();
+
+        state.setVariablePadding(a.getBoolean(
+                R.styleable.AnimatedStateListDrawable_variablePadding, state.mVariablePadding));
+        state.setConstantSize(a.getBoolean(
+                R.styleable.AnimatedStateListDrawable_constantSize, state.mConstantSize));
+        state.setEnterFadeDuration(a.getInt(
+                R.styleable.AnimatedStateListDrawable_enterFadeDuration, state.mEnterFadeDuration));
+        state.setExitFadeDuration(a.getInt(
+                R.styleable.AnimatedStateListDrawable_exitFadeDuration, state.mExitFadeDuration));
+
+        setDither(a.getBoolean(
+                R.styleable.AnimatedStateListDrawable_dither, state.mDither));
+        setAutoMirrored(a.getBoolean(
+                R.styleable.AnimatedStateListDrawable_autoMirrored, state.mAutoMirrored));
+    }
+
+    private void init() {
+        onStateChange(getState());
+    }
+
+    private void inflateChildElements(Resources r, XmlPullParser parser, AttributeSet attrs,
+            Theme theme) throws XmlPullParserException, IOException {
         int type;
 
         final int innerDepth = parser.getDepth() + 1;
@@ -386,8 +424,6 @@
                 parseTransition(r, parser, attrs, theme);
             }
         }
-
-        onStateChange(getState());
     }
 
     private int parseTransition(@NonNull Resources r, @NonNull XmlPullParser parser,
@@ -507,6 +543,8 @@
         private static final int REVERSE_SHIFT = 32;
         private static final int REVERSE_MASK = 0x1;
 
+        int[] mAnimThemeAttrs;
+
         final LongSparseLongArray mTransitions;
         final SparseIntArray mStateIds;
 
@@ -515,6 +553,7 @@
             super(orig, owner, res);
 
             if (orig != null) {
+                mAnimThemeAttrs = orig.mAnimThemeAttrs;
                 mTransitions = orig.mTransitions.clone();
                 mStateIds = orig.mStateIds.clone();
             } else {
@@ -566,6 +605,11 @@
         }
 
         @Override
+        public boolean canApplyTheme() {
+            return mAnimThemeAttrs != null || super.canApplyTheme();
+        }
+
+        @Override
         public Drawable newDrawable() {
             return new AnimatedStateListDrawable(this, null);
         }
diff --git a/graphics/java/android/graphics/drawable/AnimatedVectorDrawable.java b/graphics/java/android/graphics/drawable/AnimatedVectorDrawable.java
index a904067..e65dbaf 100644
--- a/graphics/java/android/graphics/drawable/AnimatedVectorDrawable.java
+++ b/graphics/java/android/graphics/drawable/AnimatedVectorDrawable.java
@@ -316,9 +316,8 @@
 
     @Override
     public boolean canApplyTheme() {
-        return super.canApplyTheme() || mAnimatedVectorState != null
-                && mAnimatedVectorState.mVectorDrawable != null
-                && mAnimatedVectorState.mVectorDrawable.canApplyTheme();
+        return (mAnimatedVectorState != null && mAnimatedVectorState.canApplyTheme())
+                || super.canApplyTheme();
     }
 
     @Override
@@ -374,6 +373,12 @@
         }
 
         @Override
+        public boolean canApplyTheme() {
+            return (mVectorDrawable != null && mVectorDrawable.canApplyTheme())
+                    || super.canApplyTheme();
+        }
+
+        @Override
         public Drawable newDrawable() {
             return new AnimatedVectorDrawable(this, null);
         }
diff --git a/graphics/java/android/graphics/drawable/AnimationDrawable.java b/graphics/java/android/graphics/drawable/AnimationDrawable.java
index c730a20..a8b6c94 100644
--- a/graphics/java/android/graphics/drawable/AnimationDrawable.java
+++ b/graphics/java/android/graphics/drawable/AnimationDrawable.java
@@ -16,6 +16,8 @@
 
 package android.graphics.drawable;
 
+import com.android.internal.R;
+
 import java.io.IOException;
 
 import org.xmlpull.v1.XmlPullParser;
@@ -271,27 +273,25 @@
     @Override
     public void inflate(Resources r, XmlPullParser parser, AttributeSet attrs, Theme theme)
             throws XmlPullParserException, IOException {
-
-        TypedArray a = obtainAttributes(r, theme, attrs,
-                com.android.internal.R.styleable.AnimationDrawable);
-
-        super.inflateWithAttributes(r, parser, a,
-                com.android.internal.R.styleable.AnimationDrawable_visible);
-
-        mAnimationState.setVariablePadding(a.getBoolean(
-                com.android.internal.R.styleable.AnimationDrawable_variablePadding, false));
-
-        mAnimationState.mOneShot = a.getBoolean(
-                com.android.internal.R.styleable.AnimationDrawable_oneshot, false);
-
+        final TypedArray a = obtainAttributes(r, theme, attrs, R.styleable.AnimationDrawable);
+        super.inflateWithAttributes(r, parser, a, R.styleable.AnimationDrawable_visible);
+        updateStateFromTypedArray(a);
         a.recycle();
 
+        inflateChildElements(r, parser, attrs, theme);
+
+        setFrame(0, true, false);
+    }
+
+    private void inflateChildElements(Resources r, XmlPullParser parser, AttributeSet attrs,
+            Theme theme) throws XmlPullParserException, IOException {
+        TypedArray a;
         int type;
 
         final int innerDepth = parser.getDepth()+1;
         int depth;
-        while ((type=parser.next()) != XmlPullParser.END_DOCUMENT &&
-                ((depth = parser.getDepth()) >= innerDepth || type != XmlPullParser.END_TAG)) {
+        while ((type=parser.next()) != XmlPullParser.END_DOCUMENT
+                && ((depth = parser.getDepth()) >= innerDepth || type != XmlPullParser.END_TAG)) {
             if (type != XmlPullParser.START_TAG) {
                 continue;
             }
@@ -300,17 +300,15 @@
                 continue;
             }
 
-            a = obtainAttributes(
-                    r, theme, attrs, com.android.internal.R.styleable.AnimationDrawableItem);
-            int duration = a.getInt(
-                    com.android.internal.R.styleable.AnimationDrawableItem_duration, -1);
+            a = obtainAttributes(r, theme, attrs, R.styleable.AnimationDrawableItem);
+
+            final int duration = a.getInt(R.styleable.AnimationDrawableItem_duration, -1);
             if (duration < 0) {
-                throw new XmlPullParserException(
-                        parser.getPositionDescription()
+                throw new XmlPullParserException(parser.getPositionDescription()
                         + ": <item> tag requires a 'duration' attribute");
             }
-            int drawableRes = a.getResourceId(
-                    com.android.internal.R.styleable.AnimationDrawableItem_drawable, 0);
+
+            final int drawableRes = a.getResourceId(R.styleable.AnimationDrawableItem_drawable, 0);
 
             a.recycle();
 
@@ -322,9 +320,9 @@
                     // Empty
                 }
                 if (type != XmlPullParser.START_TAG) {
-                    throw new XmlPullParserException(parser.getPositionDescription() +
-                            ": <item> tag requires a 'drawable' attribute or child tag" +
-                            " defining a drawable");
+                    throw new XmlPullParserException(parser.getPositionDescription()
+                            + ": <item> tag requires a 'drawable' attribute or child tag"
+                            + " defining a drawable");
                 }
                 dr = Drawable.createFromXmlInner(r, parser, attrs, theme);
             }
@@ -334,8 +332,14 @@
                 dr.setCallback(this);
             }
         }
+    }
 
-        setFrame(0, true, false);
+    private void updateStateFromTypedArray(TypedArray a) {
+        mAnimationState.mVariablePadding = a.getBoolean(
+                R.styleable.AnimationDrawable_variablePadding, mAnimationState.mVariablePadding);
+
+        mAnimationState.mOneShot = a.getBoolean(
+                R.styleable.AnimationDrawable_oneshot, mAnimationState.mOneShot);
     }
 
     @Override
@@ -357,7 +361,7 @@
 
     private final static class AnimationState extends DrawableContainerState {
         private int[] mDurations;
-        private boolean mOneShot;
+        private boolean mOneShot = false;
 
         AnimationState(AnimationState orig, AnimationDrawable owner,
                 Resources res) {
diff --git a/graphics/java/android/graphics/drawable/ClipDrawable.java b/graphics/java/android/graphics/drawable/ClipDrawable.java
index 669cef2..e5b2b76 100644
--- a/graphics/java/android/graphics/drawable/ClipDrawable.java
+++ b/graphics/java/android/graphics/drawable/ClipDrawable.java
@@ -16,6 +16,8 @@
 
 package android.graphics.drawable;
 
+import com.android.internal.R;
+
 import org.xmlpull.v1.XmlPullParser;
 import org.xmlpull.v1.XmlPullParserException;
 
@@ -49,7 +51,7 @@
  * @attr ref android.R.styleable#ClipDrawable_drawable
  */
 public class ClipDrawable extends Drawable implements Drawable.Callback {
-    private ClipState mClipState;
+    private ClipState mState;
     private final Rect mTmpRect = new Rect();
 
     public static final int HORIZONTAL = 1;
@@ -67,9 +69,9 @@
     public ClipDrawable(Drawable drawable, int gravity, int orientation) {
         this(null, null);
 
-        mClipState.mDrawable = drawable;
-        mClipState.mGravity = gravity;
-        mClipState.mOrientation = orientation;
+        mState.mDrawable = drawable;
+        mState.mGravity = gravity;
+        mState.mOrientation = orientation;
 
         if (drawable != null) {
             drawable.setCallback(this);
@@ -81,19 +83,22 @@
             throws XmlPullParserException, IOException {
         super.inflate(r, parser, attrs, theme);
 
-        int type;
+        final TypedArray a = obtainAttributes(r, theme, attrs, R.styleable.ClipDrawable);
 
-        TypedArray a = obtainAttributes(
-                r, theme, attrs, com.android.internal.R.styleable.ClipDrawable);
+        // Reset mDrawable to preserve old multiple-inflate behavior. This is
+        // silly, but we have CTS tests that rely on it.
+        mState.mDrawable = null;
 
-        int orientation = a.getInt(
-                com.android.internal.R.styleable.ClipDrawable_clipOrientation,
-                HORIZONTAL);
-        int g = a.getInt(com.android.internal.R.styleable.ClipDrawable_gravity, Gravity.LEFT);
-        Drawable dr = a.getDrawable(com.android.internal.R.styleable.ClipDrawable_drawable);
-
+        updateStateFromTypedArray(a);
+        inflateChildElements(r, parser, attrs, theme);
+        verifyRequiredAttributes(a);
         a.recycle();
+    }
 
+    private void inflateChildElements(Resources r, XmlPullParser parser, AttributeSet attrs,
+            Theme theme) throws XmlPullParserException, IOException {
+        Drawable dr = null;
+        int type;
         final int outerDepth = parser.getDepth();
         while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
                 && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {
@@ -103,35 +108,68 @@
             dr = Drawable.createFromXmlInner(r, parser, attrs, theme);
         }
 
-        if (dr == null) {
-            throw new IllegalArgumentException("No drawable specified for <clip>");
+        if (dr != null) {
+            mState.mDrawable = dr;
+            dr.setCallback(this);
         }
+    }
 
-        mClipState.mDrawable = dr;
-        mClipState.mOrientation = orientation;
-        mClipState.mGravity = g;
+    private void verifyRequiredAttributes(TypedArray a) throws XmlPullParserException {
+        // If we're not waiting on a theme, verify required attributes.
+        if (mState.mDrawable == null && (mState.mThemeAttrs == null
+                || mState.mThemeAttrs[R.styleable.ClipDrawable_drawable] == 0)) {
+            throw new XmlPullParserException(a.getPositionDescription()
+                    + ": <clip> tag requires a 'drawable' attribute or "
+                    + "child tag defining a drawable");
+        }
+    }
 
-        dr.setCallback(this);
+    private void updateStateFromTypedArray(TypedArray a) {
+        final ClipState state = mState;
+
+        // Account for any configuration changes.
+        state.mChangingConfigurations |= a.getChangingConfigurations();
+
+        // Extract the theme attributes, if any.
+        state.mThemeAttrs = a.extractThemeAttrs();
+
+        state.mOrientation = a.getInt(R.styleable.ClipDrawable_clipOrientation, state.mOrientation);
+        state.mGravity = a.getInt(R.styleable.ClipDrawable_gravity, state.mGravity);
+
+        final Drawable dr = a.getDrawable(R.styleable.ClipDrawable_drawable);
+        if (dr != null) {
+            state.mDrawable = dr;
+            dr.setCallback(this);
+        }
     }
 
     @Override
     public void applyTheme(Theme t) {
         super.applyTheme(t);
 
-        final ClipState state = mClipState;
-        if (state == null) {
+        final ClipState state = mState;
+        if (state == null || state.mThemeAttrs == null) {
             return;
         }
 
-        if (state.mDrawable != null) {
+        final TypedArray a = t.resolveAttributes(state.mThemeAttrs, R.styleable.ClipDrawable);
+        try {
+            updateStateFromTypedArray(a);
+            verifyRequiredAttributes(a);
+        } catch (XmlPullParserException e) {
+            throw new RuntimeException(e);
+        } finally {
+            a.recycle();
+        }
+
+        if (state.mDrawable != null && state.mDrawable.canApplyTheme()) {
             state.mDrawable.applyTheme(t);
         }
     }
 
     @Override
     public boolean canApplyTheme() {
-        final ClipState state = mClipState;
-        return state != null && state.mDrawable != null && state.mDrawable.canApplyTheme();
+        return (mState != null && mState.canApplyTheme()) || super.canApplyTheme();
     }
 
     // overrides from Drawable.Callback
@@ -165,78 +203,78 @@
     @Override
     public int getChangingConfigurations() {
         return super.getChangingConfigurations()
-                | mClipState.mChangingConfigurations
-                | mClipState.mDrawable.getChangingConfigurations();
+                | mState.mChangingConfigurations
+                | mState.mDrawable.getChangingConfigurations();
     }
 
     @Override
     public boolean getPadding(Rect padding) {
         // XXX need to adjust padding!
-        return mClipState.mDrawable.getPadding(padding);
+        return mState.mDrawable.getPadding(padding);
     }
 
     @Override
     public boolean setVisible(boolean visible, boolean restart) {
-        mClipState.mDrawable.setVisible(visible, restart);
+        mState.mDrawable.setVisible(visible, restart);
         return super.setVisible(visible, restart);
     }
 
     @Override
     public void setAlpha(int alpha) {
-        mClipState.mDrawable.setAlpha(alpha);
+        mState.mDrawable.setAlpha(alpha);
     }
 
     @Override
     public int getAlpha() {
-        return mClipState.mDrawable.getAlpha();
+        return mState.mDrawable.getAlpha();
     }
 
     @Override
     public void setColorFilter(ColorFilter cf) {
-        mClipState.mDrawable.setColorFilter(cf);
+        mState.mDrawable.setColorFilter(cf);
     }
 
     @Override
     public void setTintList(ColorStateList tint) {
-        mClipState.mDrawable.setTintList(tint);
+        mState.mDrawable.setTintList(tint);
     }
 
     @Override
     public void setTintMode(Mode tintMode) {
-        mClipState.mDrawable.setTintMode(tintMode);
+        mState.mDrawable.setTintMode(tintMode);
     }
 
     @Override
     public int getOpacity() {
-        return mClipState.mDrawable.getOpacity();
+        return mState.mDrawable.getOpacity();
     }
 
     @Override
     public boolean isStateful() {
-        return mClipState.mDrawable.isStateful();
+        return mState.mDrawable.isStateful();
     }
 
     @Override
     protected boolean onStateChange(int[] state) {
-        return mClipState.mDrawable.setState(state);
+        return mState.mDrawable.setState(state);
     }
 
     @Override
     protected boolean onLevelChange(int level) {
-        mClipState.mDrawable.setLevel(level);
+        mState.mDrawable.setLevel(level);
         invalidateSelf();
         return true;
     }
 
     @Override
     protected void onBoundsChange(Rect bounds) {
-        mClipState.mDrawable.setBounds(bounds);
+        mState.mDrawable.setBounds(bounds);
     }
 
     @Override
     public void draw(Canvas canvas) {
 
-        if (mClipState.mDrawable.getLevel() == 0) {
+        if (mState.mDrawable.getLevel() == 0) {
             return;
         }
 
@@ -244,41 +282,41 @@
         final Rect bounds = getBounds();
         int level = getLevel();
         int w = bounds.width();
-        final int iw = 0; //mClipState.mDrawable.getIntrinsicWidth();
-        if ((mClipState.mOrientation & HORIZONTAL) != 0) {
+        final int iw = 0; //mState.mDrawable.getIntrinsicWidth();
+        if ((mState.mOrientation & HORIZONTAL) != 0) {
             w -= (w - iw) * (10000 - level) / 10000;
         }
         int h = bounds.height();
-        final int ih = 0; //mClipState.mDrawable.getIntrinsicHeight();
-        if ((mClipState.mOrientation & VERTICAL) != 0) {
+        final int ih = 0; //mState.mDrawable.getIntrinsicHeight();
+        if ((mState.mOrientation & VERTICAL) != 0) {
             h -= (h - ih) * (10000 - level) / 10000;
         }
         final int layoutDirection = getLayoutDirection();
-        Gravity.apply(mClipState.mGravity, w, h, bounds, r, layoutDirection);
+        Gravity.apply(mState.mGravity, w, h, bounds, r, layoutDirection);
 
         if (w > 0 && h > 0) {
             canvas.save();
             canvas.clipRect(r);
-            mClipState.mDrawable.draw(canvas);
+            mState.mDrawable.draw(canvas);
             canvas.restore();
         }
     }
 
     @Override
     public int getIntrinsicWidth() {
-        return mClipState.mDrawable.getIntrinsicWidth();
+        return mState.mDrawable.getIntrinsicWidth();
     }
 
     @Override
     public int getIntrinsicHeight() {
-        return mClipState.mDrawable.getIntrinsicHeight();
+        return mState.mDrawable.getIntrinsicHeight();
     }
 
     @Override
     public ConstantState getConstantState() {
-        if (mClipState.canConstantState()) {
-            mClipState.mChangingConfigurations = getChangingConfigurations();
-            return mClipState;
+        if (mState.canConstantState()) {
+            mState.mChangingConfigurations = getChangingConfigurations();
+            return mState;
         }
         return null;
     }
@@ -286,14 +324,14 @@
     /** @hide */
     @Override
     public void setLayoutDirection(int layoutDirection) {
-        mClipState.mDrawable.setLayoutDirection(layoutDirection);
+        mState.mDrawable.setLayoutDirection(layoutDirection);
         super.setLayoutDirection(layoutDirection);
     }
 
     @Override
     public Drawable mutate() {
         if (!mMutated && super.mutate() == this) {
-            mClipState.mDrawable.mutate();
+            mState.mDrawable.mutate();
             mMutated = true;
         }
         return this;
@@ -304,21 +342,26 @@
      */
     public void clearMutated() {
         super.clearMutated();
-        mClipState.mDrawable.clearMutated();
+        mState.mDrawable.clearMutated();
         mMutated = false;
     }
 
     final static class ClipState extends ConstantState {
-        Drawable mDrawable;
+        int[] mThemeAttrs;
         int mChangingConfigurations;
-        int mOrientation;
-        int mGravity;
+
+        Drawable mDrawable;
+
+        int mOrientation = HORIZONTAL;
+        int mGravity = Gravity.LEFT;
 
         private boolean mCheckedConstantState;
         private boolean mCanConstantState;
 
         ClipState(ClipState orig, ClipDrawable owner, Resources res) {
             if (orig != null) {
+                mThemeAttrs = orig.mThemeAttrs;
+                mChangingConfigurations = orig.mChangingConfigurations;
                 if (res != null) {
                     mDrawable = orig.mDrawable.getConstantState().newDrawable(res);
                 } else {
@@ -335,6 +378,12 @@
         }
 
         @Override
+        public boolean canApplyTheme() {
+            return mThemeAttrs != null || (mDrawable != null && mDrawable.canApplyTheme())
+                    || super.canApplyTheme();
+        }
+
+        @Override
         public Drawable newDrawable() {
             return new ClipDrawable(this, null);
         }
@@ -360,7 +409,7 @@
     }
 
     private ClipDrawable(ClipState state, Resources res) {
-        mClipState = new ClipState(state, this, res);
+        mState = new ClipState(state, this, res);
     }
 }
 
diff --git a/graphics/java/android/graphics/drawable/DrawableContainer.java b/graphics/java/android/graphics/drawable/DrawableContainer.java
index a903288..326490f 100644
--- a/graphics/java/android/graphics/drawable/DrawableContainer.java
+++ b/graphics/java/android/graphics/drawable/DrawableContainer.java
@@ -600,11 +600,11 @@
         Drawable[] mDrawables;
         int mNumChildren;
 
-        boolean mVariablePadding;
+        boolean mVariablePadding = false;
         boolean mPaddingChecked;
         Rect mConstantPadding;
 
-        boolean mConstantSize;
+        boolean mConstantSize = false;
         boolean mComputedConstantSize;
         int mConstantWidth;
         int mConstantHeight;
@@ -625,8 +625,8 @@
         boolean mMutated;
         int mLayoutDirection;
 
-        int mEnterFadeDuration;
-        int mExitFadeDuration;
+        int mEnterFadeDuration = 0;
+        int mExitFadeDuration = 0;
 
         boolean mAutoMirrored;
 
diff --git a/graphics/java/android/graphics/drawable/GradientDrawable.java b/graphics/java/android/graphics/drawable/GradientDrawable.java
index 47e0e46..1458238 100644
--- a/graphics/java/android/graphics/drawable/GradientDrawable.java
+++ b/graphics/java/android/graphics/drawable/GradientDrawable.java
@@ -1089,7 +1089,7 @@
 
     @Override
     public boolean canApplyTheme() {
-        return super.canApplyTheme() || mGradientState != null && mGradientState.canApplyTheme();
+        return (mGradientState != null && mGradientState.canApplyTheme()) || super.canApplyTheme();
     }
 
     private void applyThemeChildElements(Theme t) {
@@ -1632,7 +1632,7 @@
         public boolean canApplyTheme() {
             return mThemeAttrs != null || mAttrSize != null || mAttrGradient != null
                     || mAttrSolid != null || mAttrStroke != null || mAttrCorners != null
-                    || mAttrPadding != null;
+                    || mAttrPadding != null || super.canApplyTheme();
         }
 
         @Override
diff --git a/graphics/java/android/graphics/drawable/InsetDrawable.java b/graphics/java/android/graphics/drawable/InsetDrawable.java
index f1800e5..b88d9e6 100644
--- a/graphics/java/android/graphics/drawable/InsetDrawable.java
+++ b/graphics/java/android/graphics/drawable/InsetDrawable.java
@@ -55,7 +55,8 @@
 public class InsetDrawable extends Drawable implements Drawable.Callback {
     private final Rect mTmpRect = new Rect();
 
-    private InsetState mInsetState;
+    private final InsetState mState;
+
     private boolean mMutated;
 
     /*package*/ InsetDrawable() {
@@ -70,11 +71,11 @@
                          int insetRight, int insetBottom) {
         this(null, null);
 
-        mInsetState.mDrawable = drawable;
-        mInsetState.mInsetLeft = insetLeft;
-        mInsetState.mInsetTop = insetTop;
-        mInsetState.mInsetRight = insetRight;
-        mInsetState.mInsetBottom = insetBottom;
+        mState.mDrawable = drawable;
+        mState.mInsetLeft = insetLeft;
+        mState.mInsetTop = insetTop;
+        mState.mInsetRight = insetRight;
+        mState.mInsetBottom = insetBottom;
 
         if (drawable != null) {
             drawable.setCallback(this);
@@ -87,11 +88,20 @@
         final TypedArray a = obtainAttributes(r, theme, attrs, R.styleable.InsetDrawable);
         super.inflateWithAttributes(r, parser, a, R.styleable.InsetDrawable_visible);
 
-        mInsetState.mDrawable = null;
-        updateStateFromTypedArray(a);
+        // Reset mDrawable to preserve old multiple-inflate behavior. This is
+        // silly, but we have CTS tests that rely on it.
+        mState.mDrawable = null;
 
+        updateStateFromTypedArray(a);
+        inflateChildElements(r, parser, attrs, theme);
+        verifyRequiredAttributes(a);
+        a.recycle();
+    }
+
+    private void inflateChildElements(Resources r, XmlPullParser parser, AttributeSet attrs,
+            Theme theme) throws XmlPullParserException, IOException {
         // Load inner XML elements.
-        if (mInsetState.mDrawable == null) {
+        if (mState.mDrawable == null) {
             int type;
             while ((type=parser.next()) == XmlPullParser.TEXT) {
             }
@@ -102,26 +112,23 @@
                                 + "child tag defining a drawable");
             }
             final Drawable dr = Drawable.createFromXmlInner(r, parser, attrs, theme);
-            mInsetState.mDrawable = dr;
+            mState.mDrawable = dr;
             dr.setCallback(this);
         }
-
-        verifyRequiredAttributes(a);
-        a.recycle();
     }
 
     private void verifyRequiredAttributes(TypedArray a) throws XmlPullParserException {
         // If we're not waiting on a theme, verify required attributes.
-        if (mInsetState.mDrawable == null && (mInsetState.mThemeAttrs == null
-                || mInsetState.mThemeAttrs[R.styleable.InsetDrawable_drawable] == 0)) {
-            throw new XmlPullParserException(a.getPositionDescription() +
-                    ": <inset> tag requires a 'drawable' attribute or "
+        if (mState.mDrawable == null && (mState.mThemeAttrs == null
+                || mState.mThemeAttrs[R.styleable.InsetDrawable_drawable] == 0)) {
+            throw new XmlPullParserException(a.getPositionDescription()
+                    + ": <inset> tag requires a 'drawable' attribute or "
                     + "child tag defining a drawable");
         }
     }
 
     private void updateStateFromTypedArray(TypedArray a) throws XmlPullParserException {
-        final InsetState state = mInsetState;
+        final InsetState state = mState;
 
         // Account for any configuration changes.
         state.mChangingConfigurations |= a.getChangingConfigurations();
@@ -169,7 +176,7 @@
     public void applyTheme(Theme t) {
         super.applyTheme(t);
 
-        final InsetState state = mInsetState;
+        final InsetState state = mState;
         if (state == null) {
             return;
         }
@@ -193,7 +200,7 @@
 
     @Override
     public boolean canApplyTheme() {
-        return super.canApplyTheme() || mInsetState != null && mInsetState.canApplyTheme();
+        return (mState != null && mState.canApplyTheme()) || super.canApplyTheme();
     }
 
     @Override
@@ -222,112 +229,112 @@
 
     @Override
     public void draw(Canvas canvas) {
-        mInsetState.mDrawable.draw(canvas);
+        mState.mDrawable.draw(canvas);
     }
 
     @Override
     public int getChangingConfigurations() {
         return super.getChangingConfigurations()
-                | mInsetState.mChangingConfigurations
-                | mInsetState.mDrawable.getChangingConfigurations();
+                | mState.mChangingConfigurations
+                | mState.mDrawable.getChangingConfigurations();
     }
 
     @Override
     public boolean getPadding(Rect padding) {
-        boolean pad = mInsetState.mDrawable.getPadding(padding);
+        boolean pad = mState.mDrawable.getPadding(padding);
 
-        padding.left += mInsetState.mInsetLeft;
-        padding.right += mInsetState.mInsetRight;
-        padding.top += mInsetState.mInsetTop;
-        padding.bottom += mInsetState.mInsetBottom;
+        padding.left += mState.mInsetLeft;
+        padding.right += mState.mInsetRight;
+        padding.top += mState.mInsetTop;
+        padding.bottom += mState.mInsetBottom;
 
-        return pad || (mInsetState.mInsetLeft | mInsetState.mInsetRight |
-                mInsetState.mInsetTop | mInsetState.mInsetBottom) != 0;
+        return pad || (mState.mInsetLeft | mState.mInsetRight |
+                mState.mInsetTop | mState.mInsetBottom) != 0;
     }
 
     /** @hide */
     @Override
     public Insets getOpticalInsets() {
         final Insets contentInsets = super.getOpticalInsets();
-        return Insets.of(contentInsets.left + mInsetState.mInsetLeft,
-                contentInsets.top + mInsetState.mInsetTop,
-                contentInsets.right + mInsetState.mInsetRight,
-                contentInsets.bottom + mInsetState.mInsetBottom);
+        return Insets.of(contentInsets.left + mState.mInsetLeft,
+                contentInsets.top + mState.mInsetTop,
+                contentInsets.right + mState.mInsetRight,
+                contentInsets.bottom + mState.mInsetBottom);
     }
 
     @Override
     public void setHotspot(float x, float y) {
-        mInsetState.mDrawable.setHotspot(x, y);
+        mState.mDrawable.setHotspot(x, y);
     }
 
     @Override
     public void setHotspotBounds(int left, int top, int right, int bottom) {
-        mInsetState.mDrawable.setHotspotBounds(left, top, right, bottom);
+        mState.mDrawable.setHotspotBounds(left, top, right, bottom);
     }
 
     /** @hide */
     @Override
     public void getHotspotBounds(Rect outRect) {
-        mInsetState.mDrawable.getHotspotBounds(outRect);
+        mState.mDrawable.getHotspotBounds(outRect);
     }
 
     @Override
     public boolean setVisible(boolean visible, boolean restart) {
-        mInsetState.mDrawable.setVisible(visible, restart);
+        mState.mDrawable.setVisible(visible, restart);
         return super.setVisible(visible, restart);
     }
 
     @Override
     public void setAlpha(int alpha) {
-        mInsetState.mDrawable.setAlpha(alpha);
+        mState.mDrawable.setAlpha(alpha);
     }
 
     @Override
     public int getAlpha() {
-        return mInsetState.mDrawable.getAlpha();
+        return mState.mDrawable.getAlpha();
     }
 
     @Override
     public void setColorFilter(ColorFilter cf) {
-        mInsetState.mDrawable.setColorFilter(cf);
+        mState.mDrawable.setColorFilter(cf);
     }
 
     @Override
     public void setTintList(ColorStateList tint) {
-        mInsetState.mDrawable.setTintList(tint);
+        mState.mDrawable.setTintList(tint);
     }
 
     @Override
     public void setTintMode(Mode tintMode) {
-        mInsetState.mDrawable.setTintMode(tintMode);
+        mState.mDrawable.setTintMode(tintMode);
     }
 
     /** {@hide} */
     @Override
     public void setLayoutDirection(int layoutDirection) {
-        mInsetState.mDrawable.setLayoutDirection(layoutDirection);
+        mState.mDrawable.setLayoutDirection(layoutDirection);
     }
 
     @Override
     public int getOpacity() {
-        return mInsetState.mDrawable.getOpacity();
+        return mState.mDrawable.getOpacity();
     }
 
     @Override
     public boolean isStateful() {
-        return mInsetState.mDrawable.isStateful();
+        return mState.mDrawable.isStateful();
     }
 
     @Override
     protected boolean onStateChange(int[] state) {
-        boolean changed = mInsetState.mDrawable.setState(state);
+        boolean changed = mState.mDrawable.setState(state);
         onBoundsChange(getBounds());
         return changed;
     }
 
     @Override
     protected boolean onLevelChange(int level) {
-        return mInsetState.mDrawable.setLevel(level);
+        return mState.mDrawable.setLevel(level);
     }
 
     @Override
@@ -335,36 +342,36 @@
         final Rect r = mTmpRect;
         r.set(bounds);
 
-        r.left += mInsetState.mInsetLeft;
-        r.top += mInsetState.mInsetTop;
-        r.right -= mInsetState.mInsetRight;
-        r.bottom -= mInsetState.mInsetBottom;
+        r.left += mState.mInsetLeft;
+        r.top += mState.mInsetTop;
+        r.right -= mState.mInsetRight;
+        r.bottom -= mState.mInsetBottom;
 
-        mInsetState.mDrawable.setBounds(r.left, r.top, r.right, r.bottom);
+        mState.mDrawable.setBounds(r.left, r.top, r.right, r.bottom);
     }
 
     @Override
     public int getIntrinsicWidth() {
-        return mInsetState.mDrawable.getIntrinsicWidth()
-                + mInsetState.mInsetLeft + mInsetState.mInsetRight;
+        return mState.mDrawable.getIntrinsicWidth()
+                + mState.mInsetLeft + mState.mInsetRight;
     }
 
     @Override
     public int getIntrinsicHeight() {
-        return mInsetState.mDrawable.getIntrinsicHeight()
-                + mInsetState.mInsetTop + mInsetState.mInsetBottom;
+        return mState.mDrawable.getIntrinsicHeight()
+                + mState.mInsetTop + mState.mInsetBottom;
     }
 
     @Override
     public void getOutline(@NonNull Outline outline) {
-        mInsetState.mDrawable.getOutline(outline);
+        mState.mDrawable.getOutline(outline);
     }
 
     @Override
     public ConstantState getConstantState() {
-        if (mInsetState.canConstantState()) {
-            mInsetState.mChangingConfigurations = getChangingConfigurations();
-            return mInsetState;
+        if (mState.canConstantState()) {
+            mState.mChangingConfigurations = getChangingConfigurations();
+            return mState;
         }
         return null;
     }
@@ -372,7 +379,7 @@
     @Override
     public Drawable mutate() {
         if (!mMutated && super.mutate() == this) {
-            mInsetState.mDrawable.mutate();
+            mState.mDrawable.mutate();
             mMutated = true;
         }
         return this;
@@ -383,7 +390,7 @@
      */
     public void clearMutated() {
         super.clearMutated();
-        mInsetState.mDrawable.clearMutated();
+        mState.mDrawable.clearMutated();
         mMutated = false;
     }
 
@@ -391,7 +398,7 @@
      * Returns the drawable wrapped by this InsetDrawable. May be null.
      */
     public Drawable getDrawable() {
-        return mInsetState.mDrawable;
+        return mState.mDrawable;
     }
 
     final static class InsetState extends ConstantState {
@@ -400,13 +407,13 @@
 
         Drawable mDrawable;
 
-        int mInsetLeft;
-        int mInsetTop;
-        int mInsetRight;
-        int mInsetBottom;
+        int mInsetLeft = 0;
+        int mInsetTop = 0;
+        int mInsetRight = 0;
+        int mInsetBottom = 0;
 
-        boolean mCheckedConstantState;
-        boolean mCanConstantState;
+        private boolean mCheckedConstantState;
+        private boolean mCanConstantState;
 
         InsetState(InsetState orig, InsetDrawable owner, Resources res) {
             if (orig != null) {
@@ -430,6 +437,12 @@
         }
 
         @Override
+        public boolean canApplyTheme() {
+            return mThemeAttrs != null || (mDrawable != null && mDrawable.canApplyTheme())
+                    || super.canApplyTheme();
+        }
+
+        @Override
         public Drawable newDrawable() {
             return new InsetDrawable(this, null);
         }
@@ -444,12 +457,6 @@
             return mChangingConfigurations;
         }
 
-        @Override
-        public boolean canApplyTheme() {
-            return super.canApplyTheme() || mThemeAttrs != null
-                    || mDrawable != null && mDrawable.canApplyTheme();
-        }
-
         boolean canConstantState() {
             if (!mCheckedConstantState) {
                 mCanConstantState = mDrawable.getConstantState() != null;
@@ -461,7 +468,7 @@
     }
 
     private InsetDrawable(InsetState state, Resources res) {
-        mInsetState = new InsetState(state, this, res);
+        mState = new InsetState(state, this, res);
     }
 }
 
diff --git a/graphics/java/android/graphics/drawable/LayerDrawable.java b/graphics/java/android/graphics/drawable/LayerDrawable.java
index 5107e10..689d225 100644
--- a/graphics/java/android/graphics/drawable/LayerDrawable.java
+++ b/graphics/java/android/graphics/drawable/LayerDrawable.java
@@ -275,7 +275,7 @@
 
     @Override
     public boolean canApplyTheme() {
-        return super.canApplyTheme() || mLayerState != null && mLayerState.canApplyTheme();
+        return (mLayerState != null && mLayerState.canApplyTheme()) || super.canApplyTheme();
     }
 
     /**
@@ -1020,7 +1020,7 @@
 
         @Override
         public boolean canApplyTheme() {
-            if (mThemeAttrs != null) {
+            if (mThemeAttrs != null || super.canApplyTheme()) {
                 return true;
             }
 
diff --git a/graphics/java/android/graphics/drawable/RippleDrawable.java b/graphics/java/android/graphics/drawable/RippleDrawable.java
index 316139b..e658279 100644
--- a/graphics/java/android/graphics/drawable/RippleDrawable.java
+++ b/graphics/java/android/graphics/drawable/RippleDrawable.java
@@ -473,7 +473,7 @@
 
     @Override
     public boolean canApplyTheme() {
-        return super.canApplyTheme() || mState != null && mState.canApplyTheme();
+        return (mState != null && mState.canApplyTheme()) || super.canApplyTheme();
     }
 
     @Override
diff --git a/graphics/java/android/graphics/drawable/RotateDrawable.java b/graphics/java/android/graphics/drawable/RotateDrawable.java
index 3f75bc3..3304b33 100644
--- a/graphics/java/android/graphics/drawable/RotateDrawable.java
+++ b/graphics/java/android/graphics/drawable/RotateDrawable.java
@@ -31,7 +31,6 @@
 import android.content.res.Resources.Theme;
 import android.util.TypedValue;
 import android.util.AttributeSet;
-import android.util.Log;
 
 import java.io.IOException;
 
@@ -314,6 +313,11 @@
     }
 
     @Override
+    public boolean canApplyTheme() {
+        return (mState != null && mState.canApplyTheme()) || super.canApplyTheme();
+    }
+
+    @Override
     public void invalidateDrawable(Drawable who) {
         final Callback callback = getCallback();
         if (callback != null) {
@@ -401,80 +405,17 @@
     @Override
     public void inflate(Resources r, XmlPullParser parser, AttributeSet attrs, Theme theme)
             throws XmlPullParserException, IOException {
-        final TypedArray a = obtainAttributes(r, theme, attrs,
-                com.android.internal.R.styleable.RotateDrawable);
+        final TypedArray a = obtainAttributes(r, theme, attrs, R.styleable.RotateDrawable);
+        super.inflateWithAttributes(r, parser, a, R.styleable.RotateDrawable_visible);
 
-        super.inflateWithAttributes(r, parser, a,
-                com.android.internal.R.styleable.RotateDrawable_visible);
+        // Reset mDrawable to preserve old multiple-inflate behavior. This is
+        // silly, but we have CTS tests that rely on it.
+        mState.mDrawable = null;
 
-        TypedValue tv = a.peekValue(com.android.internal.R.styleable.RotateDrawable_pivotX);
-        final boolean pivotXRel;
-        final float pivotX;
-        if (tv == null) {
-            pivotXRel = true;
-            pivotX = 0.5f;
-        } else {
-            pivotXRel = tv.type == TypedValue.TYPE_FRACTION;
-            pivotX = pivotXRel ? tv.getFraction(1.0f, 1.0f) : tv.getFloat();
-        }
-
-        tv = a.peekValue(com.android.internal.R.styleable.RotateDrawable_pivotY);
-        final boolean pivotYRel;
-        final float pivotY;
-        if (tv == null) {
-            pivotYRel = true;
-            pivotY = 0.5f;
-        } else {
-            pivotYRel = tv.type == TypedValue.TYPE_FRACTION;
-            pivotY = pivotYRel ? tv.getFraction(1.0f, 1.0f) : tv.getFloat();
-        }
-
-        final float fromDegrees = a.getFloat(
-                com.android.internal.R.styleable.RotateDrawable_fromDegrees, 0.0f);
-        final float toDegrees = a.getFloat(
-                com.android.internal.R.styleable.RotateDrawable_toDegrees, 360.0f);
-
-        final int res = a.getResourceId(
-                com.android.internal.R.styleable.RotateDrawable_drawable, 0);
-        Drawable drawable = null;
-        if (res > 0) {
-            drawable = r.getDrawable(res, theme);
-        }
-
+        updateStateFromTypedArray(a);
+        inflateChildElements(r, parser, attrs, theme);
+        verifyRequiredAttributes(a);
         a.recycle();
-
-        final int outerDepth = parser.getDepth();
-        int type;
-        while ((type = parser.next()) != XmlPullParser.END_DOCUMENT &&
-               (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {
-
-            if (type != XmlPullParser.START_TAG) {
-                continue;
-            }
-
-            if ((drawable = Drawable.createFromXmlInner(r, parser, attrs, theme)) == null) {
-                Log.w("drawable", "Bad element under <rotate>: "
-                        + parser .getName());
-            }
-        }
-
-        if (drawable == null) {
-            Log.w("drawable", "No drawable specified for <rotate>");
-        }
-
-        final RotateState st = mState;
-        st.mDrawable = drawable;
-        st.mPivotXRel = pivotXRel;
-        st.mPivotX = pivotX;
-        st.mPivotYRel = pivotYRel;
-        st.mPivotY = pivotY;
-        st.mFromDegrees = fromDegrees;
-        st.mCurrentDegrees = fromDegrees;
-        st.mToDegrees = toDegrees;
-
-        if (drawable != null) {
-            drawable.setCallback(this);
-        }
     }
 
     @Override
@@ -486,15 +427,82 @@
             return;
         }
 
-        if (state.mDrawable != null) {
+        if (state.mThemeAttrs != null) {
+            final TypedArray a = t.resolveAttributes(state.mThemeAttrs, R.styleable.RotateDrawable);
+            try {
+                updateStateFromTypedArray(a);
+                verifyRequiredAttributes(a);
+            } catch (XmlPullParserException e) {
+                throw new RuntimeException(e);
+            } finally {
+                a.recycle();
+            }
+        }
+
+        if (state.mDrawable != null && state.mDrawable.canApplyTheme()) {
             state.mDrawable.applyTheme(t);
         }
+
+    }
+
+    private void inflateChildElements(Resources r, XmlPullParser parser, AttributeSet attrs,
+            Theme theme) throws XmlPullParserException, IOException {
+        Drawable dr = null;
+        int type;
+        final int outerDepth = parser.getDepth();
+        while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
+                && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {
+            if (type != XmlPullParser.START_TAG) {
+                continue;
+            }
+            dr = Drawable.createFromXmlInner(r, parser, attrs, theme);
+        }
+
+        if (dr != null) {
+            mState.mDrawable = dr;
+            dr.setCallback(this);
+        }
     }
 
-    @Override
-    public boolean canApplyTheme() {
+    private void verifyRequiredAttributes(TypedArray a) throws XmlPullParserException {
+        // If we're not waiting on a theme, verify required attributes.
+        if (mState.mDrawable == null && (mState.mThemeAttrs == null
+                || mState.mThemeAttrs[R.styleable.ScaleDrawable_drawable] == 0)) {
+            throw new XmlPullParserException(a.getPositionDescription()
+                    + ": <rotate> tag requires a 'drawable' attribute or "
+                    + "child tag defining a drawable");
+        }
+    }
+
+    private void updateStateFromTypedArray(TypedArray a) {
         final RotateState state = mState;
-        return state != null && state.mDrawable != null && state.mDrawable.canApplyTheme();
+
+        // Account for any configuration changes.
+        state.mChangingConfigurations |= a.getChangingConfigurations();
+
+        // Extract the theme attributes, if any.
+        state.mThemeAttrs = a.extractThemeAttrs();
+
+        if (a.hasValue(R.styleable.RotateDrawable_pivotX)) {
+            final TypedValue tv = a.peekValue(R.styleable.RotateDrawable_pivotX);
+            state.mPivotXRel = tv.type == TypedValue.TYPE_FRACTION;
+            state.mPivotX = state.mPivotXRel ? tv.getFraction(1.0f, 1.0f) : tv.getFloat();
+        }
+
+        if (a.hasValue(R.styleable.RotateDrawable_pivotY)) {
+            final TypedValue tv = a.peekValue(R.styleable.RotateDrawable_pivotY);
+            state.mPivotYRel = tv.type == TypedValue.TYPE_FRACTION;
+            state.mPivotY = state.mPivotYRel ? tv.getFraction(1.0f, 1.0f) : tv.getFloat();
+        }
+
+        state.mFromDegrees = a.getFloat(R.styleable.RotateDrawable_fromDegrees, state.mFromDegrees);
+        state.mToDegrees = a.getFloat(R.styleable.RotateDrawable_toDegrees, state.mToDegrees);
+
+        final Drawable dr = a.getDrawable(R.styleable.RotateDrawable_drawable);
+        if (dr != null) {
+            state.mDrawable = dr;
+            dr.setCallback(this);
+        }
     }
 
     @Override
@@ -521,25 +529,28 @@
      * rotations at the same time.
      */
     final static class RotateState extends Drawable.ConstantState {
-        Drawable mDrawable;
-
+        int[] mThemeAttrs;
         int mChangingConfigurations;
 
-        boolean mPivotXRel;
-        float mPivotX;
-        boolean mPivotYRel;
-        float mPivotY;
+        Drawable mDrawable;
 
-        float mFromDegrees;
-        float mToDegrees;
+        boolean mPivotXRel = true;
+        float mPivotX = 0.5f;
+        boolean mPivotYRel = true;
+        float mPivotY = 0.5f;
 
-        float mCurrentDegrees;
+        float mFromDegrees = 0.0f;
+        float mToDegrees = 360.0f;
 
-        private boolean mCanConstantState;
+        float mCurrentDegrees = 0.0f;
+
         private boolean mCheckedConstantState;
+        private boolean mCanConstantState;
 
-        public RotateState(RotateState orig, RotateDrawable owner, Resources res) {
+        RotateState(RotateState orig, RotateDrawable owner, Resources res) {
             if (orig != null) {
+                mThemeAttrs = orig.mThemeAttrs;
+                mChangingConfigurations = orig.mChangingConfigurations;
                 if (res != null) {
                     mDrawable = orig.mDrawable.getConstantState().newDrawable(res);
                 } else {
@@ -553,13 +564,20 @@
                 mPivotX = orig.mPivotX;
                 mPivotYRel = orig.mPivotYRel;
                 mPivotY = orig.mPivotY;
-                mFromDegrees = mCurrentDegrees = orig.mFromDegrees;
+                mFromDegrees = orig.mFromDegrees;
                 mToDegrees = orig.mToDegrees;
-                mCanConstantState = mCheckedConstantState = true;
+                mCurrentDegrees = orig.mCurrentDegrees;
+                mCheckedConstantState = mCanConstantState = true;
             }
         }
 
         @Override
+        public boolean canApplyTheme() {
+            return mThemeAttrs != null || (mDrawable != null && mDrawable.canApplyTheme())
+                    || super.canApplyTheme();
+        }
+
+        @Override
         public Drawable newDrawable() {
             return new RotateDrawable(this, null);
         }
diff --git a/graphics/java/android/graphics/drawable/ScaleDrawable.java b/graphics/java/android/graphics/drawable/ScaleDrawable.java
index 9a5b8fb..35ef76f 100644
--- a/graphics/java/android/graphics/drawable/ScaleDrawable.java
+++ b/graphics/java/android/graphics/drawable/ScaleDrawable.java
@@ -16,6 +16,8 @@
 
 package android.graphics.drawable;
 
+import com.android.internal.R;
+
 import org.xmlpull.v1.XmlPullParser;
 import org.xmlpull.v1.XmlPullParserException;
 
@@ -47,7 +49,7 @@
  * @attr ref android.R.styleable#ScaleDrawable_drawable
  */
 public class ScaleDrawable extends Drawable implements Drawable.Callback {
-    private ScaleState mScaleState;
+    private ScaleState mState;
     private boolean mMutated;
     private final Rect mTmpRect = new Rect();
 
@@ -58,10 +60,10 @@
     public ScaleDrawable(Drawable drawable, int gravity, float scaleWidth, float scaleHeight) {
         this(null, null);
 
-        mScaleState.mDrawable = drawable;
-        mScaleState.mGravity = gravity;
-        mScaleState.mScaleWidth = scaleWidth;
-        mScaleState.mScaleHeight = scaleHeight;
+        mState.mDrawable = drawable;
+        mState.mGravity = gravity;
+        mState.mScaleWidth = scaleWidth;
+        mState.mScaleHeight = scaleHeight;
 
         if (drawable != null) {
             drawable.setCallback(this);
@@ -72,18 +74,18 @@
      * Returns the drawable scaled by this ScaleDrawable.
      */
     public Drawable getDrawable() {
-        return mScaleState.mDrawable;
+        return mState.mDrawable;
     }
 
-    private static float getPercent(TypedArray a, int name) {
-        String s = a.getString(name);
+    private static float getPercent(TypedArray a, int name, float defaultValue) {
+        final String s = a.getString(name);
         if (s != null) {
             if (s.endsWith("%")) {
                 String f = s.substring(0, s.length() - 1);
                 return Float.parseFloat(f) / 100.0f;
             }
         }
-        return -1;
+        return defaultValue;
     }
 
     @Override
@@ -91,20 +93,48 @@
             throws XmlPullParserException, IOException {
         super.inflate(r, parser, attrs, theme);
 
-        int type;
+        final TypedArray a = obtainAttributes(r, theme, attrs, R.styleable.ScaleDrawable);
 
-        TypedArray a = obtainAttributes(
-                r, theme, attrs, com.android.internal.R.styleable.ScaleDrawable);
+        // Reset mDrawable to preserve old multiple-inflate behavior. This is
+        // silly, but we have CTS tests that rely on it.
+        mState.mDrawable = null;
 
-        float sw = getPercent(a, com.android.internal.R.styleable.ScaleDrawable_scaleWidth);
-        float sh = getPercent(a, com.android.internal.R.styleable.ScaleDrawable_scaleHeight);
-        int g = a.getInt(com.android.internal.R.styleable.ScaleDrawable_scaleGravity, Gravity.LEFT);
-        boolean min = a.getBoolean(
-                com.android.internal.R.styleable.ScaleDrawable_useIntrinsicSizeAsMinimum, false);
-        Drawable dr = a.getDrawable(com.android.internal.R.styleable.ScaleDrawable_drawable);
-
+        updateStateFromTypedArray(a);
+        inflateChildElements(r, parser, attrs, theme);
+        verifyRequiredAttributes(a);
         a.recycle();
+    }
 
+    @Override
+    public void applyTheme(Theme t) {
+        super.applyTheme(t);
+
+        final ScaleState state = mState;
+        if (state == null) {
+            return;
+        }
+
+        if (state.mThemeAttrs != null) {
+            final TypedArray a = t.resolveAttributes(state.mThemeAttrs, R.styleable.ScaleDrawable);
+            try {
+                updateStateFromTypedArray(a);
+                verifyRequiredAttributes(a);
+            } catch (XmlPullParserException e) {
+                throw new RuntimeException(e);
+            } finally {
+                a.recycle();
+            }
+        }
+
+        if (state.mDrawable != null && state.mDrawable.canApplyTheme()) {
+            state.mDrawable.applyTheme(t);
+        }
+    }
+
+    private void inflateChildElements(Resources r, XmlPullParser parser, AttributeSet attrs,
+            Theme theme) throws XmlPullParserException, IOException {
+        Drawable dr = null;
+        int type;
         final int outerDepth = parser.getDepth();
         while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
                 && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {
@@ -114,38 +144,49 @@
             dr = Drawable.createFromXmlInner(r, parser, attrs, theme);
         }
 
-        if (dr == null) {
-            throw new IllegalArgumentException("No drawable specified for <scale>");
-        }
-
-        mScaleState.mDrawable = dr;
-        mScaleState.mScaleWidth = sw;
-        mScaleState.mScaleHeight = sh;
-        mScaleState.mGravity = g;
-        mScaleState.mUseIntrinsicSizeAsMin = min;
         if (dr != null) {
+            mState.mDrawable = dr;
+            dr.setCallback(this);
+        }
+    }
+
+    private void verifyRequiredAttributes(TypedArray a) throws XmlPullParserException {
+        // If we're not waiting on a theme, verify required attributes.
+        if (mState.mDrawable == null && (mState.mThemeAttrs == null
+                || mState.mThemeAttrs[R.styleable.ScaleDrawable_drawable] == 0)) {
+            throw new XmlPullParserException(a.getPositionDescription()
+                    + ": <scale> tag requires a 'drawable' attribute or "
+                    + "child tag defining a drawable");
+        }
+    }
+
+    private void updateStateFromTypedArray(TypedArray a) {
+        final ScaleState state = mState;
+
+        // Account for any configuration changes.
+        state.mChangingConfigurations |= a.getChangingConfigurations();
+
+        // Extract the theme attributes, if any.
+        state.mThemeAttrs = a.extractThemeAttrs();
+
+        state.mScaleWidth = getPercent(
+                a, R.styleable.ScaleDrawable_scaleWidth, state.mScaleWidth);
+        state.mScaleHeight = getPercent(
+                a, R.styleable.ScaleDrawable_scaleHeight, state.mScaleHeight);
+        state.mGravity = a.getInt(R.styleable.ScaleDrawable_scaleGravity, Gravity.LEFT);
+        state.mUseIntrinsicSizeAsMin = a.getBoolean(
+                R.styleable.ScaleDrawable_useIntrinsicSizeAsMinimum, false);
+
+        final Drawable dr = a.getDrawable(R.styleable.ScaleDrawable_drawable);
+        if (dr != null) {
+            state.mDrawable = dr;
             dr.setCallback(this);
         }
     }
 
     @Override
-    public void applyTheme(Theme t) {
-        super.applyTheme(t);
-
-        final ScaleState state = mScaleState;
-        if (state == null) {
-            return;
-        }
-
-        if (state.mDrawable != null) {
-            state.mDrawable.applyTheme(t);
-        }
-    }
-
-    @Override
     public boolean canApplyTheme() {
-        final ScaleState state = mScaleState;
-        return state != null && state.mDrawable != null && state.mDrawable.canApplyTheme();
+        return (mState != null && mState.canApplyTheme()) || super.canApplyTheme();
     }
 
     // overrides from Drawable.Callback
@@ -172,74 +213,74 @@
 
     @Override
     public void draw(Canvas canvas) {
-        if (mScaleState.mDrawable.getLevel() != 0)
-            mScaleState.mDrawable.draw(canvas);
+        if (mState.mDrawable.getLevel() != 0)
+            mState.mDrawable.draw(canvas);
     }
 
     @Override
     public int getChangingConfigurations() {
         return super.getChangingConfigurations()
-                | mScaleState.mChangingConfigurations
-                | mScaleState.mDrawable.getChangingConfigurations();
+                | mState.mChangingConfigurations
+                | mState.mDrawable.getChangingConfigurations();
     }
 
     @Override
     public boolean getPadding(Rect padding) {
         // XXX need to adjust padding!
-        return mScaleState.mDrawable.getPadding(padding);
+        return mState.mDrawable.getPadding(padding);
     }
 
     @Override
     public boolean setVisible(boolean visible, boolean restart) {
-        mScaleState.mDrawable.setVisible(visible, restart);
+        mState.mDrawable.setVisible(visible, restart);
         return super.setVisible(visible, restart);
     }
 
     @Override
     public void setAlpha(int alpha) {
-        mScaleState.mDrawable.setAlpha(alpha);
+        mState.mDrawable.setAlpha(alpha);
     }
 
     @Override
     public int getAlpha() {
-        return mScaleState.mDrawable.getAlpha();
+        return mState.mDrawable.getAlpha();
     }
 
     @Override
     public void setColorFilter(ColorFilter cf) {
-        mScaleState.mDrawable.setColorFilter(cf);
+        mState.mDrawable.setColorFilter(cf);
     }
 
     @Override
     public void setTintList(ColorStateList tint) {
-        mScaleState.mDrawable.setTintList(tint);
+        mState.mDrawable.setTintList(tint);
     }
 
     @Override
     public void setTintMode(Mode tintMode) {
-        mScaleState.mDrawable.setTintMode(tintMode);
+        mState.mDrawable.setTintMode(tintMode);
     }
 
     @Override
     public int getOpacity() {
-        return mScaleState.mDrawable.getOpacity();
+        return mState.mDrawable.getOpacity();
     }
 
     @Override
     public boolean isStateful() {
-        return mScaleState.mDrawable.isStateful();
+        return mState.mDrawable.isStateful();
     }
 
     @Override
     protected boolean onStateChange(int[] state) {
-        boolean changed = mScaleState.mDrawable.setState(state);
+        boolean changed = mState.mDrawable.setState(state);
         onBoundsChange(getBounds());
         return changed;
     }
 
     @Override
     protected boolean onLevelChange(int level) {
-        mScaleState.mDrawable.setLevel(level);
+        mState.mDrawable.setLevel(level);
         onBoundsChange(getBounds());
         invalidateSelf();
         return true;
@@ -248,41 +289,41 @@
     @Override
     protected void onBoundsChange(Rect bounds) {
         final Rect r = mTmpRect;
-        final boolean min = mScaleState.mUseIntrinsicSizeAsMin;
+        final boolean min = mState.mUseIntrinsicSizeAsMin;
         int level = getLevel();
         int w = bounds.width();
-        if (mScaleState.mScaleWidth > 0) {
-            final int iw = min ? mScaleState.mDrawable.getIntrinsicWidth() : 0;
-            w -= (int) ((w - iw) * (10000 - level) * mScaleState.mScaleWidth / 10000);
+        if (mState.mScaleWidth > 0) {
+            final int iw = min ? mState.mDrawable.getIntrinsicWidth() : 0;
+            w -= (int) ((w - iw) * (10000 - level) * mState.mScaleWidth / 10000);
         }
         int h = bounds.height();
-        if (mScaleState.mScaleHeight > 0) {
-            final int ih = min ? mScaleState.mDrawable.getIntrinsicHeight() : 0;
-            h -= (int) ((h - ih) * (10000 - level) * mScaleState.mScaleHeight / 10000);
+        if (mState.mScaleHeight > 0) {
+            final int ih = min ? mState.mDrawable.getIntrinsicHeight() : 0;
+            h -= (int) ((h - ih) * (10000 - level) * mState.mScaleHeight / 10000);
         }
         final int layoutDirection = getLayoutDirection();
-        Gravity.apply(mScaleState.mGravity, w, h, bounds, r, layoutDirection);
+        Gravity.apply(mState.mGravity, w, h, bounds, r, layoutDirection);
 
         if (w > 0 && h > 0) {
-            mScaleState.mDrawable.setBounds(r.left, r.top, r.right, r.bottom);
+            mState.mDrawable.setBounds(r.left, r.top, r.right, r.bottom);
         }
     }
 
     @Override
     public int getIntrinsicWidth() {
-        return mScaleState.mDrawable.getIntrinsicWidth();
+        return mState.mDrawable.getIntrinsicWidth();
     }
 
     @Override
     public int getIntrinsicHeight() {
-        return mScaleState.mDrawable.getIntrinsicHeight();
+        return mState.mDrawable.getIntrinsicHeight();
     }
 
     @Override
     public ConstantState getConstantState() {
-        if (mScaleState.canConstantState()) {
-            mScaleState.mChangingConfigurations = getChangingConfigurations();
-            return mScaleState;
+        if (mState.canConstantState()) {
+            mState.mChangingConfigurations = getChangingConfigurations();
+            return mState;
         }
         return null;
     }
@@ -290,7 +331,7 @@
     @Override
     public Drawable mutate() {
         if (!mMutated && super.mutate() == this) {
-            mScaleState.mDrawable.mutate();
+            mState.mDrawable.mutate();
             mMutated = true;
         }
         return this;
@@ -301,23 +342,28 @@
      */
     public void clearMutated() {
         super.clearMutated();
-        mScaleState.mDrawable.clearMutated();
+        mState.mDrawable.clearMutated();
         mMutated = false;
     }
 
     final static class ScaleState extends ConstantState {
-        Drawable mDrawable;
+        int[] mThemeAttrs;
         int mChangingConfigurations;
-        float mScaleWidth;
-        float mScaleHeight;
-        int mGravity;
-        boolean mUseIntrinsicSizeAsMin;
+
+        Drawable mDrawable;
+
+        float mScaleWidth = 1.0f;
+        float mScaleHeight = 1.0f;
+        int mGravity = Gravity.LEFT;
+        boolean mUseIntrinsicSizeAsMin = false;
 
         private boolean mCheckedConstantState;
         private boolean mCanConstantState;
 
         ScaleState(ScaleState orig, ScaleDrawable owner, Resources res) {
             if (orig != null) {
+                mThemeAttrs = orig.mThemeAttrs;
+                mChangingConfigurations = orig.mChangingConfigurations;
                 if (res != null) {
                     mDrawable = orig.mDrawable.getConstantState().newDrawable(res);
                 } else {
@@ -336,6 +382,12 @@
         }
 
         @Override
+        public boolean canApplyTheme() {
+            return mThemeAttrs != null || (mDrawable != null && mDrawable.canApplyTheme())
+                    || super.canApplyTheme();
+        }
+
+        @Override
         public Drawable newDrawable() {
             return new ScaleDrawable(this, null);
         }
@@ -361,7 +413,7 @@
     }
 
     private ScaleDrawable(ScaleState state, Resources res) {
-        mScaleState = new ScaleState(state, this, res);
+        mState = new ScaleState(state, this, res);
     }
 }
 
diff --git a/graphics/java/android/graphics/drawable/StateListDrawable.java b/graphics/java/android/graphics/drawable/StateListDrawable.java
index a299b3c..963943b 100644
--- a/graphics/java/android/graphics/drawable/StateListDrawable.java
+++ b/graphics/java/android/graphics/drawable/StateListDrawable.java
@@ -117,26 +117,48 @@
     @Override
     public void inflate(Resources r, XmlPullParser parser, AttributeSet attrs, Theme theme)
             throws XmlPullParserException, IOException {
-
         final TypedArray a = obtainAttributes(r, theme, attrs, R.styleable.StateListDrawable);
-
-        super.inflateWithAttributes(r, parser, a,
-                R.styleable.StateListDrawable_visible);
-
-        mStateListState.setVariablePadding(a.getBoolean(
-                R.styleable.StateListDrawable_variablePadding, false));
-        mStateListState.setConstantSize(a.getBoolean(
-                R.styleable.StateListDrawable_constantSize, false));
-        mStateListState.setEnterFadeDuration(a.getInt(
-                R.styleable.StateListDrawable_enterFadeDuration, 0));
-        mStateListState.setExitFadeDuration(a.getInt(
-                R.styleable.StateListDrawable_exitFadeDuration, 0));
-
-        setDither(a.getBoolean(R.styleable.StateListDrawable_dither, DEFAULT_DITHER));
-        setAutoMirrored(a.getBoolean(R.styleable.StateListDrawable_autoMirrored, false));
-
+        super.inflateWithAttributes(r, parser, a, R.styleable.StateListDrawable_visible);
+        updateStateFromTypedArray(a);
         a.recycle();
 
+        inflateChildElements(r, parser, attrs, theme);
+
+        onStateChange(getState());
+    }
+
+    /**
+     * Updates the constant state from the values in the typed array.
+     */
+    private void updateStateFromTypedArray(TypedArray a) {
+        final StateListState state = mStateListState;
+
+        // Account for any configuration changes.
+        state.mChangingConfigurations |= a.getChangingConfigurations();
+
+        // Extract the theme attributes, if any.
+        state.mThemeAttrs = a.extractThemeAttrs();
+
+        state.mVariablePadding = a.getBoolean(
+                R.styleable.StateListDrawable_variablePadding, state.mVariablePadding);
+        state.mConstantSize = a.getBoolean(
+                R.styleable.StateListDrawable_constantSize, state.mConstantSize);
+        state.mEnterFadeDuration = a.getInt(
+                R.styleable.StateListDrawable_enterFadeDuration, state.mEnterFadeDuration);
+        state.mExitFadeDuration = a.getInt(
+                R.styleable.StateListDrawable_exitFadeDuration, state.mExitFadeDuration);
+        state.mDither = a.getBoolean(
+                R.styleable.StateListDrawable_dither, state.mDither);
+        state.mAutoMirrored = a.getBoolean(
+                R.styleable.StateListDrawable_autoMirrored, state.mAutoMirrored);
+    }
+
+    /**
+     * Inflates child elements from XML.
+     */
+    private void inflateChildElements(Resources r, XmlPullParser parser, AttributeSet attrs,
+            Theme theme) throws XmlPullParserException, IOException {
+        final StateListState state = mStateListState;
         final int innerDepth = parser.getDepth() + 1;
         int type;
         int depth;
@@ -185,10 +207,8 @@
                 dr = Drawable.createFromXmlInner(r, parser, attrs, theme);
             }
 
-            mStateListState.addStateSet(states, dr);
+            state.addStateSet(states, dr);
         }
-
-        onStateChange(getState());
     }
 
     StateListState getStateListState() {
@@ -282,6 +302,7 @@
     }
 
     static class StateListState extends DrawableContainerState {
+        int[] mThemeAttrs;
         int[][] mStateSets;
 
         StateListState(StateListState orig, StateListDrawable owner, Resources res) {
@@ -298,7 +319,11 @@
                         mStateSets[i] = set.clone();
                     }
                 }
+
+                mThemeAttrs = orig.mThemeAttrs;
+                mStateSets = Arrays.copyOf(orig.mStateSets, orig.mStateSets.length);
             } else {
+                mThemeAttrs = null;
                 mStateSets = new int[getCapacity()][];
             }
         }
@@ -331,6 +356,11 @@
         }
 
         @Override
+        public boolean canApplyTheme() {
+            return mThemeAttrs != null || super.canApplyTheme();
+        }
+
+        @Override
         public void growArray(int oldSize, int newSize) {
             super.growArray(oldSize, newSize);
             final int[][] newStateSets = new int[newSize][];
diff --git a/graphics/java/android/graphics/drawable/VectorDrawable.java b/graphics/java/android/graphics/drawable/VectorDrawable.java
index 848fc53..8b0f635 100644
--- a/graphics/java/android/graphics/drawable/VectorDrawable.java
+++ b/graphics/java/android/graphics/drawable/VectorDrawable.java
@@ -361,7 +361,7 @@
 
     @Override
     public boolean canApplyTheme() {
-        return super.canApplyTheme() || mVectorState != null && mVectorState.canApplyTheme();
+        return (mVectorState != null && mVectorState.canApplyTheme()) || super.canApplyTheme();
     }
 
     @Override
@@ -750,8 +750,8 @@
 
         @Override
         public boolean canApplyTheme() {
-            return super.canApplyTheme() || mThemeAttrs != null
-                    || (mVPathRenderer != null && mVPathRenderer.canApplyTheme());
+            return mThemeAttrs != null || (mVPathRenderer != null && mVPathRenderer.canApplyTheme())
+                    || super.canApplyTheme();
         }
 
         public VectorDrawableState() {
diff --git a/graphics/java/android/graphics/pdf/PdfEditor.java b/graphics/java/android/graphics/pdf/PdfEditor.java
index 9837139..0b84d29 100644
--- a/graphics/java/android/graphics/pdf/PdfEditor.java
+++ b/graphics/java/android/graphics/pdf/PdfEditor.java
@@ -17,6 +17,10 @@
 package android.graphics.pdf;
 
 import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.graphics.Matrix;
+import android.graphics.Point;
+import android.graphics.Rect;
 import android.os.ParcelFileDescriptor;
 import android.system.ErrnoException;
 import android.system.OsConstants;
@@ -98,6 +102,109 @@
     }
 
     /**
+     * Sets a transformation and clip for a given page. The transformation matrix if
+     * non-null must be affine as per {@link android.graphics.Matrix#isAffine()}. If
+     * the clip is null, then no clipping is performed.
+     *
+     * @param pageIndex The page whose transform to set.
+     * @param transform The transformation to apply.
+     * @param clip The clip to apply.
+     */
+    public void setTransformAndClip(int pageIndex, @Nullable Matrix transform,
+            @Nullable Rect clip) {
+        throwIfClosed();
+        throwIfPageNotInDocument(pageIndex);
+        throwIfNotNullAndNotAfine(transform);
+        if (transform == null) {
+            transform = Matrix.IDENTITY_MATRIX;
+        }
+        if (clip == null) {
+            Point size = new Point();
+            getPageSize(pageIndex, size);
+            nativeSetTransformAndClip(mNativeDocument, pageIndex, transform.native_instance,
+                    0, 0, size.x, size.y);
+        } else {
+            nativeSetTransformAndClip(mNativeDocument, pageIndex, transform.native_instance,
+                    clip.left, clip.top, clip.right, clip.bottom);
+        }
+    }
+
+    /**
+     * Gets the size of a given page in mils (1/72").
+     *
+     * @param pageIndex The page index.
+     * @param outSize The size output.
+     */
+    public void getPageSize(int pageIndex, @NonNull Point outSize) {
+        throwIfClosed();
+        throwIfOutSizeNull(outSize);
+        throwIfPageNotInDocument(pageIndex);
+        nativeGetPageSize(mNativeDocument, pageIndex, outSize);
+    }
+
+    /**
+     * Gets the media box of a given page in mils (1/72").
+     *
+     * @param pageIndex The page index.
+     * @param outMediaBox The media box output.
+     */
+    public boolean getPageMediaBox(int pageIndex, @NonNull Rect outMediaBox) {
+        throwIfClosed();
+        throwIfOutMediaBoxNull(outMediaBox);
+        throwIfPageNotInDocument(pageIndex);
+        return nativeGetPageMediaBox(mNativeDocument, pageIndex, outMediaBox);
+    }
+
+    /**
+     * Sets the media box of a given page in mils (1/72").
+     *
+     * @param pageIndex The page index.
+     * @param mediaBox The media box.
+     */
+    public void setPageMediaBox(int pageIndex, @NonNull Rect mediaBox) {
+        throwIfClosed();
+        throwIfMediaBoxNull(mediaBox);
+        throwIfPageNotInDocument(pageIndex);
+        nativeSetPageMediaBox(mNativeDocument, pageIndex, mediaBox);
+    }
+
+    /**
+     * Gets the crop box of a given page in mils (1/72").
+     *
+     * @param pageIndex The page index.
+     * @param outCropBox The crop box output.
+     */
+    public boolean getPageCropBox(int pageIndex, @NonNull Rect outCropBox) {
+        throwIfClosed();
+        throwIfOutCropBoxNull(outCropBox);
+        throwIfPageNotInDocument(pageIndex);
+        return nativeGetPageCropBox(mNativeDocument, pageIndex, outCropBox);
+    }
+
+    /**
+     * Sets the crop box of a given page in mils (1/72").
+     *
+     * @param pageIndex The page index.
+     * @param cropBox The crop box.
+     */
+    public void setPageCropBox(int pageIndex, @NonNull Rect cropBox) {
+        throwIfClosed();
+        throwIfCropBoxNull(cropBox);
+        throwIfPageNotInDocument(pageIndex);
+        nativeSetPageCropBox(mNativeDocument, pageIndex, cropBox);
+    }
+
+    /**
+     * Gets whether the document prefers to be scaled for printing.
+     *
+     * @return Whether to scale the document.
+     */
+    public boolean shouldScaleForPrinting() {
+        throwIfClosed();
+        return nativeScaleForPrinting(mNativeDocument);
+    }
+
+    /**
      * Writes the PDF file to the provided destination.
      * <p>
      * <strong>Note:</strong> This method takes ownership of the passed in file
@@ -154,9 +261,57 @@
         }
     }
 
+    private void throwIfNotNullAndNotAfine(Matrix matrix) {
+        if (matrix != null && !matrix.isAffine()) {
+            throw new IllegalStateException("Matrix must be afine");
+        }
+    }
+
+    private void throwIfOutSizeNull(Point outSize) {
+        if (outSize == null) {
+            throw new NullPointerException("outSize cannot be null");
+        }
+    }
+
+    private void throwIfOutMediaBoxNull(Rect outMediaBox) {
+        if (outMediaBox == null) {
+            throw new NullPointerException("outMediaBox cannot be null");
+        }
+    }
+
+    private void throwIfMediaBoxNull(Rect mediaBox) {
+        if (mediaBox == null) {
+            throw new NullPointerException("mediaBox cannot be null");
+        }
+    }
+
+    private void throwIfOutCropBoxNull(Rect outCropBox) {
+        if (outCropBox == null) {
+            throw new NullPointerException("outCropBox cannot be null");
+        }
+    }
+
+    private void throwIfCropBoxNull(Rect cropBox) {
+        if (cropBox == null) {
+            throw new NullPointerException("cropBox cannot be null");
+        }
+    }
+
     private static native long nativeOpen(int fd, long size);
     private static native void nativeClose(long documentPtr);
     private static native int nativeGetPageCount(long documentPtr);
     private static native int nativeRemovePage(long documentPtr, int pageIndex);
     private static native void nativeWrite(long documentPtr, int fd);
+    private static native void nativeSetTransformAndClip(long documentPtr, int pageIndex,
+            long transformPtr, int clipLeft, int clipTop, int clipRight, int clipBottom);
+    private static native void nativeGetPageSize(long documentPtr, int pageIndex, Point outSize);
+    private static native boolean nativeGetPageMediaBox(long documentPtr, int pageIndex,
+            Rect outMediaBox);
+    private static native void nativeSetPageMediaBox(long documentPtr, int pageIndex,
+            Rect mediaBox);
+    private static native boolean nativeGetPageCropBox(long documentPtr, int pageIndex,
+            Rect outMediaBox);
+    private static native void nativeSetPageCropBox(long documentPtr, int pageIndex,
+            Rect mediaBox);
+    private static native boolean nativeScaleForPrinting(long documentPtr);
 }
diff --git a/include/androidfw/ResourceTypes.h b/include/androidfw/ResourceTypes.h
index ac5eca08..85e442da 100644
--- a/include/androidfw/ResourceTypes.h
+++ b/include/androidfw/ResourceTypes.h
@@ -253,7 +253,8 @@
         
     // Type of the data value.
     enum {
-        // Contains no data.
+        // The 'data' is either 0 or 1, specifying this resource is either
+        // undefined or empty, respectively.
         TYPE_NULL = 0x00,
         // The 'data' holds a ResTable_ref, a reference to another resource
         // table entry.
@@ -351,6 +352,14 @@
         COMPLEX_MANTISSA_MASK = 0xffffff
     };
 
+    // Possible data values for TYPE_NULL.
+    enum {
+        // The value is not defined.
+        DATA_NULL_UNDEFINED = 0,
+        // The value is explicitly defined as empty.
+        DATA_NULL_EMPTY = 1
+    };
+
     // The data for this item, as interpreted according to dataType.
     uint32_t data;
 
diff --git a/libs/androidfw/ResourceTypes.cpp b/libs/androidfw/ResourceTypes.cpp
index b5d2885..3bbca1a 100644
--- a/libs/androidfw/ResourceTypes.cpp
+++ b/libs/androidfw/ResourceTypes.cpp
@@ -4639,8 +4639,15 @@
 
         // It's a reference!
         if (len == 5 && s[1]=='n' && s[2]=='u' && s[3]=='l' && s[4]=='l') {
+            // Special case @null as undefined. This will be converted by
+            // AssetManager to TYPE_NULL with data DATA_NULL_UNDEFINED.
             outValue->data = 0;
             return true;
+        } else if (len == 6 && s[1]=='e' && s[2]=='m' && s[3]=='p' && s[4]=='t' && s[5]=='y') {
+            // Special case @empty as explicitly defined empty value.
+            outValue->dataType = Res_value::TYPE_NULL;
+            outValue->data = Res_value::DATA_NULL_EMPTY;
+            return true;
         } else {
             bool createIfNotFound = false;
             const char16_t* resourceRefName;
@@ -6251,7 +6258,14 @@
 void ResTable::print_value(const Package* pkg, const Res_value& value) const
 {
     if (value.dataType == Res_value::TYPE_NULL) {
-        printf("(null)\n");
+        if (value.data == Res_value::DATA_NULL_UNDEFINED) {
+            printf("(null)\n");
+        } else if (value.data == Res_value::DATA_NULL_EMPTY) {
+            printf("(null empty)\n");
+        } else {
+            // This should never happen.
+            printf("(null) 0x%08x\n", value.data);
+        }
     } else if (value.dataType == Res_value::TYPE_REFERENCE) {
         printf("(reference) 0x%08x\n", value.data);
     } else if (value.dataType == Res_value::TYPE_DYNAMIC_REFERENCE) {
diff --git a/media/java/android/media/AudioAttributes.java b/media/java/android/media/AudioAttributes.java
index 17d3251..20c4978 100644
--- a/media/java/android/media/AudioAttributes.java
+++ b/media/java/android/media/AudioAttributes.java
@@ -161,6 +161,12 @@
      * Usage value to use when the usage is for game audio.
      */
     public final static int USAGE_GAME = 14;
+    /**
+     * @hide
+     * Usage value to use when feeding audio to the platform and replacing "traditional" audio
+     * source, such as audio capture devices.
+     */
+    public final static int USAGE_VIRTUAL_SOURCE = 15;
 
     /**
      * Flag defining a behavior where the audibility of the sound will be ensured by the system.
@@ -374,6 +380,7 @@
                 case USAGE_ASSISTANCE_NAVIGATION_GUIDANCE:
                 case USAGE_ASSISTANCE_SONIFICATION:
                 case USAGE_GAME:
+                case USAGE_VIRTUAL_SOURCE:
                      mUsage = usage;
                      break;
                 default:
diff --git a/media/java/android/media/AudioManager.java b/media/java/android/media/AudioManager.java
index 716ff99..8fc0b8e 100644
--- a/media/java/android/media/AudioManager.java
+++ b/media/java/android/media/AudioManager.java
@@ -2663,9 +2663,13 @@
         }
         IAudioService service = getService();
         try {
-            if (!service.registerAudioPolicy(policy.getConfig(), policy.token())) {
+            String regId = service.registerAudioPolicy(policy.getConfig(), policy.token());
+            if (regId == null) {
                 return ERROR;
+            } else {
+                policy.setRegistration(regId);
             }
+            // successful registration
         } catch (RemoteException e) {
             Log.e(TAG, "Dead object in registerAudioPolicyAsync()", e);
             return ERROR;
diff --git a/media/java/android/media/AudioService.java b/media/java/android/media/AudioService.java
index a84fe44..2f68382 100644
--- a/media/java/android/media/AudioService.java
+++ b/media/java/android/media/AudioService.java
@@ -48,6 +48,7 @@
 import android.hardware.usb.UsbManager;
 import android.media.MediaPlayer.OnCompletionListener;
 import android.media.MediaPlayer.OnErrorListener;
+import android.media.audiopolicy.AudioMix;
 import android.media.audiopolicy.AudioPolicyConfig;
 import android.media.session.MediaSessionLegacyHelper;
 import android.os.Binder;
@@ -118,6 +119,10 @@
 
     /** Debug audio mode */
     protected static final boolean DEBUG_MODE = Log.isLoggable(TAG + ".MOD", Log.DEBUG);
+
+    /** Debug audio policy feature */
+    protected static final boolean DEBUG_AP = Log.isLoggable(TAG + ".AP", Log.DEBUG);
+
     /** Debug volumes */
     protected static final boolean DEBUG_VOL = Log.isLoggable(TAG + ".VOL", Log.DEBUG);
 
@@ -2574,13 +2579,17 @@
                             if (mScoAudioState == SCO_STATE_INACTIVE) {
                                 mScoAudioMode = scoAudioMode;
                                 if (scoAudioMode == SCO_MODE_UNDEFINED) {
-                                    mScoAudioMode = new Integer(Settings.Global.getInt(
-                                                            mContentResolver,
-                                                            "bluetooth_sco_channel_"+
-                                                            mBluetoothHeadsetDevice.getAddress(),
-                                                            SCO_MODE_VIRTUAL_CALL));
-                                    if (mScoAudioMode > SCO_MODE_MAX || mScoAudioMode < 0) {
-                                        mScoAudioMode = SCO_MODE_VIRTUAL_CALL;
+                                    if (mBluetoothHeadsetDevice != null) {
+                                        mScoAudioMode = new Integer(Settings.Global.getInt(
+                                                                mContentResolver,
+                                                                "bluetooth_sco_channel_"+
+                                                                mBluetoothHeadsetDevice.getAddress(),
+                                                                SCO_MODE_VIRTUAL_CALL));
+                                        if (mScoAudioMode > SCO_MODE_MAX || mScoAudioMode < 0) {
+                                            mScoAudioMode = SCO_MODE_VIRTUAL_CALL;
+                                        }
+                                    } else {
+                                        mScoAudioMode = SCO_MODE_RAW;
                                     }
                                 }
                                 if (mBluetoothHeadset != null && mBluetoothHeadsetDevice != null) {
@@ -5630,31 +5639,33 @@
     //==========================================================================================
     // Audio policy management
     //==========================================================================================
-    public boolean registerAudioPolicy(AudioPolicyConfig policyConfig, IBinder cb) {
+    public String registerAudioPolicy(AudioPolicyConfig policyConfig, IBinder cb) {
         //Log.v(TAG, "registerAudioPolicy for " + cb + " got policy:" + policyConfig);
+        String regId = null;
         boolean hasPermissionForPolicy =
                 (PackageManager.PERMISSION_GRANTED == mContext.checkCallingOrSelfPermission(
                         android.Manifest.permission.MODIFY_AUDIO_ROUTING));
         if (!hasPermissionForPolicy) {
             Slog.w(TAG, "Can't register audio policy for pid " + Binder.getCallingPid() + " / uid "
                     + Binder.getCallingUid() + ", need MODIFY_AUDIO_ROUTING");
-            return false;
+            return null;
         }
         synchronized (mAudioPolicies) {
-            AudioPolicyProxy app = new AudioPolicyProxy(policyConfig, cb);
             try {
+                AudioPolicyProxy app = new AudioPolicyProxy(policyConfig, cb);
                 cb.linkToDeath(app, 0/*flags*/);
+                regId = app.connectMixes();
                 mAudioPolicies.put(cb, app);
             } catch (RemoteException e) {
                 // audio policy owner has already died!
                 Slog.w(TAG, "Audio policy registration failed, could not link to " + cb +
                         " binder death", e);
-                return false;
+                return null;
             }
         }
-        // TODO implement registration with native audio policy (including permission check)
-        return true;
+        return regId;
     }
+
     public void unregisterAudioPolicyAsync(IBinder cb) {
         synchronized (mAudioPolicies) {
             AudioPolicyProxy app = mAudioPolicies.remove(cb);
@@ -5664,27 +5675,59 @@
             } else {
                 cb.unlinkToDeath(app, 0/*flags*/);
             }
+            app.disconnectMixes();
         }
-        // TODO implement registration with native audio policy
+        // TODO implement clearing mix attribute matching info in native audio policy
     }
 
-    public class AudioPolicyProxy implements IBinder.DeathRecipient {
+    /**
+     * This internal class inherits from AudioPolicyConfig which contains all the mixes and
+     * their configurations.
+     */
+    public class AudioPolicyProxy extends AudioPolicyConfig implements IBinder.DeathRecipient {
         private static final String TAG = "AudioPolicyProxy";
         AudioPolicyConfig mConfig;
         IBinder mToken;
         AudioPolicyProxy(AudioPolicyConfig config, IBinder token) {
-            mConfig = config;
+            super(config);
+            setRegistration(new String(config.toString() + ":ap:" + mAudioPolicyCounter++));
             mToken = token;
         }
 
         public void binderDied() {
             synchronized (mAudioPolicies) {
-                Log.v(TAG, "audio policy " + mToken + " died");
+                Log.i(TAG, "audio policy " + mToken + " died");
                 mAudioPolicies.remove(mToken);
+                disconnectMixes();
+            }
+        }
+
+        String connectMixes() {
+            updateMixes(AudioSystem.DEVICE_STATE_AVAILABLE);
+            return mRegistrationId;
+        }
+
+        void disconnectMixes() {
+            updateMixes(AudioSystem.DEVICE_STATE_UNAVAILABLE);
+        }
+
+        void updateMixes(int connectionState) {
+            for (AudioMix mix : mMixes) {
+                // TODO implement sending the mix attribute matching info to native audio policy
+                if (DEBUG_AP) {
+                    Log.v(TAG, "AudioPolicyProxy connect mix state=" + connectionState
+                            + " addr=" + mix.getRegistration()); }
+                AudioSystem.setDeviceConnectionState(AudioSystem.DEVICE_IN_REMOTE_SUBMIX,
+                        connectionState,
+                        mix.getRegistration());
+                AudioSystem.setDeviceConnectionState(AudioSystem.DEVICE_OUT_REMOTE_SUBMIX,
+                        connectionState,
+                        mix.getRegistration());
             }
         }
     };
 
     private HashMap<IBinder, AudioPolicyProxy> mAudioPolicies =
             new HashMap<IBinder, AudioPolicyProxy>();
+    private int mAudioPolicyCounter = 0; // always accessed synchronized on mAudioPolicies
 }
diff --git a/media/java/android/media/IAudioService.aidl b/media/java/android/media/IAudioService.aidl
index 2d8042c..317cc21 100644
--- a/media/java/android/media/IAudioService.aidl
+++ b/media/java/android/media/IAudioService.aidl
@@ -207,6 +207,6 @@
 
     boolean isHdmiSystemAudioSupported();
 
-    boolean registerAudioPolicy(in AudioPolicyConfig policyConfig, IBinder cb);
+           String registerAudioPolicy(in AudioPolicyConfig policyConfig, IBinder cb);
     oneway void unregisterAudioPolicyAsync(in IBinder cb);
 }
diff --git a/media/java/android/media/audiopolicy/AudioMix.java b/media/java/android/media/audiopolicy/AudioMix.java
index f7967f1..bb52682 100644
--- a/media/java/android/media/audiopolicy/AudioMix.java
+++ b/media/java/android/media/audiopolicy/AudioMix.java
@@ -24,13 +24,14 @@
 import java.lang.annotation.RetentionPolicy;
 
 /**
- * @hide CANDIDATE FOR PUBLIC API
+ * @hide
  */
 public class AudioMix {
 
     private AudioMixingRule mRule;
     private AudioFormat mFormat;
     private int mRouteFlags;
+    private String mRegistrationId;
 
     /**
      * All parameters are guaranteed valid through the Builder.
@@ -39,6 +40,7 @@
         mRule = rule;
         mFormat = format;
         mRouteFlags = routeFlags;
+        mRegistrationId = null;
     }
 
     /**
@@ -65,6 +67,15 @@
         return mRule;
     }
 
+    void setRegistration(String regId) {
+        mRegistrationId = regId;
+    }
+
+    /** @hide */
+    public String getRegistration() {
+        return mRegistrationId;
+    }
+
     /** @hide */
     @IntDef(flag = true,
             value = { ROUTE_FLAG_RENDER, ROUTE_FLAG_LOOP_BACK } )
diff --git a/media/java/android/media/audiopolicy/AudioMixingRule.java b/media/java/android/media/audiopolicy/AudioMixingRule.java
index ced7881..2e06a80 100644
--- a/media/java/android/media/audiopolicy/AudioMixingRule.java
+++ b/media/java/android/media/audiopolicy/AudioMixingRule.java
@@ -23,7 +23,7 @@
 
 
 /**
- * @hide CANDIDATE FOR PUBLIC API
+ * @hide
  *
  * Here's an example of creating a mixing rule for all media playback:
  * <pre>
diff --git a/media/java/android/media/audiopolicy/AudioPolicy.java b/media/java/android/media/audiopolicy/AudioPolicy.java
index 314eb88..255d828 100644
--- a/media/java/android/media/audiopolicy/AudioPolicy.java
+++ b/media/java/android/media/audiopolicy/AudioPolicy.java
@@ -17,18 +17,26 @@
 package android.media.audiopolicy;
 
 import android.annotation.IntDef;
+import android.content.Context;
+import android.content.pm.PackageManager;
+import android.media.AudioAttributes;
 import android.media.AudioFormat;
 import android.media.AudioManager;
+import android.media.AudioRecord;
+import android.media.AudioSystem;
+import android.media.AudioTrack;
+import android.media.MediaRecorder;
 import android.os.Binder;
 import android.os.IBinder;
 import android.util.Log;
+import android.util.Slog;
 
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
 import java.util.ArrayList;
 
 /**
- * @hide CANDIDATE FOR PUBLIC API
+ * @hide
  * AudioPolicy provides access to the management of audio routing and audio focus.
  */
 public class AudioPolicy {
@@ -49,11 +57,13 @@
     public static final int POLICY_STATUS_REGISTERED = 2;
 
     private int mStatus;
-    private AudioPolicyStatusListener mStatusListener = null;
+    private String mRegistrationId;
+    private AudioPolicyStatusListener mStatusListener;
 
     private final IBinder mToken = new Binder();
     /** @hide */
     public IBinder token() { return mToken; }
+    private Context mContext;
 
     private AudioPolicyConfig mConfig;
     /** @hide */
@@ -62,13 +72,14 @@
     /**
      * The parameter is guaranteed non-null through the Builder
      */
-    private AudioPolicy(AudioPolicyConfig config) {
+    private AudioPolicy(AudioPolicyConfig config, Context context) {
         mConfig = config;
         if (mConfig.mMixes.isEmpty()) {
             mStatus = POLICY_STATUS_INVALID;
         } else {
             mStatus = POLICY_STATUS_UNREGISTERED;
         }
+        mContext = context;
     }
 
     /**
@@ -76,12 +87,15 @@
      */
     public static class Builder {
         private ArrayList<AudioMix> mMixes;
+        private Context mContext;
 
         /**
          * Constructs a new Builder with no audio mixes.
+         * @param context the context for the policy
          */
-        public Builder() {
+        public Builder(Context context) {
             mMixes = new ArrayList<AudioMix>();
+            mContext = context;
         }
 
         /**
@@ -99,10 +113,115 @@
         }
 
         public AudioPolicy build() {
-            return new AudioPolicy(new AudioPolicyConfig(mMixes));
+            return new AudioPolicy(new AudioPolicyConfig(mMixes), mContext);
         }
     }
 
+    /** @hide */
+    public void setRegistration(String regId) {
+        mRegistrationId = regId;
+        mConfig.setRegistration(regId);
+    }
+
+    private boolean policyReadyToUse() {
+        if (mContext == null) {
+            Log.e(TAG, "Cannot use AudioPolicy without context");
+            return false;
+        }
+        if (mRegistrationId == null) {
+            Log.e(TAG, "Cannot use unregistered AudioPolicy");
+            return false;
+        }
+        if (!(PackageManager.PERMISSION_GRANTED == mContext.checkCallingOrSelfPermission(
+                        android.Manifest.permission.MODIFY_AUDIO_ROUTING))) {
+            Slog.w(TAG, "Cannot use AudioPolicy for pid " + Binder.getCallingPid() + " / uid "
+                    + Binder.getCallingUid() + ", needs MODIFY_AUDIO_ROUTING");
+            return false;
+        }
+        return true;
+    }
+
+    private void checkMixReadyToUse(AudioMix mix, boolean forTrack)
+            throws IllegalArgumentException{
+        if (mix == null) {
+            String msg = forTrack ? "Invalid null AudioMix for AudioTrack creation"
+                    : "Invalid null AudioMix for AudioRecord creation";
+            throw new IllegalArgumentException(msg);
+        }
+        if (!mConfig.mMixes.contains(mix)) {
+            throw new IllegalArgumentException("Invalid mix: not part of this policy");
+        }
+        if ((mix.getRouteFlags() & AudioMix.ROUTE_FLAG_LOOP_BACK) != AudioMix.ROUTE_FLAG_LOOP_BACK)
+        {
+            throw new IllegalArgumentException("Invalid AudioMix: not defined for loop back");
+        }
+    }
+
+    /**
+     * @hide
+     * Create an {@link AudioRecord} instance that is associated with the given {@link AudioMix}.
+     * Audio buffers recorded through the created instance will contain the mix of the audio
+     * streams that fed the given mixer.
+     * @param mix a non-null {@link AudioMix} instance whose routing flags was defined with
+     *     {@link AudioMix#ROUTE_FLAG_LOOP_BACK}, previously added to this policy.
+     * @return a new {@link AudioRecord} instance whose data format is the one defined in the
+     *     {@link AudioMix}, or null if this policy was not successfully registered
+     *     with {@link AudioManager#registerAudioPolicy(AudioPolicy)}.
+     * @throws IllegalArgumentException
+     */
+    public AudioRecord createAudioRecordSink(AudioMix mix) throws IllegalArgumentException {
+        if (!policyReadyToUse()) {
+            Log.e(TAG, "Cannot create AudioRecord sink for AudioMix");
+            return null;
+        }
+        checkMixReadyToUse(mix, false/*not for an AudioTrack*/);
+        // create the AudioRecord, configured for loop back, using the same format as the mix
+        AudioRecord ar = new AudioRecord(
+                new AudioAttributes.Builder()
+                        .setInternalCapturePreset(MediaRecorder.AudioSource.REMOTE_SUBMIX)
+                        .addTag(mix.getRegistration())
+                        .build(),
+                mix.getFormat(),
+                AudioRecord.getMinBufferSize(mix.getFormat().getSampleRate(),
+                        // using stereo for buffer size to avoid the current poor support for masks
+                        AudioFormat.CHANNEL_IN_STEREO, mix.getFormat().getEncoding()),
+                AudioManager.AUDIO_SESSION_ID_GENERATE
+                );
+        return ar;
+    }
+
+    /**
+     * @hide
+     * Create an {@link AudioTrack} instance that is associated with the given {@link AudioMix}.
+     * Audio buffers played through the created instance will be sent to the given mix
+     * to be recorded through the recording APIs.
+     * @param mix a non-null {@link AudioMix} instance whose routing flags was defined with
+     *     {@link AudioMix#ROUTE_FLAG_LOOP_BACK}, previously added to this policy.
+     * @returna new {@link AudioTrack} instance whose data format is the one defined in the
+     *     {@link AudioMix}, or null if this policy was not successfully registered
+     *     with {@link AudioManager#registerAudioPolicy(AudioPolicy)}.
+     * @throws IllegalArgumentException
+     */
+    public AudioTrack createAudioTrackSource(AudioMix mix) throws IllegalArgumentException {
+        if (!policyReadyToUse()) {
+            Log.e(TAG, "Cannot create AudioTrack source for AudioMix");
+            return null;
+        }
+        checkMixReadyToUse(mix, true/*for an AudioTrack*/);
+        // create the AudioTrack, configured for loop back, using the same format as the mix
+        AudioTrack at = new AudioTrack(
+                new AudioAttributes.Builder()
+                        .setUsage(AudioAttributes.USAGE_VIRTUAL_SOURCE)
+                        .addTag(mix.getRegistration())
+                        .build(),
+                mix.getFormat(),
+                AudioTrack.getMinBufferSize(mix.getFormat().getSampleRate(),
+                        mix.getFormat().getChannelMask(), mix.getFormat().getEncoding()),
+                AudioTrack.MODE_STREAM,
+                AudioManager.AUDIO_SESSION_ID_GENERATE
+                );
+        return at;
+    }
 
     public int getStatus() {
         return mStatus;
@@ -118,10 +237,9 @@
     }
 
     /** @hide */
-    @Override
-    public String toString () {
+    public String toLogFriendlyString() {
         String textDump = new String("android.media.audiopolicy.AudioPolicy:\n");
-        textDump += "config=" + mConfig.toString();
+        textDump += "config=" + mConfig.toLogFriendlyString();
         return (textDump);
     }
 
diff --git a/media/java/android/media/audiopolicy/AudioPolicyConfig.java b/media/java/android/media/audiopolicy/AudioPolicyConfig.java
index 2fc6d58..a9a4175 100644
--- a/media/java/android/media/audiopolicy/AudioPolicyConfig.java
+++ b/media/java/android/media/audiopolicy/AudioPolicyConfig.java
@@ -36,7 +36,13 @@
 
     private static final String TAG = "AudioPolicyConfig";
 
-    ArrayList<AudioMix> mMixes;
+    protected ArrayList<AudioMix> mMixes;
+
+    protected String mRegistrationId = null;
+
+    protected AudioPolicyConfig(AudioPolicyConfig conf) {
+        mMixes = conf.mMixes;
+    }
 
     AudioPolicyConfig(ArrayList<AudioMix> mixes) {
         mMixes = mixes;
@@ -117,7 +123,6 @@
         }
     }
 
-    /** @hide */
     public static final Parcelable.Creator<AudioPolicyConfig> CREATOR
             = new Parcelable.Creator<AudioPolicyConfig>() {
         /**
@@ -133,9 +138,7 @@
         }
     };
 
-    /** @hide */
-    @Override
-    public String toString () {
+    public String toLogFriendlyString () {
         String textDump = new String("android.media.audiopolicy.AudioPolicyConfig:\n");
         textDump += mMixes.size() + " AudioMix:\n";
         for(AudioMix mix : mMixes) {
@@ -166,4 +169,13 @@
         }
         return textDump;
     }
+
+    public void setRegistration(String regId) {
+        mRegistrationId = regId;
+        int mixIndex = 0;
+        for (AudioMix mix : mMixes) {
+            mix.setRegistration(mRegistrationId + "mix:" + mixIndex++);
+        }
+    }
+
 }
diff --git a/media/java/android/media/tv/ITvInputSessionWrapper.java b/media/java/android/media/tv/ITvInputSessionWrapper.java
index b8cdc4b..1ac80c1 100644
--- a/media/java/android/media/tv/ITvInputSessionWrapper.java
+++ b/media/java/android/media/tv/ITvInputSessionWrapper.java
@@ -166,6 +166,7 @@
 
     @Override
     public void release() {
+        mTvInputSessionImpl.scheduleOverlayViewCleanup();
         mCaller.executeOrSendMessage(mCaller.obtainMessage(DO_RELEASE));
     }
 
diff --git a/media/java/android/media/tv/TvInputService.java b/media/java/android/media/tv/TvInputService.java
index 5d5ea02..0ca5810 100644
--- a/media/java/android/media/tv/TvInputService.java
+++ b/media/java/android/media/tv/TvInputService.java
@@ -25,10 +25,12 @@
 import android.graphics.Rect;
 import android.hardware.hdmi.HdmiDeviceInfo;
 import android.net.Uri;
+import android.os.AsyncTask;
 import android.os.Bundle;
 import android.os.Handler;
 import android.os.IBinder;
 import android.os.Message;
+import android.os.Process;
 import android.os.RemoteCallbackList;
 import android.os.RemoteException;
 import android.text.TextUtils;
@@ -44,10 +46,12 @@
 import android.view.View;
 import android.view.WindowManager;
 import android.view.accessibility.CaptioningManager;
+import android.widget.FrameLayout;
 
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.os.SomeArgs;
 
+import java.util.ArrayList;
 import java.util.HashSet;
 import java.util.List;
 import java.util.Set;
@@ -241,16 +245,25 @@
      * Base class for derived classes to implement to provide a TV input session.
      */
     public abstract static class Session implements KeyEvent.Callback {
+        private static final int DETACH_OVERLAY_VIEW_TIMEOUT = 5000;
         private final KeyEvent.DispatcherState mDispatcherState = new KeyEvent.DispatcherState();
         private final WindowManager mWindowManager;
         final Handler mHandler;
         private WindowManager.LayoutParams mWindowParams;
         private Surface mSurface;
+        private Context mContext;
+        private FrameLayout mOverlayViewContainer;
         private View mOverlayView;
+        private OverlayViewCleanUpTask mOverlayViewCleanUpTask;
         private boolean mOverlayViewEnabled;
         private IBinder mWindowToken;
         private Rect mOverlayFrame;
+
+        private Object mLock = new Object();
+        // @GuardedBy("mLock")
         private ITvInputSessionCallback mSessionCallback;
+        // @GuardedBy("mLock")
+        private List<Runnable> mPendingActions = new ArrayList<>();
 
         /**
          * Creates a new Session.
@@ -258,6 +271,7 @@
          * @param context The context of the application
          */
         public Session(Context context) {
+            mContext = context;
             mWindowManager = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
             mHandler = new Handler(context.getMainLooper());
         }
@@ -295,11 +309,12 @@
          * @param eventArgs Optional arguments of the event.
          * @hide
          */
+        @SystemApi
         public void notifySessionEvent(final String eventType, final Bundle eventArgs) {
             if (eventType == null) {
                 throw new IllegalArgumentException("eventType should not be null.");
             }
-            runOnMainThread(new Runnable() {
+            executeOrPostRunnable(new Runnable() {
                 @Override
                 public void run() {
                     try {
@@ -318,7 +333,7 @@
          * @param channelUri The URI of a channel.
          */
         public void notifyChannelRetuned(final Uri channelUri) {
-            runOnMainThread(new Runnable() {
+            executeOrPostRunnable(new Runnable() {
                 @Override
                 public void run() {
                     try {
@@ -355,7 +370,7 @@
             trackIdSet.clear();
 
             // TODO: Validate the track list.
-            runOnMainThread(new Runnable() {
+            executeOrPostRunnable(new Runnable() {
                 @Override
                 public void run() {
                     try {
@@ -383,7 +398,7 @@
          * @see #onSelectTrack
          */
         public void notifyTrackSelected(final int type, final String trackId) {
-            runOnMainThread(new Runnable() {
+            executeOrPostRunnable(new Runnable() {
                 @Override
                 public void run() {
                     try {
@@ -404,7 +419,7 @@
          * @see #notifyVideoUnavailable
          */
         public void notifyVideoAvailable() {
-            runOnMainThread(new Runnable() {
+            executeOrPostRunnable(new Runnable() {
                 @Override
                 public void run() {
                     try {
@@ -436,7 +451,7 @@
                     || reason > TvInputManager.VIDEO_UNAVAILABLE_REASON_END) {
                 throw new IllegalArgumentException("Unknown reason: " + reason);
             }
-            runOnMainThread(new Runnable() {
+            executeOrPostRunnable(new Runnable() {
                 @Override
                 public void run() {
                     try {
@@ -475,7 +490,7 @@
          * @see TvInputManager
          */
         public void notifyContentAllowed() {
-            runOnMainThread(new Runnable() {
+            executeOrPostRunnable(new Runnable() {
                 @Override
                 public void run() {
                     try {
@@ -515,7 +530,7 @@
          * @see TvInputManager
          */
         public void notifyContentBlocked(final TvContentRating rating) {
-            runOnMainThread(new Runnable() {
+            executeOrPostRunnable(new Runnable() {
                 @Override
                 public void run() {
                     try {
@@ -544,7 +559,7 @@
             if (left > right || top > bottm) {
                 throw new IllegalArgumentException("Invalid parameter");
             }
-            runOnMainThread(new Runnable() {
+            executeOrPostRunnable(new Runnable() {
                 @Override
                 public void run() {
                     try {
@@ -846,12 +861,18 @@
          * session.
          */
         void release() {
-            removeOverlayView(true);
             onRelease();
             if (mSurface != null) {
                 mSurface.release();
                 mSurface = null;
             }
+            synchronized(mLock) {
+                mSessionCallback = null;
+                mPendingActions.clear();
+            }
+            // Removes the overlay view lastly so that any hanging on the main thread can be handled
+            // in {@link #scheduleOverlayViewCleanup}.
+            removeOverlayView(true);
         }
 
         /**
@@ -936,9 +957,8 @@
          * @param frame A position of the overlay view.
          */
         void createOverlayView(IBinder windowToken, Rect frame) {
-            if (mOverlayView != null) {
-                mWindowManager.removeView(mOverlayView);
-                mOverlayView = null;
+            if (mOverlayViewContainer != null) {
+                removeOverlayView(false);
             }
             if (DEBUG) Log.d(TAG, "create overlay view(" + frame + ")");
             mWindowToken = windowToken;
@@ -951,6 +971,15 @@
             if (mOverlayView == null) {
                 return;
             }
+            if (mOverlayViewCleanUpTask != null) {
+                mOverlayViewCleanUpTask.cancel(true);
+                mOverlayViewCleanUpTask = null;
+            }
+            // Creates a container view to check hanging on the overlay view detaching.
+            // Adding/removing the overlay view to/from the container make the view attach/detach
+            // logic run on the main thread.
+            mOverlayViewContainer = new FrameLayout(mContext);
+            mOverlayViewContainer.addView(mOverlayView);
             // TvView's window type is TYPE_APPLICATION_MEDIA and we want to create
             // an overlay window above the media window but below the application window.
             int type = WindowManager.LayoutParams.TYPE_APPLICATION_MEDIA_OVERLAY;
@@ -967,7 +996,7 @@
                     WindowManager.LayoutParams.PRIVATE_FLAG_NO_MOVE_ANIMATION;
             mWindowParams.gravity = Gravity.START | Gravity.TOP;
             mWindowParams.token = windowToken;
-            mWindowManager.addView(mOverlayView, mWindowParams);
+            mWindowManager.addView(mOverlayViewContainer, mWindowParams);
         }
 
         /**
@@ -984,33 +1013,51 @@
                 onOverlayViewSizeChanged(frame.right - frame.left, frame.bottom - frame.top);
             }
             mOverlayFrame = frame;
-            if (!mOverlayViewEnabled || mOverlayView == null) {
+            if (!mOverlayViewEnabled || mOverlayViewContainer == null) {
                 return;
             }
             mWindowParams.x = frame.left;
             mWindowParams.y = frame.top;
             mWindowParams.width = frame.right - frame.left;
             mWindowParams.height = frame.bottom - frame.top;
-            mWindowManager.updateViewLayout(mOverlayView, mWindowParams);
+            mWindowManager.updateViewLayout(mOverlayViewContainer, mWindowParams);
         }
 
         /**
          * Removes the current overlay view.
          */
         void removeOverlayView(boolean clearWindowToken) {
-            if (DEBUG) Log.d(TAG, "removeOverlayView(" + mOverlayView + ")");
+            if (DEBUG) Log.d(TAG, "removeOverlayView(" + mOverlayViewContainer + ")");
             if (clearWindowToken) {
                 mWindowToken = null;
                 mOverlayFrame = null;
             }
-            if (mOverlayView != null) {
-                mWindowManager.removeView(mOverlayView);
+            if (mOverlayViewContainer != null) {
+                // Removes the overlay view from the view hierarchy in advance so that it can be
+                // cleaned up in the {@link OverlayViewCleanUpTask} if the remove process is
+                // hanging.
+                mOverlayViewContainer.removeView(mOverlayView);
                 mOverlayView = null;
+                mWindowManager.removeView(mOverlayViewContainer);
+                mOverlayViewContainer = null;
                 mWindowParams = null;
             }
         }
 
         /**
+         * Schedules a task which checks whether the overlay view is detached and kills the process
+         * if it is not. Note that this method is expected to be called in a non-main thread.
+         */
+        void scheduleOverlayViewCleanup() {
+            View overlayViewParent = mOverlayViewContainer;
+            if (overlayViewParent != null) {
+                mOverlayViewCleanUpTask = new OverlayViewCleanUpTask();
+                mOverlayViewCleanUpTask.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR,
+                        overlayViewParent);
+            }
+        }
+
+        /**
          * Takes care of dispatching incoming input events and tells whether the event was handled.
          */
         int dispatchInputEvent(InputEvent event, InputEventReceiver receiver) {
@@ -1039,37 +1086,70 @@
                     }
                 }
             }
-            if (mOverlayView == null || !mOverlayView.isAttachedToWindow()) {
+            if (mOverlayViewContainer == null || !mOverlayViewContainer.isAttachedToWindow()) {
                 return TvInputManager.Session.DISPATCH_NOT_HANDLED;
             }
-            if (!mOverlayView.hasWindowFocus()) {
-                mOverlayView.getViewRootImpl().windowFocusChanged(true, true);
+            if (!mOverlayViewContainer.hasWindowFocus()) {
+                mOverlayViewContainer.getViewRootImpl().windowFocusChanged(true, true);
             }
-            if (isNavigationKey && mOverlayView.hasFocusable()) {
+            if (isNavigationKey && mOverlayViewContainer.hasFocusable()) {
                 // If mOverlayView has focusable views, navigation key events should be always
                 // handled. If not, it can make the application UI navigation messed up.
                 // For example, in the case that the left-most view is focused, a left key event
                 // will not be handled in ViewRootImpl. Then, the left key event will be handled in
                 // the application during the UI navigation of the TV input.
-                mOverlayView.getViewRootImpl().dispatchInputEvent(event);
+                mOverlayViewContainer.getViewRootImpl().dispatchInputEvent(event);
                 return TvInputManager.Session.DISPATCH_HANDLED;
             } else {
-                mOverlayView.getViewRootImpl().dispatchInputEvent(event, receiver);
+                mOverlayViewContainer.getViewRootImpl().dispatchInputEvent(event, receiver);
                 return TvInputManager.Session.DISPATCH_IN_PROGRESS;
             }
         }
 
-        private void setSessionCallback(ITvInputSessionCallback callback) {
-            mSessionCallback = callback;
+        private void initialize(ITvInputSessionCallback callback) {
+            synchronized(mLock) {
+                mSessionCallback = callback;
+                for (Runnable runnable : mPendingActions) {
+                    runnable.run();
+                }
+                mPendingActions.clear();
+            }
         }
 
-        private final void runOnMainThread(Runnable action) {
-            if (mHandler.getLooper().isCurrentThread() && mSessionCallback != null) {
-                action.run();
-            } else {
-                // Posts the runnable if this is not called from the main thread or the session
-                // is not initialized yet.
-                mHandler.post(action);
+        private final void executeOrPostRunnable(Runnable action) {
+            synchronized(mLock) {
+                if (mSessionCallback == null) {
+                    // The session is not initialized yet.
+                    mPendingActions.add(action);
+                } else {
+                    if (mHandler.getLooper().isCurrentThread()) {
+                        action.run();
+                    } else {
+                        // Posts the runnable if this is not called from the main thread
+                        mHandler.post(action);
+                    }
+                }
+            }
+        }
+
+        private final class OverlayViewCleanUpTask extends AsyncTask<View, Void, Void> {
+            @Override
+            protected Void doInBackground(View... views) {
+                View overlayViewParent = views[0];
+                try {
+                    Thread.sleep(DETACH_OVERLAY_VIEW_TIMEOUT);
+                } catch (InterruptedException e) {
+                    return null;
+                }
+                if (isCancelled()) {
+                    return null;
+                }
+                if (overlayViewParent.isAttachedToWindow()) {
+                    Log.e(TAG, "Time out on releasing overlay view. Killing "
+                            + overlayViewParent.getContext().getPackageName());
+                    Process.killProcess(Process.myPid());
+                }
+                return null;
             }
         }
     }
@@ -1125,13 +1205,15 @@
                 mHardwareSession = session;
                 SomeArgs args = SomeArgs.obtain();
                 if (session != null) {
-                    args.arg1 = mProxySession;
-                    args.arg2 = mProxySessionCallback;
-                    args.arg3 = session.getToken();
+                    args.arg1 = HardwareSession.this;
+                    args.arg2 = mProxySession;
+                    args.arg3 = mProxySessionCallback;
+                    args.arg4 = session.getToken();
                 } else {
                     args.arg1 = null;
-                    args.arg2 = mProxySessionCallback;
-                    args.arg3 = null;
+                    args.arg2 = null;
+                    args.arg3 = mProxySessionCallback;
+                    args.arg4 = null;
                     onRelease();
                 }
                 mServiceHandler.obtainMessage(ServiceHandler.DO_NOTIFY_SESSION_CREATED, args)
@@ -1269,7 +1351,6 @@
                         }
                         return;
                     }
-                    sessionImpl.setSessionCallback(cb);
                     ITvInputSession stub = new ITvInputSessionWrapper(TvInputService.this,
                             sessionImpl, channel);
                     if (sessionImpl instanceof HardwareSession) {
@@ -1300,9 +1381,10 @@
                                 proxySession.mHardwareSessionCallback, mServiceHandler);
                     } else {
                         SomeArgs someArgs = SomeArgs.obtain();
-                        someArgs.arg1 = stub;
-                        someArgs.arg2 = cb;
-                        someArgs.arg3 = null;
+                        someArgs.arg1 = sessionImpl;
+                        someArgs.arg2 = stub;
+                        someArgs.arg3 = cb;
+                        someArgs.arg4 = null;
                         mServiceHandler.obtainMessage(ServiceHandler.DO_NOTIFY_SESSION_CREATED,
                                 someArgs).sendToTarget();
                     }
@@ -1310,14 +1392,18 @@
                 }
                 case DO_NOTIFY_SESSION_CREATED: {
                     SomeArgs args = (SomeArgs) msg.obj;
-                    ITvInputSession stub = (ITvInputSession) args.arg1;
-                    ITvInputSessionCallback cb = (ITvInputSessionCallback) args.arg2;
-                    IBinder hardwareSessionToken = (IBinder) args.arg3;
+                    Session sessionImpl = (Session) args.arg1;
+                    ITvInputSession stub = (ITvInputSession) args.arg2;
+                    ITvInputSessionCallback cb = (ITvInputSessionCallback) args.arg3;
+                    IBinder hardwareSessionToken = (IBinder) args.arg4;
                     try {
                         cb.onSessionCreated(stub, hardwareSessionToken);
                     } catch (RemoteException e) {
                         Log.e(TAG, "error in onSessionCreated");
                     }
+                    if (sessionImpl != null) {
+                        sessionImpl.initialize(cb);
+                    }
                     args.recycle();
                     return;
                 }
diff --git a/packages/PrintSpooler/src/com/android/printspooler/model/PageContentRepository.java b/packages/PrintSpooler/src/com/android/printspooler/model/PageContentRepository.java
index a54334a..35930cd 100644
--- a/packages/PrintSpooler/src/com/android/printspooler/model/PageContentRepository.java
+++ b/packages/PrintSpooler/src/com/android/printspooler/model/PageContentRepository.java
@@ -463,7 +463,8 @@
                     }
                     Intent intent = new Intent(PdfManipulationService.ACTION_GET_RENDERER);
                     intent.setClass(mContext, PdfManipulationService.class);
-                    intent.setData(Uri.fromParts("fake-scheme", String.valueOf(hashCode()), null));
+                    intent.setData(Uri.fromParts("fake-scheme", String.valueOf(
+                            AsyncRenderer.this.hashCode()), null));
                     mContext.bindService(intent, AsyncRenderer.this, Context.BIND_AUTO_CREATE);
                     mBoundToService = true;
                 }
diff --git a/packages/PrintSpooler/src/com/android/printspooler/renderer/IPdfEditor.aidl b/packages/PrintSpooler/src/com/android/printspooler/renderer/IPdfEditor.aidl
index b450ccb..01cabe1 100644
--- a/packages/PrintSpooler/src/com/android/printspooler/renderer/IPdfEditor.aidl
+++ b/packages/PrintSpooler/src/com/android/printspooler/renderer/IPdfEditor.aidl
@@ -18,6 +18,7 @@
 
 import android.os.ParcelFileDescriptor;
 import android.print.PageRange;
+import android.print.PrintAttributes;
 
 /**
  * Interface for communication with a remote pdf editor.
@@ -25,6 +26,7 @@
 interface IPdfEditor {
     int openDocument(in ParcelFileDescriptor source);
     void removePages(in PageRange[] pages);
+    void applyPrintAttributes(in PrintAttributes attributes);
     void write(in ParcelFileDescriptor destination);
     void closeDocument();
 }
diff --git a/packages/PrintSpooler/src/com/android/printspooler/renderer/PdfManipulationService.java b/packages/PrintSpooler/src/com/android/printspooler/renderer/PdfManipulationService.java
index 00e5051..0462e4d 100644
--- a/packages/PrintSpooler/src/com/android/printspooler/renderer/PdfManipulationService.java
+++ b/packages/PrintSpooler/src/com/android/printspooler/renderer/PdfManipulationService.java
@@ -87,7 +87,7 @@
                     }
                     mRenderer = new PdfRenderer(source);
                     return mRenderer.getPageCount();
-                } catch (IOException|IllegalStateException e) {
+                } catch (IOException | IllegalStateException e) {
                     IoUtils.closeQuietly(source);
                     Log.e(LOG_TAG, "Cannot open file", e);
                     return MALFORMED_PDF_FILE_ERROR;
@@ -217,7 +217,7 @@
                     }
                     mEditor = new PdfEditor(source);
                     return mEditor.getPageCount();
-                } catch (IOException|IllegalStateException e) {
+                } catch (IOException | IllegalStateException e) {
                     IoUtils.closeQuietly(source);
                     Log.e(LOG_TAG, "Cannot open file", e);
                     throw new RemoteException(e.toString());
@@ -246,6 +246,111 @@
         }
 
         @Override
+        public void applyPrintAttributes(PrintAttributes attributes) {
+            synchronized (mLock) {
+                throwIfNotOpened();
+                if (DEBUG) {
+                    Log.i(LOG_TAG, "applyPrintAttributes()");
+                }
+
+                Rect mediaBox = new Rect();
+                Rect cropBox = new Rect();
+                Matrix transform = new Matrix();
+
+                final boolean contentPortrait = attributes.getMediaSize().isPortrait();
+
+                final boolean layoutDirectionRtl = getResources().getConfiguration()
+                        .getLayoutDirection() == View.LAYOUT_DIRECTION_RTL;
+
+                // We do not want to rotate the media box, so take into account orientation.
+                final int dstWidthPts = contentPortrait
+                        ? pointsFromMils(attributes.getMediaSize().getWidthMils())
+                        : pointsFromMils(attributes.getMediaSize().getHeightMils());
+                final int dstHeightPts = contentPortrait
+                        ? pointsFromMils(attributes.getMediaSize().getHeightMils())
+                        : pointsFromMils(attributes.getMediaSize().getWidthMils());
+
+                final boolean scaleForPrinting = mEditor.shouldScaleForPrinting();
+
+                final int pageCount = mEditor.getPageCount();
+                for (int i = 0; i < pageCount; i++) {
+                    if (!mEditor.getPageMediaBox(i, mediaBox)) {
+                        Log.e(LOG_TAG, "Malformed PDF file");
+                        return;
+                    }
+
+                    final int srcWidthPts = mediaBox.width();
+                    final int srcHeightPts = mediaBox.height();
+
+                    // Update the media box with the desired size.
+                    mediaBox.right = dstWidthPts;
+                    mediaBox.bottom = dstHeightPts;
+                    mEditor.setPageMediaBox(i, mediaBox);
+
+                    // Make sure content is top-left after media box resize.
+                    transform.setTranslate(0, srcHeightPts - dstHeightPts);
+
+                    // Rotate the content if in landscape.
+                    if (!contentPortrait) {
+                        transform.postRotate(270);
+                        transform.postTranslate(0, dstHeightPts);
+                    }
+
+                    // Scale the content if document allows it.
+                    final float scale;
+                    if (scaleForPrinting) {
+                        if (contentPortrait) {
+                            scale = Math.min((float) dstWidthPts / srcWidthPts,
+                                    (float) dstHeightPts / srcHeightPts);
+                            transform.postScale(scale, scale);
+                        } else {
+                            scale = Math.min((float) dstWidthPts / srcHeightPts,
+                                    (float) dstHeightPts / srcWidthPts);
+                            transform.postScale(scale, scale, mediaBox.left, mediaBox.bottom);
+                        }
+                    } else {
+                        scale = 1.0f;
+                    }
+
+                    // Update the crop box relatively to the media box change, if needed.
+                    if (mEditor.getPageCropBox(i, cropBox)) {
+                        cropBox.left = (int) (cropBox.left * scale + 0.5f);
+                        cropBox.top = (int) (cropBox.top * scale + 0.5f);
+                        cropBox.right = (int) (cropBox.right * scale + 0.5f);
+                        cropBox.bottom = (int) (cropBox.bottom * scale + 0.5f);
+                        cropBox.intersect(mediaBox);
+                        mEditor.setPageCropBox(i, cropBox);
+                    }
+
+                    // If in RTL mode put the content in the logical top-right corner.
+                    if (layoutDirectionRtl) {
+                        final float dx = contentPortrait
+                                ? dstWidthPts - (int) (srcWidthPts * scale + 0.5f) : 0;
+                        final float dy = contentPortrait
+                                ? 0 : - (dstHeightPts - (int) (srcWidthPts * scale + 0.5f));
+                        transform.postTranslate(dx, dy);
+                    }
+
+                    // Adjust the physical margins if needed.
+                    Margins minMargins = attributes.getMinMargins();
+                    final int paddingLeftPts = pointsFromMils(minMargins.getLeftMils());
+                    final int paddingTopPts = pointsFromMils(minMargins.getTopMils());
+                    final int paddingRightPts = pointsFromMils(minMargins.getRightMils());
+                    final int paddingBottomPts = pointsFromMils(minMargins.getBottomMils());
+
+                    Rect clip = new Rect(mediaBox);
+                    clip.left += paddingLeftPts;
+                    clip.top += paddingTopPts;
+                    clip.right -= paddingRightPts;
+                    clip.bottom -= paddingBottomPts;
+
+                    // Apply the accumulated transforms.
+                    mEditor.setTransformAndClip(i, transform, clip);
+                }
+            }
+        }
+
+        @Override
         public void write(ParcelFileDescriptor destination) throws RemoteException {
             synchronized (mLock) {
                 try {
diff --git a/packages/PrintSpooler/src/com/android/printspooler/ui/PrintActivity.java b/packages/PrintSpooler/src/com/android/printspooler/ui/PrintActivity.java
index 15ea9a7..f361884 100644
--- a/packages/PrintSpooler/src/com/android/printspooler/ui/PrintActivity.java
+++ b/packages/PrintSpooler/src/com/android/printspooler/ui/PrintActivity.java
@@ -592,7 +592,7 @@
             mDestinationSpinner.post(new Runnable() {
                 @Override
                 public void run() {
-                    shredPagesAndFinish(uri);
+                    transformDocumentAndFinish(uri);
                 }
             });
         } else if (resultCode == RESULT_CANCELED) {
@@ -922,7 +922,7 @@
         if (mCurrentPrinter == mDestinationSpinnerAdapter.getPdfPrinter()) {
             startCreateDocumentActivity();
         } else {
-            shredPagesAndFinish(null);
+            transformDocumentAndFinish(null);
         }
     }
 
@@ -1597,8 +1597,11 @@
         return true;
     }
 
-    private void shredPagesAndFinish(final Uri writeToUri) {
-        new PageShredder(this, mPrintJob, mFileProvider, new Runnable() {
+    private void transformDocumentAndFinish(final Uri writeToUri) {
+        // If saving to PDF, apply the attibutes as we are acting as a print service.
+        PrintAttributes attributes = mDestinationSpinnerAdapter.getPdfPrinter() == mCurrentPrinter
+                ?  mPrintJob.getAttributes() : null;
+        new DocumentTransformer(this, mPrintJob, mFileProvider, attributes, new Runnable() {
             @Override
             public void run() {
                 if (writeToUri != null) {
@@ -1606,7 +1609,7 @@
                 }
                 doFinish();
             }
-        }).shred();
+        }).transform();
     }
 
     private void doFinish() {
@@ -2329,7 +2332,7 @@
         }
     }
 
-    private static final class PageShredder implements ServiceConnection {
+    private static final class DocumentTransformer implements ServiceConnection {
         private static final String TEMP_FILE_PREFIX = "print_job";
         private static final String TEMP_FILE_EXTENSION = ".pdf";
 
@@ -2341,20 +2344,24 @@
 
         private final PageRange[] mPagesToShred;
 
+        private final PrintAttributes mAttributesToApply;
+
         private final Runnable mCallback;
 
-        public PageShredder(Context context, PrintJobInfo printJob,
-                MutexFileProvider fileProvider, Runnable callback) {
+        public DocumentTransformer(Context context, PrintJobInfo printJob,
+                MutexFileProvider fileProvider, PrintAttributes attributes,
+                Runnable callback) {
             mContext = context;
             mPrintJob = printJob;
             mFileProvider = fileProvider;
             mCallback = callback;
             mPagesToShred = computePagesToShred(mPrintJob);
+            mAttributesToApply = attributes;
         }
 
-        public void shred() {
+        public void transform() {
             // If we have only the pages we want, done.
-            if (mPagesToShred.length <= 0) {
+            if (mPagesToShred.length <= 0 && mAttributesToApply == null) {
                 mCallback.run();
                 return;
             }
@@ -2376,14 +2383,14 @@
                     // final and this code is the last one to touch
                     // them as shredding is the very last step, so the
                     // UI is not interactive at this point.
-                    shredPages(editor);
+                    doTransform(editor);
                     updatePrintJob();
                     return null;
                 }
 
                 @Override
                 protected void onPostExecute(Void aVoid) {
-                    mContext.unbindService(PageShredder.this);
+                    mContext.unbindService(DocumentTransformer.this);
                     mCallback.run();
                 }
             }.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
@@ -2394,7 +2401,7 @@
             /* do nothing */
         }
 
-        private void shredPages(IPdfEditor editor) {
+        private void doTransform(IPdfEditor editor) {
             File tempFile = null;
             ParcelFileDescriptor src = null;
             ParcelFileDescriptor dst = null;
@@ -2413,6 +2420,11 @@
                 // Drop the pages.
                 editor.removePages(mPagesToShred);
 
+                // Apply print attributes if needed.
+                if (mAttributesToApply != null) {
+                    editor.applyPrintAttributes(mAttributesToApply);
+                }
+
                 // Write the modified PDF to a temp file.
                 tempFile = File.createTempFile(TEMP_FILE_PREFIX, TEMP_FILE_EXTENSION,
                         mContext.getCacheDir());
diff --git a/packages/SystemUI/res/drawable/ic_dismiss_all.xml b/packages/SystemUI/res/drawable/ic_dismiss_all.xml
index 8e5e572..c32e5b11 100644
--- a/packages/SystemUI/res/drawable/ic_dismiss_all.xml
+++ b/packages/SystemUI/res/drawable/ic_dismiss_all.xml
@@ -16,6 +16,7 @@
 <vector xmlns:android="http://schemas.android.com/apk/res/android"
     android:width="24dp"
     android:height="24dp"
+    android:autoMirrored="true"
     android:viewportWidth="48.0"
     android:viewportHeight="48.0">
     <path
diff --git a/packages/SystemUI/res/drawable/ic_qs_signal_1.xml b/packages/SystemUI/res/drawable/ic_qs_signal_1.xml
index adbda4a..7fb423e 100644
--- a/packages/SystemUI/res/drawable/ic_qs_signal_1.xml
+++ b/packages/SystemUI/res/drawable/ic_qs_signal_1.xml
@@ -21,14 +21,14 @@
         android:viewportHeight="24.0">
     <path
         android:fillColor="#FFFFFFFF"
-        android:pathData="M19.700001,20.000000l2.000000,0.000000l0.000000,2.000000l-2.000000,0.000000z"/>
+        android:pathData="M19.7,20.0l2.0,0.0l0.0,2.0l-2.0,0.0z"/>
     <path
         android:fillColor="#FFFFFFFF"
-        android:pathData="M19.700001,10.000000l2.000000,0.000000l0.000000,8.100000l-2.000000,0.000000z"/>
+        android:pathData="M19.7,10.0l2.0,0.0l0.0,8.1l-2.0,0.0z"/>
+    <path
+        android:fillColor="#4DFFFFFF"
+        android:pathData="M17.7,8.0l4.299999,0.0 0.0,-6.0 -20.0,20.0 15.700001,0.0z"/>
     <path
         android:fillColor="#FFFFFFFF"
-        android:pathData="M11.300000,12.700000l-9.300000,9.300000 9.300000,0.000000z"/>
-    <path
-        android:pathData="M17.700001,8.000000l4.299999,0.000000 0.000000,-6.000000 -20.000000,20.000000 15.700001,0.000000z"
-        android:fillColor="#4DFFFFFF"/>
+        android:pathData="M10.1,13.9l-8.1,8.1 8.1,0.0z"/>
 </vector>
diff --git a/packages/SystemUI/res/drawable/ic_qs_signal_full_1.xml b/packages/SystemUI/res/drawable/ic_qs_signal_full_1.xml
index a71e33a..8baa4eb 100644
--- a/packages/SystemUI/res/drawable/ic_qs_signal_full_1.xml
+++ b/packages/SystemUI/res/drawable/ic_qs_signal_full_1.xml
@@ -21,8 +21,8 @@
         android:viewportHeight="24.0">
     <path
         android:fillColor="#4DFFFFFF"
-        android:pathData="M2.000000,22.000000l20.000000,0.000000 0.000000,-20.000000z"/>
+        android:pathData="M2.0,22.0l20.0,0.0 0.0,-20.0z"/>
     <path
         android:fillColor="#FFFFFFFF"
-        android:pathData="M11.300000,12.700000l-9.300000,9.300000 9.300000,0.000000z"/>
+        android:pathData="M10.1,13.9l-8.1,8.1 8.1,0.0z"/>
 </vector>
diff --git a/packages/SystemUI/res/drawable/stat_sys_signal_1.xml b/packages/SystemUI/res/drawable/stat_sys_signal_1.xml
index a53e946..d1124ee 100644
--- a/packages/SystemUI/res/drawable/stat_sys_signal_1.xml
+++ b/packages/SystemUI/res/drawable/stat_sys_signal_1.xml
@@ -21,14 +21,14 @@
         android:viewportHeight="24.0">
     <path
         android:fillColor="#FFFFFFFF"
-        android:pathData="M19.700001,20.000000l2.000000,0.000000l0.000000,2.000000l-2.000000,0.000000z"/>
+        android:pathData="M19.7,20.0l2.0,0.0l0.0,2.0l-2.0,0.0z"/>
     <path
         android:fillColor="#FFFFFFFF"
-        android:pathData="M19.700001,10.000000l2.000000,0.000000l0.000000,8.100000l-2.000000,0.000000z"/>
+        android:pathData="M19.7,10.0l2.0,0.0l0.0,8.1l-2.0,0.0z"/>
+    <path
+        android:fillColor="#4DFFFFFF"
+        android:pathData="M17.7,8.0l4.299999,0.0 0.0,-6.0 -20.0,20.0 15.700001,0.0z"/>
     <path
         android:fillColor="#FFFFFFFF"
-        android:pathData="M11.300000,12.700000l-9.300000,9.300000 9.300000,0.000000z"/>
-    <path
-        android:pathData="M17.700001,8.000000l4.299999,0.000000 0.000000,-6.000000 -20.000000,20.000000 15.700001,0.000000z"
-        android:fillColor="#4DFFFFFF"/>
+        android:pathData="M10.1,13.9l-8.1,8.1 8.1,0.0z"/>
 </vector>
diff --git a/packages/SystemUI/res/drawable/stat_sys_signal_1_fully.xml b/packages/SystemUI/res/drawable/stat_sys_signal_1_fully.xml
index 6bc55cd..29eda94 100644
--- a/packages/SystemUI/res/drawable/stat_sys_signal_1_fully.xml
+++ b/packages/SystemUI/res/drawable/stat_sys_signal_1_fully.xml
@@ -21,8 +21,8 @@
         android:viewportHeight="24.0">
     <path
         android:fillColor="#4DFFFFFF"
-        android:pathData="M2.000000,22.000000l20.000000,0.000000 0.000000,-20.000000z"/>
+        android:pathData="M2.0,22.0l20.0,0.0 0.0,-20.0z"/>
     <path
         android:fillColor="#FFFFFFFF"
-        android:pathData="M11.300000,12.700000l-9.300000,9.300000 9.300000,0.000000z"/>
+        android:pathData="M10.1,13.9l-8.1,8.1 8.1,0.0z"/>
 </vector>
diff --git a/packages/SystemUI/res/values-am/strings.xml b/packages/SystemUI/res/values-am/strings.xml
index f08d99e..5b21f3f 100644
--- a/packages/SystemUI/res/values-am/strings.xml
+++ b/packages/SystemUI/res/values-am/strings.xml
@@ -275,8 +275,7 @@
     <string name="quick_settings_cellular_detail_data_warning" msgid="2440098045692399009">"የ<xliff:g id="DATA_LIMIT">%s</xliff:g> ማስጠንቀቂያ"</string>
     <string name="recents_empty_message" msgid="8682129509540827999">"የቅርብ ጊዜ ማያ ገጾችዎ እዚህ ይታያሉ"</string>
     <string name="recents_app_info_button_label" msgid="2890317189376000030">"የመተግበሪያ መረጃ"</string>
-    <!-- no translation found for recents_lock_to_app_button_label (6942899049072506044) -->
-    <skip />
+    <string name="recents_lock_to_app_button_label" msgid="6942899049072506044">"ማያ ገጽ መሰካት"</string>
     <string name="recents_search_bar_label" msgid="8074997400187836677">"ፈልግ"</string>
     <string name="recents_launch_error_message" msgid="2969287838120550506">"<xliff:g id="APP">%s</xliff:g>ን መጀመር አልተቻለም።"</string>
     <string name="expanded_header_battery_charged" msgid="5945855970267657951">"ባትሪ ሞልቷል"</string>
diff --git a/packages/SystemUI/res/values-bg/strings.xml b/packages/SystemUI/res/values-bg/strings.xml
index 2011135..3a2eabd 100644
--- a/packages/SystemUI/res/values-bg/strings.xml
+++ b/packages/SystemUI/res/values-bg/strings.xml
@@ -275,8 +275,7 @@
     <string name="quick_settings_cellular_detail_data_warning" msgid="2440098045692399009">"Предупреждение: <xliff:g id="DATA_LIMIT">%s</xliff:g>"</string>
     <string name="recents_empty_message" msgid="8682129509540827999">"Скорошните ви екрани се показват тук"</string>
     <string name="recents_app_info_button_label" msgid="2890317189376000030">"Информация за приложението"</string>
-    <!-- no translation found for recents_lock_to_app_button_label (6942899049072506044) -->
-    <skip />
+    <string name="recents_lock_to_app_button_label" msgid="6942899049072506044">"фиксиране на екрана"</string>
     <string name="recents_search_bar_label" msgid="8074997400187836677">"търсене"</string>
     <string name="recents_launch_error_message" msgid="2969287838120550506">"<xliff:g id="APP">%s</xliff:g> не можа да стартира."</string>
     <string name="expanded_header_battery_charged" msgid="5945855970267657951">"Заредена"</string>
diff --git a/packages/SystemUI/res/values-bn-rBD/strings.xml b/packages/SystemUI/res/values-bn-rBD/strings.xml
index 60872f5..ff1d1a0 100644
--- a/packages/SystemUI/res/values-bn-rBD/strings.xml
+++ b/packages/SystemUI/res/values-bn-rBD/strings.xml
@@ -275,8 +275,7 @@
     <string name="quick_settings_cellular_detail_data_warning" msgid="2440098045692399009">"<xliff:g id="DATA_LIMIT">%s</xliff:g> সতর্কতা"</string>
     <string name="recents_empty_message" msgid="8682129509540827999">"আপনার সাম্প্রতিক স্ক্রীনগুলো এখানে দেখা যাবে"</string>
     <string name="recents_app_info_button_label" msgid="2890317189376000030">"অ্যাপ্লিকেশানের তথ্য"</string>
-    <!-- no translation found for recents_lock_to_app_button_label (6942899049072506044) -->
-    <skip />
+    <string name="recents_lock_to_app_button_label" msgid="6942899049072506044">"স্ক্রীন পিন করা"</string>
     <string name="recents_search_bar_label" msgid="8074997400187836677">"অনুসন্ধান"</string>
     <string name="recents_launch_error_message" msgid="2969287838120550506">"<xliff:g id="APP">%s</xliff:g> শুরু করা যায়নি৷"</string>
     <string name="expanded_header_battery_charged" msgid="5945855970267657951">"চার্জ হয়েছে"</string>
diff --git a/packages/SystemUI/res/values-ca/strings.xml b/packages/SystemUI/res/values-ca/strings.xml
index 9f74571..feb326c 100644
--- a/packages/SystemUI/res/values-ca/strings.xml
+++ b/packages/SystemUI/res/values-ca/strings.xml
@@ -277,8 +277,7 @@
     <string name="quick_settings_cellular_detail_data_warning" msgid="2440098045692399009">"Advertiment: <xliff:g id="DATA_LIMIT">%s</xliff:g>"</string>
     <string name="recents_empty_message" msgid="8682129509540827999">"Aquí es mostren les teves pantalles recents."</string>
     <string name="recents_app_info_button_label" msgid="2890317189376000030">"Informació de l\'aplicació"</string>
-    <!-- no translation found for recents_lock_to_app_button_label (6942899049072506044) -->
-    <skip />
+    <string name="recents_lock_to_app_button_label" msgid="6942899049072506044">"fixació de pantalla"</string>
     <string name="recents_search_bar_label" msgid="8074997400187836677">"cerca"</string>
     <string name="recents_launch_error_message" msgid="2969287838120550506">"No s\'ha pogut iniciar <xliff:g id="APP">%s</xliff:g>."</string>
     <string name="expanded_header_battery_charged" msgid="5945855970267657951">"Carregada"</string>
diff --git a/packages/SystemUI/res/values-da/strings.xml b/packages/SystemUI/res/values-da/strings.xml
index c102f13..ae8ccf3 100644
--- a/packages/SystemUI/res/values-da/strings.xml
+++ b/packages/SystemUI/res/values-da/strings.xml
@@ -275,8 +275,7 @@
     <string name="quick_settings_cellular_detail_data_warning" msgid="2440098045692399009">"Advarsel ved <xliff:g id="DATA_LIMIT">%s</xliff:g>"</string>
     <string name="recents_empty_message" msgid="8682129509540827999">"Dine seneste skærme vises her"</string>
     <string name="recents_app_info_button_label" msgid="2890317189376000030">"Oplysninger om applikationen"</string>
-    <!-- no translation found for recents_lock_to_app_button_label (6942899049072506044) -->
-    <skip />
+    <string name="recents_lock_to_app_button_label" msgid="6942899049072506044">"skærmfastholdelse"</string>
     <string name="recents_search_bar_label" msgid="8074997400187836677">"søg"</string>
     <string name="recents_launch_error_message" msgid="2969287838120550506">"<xliff:g id="APP">%s</xliff:g> kunne ikke startes."</string>
     <string name="expanded_header_battery_charged" msgid="5945855970267657951">"Opladet"</string>
diff --git a/packages/SystemUI/res/values-el/strings.xml b/packages/SystemUI/res/values-el/strings.xml
index d924cea..946dc2c 100644
--- a/packages/SystemUI/res/values-el/strings.xml
+++ b/packages/SystemUI/res/values-el/strings.xml
@@ -277,8 +277,7 @@
     <string name="quick_settings_cellular_detail_data_warning" msgid="2440098045692399009">"Προειδοποίηση για <xliff:g id="DATA_LIMIT">%s</xliff:g>"</string>
     <string name="recents_empty_message" msgid="8682129509540827999">"Οι πρόσφατες οθόνες σας εμφανίζονται εδώ"</string>
     <string name="recents_app_info_button_label" msgid="2890317189376000030">"Πληροφορίες εφαρμογής"</string>
-    <!-- no translation found for recents_lock_to_app_button_label (6942899049072506044) -->
-    <skip />
+    <string name="recents_lock_to_app_button_label" msgid="6942899049072506044">"καρφίτσωμα οθόνης"</string>
     <string name="recents_search_bar_label" msgid="8074997400187836677">"αναζήτηση"</string>
     <string name="recents_launch_error_message" msgid="2969287838120550506">"Δεν ήταν δυνατή η εκκίνηση της εφαρμογής <xliff:g id="APP">%s</xliff:g>."</string>
     <string name="expanded_header_battery_charged" msgid="5945855970267657951">"Φορτίστηκε"</string>
diff --git a/packages/SystemUI/res/values-es-rUS/strings.xml b/packages/SystemUI/res/values-es-rUS/strings.xml
index 0e723ea..d3aab3b 100644
--- a/packages/SystemUI/res/values-es-rUS/strings.xml
+++ b/packages/SystemUI/res/values-es-rUS/strings.xml
@@ -277,8 +277,7 @@
     <string name="quick_settings_cellular_detail_data_warning" msgid="2440098045692399009">"Advertencia de <xliff:g id="DATA_LIMIT">%s</xliff:g>"</string>
     <string name="recents_empty_message" msgid="8682129509540827999">"Las pantallas recientes aparecen aquí."</string>
     <string name="recents_app_info_button_label" msgid="2890317189376000030">"Información de la aplicación"</string>
-    <!-- no translation found for recents_lock_to_app_button_label (6942899049072506044) -->
-    <skip />
+    <string name="recents_lock_to_app_button_label" msgid="6942899049072506044">"Fijar pantalla"</string>
     <string name="recents_search_bar_label" msgid="8074997400187836677">"buscar"</string>
     <string name="recents_launch_error_message" msgid="2969287838120550506">"No se pudo iniciar <xliff:g id="APP">%s</xliff:g>."</string>
     <string name="expanded_header_battery_charged" msgid="5945855970267657951">"Cargada"</string>
diff --git a/packages/SystemUI/res/values-es/strings.xml b/packages/SystemUI/res/values-es/strings.xml
index b8e4e4e..1530bf3 100644
--- a/packages/SystemUI/res/values-es/strings.xml
+++ b/packages/SystemUI/res/values-es/strings.xml
@@ -275,8 +275,7 @@
     <string name="quick_settings_cellular_detail_data_warning" msgid="2440098045692399009">"Advertencia de <xliff:g id="DATA_LIMIT">%s</xliff:g>"</string>
     <string name="recents_empty_message" msgid="8682129509540827999">"Aquí aparecerán tus pantallas recientes"</string>
     <string name="recents_app_info_button_label" msgid="2890317189376000030">"Información de la aplicación"</string>
-    <!-- no translation found for recents_lock_to_app_button_label (6942899049072506044) -->
-    <skip />
+    <string name="recents_lock_to_app_button_label" msgid="6942899049072506044">"fijación de pantalla"</string>
     <string name="recents_search_bar_label" msgid="8074997400187836677">"buscar"</string>
     <string name="recents_launch_error_message" msgid="2969287838120550506">"No se ha podido iniciar <xliff:g id="APP">%s</xliff:g>."</string>
     <string name="expanded_header_battery_charged" msgid="5945855970267657951">"Cargada"</string>
diff --git a/packages/SystemUI/res/values-et-rEE/strings.xml b/packages/SystemUI/res/values-et-rEE/strings.xml
index be85166..55d6d1f 100644
--- a/packages/SystemUI/res/values-et-rEE/strings.xml
+++ b/packages/SystemUI/res/values-et-rEE/strings.xml
@@ -275,8 +275,7 @@
     <string name="quick_settings_cellular_detail_data_warning" msgid="2440098045692399009">"<xliff:g id="DATA_LIMIT">%s</xliff:g> hoiatus"</string>
     <string name="recents_empty_message" msgid="8682129509540827999">"Teie viimane ekraanikuva ilmub siia"</string>
     <string name="recents_app_info_button_label" msgid="2890317189376000030">"Rakenduste teave"</string>
-    <!-- no translation found for recents_lock_to_app_button_label (6942899049072506044) -->
-    <skip />
+    <string name="recents_lock_to_app_button_label" msgid="6942899049072506044">"ekraanikuva kinnitamine"</string>
     <string name="recents_search_bar_label" msgid="8074997400187836677">"otsing"</string>
     <string name="recents_launch_error_message" msgid="2969287838120550506">"Rakendust <xliff:g id="APP">%s</xliff:g> ei saanud käivitada."</string>
     <string name="expanded_header_battery_charged" msgid="5945855970267657951">"Laetud"</string>
diff --git a/packages/SystemUI/res/values-eu-rES/strings.xml b/packages/SystemUI/res/values-eu-rES/strings.xml
index 84874d3..01cd860 100644
--- a/packages/SystemUI/res/values-eu-rES/strings.xml
+++ b/packages/SystemUI/res/values-eu-rES/strings.xml
@@ -275,8 +275,7 @@
     <string name="quick_settings_cellular_detail_data_warning" msgid="2440098045692399009">"Abisua: <xliff:g id="DATA_LIMIT">%s</xliff:g>"</string>
     <string name="recents_empty_message" msgid="8682129509540827999">"Ikusitako azken pantailak erakusten dira hemen"</string>
     <string name="recents_app_info_button_label" msgid="2890317189376000030">"Aplikazioaren informazioa"</string>
-    <!-- no translation found for recents_lock_to_app_button_label (6942899049072506044) -->
-    <skip />
+    <string name="recents_lock_to_app_button_label" msgid="6942899049072506044">"pantaila-ainguratzea"</string>
     <string name="recents_search_bar_label" msgid="8074997400187836677">"bilatu"</string>
     <string name="recents_launch_error_message" msgid="2969287838120550506">"Ezin izan da hasi <xliff:g id="APP">%s</xliff:g>."</string>
     <string name="expanded_header_battery_charged" msgid="5945855970267657951">"Kargatuta"</string>
@@ -300,7 +299,7 @@
     <string name="phone_hint" msgid="3101468054914424646">"Telefonoa irekitzeko, pasatu hatza eskuinera."</string>
     <string name="camera_hint" msgid="5241441720959174226">"Kamera irekitzeko, pasatu hatza ezkerrera."</string>
     <string name="interruption_level_none" msgid="3831278883136066646">"Bat ere ez"</string>
-    <string name="interruption_level_priority" msgid="6517366750688942030">"Lehentasuna"</string>
+    <string name="interruption_level_priority" msgid="6517366750688942030">"Lehentas."</string>
     <string name="interruption_level_all" msgid="1330581184930945764">"Guztiak"</string>
     <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"Kargatzen (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> guztiz kargatu arte)"</string>
     <string name="accessibility_multi_user_switch_switcher" msgid="7305948938141024937">"Aldatu erabiltzailea"</string>
diff --git a/packages/SystemUI/res/values-fi/strings.xml b/packages/SystemUI/res/values-fi/strings.xml
index be27fb1..0d5281c 100644
--- a/packages/SystemUI/res/values-fi/strings.xml
+++ b/packages/SystemUI/res/values-fi/strings.xml
@@ -275,8 +275,7 @@
     <string name="quick_settings_cellular_detail_data_warning" msgid="2440098045692399009">"<xliff:g id="DATA_LIMIT">%s</xliff:g> – varoitus"</string>
     <string name="recents_empty_message" msgid="8682129509540827999">"Äskettäin käytetyt ruudut näkyvät tässä"</string>
     <string name="recents_app_info_button_label" msgid="2890317189376000030">"Sovellustiedot"</string>
-    <!-- no translation found for recents_lock_to_app_button_label (6942899049072506044) -->
-    <skip />
+    <string name="recents_lock_to_app_button_label" msgid="6942899049072506044">"näytön kiinnitys"</string>
     <string name="recents_search_bar_label" msgid="8074997400187836677">"haku"</string>
     <string name="recents_launch_error_message" msgid="2969287838120550506">"Sovelluksen <xliff:g id="APP">%s</xliff:g> käynnistäminen epäonnistui."</string>
     <string name="expanded_header_battery_charged" msgid="5945855970267657951">"Ladattu"</string>
diff --git a/packages/SystemUI/res/values-fr-rCA/strings.xml b/packages/SystemUI/res/values-fr-rCA/strings.xml
index a52655e..5119bab 100644
--- a/packages/SystemUI/res/values-fr-rCA/strings.xml
+++ b/packages/SystemUI/res/values-fr-rCA/strings.xml
@@ -277,8 +277,7 @@
     <string name="quick_settings_cellular_detail_data_warning" msgid="2440098045692399009">"Avertissement : <xliff:g id="DATA_LIMIT">%s</xliff:g>"</string>
     <string name="recents_empty_message" msgid="8682129509540827999">"Vos écrans récents s\'affichent ici"</string>
     <string name="recents_app_info_button_label" msgid="2890317189376000030">"Détails de l\'application"</string>
-    <!-- no translation found for recents_lock_to_app_button_label (6942899049072506044) -->
-    <skip />
+    <string name="recents_lock_to_app_button_label" msgid="6942899049072506044">"épinglage d\'écran"</string>
     <string name="recents_search_bar_label" msgid="8074997400187836677">"rechercher"</string>
     <string name="recents_launch_error_message" msgid="2969287838120550506">"Impossible de lancer <xliff:g id="APP">%s</xliff:g>."</string>
     <string name="expanded_header_battery_charged" msgid="5945855970267657951">"Chargée"</string>
diff --git a/packages/SystemUI/res/values-fr/strings.xml b/packages/SystemUI/res/values-fr/strings.xml
index 26fa5a2..52f05db 100644
--- a/packages/SystemUI/res/values-fr/strings.xml
+++ b/packages/SystemUI/res/values-fr/strings.xml
@@ -277,8 +277,7 @@
     <string name="quick_settings_cellular_detail_data_warning" msgid="2440098045692399009">"Avertissement : <xliff:g id="DATA_LIMIT">%s</xliff:g>"</string>
     <string name="recents_empty_message" msgid="8682129509540827999">"Vos écrans récents s\'affichent ici"</string>
     <string name="recents_app_info_button_label" msgid="2890317189376000030">"Informations sur l\'application"</string>
-    <!-- no translation found for recents_lock_to_app_button_label (6942899049072506044) -->
-    <skip />
+    <string name="recents_lock_to_app_button_label" msgid="6942899049072506044">"épinglage d\'écran"</string>
     <string name="recents_search_bar_label" msgid="8074997400187836677">"rechercher"</string>
     <string name="recents_launch_error_message" msgid="2969287838120550506">"Impossible de lancer <xliff:g id="APP">%s</xliff:g>."</string>
     <string name="expanded_header_battery_charged" msgid="5945855970267657951">"Chargé"</string>
diff --git a/packages/SystemUI/res/values-gl-rES/strings.xml b/packages/SystemUI/res/values-gl-rES/strings.xml
index 1d9b63a..f5b773f 100644
--- a/packages/SystemUI/res/values-gl-rES/strings.xml
+++ b/packages/SystemUI/res/values-gl-rES/strings.xml
@@ -277,8 +277,7 @@
     <string name="quick_settings_cellular_detail_data_warning" msgid="2440098045692399009">"Advertencia <xliff:g id="DATA_LIMIT">%s</xliff:g>"</string>
     <string name="recents_empty_message" msgid="8682129509540827999">"As túas pantallas recentes aparecen aquí"</string>
     <string name="recents_app_info_button_label" msgid="2890317189376000030">"Información da aplicación"</string>
-    <!-- no translation found for recents_lock_to_app_button_label (6942899049072506044) -->
-    <skip />
+    <string name="recents_lock_to_app_button_label" msgid="6942899049072506044">"fixación de pantalla"</string>
     <string name="recents_search_bar_label" msgid="8074997400187836677">"buscar"</string>
     <string name="recents_launch_error_message" msgid="2969287838120550506">"Non foi posible iniciar <xliff:g id="APP">%s</xliff:g>."</string>
     <string name="expanded_header_battery_charged" msgid="5945855970267657951">"Cargada"</string>
diff --git a/packages/SystemUI/res/values-hr/strings.xml b/packages/SystemUI/res/values-hr/strings.xml
index 0ad9f3e..101b4cd 100644
--- a/packages/SystemUI/res/values-hr/strings.xml
+++ b/packages/SystemUI/res/values-hr/strings.xml
@@ -275,8 +275,7 @@
     <string name="quick_settings_cellular_detail_data_warning" msgid="2440098045692399009">"Upozorenje <xliff:g id="DATA_LIMIT">%s</xliff:g>"</string>
     <string name="recents_empty_message" msgid="8682129509540827999">"Ovdje se pojavljuju vaši nedavni zasloni"</string>
     <string name="recents_app_info_button_label" msgid="2890317189376000030">"Informacije o aplikaciji"</string>
-    <!-- no translation found for recents_lock_to_app_button_label (6942899049072506044) -->
-    <skip />
+    <string name="recents_lock_to_app_button_label" msgid="6942899049072506044">"prikačivanje zaslona"</string>
     <string name="recents_search_bar_label" msgid="8074997400187836677">"pretraži"</string>
     <string name="recents_launch_error_message" msgid="2969287838120550506">"Aplikacija <xliff:g id="APP">%s</xliff:g> nije pokrenuta."</string>
     <string name="expanded_header_battery_charged" msgid="5945855970267657951">"Napunjeno"</string>
diff --git a/packages/SystemUI/res/values-hu/strings.xml b/packages/SystemUI/res/values-hu/strings.xml
index 591e6fa..0b7dff3 100644
--- a/packages/SystemUI/res/values-hu/strings.xml
+++ b/packages/SystemUI/res/values-hu/strings.xml
@@ -275,8 +275,7 @@
     <string name="quick_settings_cellular_detail_data_warning" msgid="2440098045692399009">"Figyelem! <xliff:g id="DATA_LIMIT">%s</xliff:g>"</string>
     <string name="recents_empty_message" msgid="8682129509540827999">"A legutóbbi képernyők itt jelennek meg"</string>
     <string name="recents_app_info_button_label" msgid="2890317189376000030">"Az alkalmazás adatai"</string>
-    <!-- no translation found for recents_lock_to_app_button_label (6942899049072506044) -->
-    <skip />
+    <string name="recents_lock_to_app_button_label" msgid="6942899049072506044">"képernyő rögzítése"</string>
     <string name="recents_search_bar_label" msgid="8074997400187836677">"keresés"</string>
     <string name="recents_launch_error_message" msgid="2969287838120550506">"Nem lehet elindítani a következőt: <xliff:g id="APP">%s</xliff:g>."</string>
     <string name="expanded_header_battery_charged" msgid="5945855970267657951">"Feltöltve"</string>
diff --git a/packages/SystemUI/res/values-hy-rAM/strings.xml b/packages/SystemUI/res/values-hy-rAM/strings.xml
index 5db23b8..e56633a 100644
--- a/packages/SystemUI/res/values-hy-rAM/strings.xml
+++ b/packages/SystemUI/res/values-hy-rAM/strings.xml
@@ -275,8 +275,7 @@
     <string name="quick_settings_cellular_detail_data_warning" msgid="2440098045692399009">"<xliff:g id="DATA_LIMIT">%s</xliff:g> զգուշացում"</string>
     <string name="recents_empty_message" msgid="8682129509540827999">"Ձեր վերջին էկրանները տեսանելի են այստեղ"</string>
     <string name="recents_app_info_button_label" msgid="2890317189376000030">"Հավելվածի մասին"</string>
-    <!-- no translation found for recents_lock_to_app_button_label (6942899049072506044) -->
-    <skip />
+    <string name="recents_lock_to_app_button_label" msgid="6942899049072506044">"էկրանի ամրակցում"</string>
     <string name="recents_search_bar_label" msgid="8074997400187836677">"որոնել"</string>
     <string name="recents_launch_error_message" msgid="2969287838120550506">"Հնարավոր չէ գործարկել <xliff:g id="APP">%s</xliff:g>-ը:"</string>
     <string name="expanded_header_battery_charged" msgid="5945855970267657951">"Լիցքավորված է"</string>
diff --git a/packages/SystemUI/res/values-is-rIS/strings.xml b/packages/SystemUI/res/values-is-rIS/strings.xml
index 0a05864..cac5b27 100644
--- a/packages/SystemUI/res/values-is-rIS/strings.xml
+++ b/packages/SystemUI/res/values-is-rIS/strings.xml
@@ -275,8 +275,7 @@
     <string name="quick_settings_cellular_detail_data_warning" msgid="2440098045692399009">"<xliff:g id="DATA_LIMIT">%s</xliff:g> viðvörun"</string>
     <string name="recents_empty_message" msgid="8682129509540827999">"Nýlegar skjámyndir birtast hér"</string>
     <string name="recents_app_info_button_label" msgid="2890317189376000030">"Forritsupplýsingar"</string>
-    <!-- no translation found for recents_lock_to_app_button_label (6942899049072506044) -->
-    <skip />
+    <string name="recents_lock_to_app_button_label" msgid="6942899049072506044">"skjáfesting"</string>
     <string name="recents_search_bar_label" msgid="8074997400187836677">"leita"</string>
     <string name="recents_launch_error_message" msgid="2969287838120550506">"Ekki var hægt að ræsa <xliff:g id="APP">%s</xliff:g>."</string>
     <string name="expanded_header_battery_charged" msgid="5945855970267657951">"Fullhlaðin"</string>
diff --git a/packages/SystemUI/res/values-it/strings.xml b/packages/SystemUI/res/values-it/strings.xml
index 82711f1..150bcec 100644
--- a/packages/SystemUI/res/values-it/strings.xml
+++ b/packages/SystemUI/res/values-it/strings.xml
@@ -277,8 +277,7 @@
     <string name="quick_settings_cellular_detail_data_warning" msgid="2440098045692399009">"Avviso <xliff:g id="DATA_LIMIT">%s</xliff:g>"</string>
     <string name="recents_empty_message" msgid="8682129509540827999">"Le tue schermate recenti vengono visualizzate in questa sezione"</string>
     <string name="recents_app_info_button_label" msgid="2890317189376000030">"Informazioni sull\'applicazione"</string>
-    <!-- no translation found for recents_lock_to_app_button_label (6942899049072506044) -->
-    <skip />
+    <string name="recents_lock_to_app_button_label" msgid="6942899049072506044">"blocco su schermo"</string>
     <string name="recents_search_bar_label" msgid="8074997400187836677">"cerca"</string>
     <string name="recents_launch_error_message" msgid="2969287838120550506">"Impossibile avviare <xliff:g id="APP">%s</xliff:g>."</string>
     <string name="expanded_header_battery_charged" msgid="5945855970267657951">"Carica"</string>
diff --git a/packages/SystemUI/res/values-ja/strings.xml b/packages/SystemUI/res/values-ja/strings.xml
index 81e38ea..22501d2 100644
--- a/packages/SystemUI/res/values-ja/strings.xml
+++ b/packages/SystemUI/res/values-ja/strings.xml
@@ -277,8 +277,7 @@
     <string name="quick_settings_cellular_detail_data_warning" msgid="2440098045692399009">"警告: 上限は<xliff:g id="DATA_LIMIT">%s</xliff:g>です"</string>
     <string name="recents_empty_message" msgid="8682129509540827999">"ここに最近の画面が表示されます"</string>
     <string name="recents_app_info_button_label" msgid="2890317189376000030">"アプリ情報"</string>
-    <!-- no translation found for recents_lock_to_app_button_label (6942899049072506044) -->
-    <skip />
+    <string name="recents_lock_to_app_button_label" msgid="6942899049072506044">"画面固定"</string>
     <string name="recents_search_bar_label" msgid="8074997400187836677">"検索"</string>
     <string name="recents_launch_error_message" msgid="2969287838120550506">"<xliff:g id="APP">%s</xliff:g>を開始できません。"</string>
     <string name="expanded_header_battery_charged" msgid="5945855970267657951">"充電が完了しました"</string>
diff --git a/packages/SystemUI/res/values-kk-rKZ/strings.xml b/packages/SystemUI/res/values-kk-rKZ/strings.xml
index fd93009..34ee563 100644
--- a/packages/SystemUI/res/values-kk-rKZ/strings.xml
+++ b/packages/SystemUI/res/values-kk-rKZ/strings.xml
@@ -275,8 +275,7 @@
     <string name="quick_settings_cellular_detail_data_warning" msgid="2440098045692399009">"<xliff:g id="DATA_LIMIT">%s</xliff:g> туралы ескерту"</string>
     <string name="recents_empty_message" msgid="8682129509540827999">"Мұнда жақындағы экрандар көрсетіледі"</string>
     <string name="recents_app_info_button_label" msgid="2890317189376000030">"Қолданба туралы ақпарат"</string>
-    <!-- no translation found for recents_lock_to_app_button_label (6942899049072506044) -->
-    <skip />
+    <string name="recents_lock_to_app_button_label" msgid="6942899049072506044">"экранды бекіту"</string>
     <string name="recents_search_bar_label" msgid="8074997400187836677">"іздеу"</string>
     <string name="recents_launch_error_message" msgid="2969287838120550506">"<xliff:g id="APP">%s</xliff:g> іске қосу мүмкін болмады."</string>
     <string name="expanded_header_battery_charged" msgid="5945855970267657951">"Зарядталды"</string>
diff --git a/packages/SystemUI/res/values-kn-rIN/strings.xml b/packages/SystemUI/res/values-kn-rIN/strings.xml
index 174c0a9..99d8acd 100644
--- a/packages/SystemUI/res/values-kn-rIN/strings.xml
+++ b/packages/SystemUI/res/values-kn-rIN/strings.xml
@@ -275,8 +275,7 @@
     <string name="quick_settings_cellular_detail_data_warning" msgid="2440098045692399009">"<xliff:g id="DATA_LIMIT">%s</xliff:g> ಎಚ್ಚರಿಕೆ"</string>
     <string name="recents_empty_message" msgid="8682129509540827999">"ನಿಮ್ಮ ಇತ್ತೀಚಿನ ಪರದೆಗಳು ಇಲ್ಲಿ ಕಾಣಿಸಿಕೊಳ್ಳುತ್ತವೆ"</string>
     <string name="recents_app_info_button_label" msgid="2890317189376000030">"ಅಪ್ಲಿಕೇಶನ್ ಮಾಹಿತಿ"</string>
-    <!-- no translation found for recents_lock_to_app_button_label (6942899049072506044) -->
-    <skip />
+    <string name="recents_lock_to_app_button_label" msgid="6942899049072506044">"ಪರದೆ ಪಿನ್ನಿಂಗ್"</string>
     <string name="recents_search_bar_label" msgid="8074997400187836677">"ಹುಡುಕಾಟ"</string>
     <string name="recents_launch_error_message" msgid="2969287838120550506">"<xliff:g id="APP">%s</xliff:g> ಪ್ರಾರಂಭಿಸಲು ಸಾದ್ಯವಿಲ್ಲ."</string>
     <string name="expanded_header_battery_charged" msgid="5945855970267657951">"ಚಾರ್ಜ್ ಆಗಿದೆ"</string>
diff --git a/packages/SystemUI/res/values-ko/strings.xml b/packages/SystemUI/res/values-ko/strings.xml
index 1914116..f00bc01 100644
--- a/packages/SystemUI/res/values-ko/strings.xml
+++ b/packages/SystemUI/res/values-ko/strings.xml
@@ -275,8 +275,7 @@
     <string name="quick_settings_cellular_detail_data_warning" msgid="2440098045692399009">"<xliff:g id="DATA_LIMIT">%s</xliff:g> 경고"</string>
     <string name="recents_empty_message" msgid="8682129509540827999">"여기에 최근 화면이 표시됩니다."</string>
     <string name="recents_app_info_button_label" msgid="2890317189376000030">"애플리케이션 정보"</string>
-    <!-- no translation found for recents_lock_to_app_button_label (6942899049072506044) -->
-    <skip />
+    <string name="recents_lock_to_app_button_label" msgid="6942899049072506044">"화면 고정"</string>
     <string name="recents_search_bar_label" msgid="8074997400187836677">"검색"</string>
     <string name="recents_launch_error_message" msgid="2969287838120550506">"<xliff:g id="APP">%s</xliff:g>을(를) 시작할 수 없습니다."</string>
     <string name="expanded_header_battery_charged" msgid="5945855970267657951">"충전됨"</string>
diff --git a/packages/SystemUI/res/values-ky-rKG/strings.xml b/packages/SystemUI/res/values-ky-rKG/strings.xml
index 44babae..fc228156 100644
--- a/packages/SystemUI/res/values-ky-rKG/strings.xml
+++ b/packages/SystemUI/res/values-ky-rKG/strings.xml
@@ -300,8 +300,7 @@
     <string name="quick_settings_cellular_detail_data_warning" msgid="2440098045692399009">"<xliff:g id="DATA_LIMIT">%s</xliff:g> эскертүү"</string>
     <string name="recents_empty_message" msgid="8682129509540827999">"Акыркы экрандарыңыз бул жерден көрүнөт"</string>
     <string name="recents_app_info_button_label" msgid="2890317189376000030">"Колдонмо жөнүндө маалымат"</string>
-    <!-- no translation found for recents_lock_to_app_button_label (6942899049072506044) -->
-    <skip />
+    <string name="recents_lock_to_app_button_label" msgid="6942899049072506044">"экран кадоо"</string>
     <string name="recents_search_bar_label" msgid="8074997400187836677">"издөө"</string>
     <string name="recents_launch_error_message" msgid="2969287838120550506">"<xliff:g id="APP">%s</xliff:g> баштай алган жок."</string>
     <string name="expanded_header_battery_charged" msgid="5945855970267657951">"Кубатталды"</string>
diff --git a/packages/SystemUI/res/values-lo-rLA/strings.xml b/packages/SystemUI/res/values-lo-rLA/strings.xml
index 5cba7f3..79a225d 100644
--- a/packages/SystemUI/res/values-lo-rLA/strings.xml
+++ b/packages/SystemUI/res/values-lo-rLA/strings.xml
@@ -275,8 +275,7 @@
     <string name="quick_settings_cellular_detail_data_warning" msgid="2440098045692399009">"ຄຳ​ເຕືອນ <xliff:g id="DATA_LIMIT">%s</xliff:g>"</string>
     <string name="recents_empty_message" msgid="8682129509540827999">"Your recent screens appear here"</string>
     <string name="recents_app_info_button_label" msgid="2890317189376000030">"​ຂໍ້​ມູນ​ແອັບ​ພ​ລິ​ເຄ​ຊັນ"</string>
-    <!-- no translation found for recents_lock_to_app_button_label (6942899049072506044) -->
-    <skip />
+    <string name="recents_lock_to_app_button_label" msgid="6942899049072506044">"ການ​ປັກ​ໝຸດ​ໜ້າ​ຈໍ"</string>
     <string name="recents_search_bar_label" msgid="8074997400187836677">"ຊອກຫາ"</string>
     <string name="recents_launch_error_message" msgid="2969287838120550506">"ບໍ່​ສາ​ມາດ​ເລີ່ມ <xliff:g id="APP">%s</xliff:g> ໄດ້."</string>
     <string name="expanded_header_battery_charged" msgid="5945855970267657951">"ສາກເຕັມແລ້ວ."</string>
diff --git a/packages/SystemUI/res/values-lt/strings.xml b/packages/SystemUI/res/values-lt/strings.xml
index 342b985..376d78e 100644
--- a/packages/SystemUI/res/values-lt/strings.xml
+++ b/packages/SystemUI/res/values-lt/strings.xml
@@ -275,8 +275,7 @@
     <string name="quick_settings_cellular_detail_data_warning" msgid="2440098045692399009">"<xliff:g id="DATA_LIMIT">%s</xliff:g> įspėjimas"</string>
     <string name="recents_empty_message" msgid="8682129509540827999">"Čia rodomi naujausi ekranai"</string>
     <string name="recents_app_info_button_label" msgid="2890317189376000030">"Programos informacija"</string>
-    <!-- no translation found for recents_lock_to_app_button_label (6942899049072506044) -->
-    <skip />
+    <string name="recents_lock_to_app_button_label" msgid="6942899049072506044">"ekrano prisegimas"</string>
     <string name="recents_search_bar_label" msgid="8074997400187836677">"paieška"</string>
     <string name="recents_launch_error_message" msgid="2969287838120550506">"Nepavyko paleisti <xliff:g id="APP">%s</xliff:g>."</string>
     <string name="expanded_header_battery_charged" msgid="5945855970267657951">"Įkrautas"</string>
diff --git a/packages/SystemUI/res/values-lv/strings.xml b/packages/SystemUI/res/values-lv/strings.xml
index 960f52c..fe88b10 100644
--- a/packages/SystemUI/res/values-lv/strings.xml
+++ b/packages/SystemUI/res/values-lv/strings.xml
@@ -275,8 +275,7 @@
     <string name="quick_settings_cellular_detail_data_warning" msgid="2440098045692399009">"<xliff:g id="DATA_LIMIT">%s</xliff:g> brīdinājums"</string>
     <string name="recents_empty_message" msgid="8682129509540827999">"Jūsu pēdējie ekrāni tiek rādīti šeit."</string>
     <string name="recents_app_info_button_label" msgid="2890317189376000030">"Informācija par lietojumprogrammu"</string>
-    <!-- no translation found for recents_lock_to_app_button_label (6942899049072506044) -->
-    <skip />
+    <string name="recents_lock_to_app_button_label" msgid="6942899049072506044">"Piespraust ekrānu"</string>
     <string name="recents_search_bar_label" msgid="8074997400187836677">"Meklēt"</string>
     <string name="recents_launch_error_message" msgid="2969287838120550506">"Nevarēja palaist lietotni <xliff:g id="APP">%s</xliff:g>."</string>
     <string name="expanded_header_battery_charged" msgid="5945855970267657951">"Akumulators uzlādēts"</string>
diff --git a/packages/SystemUI/res/values-mk-rMK/strings.xml b/packages/SystemUI/res/values-mk-rMK/strings.xml
index 46cb4a6d..67d6f66 100644
--- a/packages/SystemUI/res/values-mk-rMK/strings.xml
+++ b/packages/SystemUI/res/values-mk-rMK/strings.xml
@@ -277,8 +277,7 @@
     <string name="quick_settings_cellular_detail_data_warning" msgid="2440098045692399009">"Предупредување за <xliff:g id="DATA_LIMIT">%s</xliff:g>"</string>
     <string name="recents_empty_message" msgid="8682129509540827999">"Вашите неодамнешни екрани се појавуваат тука"</string>
     <string name="recents_app_info_button_label" msgid="2890317189376000030">"Информации за апликацијата"</string>
-    <!-- no translation found for recents_lock_to_app_button_label (6942899049072506044) -->
-    <skip />
+    <string name="recents_lock_to_app_button_label" msgid="6942899049072506044">"прикачување екран"</string>
     <string name="recents_search_bar_label" msgid="8074997400187836677">"пребарај"</string>
     <string name="recents_launch_error_message" msgid="2969287838120550506">"<xliff:g id="APP">%s</xliff:g> не може да се вклучи."</string>
     <string name="expanded_header_battery_charged" msgid="5945855970267657951">"Наполнета"</string>
diff --git a/packages/SystemUI/res/values-ml-rIN/strings.xml b/packages/SystemUI/res/values-ml-rIN/strings.xml
index 30423ff4..ec22c91 100644
--- a/packages/SystemUI/res/values-ml-rIN/strings.xml
+++ b/packages/SystemUI/res/values-ml-rIN/strings.xml
@@ -275,8 +275,7 @@
     <string name="quick_settings_cellular_detail_data_warning" msgid="2440098045692399009">"<xliff:g id="DATA_LIMIT">%s</xliff:g> മുന്നറിയിപ്പ്"</string>
     <string name="recents_empty_message" msgid="8682129509540827999">"നിങ്ങളുടെ പുതിയ സ്ക്രീനുകൾ ഇവിടെ ദൃശ്യമാകുന്നു"</string>
     <string name="recents_app_info_button_label" msgid="2890317189376000030">"അപ്ലിക്കേഷൻ വിവരം"</string>
-    <!-- no translation found for recents_lock_to_app_button_label (6942899049072506044) -->
-    <skip />
+    <string name="recents_lock_to_app_button_label" msgid="6942899049072506044">"സ്ക്രീൻ പിൻ ചെയ്യൽ"</string>
     <string name="recents_search_bar_label" msgid="8074997400187836677">"തിരയുക"</string>
     <string name="recents_launch_error_message" msgid="2969287838120550506">"<xliff:g id="APP">%s</xliff:g> ആരംഭിക്കാനായില്ല."</string>
     <string name="expanded_header_battery_charged" msgid="5945855970267657951">"ചാർജ്ജുചെയ്‌തു"</string>
diff --git a/packages/SystemUI/res/values-ms-rMY/strings.xml b/packages/SystemUI/res/values-ms-rMY/strings.xml
index 9da46d8..27b2184 100644
--- a/packages/SystemUI/res/values-ms-rMY/strings.xml
+++ b/packages/SystemUI/res/values-ms-rMY/strings.xml
@@ -275,8 +275,7 @@
     <string name="quick_settings_cellular_detail_data_warning" msgid="2440098045692399009">"Amaran <xliff:g id="DATA_LIMIT">%s</xliff:g>"</string>
     <string name="recents_empty_message" msgid="8682129509540827999">"Skrin terbaru anda terpapar di sini"</string>
     <string name="recents_app_info_button_label" msgid="2890317189376000030">"Maklumat Aplikasi"</string>
-    <!-- no translation found for recents_lock_to_app_button_label (6942899049072506044) -->
-    <skip />
+    <string name="recents_lock_to_app_button_label" msgid="6942899049072506044">"penyematan skrin"</string>
     <string name="recents_search_bar_label" msgid="8074997400187836677">"cari"</string>
     <string name="recents_launch_error_message" msgid="2969287838120550506">"Tidak dapat memulakan <xliff:g id="APP">%s</xliff:g>."</string>
     <string name="expanded_header_battery_charged" msgid="5945855970267657951">"Sudah dicas"</string>
diff --git a/packages/SystemUI/res/values-nb/strings.xml b/packages/SystemUI/res/values-nb/strings.xml
index 22b5943..da01a12 100644
--- a/packages/SystemUI/res/values-nb/strings.xml
+++ b/packages/SystemUI/res/values-nb/strings.xml
@@ -31,7 +31,7 @@
   </plurals>
     <string name="status_bar_no_notifications_title" msgid="4755261167193833213">"Ingen varslinger"</string>
     <string name="status_bar_ongoing_events_title" msgid="1682504513316879202">"Aktiviteter"</string>
-    <string name="status_bar_latest_events_title" msgid="6594767438577593172">"Varslinger"</string>
+    <string name="status_bar_latest_events_title" msgid="6594767438577593172">"Varsler"</string>
     <string name="battery_low_title" msgid="6456385927409742437">"Batterikapasiteten er lav"</string>
     <string name="battery_low_percent_format" msgid="2900940511201380775">"<xliff:g id="PERCENTAGE">%s</xliff:g> gjenstår"</string>
     <string name="battery_low_percent_format_saver_started" msgid="6859235584035338833">"<xliff:g id="PERCENTAGE">%s</xliff:g> gjenstår. Batterisparing er på."</string>
@@ -48,7 +48,7 @@
     <string name="status_bar_settings_auto_rotation" msgid="3790482541357798421">"Roter skjerm automatisk"</string>
     <string name="status_bar_settings_mute_label" msgid="554682549917429396">"DEMPET"</string>
     <string name="status_bar_settings_auto_brightness_label" msgid="511453614962324674">"AUTO"</string>
-    <string name="status_bar_settings_notifications" msgid="397146176280905137">"Varslinger"</string>
+    <string name="status_bar_settings_notifications" msgid="397146176280905137">"Varsler"</string>
     <string name="bluetooth_tethered" msgid="7094101612161133267">"Bluetooth tilknyttet"</string>
     <string name="status_bar_input_method_settings_configure_input_methods" msgid="3504292471512317827">"Konfigurer inndatametoder"</string>
     <string name="status_bar_use_physical_keyboard" msgid="7551903084416057810">"Fysisk tastatur"</string>
@@ -148,7 +148,7 @@
     <string name="accessibility_airplane_mode" msgid="834748999790763092">"Flymodus."</string>
     <string name="accessibility_battery_level" msgid="7451474187113371965">"Batteri – <xliff:g id="NUMBER">%d</xliff:g> prosent."</string>
     <string name="accessibility_settings_button" msgid="799583911231893380">"Systeminnstillinger."</string>
-    <string name="accessibility_notifications_button" msgid="4498000369779421892">"Varslinger."</string>
+    <string name="accessibility_notifications_button" msgid="4498000369779421892">"Varsler."</string>
     <string name="accessibility_remove_notification" msgid="3603099514902182350">"Fjern varsling"</string>
     <string name="accessibility_gps_enabled" msgid="3511469499240123019">"GPS er aktivert."</string>
     <string name="accessibility_gps_acquiring" msgid="8959333351058967158">"Henting av GPS-signal."</string>
@@ -275,8 +275,7 @@
     <string name="quick_settings_cellular_detail_data_warning" msgid="2440098045692399009">"Advarsel for <xliff:g id="DATA_LIMIT">%s</xliff:g>"</string>
     <string name="recents_empty_message" msgid="8682129509540827999">"De sist brukte skjermene dine vises her"</string>
     <string name="recents_app_info_button_label" msgid="2890317189376000030">"Appinformasjon"</string>
-    <!-- no translation found for recents_lock_to_app_button_label (6942899049072506044) -->
-    <skip />
+    <string name="recents_lock_to_app_button_label" msgid="6942899049072506044">"én-appsmodus"</string>
     <string name="recents_search_bar_label" msgid="8074997400187836677">"Søk"</string>
     <string name="recents_launch_error_message" msgid="2969287838120550506">"Kunne ikke starte <xliff:g id="APP">%s</xliff:g>."</string>
     <string name="expanded_header_battery_charged" msgid="5945855970267657951">"Oppladet"</string>
diff --git a/packages/SystemUI/res/values-nl/strings.xml b/packages/SystemUI/res/values-nl/strings.xml
index 4987619..2663231 100644
--- a/packages/SystemUI/res/values-nl/strings.xml
+++ b/packages/SystemUI/res/values-nl/strings.xml
@@ -275,8 +275,7 @@
     <string name="quick_settings_cellular_detail_data_warning" msgid="2440098045692399009">"Waarschuwing voor <xliff:g id="DATA_LIMIT">%s</xliff:g>"</string>
     <string name="recents_empty_message" msgid="8682129509540827999">"Uw recente schermen worden hier weergegeven"</string>
     <string name="recents_app_info_button_label" msgid="2890317189376000030">"App-informatie"</string>
-    <!-- no translation found for recents_lock_to_app_button_label (6942899049072506044) -->
-    <skip />
+    <string name="recents_lock_to_app_button_label" msgid="6942899049072506044">"scherm vastzetten"</string>
     <string name="recents_search_bar_label" msgid="8074997400187836677">"zoeken"</string>
     <string name="recents_launch_error_message" msgid="2969287838120550506">"Kan <xliff:g id="APP">%s</xliff:g> niet starten."</string>
     <string name="expanded_header_battery_charged" msgid="5945855970267657951">"Opgeladen"</string>
diff --git a/packages/SystemUI/res/values-pl/strings.xml b/packages/SystemUI/res/values-pl/strings.xml
index 9b58984..fc79990 100644
--- a/packages/SystemUI/res/values-pl/strings.xml
+++ b/packages/SystemUI/res/values-pl/strings.xml
@@ -247,7 +247,7 @@
     <string name="quick_settings_wifi_label" msgid="9135344704899546041">"Wi-Fi"</string>
     <string name="quick_settings_wifi_not_connected" msgid="7171904845345573431">"Brak połączenia"</string>
     <string name="quick_settings_wifi_no_network" msgid="2221993077220856376">"Brak sieci"</string>
-    <string name="quick_settings_wifi_off_label" msgid="7558778100843885864">"Wyłącz Wi-Fi"</string>
+    <string name="quick_settings_wifi_off_label" msgid="7558778100843885864">"Wi-Fi wyłączone"</string>
     <string name="quick_settings_wifi_detail_empty_text" msgid="2831702993995222755">"Brak dostępnych zapisanych sieci"</string>
     <string name="quick_settings_cast_title" msgid="1893629685050355115">"Przesyłaj ekran"</string>
     <string name="quick_settings_casting" msgid="6601710681033353316">"Przesyłam"</string>
@@ -275,8 +275,7 @@
     <string name="quick_settings_cellular_detail_data_warning" msgid="2440098045692399009">"Ostrzeżenie: <xliff:g id="DATA_LIMIT">%s</xliff:g>"</string>
     <string name="recents_empty_message" msgid="8682129509540827999">"Tutaj pojawią się ostatnie ekrany"</string>
     <string name="recents_app_info_button_label" msgid="2890317189376000030">"Informacje o aplikacji"</string>
-    <!-- no translation found for recents_lock_to_app_button_label (6942899049072506044) -->
-    <skip />
+    <string name="recents_lock_to_app_button_label" msgid="6942899049072506044">"przypinanie ekranu"</string>
     <string name="recents_search_bar_label" msgid="8074997400187836677">"szukaj"</string>
     <string name="recents_launch_error_message" msgid="2969287838120550506">"Nie udało się uruchomić aplikacji <xliff:g id="APP">%s</xliff:g>."</string>
     <string name="expanded_header_battery_charged" msgid="5945855970267657951">"Naładowana"</string>
diff --git a/packages/SystemUI/res/values-pt-rPT/strings.xml b/packages/SystemUI/res/values-pt-rPT/strings.xml
index b7c37b8..bc345b1 100644
--- a/packages/SystemUI/res/values-pt-rPT/strings.xml
+++ b/packages/SystemUI/res/values-pt-rPT/strings.xml
@@ -275,8 +275,7 @@
     <string name="quick_settings_cellular_detail_data_warning" msgid="2440098045692399009">"Aviso de <xliff:g id="DATA_LIMIT">%s</xliff:g>"</string>
     <string name="recents_empty_message" msgid="8682129509540827999">"Os ecrãs recentes aparecem aqui"</string>
     <string name="recents_app_info_button_label" msgid="2890317189376000030">"Informações da aplicação"</string>
-    <!-- no translation found for recents_lock_to_app_button_label (6942899049072506044) -->
-    <skip />
+    <string name="recents_lock_to_app_button_label" msgid="6942899049072506044">"fixação no ecrã"</string>
     <string name="recents_search_bar_label" msgid="8074997400187836677">"pesquisar"</string>
     <string name="recents_launch_error_message" msgid="2969287838120550506">"Não foi possível iniciar o <xliff:g id="APP">%s</xliff:g>."</string>
     <string name="expanded_header_battery_charged" msgid="5945855970267657951">"Carregada"</string>
diff --git a/packages/SystemUI/res/values-ro/strings.xml b/packages/SystemUI/res/values-ro/strings.xml
index ffa73b2..481a6dd 100644
--- a/packages/SystemUI/res/values-ro/strings.xml
+++ b/packages/SystemUI/res/values-ro/strings.xml
@@ -275,8 +275,7 @@
     <string name="quick_settings_cellular_detail_data_warning" msgid="2440098045692399009">"Avertizare: <xliff:g id="DATA_LIMIT">%s</xliff:g>"</string>
     <string name="recents_empty_message" msgid="8682129509540827999">"Ecranele dvs. recente apar aici"</string>
     <string name="recents_app_info_button_label" msgid="2890317189376000030">"Informații despre aplicație"</string>
-    <!-- no translation found for recents_lock_to_app_button_label (6942899049072506044) -->
-    <skip />
+    <string name="recents_lock_to_app_button_label" msgid="6942899049072506044">"fixare pe ecran"</string>
     <string name="recents_search_bar_label" msgid="8074997400187836677">"căutare"</string>
     <string name="recents_launch_error_message" msgid="2969287838120550506">"<xliff:g id="APP">%s</xliff:g> nu a putut porni."</string>
     <string name="expanded_header_battery_charged" msgid="5945855970267657951">"S-a încărcat"</string>
diff --git a/packages/SystemUI/res/values-ru/strings.xml b/packages/SystemUI/res/values-ru/strings.xml
index 9f82006..858b787 100644
--- a/packages/SystemUI/res/values-ru/strings.xml
+++ b/packages/SystemUI/res/values-ru/strings.xml
@@ -277,8 +277,7 @@
     <string name="quick_settings_cellular_detail_data_warning" msgid="2440098045692399009">"Предупреждение: <xliff:g id="DATA_LIMIT">%s</xliff:g>"</string>
     <string name="recents_empty_message" msgid="8682129509540827999">"Здесь будут показаны недавние приложения"</string>
     <string name="recents_app_info_button_label" msgid="2890317189376000030">"Сведения о приложении"</string>
-    <!-- no translation found for recents_lock_to_app_button_label (6942899049072506044) -->
-    <skip />
+    <string name="recents_lock_to_app_button_label" msgid="6942899049072506044">"Заблокировать в приложении"</string>
     <string name="recents_search_bar_label" msgid="8074997400187836677">"поиск"</string>
     <string name="recents_launch_error_message" msgid="2969287838120550506">"Не удалось запустить приложение \"<xliff:g id="APP">%s</xliff:g>\""</string>
     <string name="expanded_header_battery_charged" msgid="5945855970267657951">"Батарея заряжена"</string>
diff --git a/packages/SystemUI/res/values-si-rLK/strings.xml b/packages/SystemUI/res/values-si-rLK/strings.xml
index 3152868..b0a6b47 100644
--- a/packages/SystemUI/res/values-si-rLK/strings.xml
+++ b/packages/SystemUI/res/values-si-rLK/strings.xml
@@ -275,8 +275,7 @@
     <string name="quick_settings_cellular_detail_data_warning" msgid="2440098045692399009">"<xliff:g id="DATA_LIMIT">%s</xliff:g> අවවාද කිරීම"</string>
     <string name="recents_empty_message" msgid="8682129509540827999">"මෙහි ඔබගේ මෑතක තිර පෙන්නුම් කරයි"</string>
     <string name="recents_app_info_button_label" msgid="2890317189376000030">"යෙදුම් තොරතුරු"</string>
-    <!-- no translation found for recents_lock_to_app_button_label (6942899049072506044) -->
-    <skip />
+    <string name="recents_lock_to_app_button_label" msgid="6942899049072506044">"තිර ඇමිණීම"</string>
     <string name="recents_search_bar_label" msgid="8074997400187836677">"සෙවීම"</string>
     <string name="recents_launch_error_message" msgid="2969287838120550506">"<xliff:g id="APP">%s</xliff:g> ආරම්භ කළ නොහැක."</string>
     <string name="expanded_header_battery_charged" msgid="5945855970267657951">"අරෝපිතයි"</string>
diff --git a/packages/SystemUI/res/values-sl/strings.xml b/packages/SystemUI/res/values-sl/strings.xml
index 74faa1d..b6437a2 100644
--- a/packages/SystemUI/res/values-sl/strings.xml
+++ b/packages/SystemUI/res/values-sl/strings.xml
@@ -275,8 +275,7 @@
     <string name="quick_settings_cellular_detail_data_warning" msgid="2440098045692399009">"Opozorilo – <xliff:g id="DATA_LIMIT">%s</xliff:g>"</string>
     <string name="recents_empty_message" msgid="8682129509540827999">"Vaši nedavni zasloni so prikazani tu"</string>
     <string name="recents_app_info_button_label" msgid="2890317189376000030">"Podatki o aplikaciji"</string>
-    <!-- no translation found for recents_lock_to_app_button_label (6942899049072506044) -->
-    <skip />
+    <string name="recents_lock_to_app_button_label" msgid="6942899049072506044">"pripenjanje zaslona"</string>
     <string name="recents_search_bar_label" msgid="8074997400187836677">"iskanje"</string>
     <string name="recents_launch_error_message" msgid="2969287838120550506">"Aplikacije <xliff:g id="APP">%s</xliff:g> ni bilo mogoče zagnati."</string>
     <string name="expanded_header_battery_charged" msgid="5945855970267657951">"Akumulator napolnjen"</string>
diff --git a/packages/SystemUI/res/values-sr/strings.xml b/packages/SystemUI/res/values-sr/strings.xml
index 630f9ce..d47cf48 100644
--- a/packages/SystemUI/res/values-sr/strings.xml
+++ b/packages/SystemUI/res/values-sr/strings.xml
@@ -275,8 +275,7 @@
     <string name="quick_settings_cellular_detail_data_warning" msgid="2440098045692399009">"Упозорење за <xliff:g id="DATA_LIMIT">%s</xliff:g>"</string>
     <string name="recents_empty_message" msgid="8682129509540827999">"Недавни екрани се појављују овде"</string>
     <string name="recents_app_info_button_label" msgid="2890317189376000030">"Информације о апликацији"</string>
-    <!-- no translation found for recents_lock_to_app_button_label (6942899049072506044) -->
-    <skip />
+    <string name="recents_lock_to_app_button_label" msgid="6942899049072506044">"качење екрана"</string>
     <string name="recents_search_bar_label" msgid="8074997400187836677">"претражи"</string>
     <string name="recents_launch_error_message" msgid="2969287838120550506">"Покретање апликације <xliff:g id="APP">%s</xliff:g> није успело."</string>
     <string name="expanded_header_battery_charged" msgid="5945855970267657951">"Напуњена је"</string>
diff --git a/packages/SystemUI/res/values-sv/strings.xml b/packages/SystemUI/res/values-sv/strings.xml
index a58dc68..ca0cfc6 100644
--- a/packages/SystemUI/res/values-sv/strings.xml
+++ b/packages/SystemUI/res/values-sv/strings.xml
@@ -275,8 +275,7 @@
     <string name="quick_settings_cellular_detail_data_warning" msgid="2440098045692399009">"Varning <xliff:g id="DATA_LIMIT">%s</xliff:g>"</string>
     <string name="recents_empty_message" msgid="8682129509540827999">"Dina senaste skärmar visas här"</string>
     <string name="recents_app_info_button_label" msgid="2890317189376000030">"Appinformation"</string>
-    <!-- no translation found for recents_lock_to_app_button_label (6942899049072506044) -->
-    <skip />
+    <string name="recents_lock_to_app_button_label" msgid="6942899049072506044">"fästa skärmen"</string>
     <string name="recents_search_bar_label" msgid="8074997400187836677">"sök"</string>
     <string name="recents_launch_error_message" msgid="2969287838120550506">"Det gick inte att starta appen <xliff:g id="APP">%s</xliff:g>."</string>
     <string name="expanded_header_battery_charged" msgid="5945855970267657951">"Laddat"</string>
diff --git a/packages/SystemUI/res/values-sw/strings.xml b/packages/SystemUI/res/values-sw/strings.xml
index d46d5b6..58e0c41 100644
--- a/packages/SystemUI/res/values-sw/strings.xml
+++ b/packages/SystemUI/res/values-sw/strings.xml
@@ -275,8 +275,7 @@
     <string name="quick_settings_cellular_detail_data_warning" msgid="2440098045692399009">"Onyo <xliff:g id="DATA_LIMIT">%s</xliff:g>"</string>
     <string name="recents_empty_message" msgid="8682129509540827999">"Skrini zako za hivi majuzi huonekana hapa"</string>
     <string name="recents_app_info_button_label" msgid="2890317189376000030">"Maelezo ya Programu"</string>
-    <!-- no translation found for recents_lock_to_app_button_label (6942899049072506044) -->
-    <skip />
+    <string name="recents_lock_to_app_button_label" msgid="6942899049072506044">"kudumisha programu moja"</string>
     <string name="recents_search_bar_label" msgid="8074997400187836677">"tafuta"</string>
     <string name="recents_launch_error_message" msgid="2969287838120550506">"Haikuweza kuanzisha <xliff:g id="APP">%s</xliff:g>."</string>
     <string name="expanded_header_battery_charged" msgid="5945855970267657951">"Betri imejaa"</string>
diff --git a/packages/SystemUI/res/values-ta-rIN/strings.xml b/packages/SystemUI/res/values-ta-rIN/strings.xml
index 850a964..847529c 100644
--- a/packages/SystemUI/res/values-ta-rIN/strings.xml
+++ b/packages/SystemUI/res/values-ta-rIN/strings.xml
@@ -275,8 +275,7 @@
     <string name="quick_settings_cellular_detail_data_warning" msgid="2440098045692399009">"<xliff:g id="DATA_LIMIT">%s</xliff:g> எச்சரிக்கை"</string>
     <string name="recents_empty_message" msgid="8682129509540827999">"சமீபத்திய திரைகள் இங்கு தோன்றும்"</string>
     <string name="recents_app_info_button_label" msgid="2890317189376000030">"பயன்பாட்டு தகவல்"</string>
-    <!-- no translation found for recents_lock_to_app_button_label (6942899049072506044) -->
-    <skip />
+    <string name="recents_lock_to_app_button_label" msgid="6942899049072506044">"திரையை பின் செய்தல்"</string>
     <string name="recents_search_bar_label" msgid="8074997400187836677">"தேடு"</string>
     <string name="recents_launch_error_message" msgid="2969287838120550506">"<xliff:g id="APP">%s</xliff:g>ஐத் தொடங்க முடியவில்லை."</string>
     <string name="expanded_header_battery_charged" msgid="5945855970267657951">"சார்ஜ் செய்யப்பட்டது"</string>
diff --git a/packages/SystemUI/res/values-tr/strings.xml b/packages/SystemUI/res/values-tr/strings.xml
index 269743b..e295be2 100644
--- a/packages/SystemUI/res/values-tr/strings.xml
+++ b/packages/SystemUI/res/values-tr/strings.xml
@@ -275,8 +275,7 @@
     <string name="quick_settings_cellular_detail_data_warning" msgid="2440098045692399009">"<xliff:g id="DATA_LIMIT">%s</xliff:g> uyarısı"</string>
     <string name="recents_empty_message" msgid="8682129509540827999">"Son ekranlarınız burada görünür"</string>
     <string name="recents_app_info_button_label" msgid="2890317189376000030">"Uygulama Bilgileri"</string>
-    <!-- no translation found for recents_lock_to_app_button_label (6942899049072506044) -->
-    <skip />
+    <string name="recents_lock_to_app_button_label" msgid="6942899049072506044">"ekran sabitleme"</string>
     <string name="recents_search_bar_label" msgid="8074997400187836677">"ara"</string>
     <string name="recents_launch_error_message" msgid="2969287838120550506">"<xliff:g id="APP">%s</xliff:g> başlatılamadı."</string>
     <string name="expanded_header_battery_charged" msgid="5945855970267657951">"Ödeme alındı"</string>
diff --git a/packages/SystemUI/res/values-uk/strings.xml b/packages/SystemUI/res/values-uk/strings.xml
index 6e31484..6798df1 100644
--- a/packages/SystemUI/res/values-uk/strings.xml
+++ b/packages/SystemUI/res/values-uk/strings.xml
@@ -275,8 +275,7 @@
     <string name="quick_settings_cellular_detail_data_warning" msgid="2440098045692399009">"Застереження: <xliff:g id="DATA_LIMIT">%s</xliff:g>"</string>
     <string name="recents_empty_message" msgid="8682129509540827999">"Ваші останні екрани відображаються тут"</string>
     <string name="recents_app_info_button_label" msgid="2890317189376000030">"Інформація про додаток"</string>
-    <!-- no translation found for recents_lock_to_app_button_label (6942899049072506044) -->
-    <skip />
+    <string name="recents_lock_to_app_button_label" msgid="6942899049072506044">"закріпити екран"</string>
     <string name="recents_search_bar_label" msgid="8074997400187836677">"пошук"</string>
     <string name="recents_launch_error_message" msgid="2969287838120550506">"Не вдалося запустити <xliff:g id="APP">%s</xliff:g>."</string>
     <string name="expanded_header_battery_charged" msgid="5945855970267657951">"Заряджено"</string>
diff --git a/packages/SystemUI/res/values-ur-rPK/strings.xml b/packages/SystemUI/res/values-ur-rPK/strings.xml
index e3c174e..6b05ac52 100644
--- a/packages/SystemUI/res/values-ur-rPK/strings.xml
+++ b/packages/SystemUI/res/values-ur-rPK/strings.xml
@@ -275,8 +275,7 @@
     <string name="quick_settings_cellular_detail_data_warning" msgid="2440098045692399009">"<xliff:g id="DATA_LIMIT">%s</xliff:g> وارننگ"</string>
     <string name="recents_empty_message" msgid="8682129509540827999">"آپ کی حالیہ اسکرینز یہاں ظاہر ہوتی ہیں"</string>
     <string name="recents_app_info_button_label" msgid="2890317189376000030">"ایپلیکیشن کی معلومات"</string>
-    <!-- no translation found for recents_lock_to_app_button_label (6942899049072506044) -->
-    <skip />
+    <string name="recents_lock_to_app_button_label" msgid="6942899049072506044">"اسکرین کو پن کرنا"</string>
     <string name="recents_search_bar_label" msgid="8074997400187836677">"تلاش کریں"</string>
     <string name="recents_launch_error_message" msgid="2969287838120550506">"<xliff:g id="APP">%s</xliff:g> کو شروع نہیں کیا جا سکا۔"</string>
     <string name="expanded_header_battery_charged" msgid="5945855970267657951">"چارج ہوگئی"</string>
diff --git a/packages/SystemUI/res/values-uz-rUZ/strings.xml b/packages/SystemUI/res/values-uz-rUZ/strings.xml
index 3430cf9..c561400 100644
--- a/packages/SystemUI/res/values-uz-rUZ/strings.xml
+++ b/packages/SystemUI/res/values-uz-rUZ/strings.xml
@@ -275,8 +275,7 @@
     <string name="quick_settings_cellular_detail_data_warning" msgid="2440098045692399009">"Ogohlantirish: <xliff:g id="DATA_LIMIT">%s</xliff:g>"</string>
     <string name="recents_empty_message" msgid="8682129509540827999">"Siz yaqinda ishlatgan ilova ekranlari bu yerda ko‘rinadi"</string>
     <string name="recents_app_info_button_label" msgid="2890317189376000030">"Ilova haqida ma’lumot"</string>
-    <!-- no translation found for recents_lock_to_app_button_label (6942899049072506044) -->
-    <skip />
+    <string name="recents_lock_to_app_button_label" msgid="6942899049072506044">"ekranni qadab qo‘yish"</string>
     <string name="recents_search_bar_label" msgid="8074997400187836677">"qidirish"</string>
     <string name="recents_launch_error_message" msgid="2969287838120550506">"“<xliff:g id="APP">%s</xliff:g>” ilovasini ishga tushirib bo‘lmadi."</string>
     <string name="expanded_header_battery_charged" msgid="5945855970267657951">"Batareya quvvati to‘ldi"</string>
diff --git a/packages/SystemUI/res/values-zh-rCN/strings.xml b/packages/SystemUI/res/values-zh-rCN/strings.xml
index b511baff..8895799 100644
--- a/packages/SystemUI/res/values-zh-rCN/strings.xml
+++ b/packages/SystemUI/res/values-zh-rCN/strings.xml
@@ -277,8 +277,7 @@
     <string name="quick_settings_cellular_detail_data_warning" msgid="2440098045692399009">"<xliff:g id="DATA_LIMIT">%s</xliff:g>警告"</string>
     <string name="recents_empty_message" msgid="8682129509540827999">"您最近浏览过的屏幕会显示在此处"</string>
     <string name="recents_app_info_button_label" msgid="2890317189376000030">"应用信息"</string>
-    <!-- no translation found for recents_lock_to_app_button_label (6942899049072506044) -->
-    <skip />
+    <string name="recents_lock_to_app_button_label" msgid="6942899049072506044">"固定屏幕"</string>
     <string name="recents_search_bar_label" msgid="8074997400187836677">"搜索"</string>
     <string name="recents_launch_error_message" msgid="2969287838120550506">"无法启动<xliff:g id="APP">%s</xliff:g>。"</string>
     <string name="expanded_header_battery_charged" msgid="5945855970267657951">"充电完成"</string>
diff --git a/packages/SystemUI/src/com/android/systemui/ExpandHelper.java b/packages/SystemUI/src/com/android/systemui/ExpandHelper.java
index 0f8fe1c..d42ac61 100644
--- a/packages/SystemUI/src/com/android/systemui/ExpandHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/ExpandHelper.java
@@ -351,6 +351,9 @@
                 mVelocityTracker.addMovement(event);
                 break;
             case MotionEvent.ACTION_MOVE:
+                if (mVelocityTracker == null) {
+                    mVelocityTracker = VelocityTracker.obtain();
+                }
                 mVelocityTracker.addMovement(event);
                 break;
             default:
diff --git a/packages/SystemUI/src/com/android/systemui/SwipeHelper.java b/packages/SystemUI/src/com/android/systemui/SwipeHelper.java
index 0d393bf..f206e56 100644
--- a/packages/SystemUI/src/com/android/systemui/SwipeHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/SwipeHelper.java
@@ -311,11 +311,14 @@
         final View animView = mCallback.getChildContentView(view);
         final boolean canAnimViewBeDismissed = mCallback.canChildBeDismissed(view);
         float newPos;
+        boolean isLayoutRtl = view.getLayoutDirection() == View.LAYOUT_DIRECTION_RTL;
 
         if (velocity < 0
                 || (velocity == 0 && getTranslation(animView) < 0)
                 // if we use the Menu to dismiss an item in landscape, animate up
-                || (velocity == 0 && getTranslation(animView) == 0 && mSwipeDirection == Y)) {
+                || (velocity == 0 && getTranslation(animView) == 0 && mSwipeDirection == Y)
+                // if the language is rtl we prefer swiping to the left
+                || (velocity == 0 && getTranslation(animView) == 0 && isLayoutRtl)) {
             newPos = -getSize(animView);
         } else {
             newPos = getSize(animView);
diff --git a/packages/SystemUI/src/com/android/systemui/power/PowerNotificationWarnings.java b/packages/SystemUI/src/com/android/systemui/power/PowerNotificationWarnings.java
index f5df1a9..4391bfc 100644
--- a/packages/SystemUI/src/com/android/systemui/power/PowerNotificationWarnings.java
+++ b/packages/SystemUI/src/com/android/systemui/power/PowerNotificationWarnings.java
@@ -66,6 +66,7 @@
     private static final String ACTION_SHOW_BATTERY_SETTINGS = "PNW.batterySettings";
     private static final String ACTION_START_SAVER = "PNW.startSaver";
     private static final String ACTION_STOP_SAVER = "PNW.stopSaver";
+    private static final String ACTION_DISMISSED_WARNING = "PNW.dismissedWarning";
 
     private static final AudioAttributes AUDIO_ATTRIBUTES = new AudioAttributes.Builder()
             .setContentType(AudioAttributes.CONTENT_TYPE_SONIFICATION)
@@ -180,6 +181,7 @@
                 .setContentTitle(mContext.getString(R.string.battery_low_title))
                 .setContentText(mContext.getString(textRes, percentage))
                 .setOnlyAlertOnce(true)
+                .setDeleteIntent(pendingBroadcast(ACTION_DISMISSED_WARNING))
                 .setPriority(Notification.PRIORITY_MAX)
                 .setVisibility(Notification.VISIBILITY_PUBLIC)
                 .setColor(mContext.getResources().getColor(
@@ -374,6 +376,7 @@
             filter.addAction(ACTION_SHOW_BATTERY_SETTINGS);
             filter.addAction(ACTION_START_SAVER);
             filter.addAction(ACTION_STOP_SAVER);
+            filter.addAction(ACTION_DISMISSED_WARNING);
             mContext.registerReceiverAsUser(this, UserHandle.ALL, filter, null, mHandler);
         }
 
@@ -391,6 +394,8 @@
                 dismissSaverNotification();
                 dismissLowBatteryNotification();
                 setSaverMode(false);
+            } else if (action.equals(ACTION_DISMISSED_WARNING)) {
+                dismissLowBatteryWarning();
             }
         }
     }
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java b/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java
index fdebdd3..54a8414 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java
@@ -542,7 +542,10 @@
 
         @Override
         public void onAnimationEnd(Animator animation) {
-            setGridContentVisibility(false);
+            // Only hide content if still in detail state.
+            if (mDetailRecord != null) {
+                setGridContentVisibility(false);
+            }
         }
     };
 
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/ActivatableNotificationView.java b/packages/SystemUI/src/com/android/systemui/statusbar/ActivatableNotificationView.java
index e4faa6a..02b9378 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/ActivatableNotificationView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/ActivatableNotificationView.java
@@ -508,7 +508,7 @@
         if (mAppearAnimator != null) {
             mAppearAnimator.cancel();
         }
-        mAnimationTranslationY = translationDirection * mActualHeight;
+        mAnimationTranslationY = translationDirection * getActualHeight();
         if (mAppearAnimationFraction == -1.0f) {
             // not initialized yet, we start anew
             if (isAppearing) {
@@ -601,14 +601,15 @@
 
         float top;
         float bottom;
+        final int actualHeight = getActualHeight();
         if (mAnimationTranslationY > 0.0f) {
-            bottom = mActualHeight - heightFraction * mAnimationTranslationY * 0.1f
+            bottom = actualHeight - heightFraction * mAnimationTranslationY * 0.1f
                     - translateYTotalAmount;
             top = bottom * heightFraction;
         } else {
-            top = heightFraction * (mActualHeight + mAnimationTranslationY) * 0.1f -
+            top = heightFraction * (actualHeight + mAnimationTranslationY) * 0.1f -
                     translateYTotalAmount;
-            bottom = mActualHeight * (1 - heightFraction) + top * heightFraction;
+            bottom = actualHeight * (1 - heightFraction) + top * heightFraction;
         }
         mAppearAnimationRect.set(left, top, right, bottom);
         setOutlineRect(left, top + mAppearAnimationTranslation, right,
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java
index 1b4bdf8..09d0b5d 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java
@@ -59,6 +59,7 @@
 import android.service.notification.StatusBarNotification;
 import android.text.TextUtils;
 import android.util.Log;
+import android.util.Slog;
 import android.util.SparseArray;
 import android.util.SparseBooleanArray;
 import android.view.Display;
@@ -113,6 +114,9 @@
     public static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
     public static final boolean MULTIUSER_DEBUG = false;
 
+    // STOPSHIP disable once we resolve b/18102199
+    private static final boolean NOTIFICATION_CLICK_DEBUG = true;
+
     protected static final int MSG_SHOW_RECENT_APPS = 1019;
     protected static final int MSG_HIDE_RECENT_APPS = 1020;
     protected static final int MSG_TOGGLE_RECENTS_APPS = 1021;
@@ -325,6 +329,9 @@
                 ViewGroup actionGroup = (ViewGroup) parent;
                 index = actionGroup.indexOfChild(view);
             }
+            if (NOTIFICATION_CLICK_DEBUG) {
+                Log.d(TAG, "Clicked on button " + index + " for " + key);
+            }
             try {
                 mBarService.onNotificationActionClick(key, index);
             } catch (RemoteException e) {
@@ -1515,6 +1522,9 @@
         }
 
         public void onClick(final View v) {
+            if (NOTIFICATION_CLICK_DEBUG) {
+                Log.d(TAG, "Clicked on content of " + mNotificationKey);
+            }
             final boolean keyguardShowing = mStatusBarKeyguardViewManager.isShowing();
             final boolean afterKeyguardGone = mIntent.isActivity()
                     && PreviewInflater.wouldLaunchResolverActivity(mContext, mIntent.getIntent(),
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/DismissView.java b/packages/SystemUI/src/com/android/systemui/statusbar/DismissView.java
index 897dbf2..479c2fb 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/DismissView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/DismissView.java
@@ -36,4 +36,11 @@
     public void setOnButtonClickListener(OnClickListener listener) {
         mContent.setOnClickListener(listener);
     }
+
+    public boolean isOnEmptySpace(float touchX, float touchY) {
+        return touchX < mContent.getX()
+                || touchX > mContent.getX() + mContent.getWidth()
+                || touchY < mContent.getY()
+                || touchY > mContent.getY() + mContent.getHeight();
+    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java b/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java
index 556c423..a4e5e74 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java
@@ -23,10 +23,8 @@
 import android.service.notification.StatusBarNotification;
 import android.util.AttributeSet;
 import android.view.View;
-import android.view.ViewGroup;
 import android.view.ViewStub;
 import android.view.accessibility.AccessibilityEvent;
-
 import android.widget.ImageView;
 import com.android.systemui.R;
 
@@ -156,9 +154,9 @@
     }
 
     public void resetHeight() {
+        super.resetHeight();
         mMaxExpandHeight = 0;
         mWasReset = true;
-        mActualHeight = 0;
         onHeightReset();
         requestLayout();
     }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableOutlineView.java b/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableOutlineView.java
index f85d32b..a18fff2 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableOutlineView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableOutlineView.java
@@ -41,7 +41,7 @@
                     outline.setRect(0,
                             mClipTopAmount,
                             getWidth(),
-                            Math.max(mActualHeight, mClipTopAmount));
+                            Math.max(getActualHeight(), mClipTopAmount));
                 } else {
                     outline.setRect(mOutlineRect);
                 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableView.java b/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableView.java
index c8f756e..edfbe86 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableView.java
@@ -36,7 +36,7 @@
     private final int mMaxNotificationHeight;
 
     private OnHeightChangedListener mOnHeightChangedListener;
-    protected int mActualHeight;
+    private int mActualHeight;
     protected int mClipTopAmount;
     private boolean mActualHeightInitialized;
     private ArrayList<View> mMatchParentViews = new ArrayList<View>();
@@ -103,6 +103,11 @@
         }
     }
 
+    protected void resetHeight() {
+        mActualHeight = 0;
+        mActualHeightInitialized = false;
+    }
+
     protected int getInitialHeight() {
         return getHeight();
     }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationBackgroundView.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationBackgroundView.java
index 5db680a..0fc46e9 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationBackgroundView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationBackgroundView.java
@@ -23,9 +23,7 @@
 import android.graphics.drawable.Drawable;
 import android.graphics.drawable.RippleDrawable;
 import android.util.AttributeSet;
-import android.view.MotionEvent;
 import android.view.View;
-import com.android.systemui.R;
 
 /**
  * A view that can be used for both the dimmed and normal background of an notification.
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationContentView.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationContentView.java
index 502490f..9b11f9b 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationContentView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationContentView.java
@@ -27,11 +27,11 @@
 import android.graphics.drawable.Drawable;
 import android.util.AttributeSet;
 import android.view.View;
+import android.view.ViewTreeObserver;
 import android.view.animation.Interpolator;
 import android.view.animation.LinearInterpolator;
 import android.widget.FrameLayout;
 import android.widget.ImageView;
-
 import com.android.systemui.R;
 
 /**
@@ -60,6 +60,16 @@
     private boolean mDark;
 
     private final Paint mFadePaint = new Paint();
+    private boolean mAnimate;
+    private ViewTreeObserver.OnPreDrawListener mEnableAnimationPredrawListener
+            = new ViewTreeObserver.OnPreDrawListener() {
+        @Override
+        public boolean onPreDraw() {
+            mAnimate = true;
+            getViewTreeObserver().removeOnPreDrawListener(this);
+            return true;
+        }
+    };
 
     public NotificationContentView(Context context, AttributeSet attrs) {
         super(context, attrs);
@@ -73,6 +83,12 @@
         updateClipping();
     }
 
+    @Override
+    protected void onFinishInflate() {
+        super.onFinishInflate();
+        updateVisibility();
+    }
+
     public void reset() {
         if (mContractedChild != null) {
             mContractedChild.animate().cancel();
@@ -117,9 +133,31 @@
         selectLayout(false /* animate */, true /* force */);
     }
 
+    @Override
+    protected void onVisibilityChanged(View changedView, int visibility) {
+        super.onVisibilityChanged(changedView, visibility);
+        updateVisibility();
+    }
+
+    private void updateVisibility() {
+        setVisible(isShown());
+    }
+
+    private void setVisible(final boolean isVisible) {
+        if (isVisible) {
+
+            // We only animate if we are drawn at least once, otherwise the view might animate when
+            // it's shown the first time
+            getViewTreeObserver().addOnPreDrawListener(mEnableAnimationPredrawListener);
+        } else {
+            getViewTreeObserver().removeOnPreDrawListener(mEnableAnimationPredrawListener);
+            mAnimate = false;
+        }
+    }
+
     public void setActualHeight(int actualHeight) {
         mActualHeight = actualHeight;
-        selectLayout(true /* animate */, false /* force */);
+        selectLayout(mAnimate /* animate */, false /* force */);
         updateClipping();
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/DemoStatusIcons.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/DemoStatusIcons.java
index 682c01c..6cb5bcc 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/DemoStatusIcons.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/DemoStatusIcons.java
@@ -159,7 +159,7 @@
             }
         }
         StatusBarIcon icon = new StatusBarIcon(iconPkg, UserHandle.CURRENT, iconId, 0, 0, "Demo");
-        StatusBarIconView v = new StatusBarIconView(getContext(), null);
+        StatusBarIconView v = new StatusBarIconView(getContext(), null, null);
         v.setTag(slot);
         v.set(icon);
         addView(v, 0, new LinearLayout.LayoutParams(mIconSize, mIconSize));
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeParameters.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeParameters.java
index a956151..6fd6758 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeParameters.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeParameters.java
@@ -48,6 +48,7 @@
         pw.print("    getDisplayStateSupported(): "); pw.println(getDisplayStateSupported());
         pw.print("    getPulseDuration(): "); pw.println(getPulseDuration());
         pw.print("    getPulseInDuration(): "); pw.println(getPulseInDuration());
+        pw.print("    getPulseInDelay(): "); pw.println(getPulseInDelay());
         pw.print("    getPulseInVisibleDuration(): "); pw.println(getPulseVisibleDuration());
         pw.print("    getPulseOutDuration(): "); pw.println(getPulseOutDuration());
         pw.print("    getPulseOnSigMotion(): "); pw.println(getPulseOnSigMotion());
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
index 0bde7ef..d9e44c3 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
@@ -52,7 +52,7 @@
 public class NotificationPanelView extends PanelView implements
         ExpandableView.OnHeightChangedListener, ObservableScrollView.Listener,
         View.OnClickListener, NotificationStackScrollLayout.OnOverscrollTopChangedListener,
-        KeyguardAffordanceHelper.Callback {
+        KeyguardAffordanceHelper.Callback, NotificationStackScrollLayout.OnEmptySpaceClickListener {
 
     // Cap and total height of Roboto font. Needs to be adjusted when font for the big clock is
     // changed.
@@ -197,6 +197,7 @@
                 findViewById(R.id.notification_stack_scroller);
         mNotificationStackScroller.setOnHeightChangedListener(this);
         mNotificationStackScroller.setOverscrollTopChangedListener(this);
+        mNotificationStackScroller.setOnEmptySpaceClickListener(this);
         mNotificationStackScroller.setScrollView(mScrollView);
         mFastOutSlowInInterpolator = AnimationUtils.loadInterpolator(getContext(),
                 android.R.interpolator.fast_out_slow_in);
@@ -526,13 +527,15 @@
                 mIntercepting = false;
                 break;
         }
+        return super.onInterceptTouchEvent(event);
+    }
 
-        // Allow closing the whole panel when in SHADE state.
-        if (mStatusBarState == StatusBarState.SHADE) {
-            return super.onInterceptTouchEvent(event);
-        } else {
-            return !mQsExpanded && super.onInterceptTouchEvent(event);
-        }
+    @Override
+    protected boolean isInContentBounds(float x, float y) {
+        float yTransformed = y - mNotificationStackScroller.getY();
+        float stackScrollerX = mNotificationStackScroller.getX();
+        return mNotificationStackScroller.isInContentBounds(yTransformed) && stackScrollerX < x
+                && x < stackScrollerX + mNotificationStackScroller.getWidth();
     }
 
     private void resetDownStates(MotionEvent event) {
@@ -636,10 +639,9 @@
     }
 
     private boolean isInQsArea(float x, float y) {
-        return mStatusBarState != StatusBarState.SHADE ||
-                (x >= mScrollView.getLeft() && x <= mScrollView.getRight()) &&
-                        (y <= mNotificationStackScroller.getBottomMostNotificationBottom()
-                                || y <= mQsContainer.getY() + mQsContainer.getHeight());
+        return (x >= mScrollView.getLeft() && x <= mScrollView.getRight()) &&
+                (y <= mNotificationStackScroller.getBottomMostNotificationBottom()
+                || y <= mQsContainer.getY() + mQsContainer.getHeight());
     }
 
     private void handleQsDown(MotionEvent event) {
@@ -1110,9 +1112,26 @@
     }
 
     private float calculateQsTopPadding() {
-        // We can only do the smoother transition on Keyguard when we also are not collapsing from a
-        // scrolled quick settings.
-        if (mKeyguardShowing && mScrollYOverride == -1) {
+        if (mKeyguardShowing
+                && (mTwoFingerQsExpand || mIsExpanding && mQsExpandedWhenExpandingStarted)) {
+
+            // Either QS pushes the notifications down when fully expanded, or QS is fully above the
+            // notifications (mostly on tablets). maxNotifications denotes the normal top padding
+            // on Keyguard, maxQs denotes the top padding from the quick settings panel. We need to
+            // take the maximum and linearly interpolate with the panel expansion for a nice motion.
+            int maxNotifications = mClockPositionResult.stackScrollerPadding
+                    - mClockPositionResult.stackScrollerPaddingAdjustment
+                    - mNotificationTopPadding;
+            int maxQs = getTempQsMaxExpansion();
+            int max = mStatusBarState == StatusBarState.KEYGUARD
+                    ? Math.max(maxNotifications, maxQs)
+                    : maxQs;
+            return (int) interpolate(getExpandedFraction(),
+                    mQsMinExpansionHeight, max);
+        } else if (mKeyguardShowing && mScrollYOverride == -1) {
+
+            // We can only do the smoother transition on Keyguard when we also are not collapsing
+            // from a scrolled quick settings.
             return interpolate(getQsExpansionFraction(),
                     mNotificationStackScroller.getIntrinsicPadding() - mNotificationTopPadding,
                     mQsMaxExpansionHeight);
@@ -1124,7 +1143,9 @@
     private void requestScrollerTopPaddingUpdate(boolean animate) {
         mNotificationStackScroller.updateTopPadding(calculateQsTopPadding(),
                 mScrollView.getScrollY(),
-                mAnimateNextTopPaddingChange || animate);
+                mAnimateNextTopPaddingChange || animate,
+                mKeyguardShowing
+                        && (mTwoFingerQsExpand || mIsExpanding && mQsExpandedWhenExpandingStarted));
         mAnimateNextTopPaddingChange = false;
     }
 
@@ -1254,18 +1275,27 @@
 
     @Override
     protected void onHeightUpdated(float expandedHeight) {
-        if (!mQsExpanded) {
+        if (!mQsExpanded || mTwoFingerQsExpand || mIsExpanding && mQsExpandedWhenExpandingStarted) {
             positionClockAndNotifications();
         }
         if (mTwoFingerQsExpand || mQsExpanded && !mQsTracking && mQsExpansionAnimator == null
                 && !mQsExpansionFromOverscroll) {
-            float panelHeightQsCollapsed = mNotificationStackScroller.getIntrinsicPadding()
-                    + mNotificationStackScroller.getMinStackHeight()
-                    + mNotificationStackScroller.getNotificationTopPadding();
-            float panelHeightQsExpanded = calculatePanelHeightQsExpanded();
-            float t = (expandedHeight - panelHeightQsCollapsed)
-                    / (panelHeightQsExpanded - panelHeightQsCollapsed);
+            float t;
+            if (mKeyguardShowing) {
 
+                // On Keyguard, interpolate the QS expansion linearly to the panel expansion
+                t = expandedHeight / getMaxPanelHeight();
+            } else {
+
+                // In Shade, interpolate linearly such that QS is closed whenever panel height is
+                // minimum QS expansion + minStackHeight
+                float panelHeightQsCollapsed = mNotificationStackScroller.getIntrinsicPadding()
+                        + mNotificationStackScroller.getMinStackHeight()
+                        + mNotificationStackScroller.getNotificationTopPadding();
+                float panelHeightQsExpanded = calculatePanelHeightQsExpanded();
+                t = (expandedHeight - panelHeightQsCollapsed)
+                        / (panelHeightQsExpanded - panelHeightQsCollapsed);
+            }
             setQsExpansion(mQsMinExpansionHeight
                     + t * (getTempQsMaxExpansion() - mQsMinExpansionHeight));
         }
@@ -1299,8 +1329,10 @@
         float notificationHeight = mNotificationStackScroller.getHeight()
                 - mNotificationStackScroller.getEmptyBottomMargin()
                 - mNotificationStackScroller.getTopPadding();
-        float totalHeight = mQsMaxExpansionHeight + notificationHeight
-                + mNotificationStackScroller.getNotificationTopPadding();
+        float totalHeight = Math.max(
+                mQsMaxExpansionHeight + mNotificationStackScroller.getNotificationTopPadding(),
+                mClockPositionResult.stackScrollerPadding - mTopPaddingAdjustment)
+                + notificationHeight;
         if (totalHeight > mNotificationStackScroller.getHeight()) {
             float fullyCollapsedHeight = mQsMaxExpansionHeight
                     + mNotificationStackScroller.getMinStackHeight()
@@ -1433,7 +1465,7 @@
         super.onExpandingStarted();
         mNotificationStackScroller.onExpansionStarted();
         mIsExpanding = true;
-        mQsExpandedWhenExpandingStarted = mQsExpanded;
+        mQsExpandedWhenExpandingStarted = mQsFullyExpanded;
         if (mQsExpanded) {
             onQsExpansionStarted();
         }
@@ -1487,11 +1519,12 @@
     @Override
     protected void onTrackingStarted() {
         super.onTrackingStarted();
+        if (mQsFullyExpanded) {
+            mTwoFingerQsExpand = true;
+        }
         if (mStatusBar.getBarState() == StatusBarState.KEYGUARD
                 || mStatusBar.getBarState() == StatusBarState.SHADE_LOCKED) {
             mAfforanceHelper.animateHideLeftRightIcon();
-        } else if (mQsExpanded) {
-            mTwoFingerQsExpand = true;
         }
     }
 
@@ -1867,4 +1900,9 @@
     public void onScreenTurnedOn() {
         mKeyguardStatusView.refreshTime();
     }
+
+    @Override
+    public void onEmptySpaceClicked(float x, float y) {
+        onEmptySpaceClick(x);
+    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java
index 0ddda8a..c706ef0 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java
@@ -70,6 +70,7 @@
     private boolean mOverExpandedBeforeFling;
     private boolean mTouchAboveFalsingThreshold;
     private int mUnlockFalsingThreshold;
+    private boolean mTouchStartedInEmptyArea;
 
     private ValueAnimator mHeightAnimator;
     private ObjectAnimator mPeekAnimator;
@@ -284,7 +285,7 @@
                                 || mInitialOffsetOnTouch == 0f)) {
                     mTouchSlopExceeded = true;
                     if (waitForTouchSlop && !mTracking) {
-                        if (!mJustPeeked) {
+                        if (!mJustPeeked && mInitialOffsetOnTouch != 0f) {
                             mInitialOffsetOnTouch = mExpandedHeight;
                             mInitialTouchX = x;
                             mInitialTouchY = y;
@@ -409,6 +410,7 @@
                 }
                 mInitialTouchY = y;
                 mInitialTouchX = x;
+                mTouchStartedInEmptyArea = !isInContentBounds(x, y);
                 mTouchSlopExceeded = false;
                 mJustPeeked = false;
                 mPanelClosedOnDown = mExpandedHeight == 0.0f;
@@ -432,7 +434,7 @@
             case MotionEvent.ACTION_MOVE:
                 final float h = y - mInitialTouchY;
                 trackMovement(event);
-                if (scrolledToBottom) {
+                if (scrolledToBottom || mTouchStartedInEmptyArea) {
                     if (h < -mTouchSlop && h < -Math.abs(x - mInitialTouchX)) {
                         cancelHeightAnimator();
                         mInitialOffsetOnTouch = mExpandedHeight;
@@ -452,6 +454,11 @@
         return false;
     }
 
+    /**
+     * @return Whether a pair of coordinates are inside the visible view content bounds.
+     */
+    protected abstract boolean isInContentBounds(float x, float y);
+
     private void cancelHeightAnimator() {
         if (mHeightAnimator != null) {
             mHeightAnimator.cancel();
@@ -632,10 +639,10 @@
         }
 
         mExpandedHeight = Math.max(0, mExpandedHeight);
-        onHeightUpdated(mExpandedHeight);
         mExpandedFraction = Math.min(1f, fhWithoutOverExpansion == 0
                 ? 0
                 : mExpandedHeight / fhWithoutOverExpansion);
+        onHeightUpdated(mExpandedHeight);
         notifyBarPanelExpansionChanged();
     }
 
@@ -903,7 +910,7 @@
      *
      * @return whether the panel will be expanded after the action performed by this method
      */
-    private boolean onEmptySpaceClick(float x) {
+    protected boolean onEmptySpaceClick(float x) {
         if (mHintAnimationRunning) {
             return true;
         }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java b/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java
index 4a20406..87ce565 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java
@@ -40,6 +40,7 @@
 import com.android.systemui.statusbar.ExpandableNotificationRow;
 import com.android.systemui.statusbar.ExpandableView;
 import com.android.systemui.statusbar.SpeedBumpView;
+import com.android.systemui.statusbar.StackScrollerDecorView;
 import com.android.systemui.statusbar.StatusBarState;
 import com.android.systemui.statusbar.phone.PhoneStatusBar;
 import com.android.systemui.statusbar.policy.ScrollAdapter;
@@ -70,6 +71,12 @@
     private SwipeHelper mSwipeHelper;
     private boolean mSwipingInProgress;
     private int mCurrentStackHeight = Integer.MAX_VALUE;
+
+    /**
+     * mCurrentStackHeight is the actual stack height, mLastSetStackHeight is the stack height set
+     * externally from {@link #setStackHeight}
+     */
+    private float mLastSetStackHeight;
     private int mOwnScrollY;
     private int mMaxLayoutHeight;
 
@@ -84,6 +91,9 @@
     private int mLastMotionY;
     private int mDownX;
     private int mActivePointerId;
+    private boolean mTouchIsClick;
+    private float mInitialTouchX;
+    private float mInitialTouchY;
 
     private int mSidePaddings;
     private Paint mDebugPaint;
@@ -133,6 +143,7 @@
     private OnChildLocationsChangedListener mListener;
     private OnOverscrollTopChangedListener mOverscrollTopChangedListener;
     private ExpandableView.OnHeightChangedListener mOnHeightChangedListener;
+    private OnEmptySpaceClickListener mOnEmptySpaceClickListener;
     private boolean mNeedsAnimation;
     private boolean mTopPaddingNeedsAnimation;
     private boolean mDimmedNeedsAnimation;
@@ -367,6 +378,9 @@
         if (childViewState == null) {
             return ViewState.LOCATION_UNKNOWN;
         }
+        if (childViewState.gone) {
+            return ViewState.LOCATION_GONE;
+        }
         return childViewState.location;
     }
 
@@ -445,6 +459,7 @@
      * @param height the new height of the stack
      */
     public void setStackHeight(float height) {
+        mLastSetStackHeight = height;
         setIsExpanded(height > 0.0f);
         int newStackHeight = (int) height;
         int minStackHeight = getMinStackHeight();
@@ -581,7 +596,9 @@
         final int count = getChildCount();
         for (int childIdx = 0; childIdx < count; childIdx++) {
             ExpandableView slidingChild = (ExpandableView) getChildAt(childIdx);
-            if (slidingChild.getVisibility() == GONE) {
+            if (slidingChild.getVisibility() == GONE
+                    || slidingChild instanceof StackScrollerDecorView
+                    || slidingChild == mSpeedBumpView) {
                 continue;
             }
             float childTop = slidingChild.getTranslationY();
@@ -687,6 +704,7 @@
             transformTouchEvent(ev, this, mScrollView);
             return mScrollView.onTouchEvent(ev);
         }
+        handleEmptySpaceClick(ev);
         boolean expandWantsIt = false;
         if (!mSwipingInProgress && !mOnlyScrollingInThisMotion && isScrollingEnabled()) {
             if (isCancelOrUp) {
@@ -1338,7 +1356,19 @@
                 && initialVelocity > 0;
     }
 
-    public void updateTopPadding(float qsHeight, int scrollY, boolean animate) {
+    /**
+     * Updates the top padding of the notifications, taking {@link #getIntrinsicPadding()} into
+     * account.
+     *
+     * @param qsHeight the top padding imposed by the quick settings panel
+     * @param scrollY how much the notifications are scrolled inside the QS/notifications scroll
+     *                container
+     * @param animate whether to animate the change
+     * @param ignoreIntrinsicPadding if true, {@link #getIntrinsicPadding()} is ignored and
+     *                               {@code qsHeight} is the final top padding
+     */
+    public void updateTopPadding(float qsHeight, int scrollY, boolean animate,
+            boolean ignoreIntrinsicPadding) {
         float start = qsHeight - scrollY + mNotificationTopPadding;
         float stackHeight = getHeight() - start;
         int minStackHeight = getMinStackHeight();
@@ -1346,13 +1376,13 @@
             float overflow = minStackHeight - stackHeight;
             stackHeight = minStackHeight;
             start = getHeight() - stackHeight;
-            setTranslationY(overflow);
             mTopPaddingOverflow = overflow;
         } else {
-            setTranslationY(0);
             mTopPaddingOverflow = 0;
         }
-        setTopPadding(clampPadding((int) start), animate);
+        setTopPadding(ignoreIntrinsicPadding ? (int) start : clampPadding((int) start),
+                animate);
+        setStackHeight(mLastSetStackHeight);
     }
 
     public int getNotificationTopPadding() {
@@ -1430,6 +1460,7 @@
             transformTouchEvent(ev, mScrollView, this);
         }
         initDownStates(ev);
+        handleEmptySpaceClick(ev);
         boolean expandWantsIt = false;
         if (!mSwipingInProgress && !mOnlyScrollingInThisMotion && isScrollingEnabled()) {
             expandWantsIt = mExpandHelper.onInterceptTouchEvent(ev);
@@ -1448,11 +1479,31 @@
         return swipeWantsIt || scrollWantsIt || expandWantsIt || super.onInterceptTouchEvent(ev);
     }
 
+    private void handleEmptySpaceClick(MotionEvent ev) {
+        switch (ev.getActionMasked()) {
+            case MotionEvent.ACTION_MOVE:
+                if (mTouchIsClick && (Math.abs(ev.getY() - mInitialTouchY) > mTouchSlop
+                        || Math.abs(ev.getX() - mInitialTouchX) > mTouchSlop )) {
+                    mTouchIsClick = false;
+                }
+                break;
+            case MotionEvent.ACTION_UP:
+                if (mPhoneStatusBar.getBarState() != StatusBarState.KEYGUARD && mTouchIsClick &&
+                        isBelowLastNotification(mInitialTouchX, mInitialTouchY)) {
+                    mOnEmptySpaceClickListener.onEmptySpaceClicked(mInitialTouchX, mInitialTouchY);
+                }
+                break;
+        }
+    }
+
     private void initDownStates(MotionEvent ev) {
         if (ev.getAction() == MotionEvent.ACTION_DOWN) {
             mExpandedInThisMotion = false;
             mOnlyScrollingInThisMotion = !mScroller.isFinished();
             mDisallowScrollingInThisMotion = false;
+            mTouchIsClick = true;
+            mInitialTouchX = ev.getX();
+            mInitialTouchY = ev.getY();
         }
     }
 
@@ -1886,7 +1937,14 @@
      * @return Whether the specified motion event is actually happening over the content.
      */
     private boolean isInContentBounds(MotionEvent event) {
-        return event.getY() < getHeight() - getEmptyBottomMargin();
+        return isInContentBounds(event.getY());
+    }
+
+    /**
+     * @return Whether a y coordinate is inside the content.
+     */
+    public boolean isInContentBounds(float y) {
+        return y < getHeight() - getEmptyBottomMargin();
     }
 
     private void setIsBeingDragged(boolean isDragged) {
@@ -1995,6 +2053,10 @@
         this.mOnHeightChangedListener = mOnHeightChangedListener;
     }
 
+    public void setOnEmptySpaceClickListener(OnEmptySpaceClickListener listener) {
+        mOnEmptySpaceClickListener = listener;
+    }
+
     public void onChildAnimationFinished() {
         requestChildrenUpdate();
     }
@@ -2245,6 +2307,24 @@
         }
     }
 
+    private boolean isBelowLastNotification(float touchX, float touchY) {
+        ExpandableView lastChildNotGone = (ExpandableView) getLastChildNotGone();
+        if (lastChildNotGone == null) {
+            return touchY > mIntrinsicPadding;
+        }
+        if (lastChildNotGone != mDismissView && lastChildNotGone != mEmptyShadeView) {
+            return touchY > lastChildNotGone.getY() + lastChildNotGone.getActualHeight();
+        } else if (lastChildNotGone == mEmptyShadeView) {
+            return touchY > mEmptyShadeView.getY();
+        } else {
+            float dismissY = mDismissView.getY();
+            boolean belowDismissView = touchY > dismissY + mDismissView.getActualHeight();
+            return belowDismissView || (touchY > dismissY
+                    && mDismissView.isOnEmptySpace(touchX - mDismissView.getX(),
+                    touchY - dismissY));
+        }
+    }
+
     /**
      * A listener that is notified when some child locations might have changed.
      */
@@ -2253,6 +2333,13 @@
     }
 
     /**
+     * A listener that is notified when the empty space below the notifications is clicked on
+     */
+    public interface OnEmptySpaceClickListener {
+        public void onEmptySpaceClicked(float x, float y);
+    }
+
+    /**
      * A listener that gets notified when the overscroll at the top has changed.
      */
     public interface OnOverscrollTopChangedListener {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackScrollAlgorithm.java b/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackScrollAlgorithm.java
index 853628e..ddc4251 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackScrollAlgorithm.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackScrollAlgorithm.java
@@ -200,15 +200,25 @@
             // apply clipping and shadow
             float newNotificationEnd = newYTranslation + newHeight;
 
-            // In the unlocked shade we have to clip a little bit higher because of the rounded
-            // corners of the notifications.
-            float clippingCorrection = state.dimmed ? 0 : mRoundedRectCornerRadius * state.scale;
+            float clipHeight;
+            if (previousNotificationIsSwiped) {
+                // When the previous notification is swiped, we don't clip the content to the
+                // bottom of it.
+                clipHeight = newHeight;
+            } else {
+                clipHeight = newNotificationEnd - previousNotificationEnd;
+                clipHeight = Math.max(0.0f, clipHeight);
+                if (clipHeight != 0.0f) {
 
-            // When the previous notification is swiped, we don't clip the content to the
-            // bottom of it.
-            float clipHeight = previousNotificationIsSwiped
-                    ? newHeight
-                    : newNotificationEnd - (previousNotificationEnd - clippingCorrection);
+                    // In the unlocked shade we have to clip a little bit higher because of the rounded
+                    // corners of the notifications, but only if we are not fully overlapped by
+                    // the top card.
+                    float clippingCorrection = state.dimmed
+                            ? 0
+                            : mRoundedRectCornerRadius * state.scale;
+                    clipHeight += clippingCorrection;
+                }
+            }
 
             updateChildClippingAndBackground(state, newHeight, clipHeight,
                     newHeight - (previousNotificationStart - newYTranslation));
@@ -669,7 +679,11 @@
             StackScrollState.ViewState childViewState = resultState.getViewStateForView(child);
             if (i < algorithmState.itemsInTopStack) {
                 float stackIndex = algorithmState.itemsInTopStack - i;
-                stackIndex = Math.min(stackIndex, MAX_ITEMS_IN_TOP_STACK + 2);
+
+                // Ensure that the topmost item is a little bit higher than the rest when fully
+                // scrolled, to avoid drawing errors when swiping it out
+                float max = MAX_ITEMS_IN_TOP_STACK + (i == 0 ? 2.5f : 2);
+                stackIndex = Math.min(stackIndex, max);
                 if (i == 0 && algorithmState.itemsInTopStack < 2.0f) {
 
                     // We only have the top item and an additional item in the top stack,
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackScrollState.java b/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackScrollState.java
index 0967ecd..4611370 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackScrollState.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackScrollState.java
@@ -119,9 +119,7 @@
                     }
 
                     // apply alpha
-                    if (!becomesInvisible) {
-                        child.setAlpha(newAlpha);
-                    }
+                    child.setAlpha(newAlpha);
                 }
 
                 // apply visibility
@@ -236,6 +234,8 @@
         public static final int LOCATION_MAIN_AREA = 0x08;
         public static final int LOCATION_BOTTOM_STACK_PEEKING = 0x10;
         public static final int LOCATION_BOTTOM_STACK_HIDDEN = 0x20;
+        /** The view isn't layouted at all. */
+        public static final int LOCATION_GONE = 0x40;
 
         float alpha;
         float yTranslation;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackStateAnimator.java b/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackStateAnimator.java
index 433357e..674642b 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackStateAnimator.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackStateAnimator.java
@@ -477,6 +477,7 @@
                 if (newEndValue == 0 && !mWasCancelled) {
                     child.setVisibility(View.INVISIBLE);
                 }
+                // remove the tag when the animation is finished
                 child.setTag(TAG_ANIMATOR_ALPHA, null);
                 child.setTag(TAG_START_ALPHA, null);
                 child.setTag(TAG_END_ALPHA, null);
@@ -498,13 +499,7 @@
             animator.setStartDelay(delay);
         }
         animator.addListener(getGlobalAnimationFinishedListener());
-        // remove the tag when the animation is finished
-        animator.addListener(new AnimatorListenerAdapter() {
-            @Override
-            public void onAnimationEnd(Animator animation) {
 
-            }
-        });
         startAnimator(animator);
         child.setTag(TAG_ANIMATOR_ALPHA, animator);
         child.setTag(TAG_START_ALPHA, child.getAlpha());
diff --git a/policy/src/com/android/internal/policy/impl/PhoneWindow.java b/policy/src/com/android/internal/policy/impl/PhoneWindow.java
index 1ed61fd..4714826 100644
--- a/policy/src/com/android/internal/policy/impl/PhoneWindow.java
+++ b/policy/src/com/android/internal/policy/impl/PhoneWindow.java
@@ -1332,6 +1332,22 @@
     }
 
     @Override
+    public final void setElevation(float elevation) {
+        mElevation = elevation;
+        if (mDecor != null) {
+            mDecor.setElevation(elevation);
+        }
+    }
+
+    @Override
+    public final void setClipToOutline(boolean clipToOutline) {
+        mClipToOutline = clipToOutline;
+        if (mDecor != null) {
+            mDecor.setClipToOutline(clipToOutline);
+        }
+    }
+
+    @Override
     public final void setBackgroundDrawable(Drawable drawable) {
         if (drawable != mBackgroundDrawable || mBackgroundResource != 0) {
             mBackgroundResource = 0;
diff --git a/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java b/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
index 558cf56..fb2a17b 100644
--- a/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
+++ b/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
@@ -5352,7 +5352,11 @@
                             return true;
                         }
                     };
-                    mBootMsgDialog.setTitle(R.string.android_upgrading_title);
+                    if (mContext.getPackageManager().isUpgrade()) {
+                        mBootMsgDialog.setTitle(R.string.android_upgrading_title);
+                    } else {
+                        mBootMsgDialog.setTitle(R.string.android_start_title);
+                    }
                     mBootMsgDialog.setProgressStyle(ProgressDialog.STYLE_SPINNER);
                     mBootMsgDialog.setIndeterminate(true);
                     mBootMsgDialog.getWindow().setType(
diff --git a/services/core/java/com/android/server/InputMethodManagerService.java b/services/core/java/com/android/server/InputMethodManagerService.java
index 1623eac..edea274 100644
--- a/services/core/java/com/android/server/InputMethodManagerService.java
+++ b/services/core/java/com/android/server/InputMethodManagerService.java
@@ -774,7 +774,11 @@
         if (defIm == null && mMethodList.size() > 0) {
             defIm = InputMethodUtils.getMostApplicableDefaultIME(
                     mSettings.getEnabledInputMethodListLocked());
-            Slog.i(TAG, "No default found, using " + defIm.getId());
+            if (defIm != null) {
+                Slog.i(TAG, "Default found, using " + defIm.getId());
+            } else {
+                Slog.i(TAG, "No default found");
+            }
         }
         if (defIm != null) {
             setSelectedInputMethodAndSubtypeLocked(defIm, NOT_A_SUBTYPE_ID, false);
diff --git a/services/core/java/com/android/server/NetworkManagementService.java b/services/core/java/com/android/server/NetworkManagementService.java
index d03a154..0f033d71 100644
--- a/services/core/java/com/android/server/NetworkManagementService.java
+++ b/services/core/java/com/android/server/NetworkManagementService.java
@@ -940,6 +940,17 @@
     }
 
     @Override
+    public void setInterfaceIpv6NdOffload(String iface, boolean enable) {
+        mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
+        try {
+            mConnector.execute(
+                    "interface", "ipv6ndoffload", iface, (enable ? "enable" : "disable"));
+        } catch (NativeDaemonConnectorException e) {
+            throw e.rethrowAsParcelableException();
+        }
+    }
+
+    @Override
     public void addRoute(int netId, RouteInfo route) {
         modifyRoute("add", "" + netId, route);
     }
diff --git a/services/core/java/com/android/server/Watchdog.java b/services/core/java/com/android/server/Watchdog.java
index 89e3f49..8e46c4d 100644
--- a/services/core/java/com/android/server/Watchdog.java
+++ b/services/core/java/com/android/server/Watchdog.java
@@ -415,15 +415,9 @@
                 dumpKernelStackTraces();
             }
 
-            // Trigger the kernel to dump all blocked threads to the kernel log
-            try {
-                FileWriter sysrq_trigger = new FileWriter("/proc/sysrq-trigger");
-                sysrq_trigger.write("w");
-                sysrq_trigger.close();
-            } catch (IOException e) {
-                Slog.e(TAG, "Failed to write to /proc/sysrq-trigger");
-                Slog.e(TAG, e.getMessage());
-            }
+            // Trigger the kernel to dump all blocked threads, and backtraces on all CPUs to the kernel log
+            doSysRq('w');
+            doSysRq('l');
 
             // Try to add the error to the dropbox, but assuming that the ActivityManager
             // itself may be deadlocked.  (which has happened, causing this statement to
@@ -488,6 +482,16 @@
         }
     }
 
+    private void doSysRq(char c) {
+        try {
+            FileWriter sysrq_trigger = new FileWriter("/proc/sysrq-trigger");
+            sysrq_trigger.write(c);
+            sysrq_trigger.close();
+        } catch (IOException e) {
+            Slog.w(TAG, "Failed to write to /proc/sysrq-trigger", e);
+        }
+    }
+
     private File dumpKernelStackTraces() {
         String tracesPath = SystemProperties.get("dalvik.vm.stack-trace-file", null);
         if (tracesPath == null || tracesPath.length() == 0) {
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index 9f1ce0b..9179cc4 100755
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -1606,197 +1606,7 @@
                 final ArrayList<ProcessMemInfo> memInfos = (ArrayList<ProcessMemInfo>)msg.obj;
                 Thread thread = new Thread() {
                     @Override public void run() {
-                        final SparseArray<ProcessMemInfo> infoMap
-                                = new SparseArray<ProcessMemInfo>(memInfos.size());
-                        for (int i=0, N=memInfos.size(); i<N; i++) {
-                            ProcessMemInfo mi = memInfos.get(i);
-                            infoMap.put(mi.pid, mi);
-                        }
-                        updateCpuStatsNow();
-                        synchronized (mProcessCpuTracker) {
-                            final int N = mProcessCpuTracker.countStats();
-                            for (int i=0; i<N; i++) {
-                                ProcessCpuTracker.Stats st = mProcessCpuTracker.getStats(i);
-                                if (st.vsize > 0) {
-                                    long pss = Debug.getPss(st.pid, null);
-                                    if (pss > 0) {
-                                        if (infoMap.indexOfKey(st.pid) < 0) {
-                                            ProcessMemInfo mi = new ProcessMemInfo(st.name, st.pid,
-                                                    ProcessList.NATIVE_ADJ, -1, "native", null);
-                                            mi.pss = pss;
-                                            memInfos.add(mi);
-                                        }
-                                    }
-                                }
-                            }
-                        }
-
-                        long totalPss = 0;
-                        for (int i=0, N=memInfos.size(); i<N; i++) {
-                            ProcessMemInfo mi = memInfos.get(i);
-                            if (mi.pss == 0) {
-                                mi.pss = Debug.getPss(mi.pid, null);
-                            }
-                            totalPss += mi.pss;
-                        }
-                        Collections.sort(memInfos, new Comparator<ProcessMemInfo>() {
-                            @Override public int compare(ProcessMemInfo lhs, ProcessMemInfo rhs) {
-                                if (lhs.oomAdj != rhs.oomAdj) {
-                                    return lhs.oomAdj < rhs.oomAdj ? -1 : 1;
-                                }
-                                if (lhs.pss != rhs.pss) {
-                                    return lhs.pss < rhs.pss ? 1 : -1;
-                                }
-                                return 0;
-                            }
-                        });
-
-                        StringBuilder tag = new StringBuilder(128);
-                        StringBuilder stack = new StringBuilder(128);
-                        tag.append("Low on memory -- ");
-                        appendMemBucket(tag, totalPss, "total", false);
-                        appendMemBucket(stack, totalPss, "total", true);
-
-                        StringBuilder logBuilder = new StringBuilder(1024);
-                        logBuilder.append("Low on memory:\n");
-
-                        boolean firstLine = true;
-                        int lastOomAdj = Integer.MIN_VALUE;
-                        for (int i=0, N=memInfos.size(); i<N; i++) {
-                            ProcessMemInfo mi = memInfos.get(i);
-
-                            if (mi.oomAdj != ProcessList.NATIVE_ADJ
-                                    && (mi.oomAdj < ProcessList.SERVICE_ADJ
-                                            || mi.oomAdj == ProcessList.HOME_APP_ADJ
-                                            || mi.oomAdj == ProcessList.PREVIOUS_APP_ADJ)) {
-                                if (lastOomAdj != mi.oomAdj) {
-                                    lastOomAdj = mi.oomAdj;
-                                    if (mi.oomAdj <= ProcessList.FOREGROUND_APP_ADJ) {
-                                        tag.append(" / ");
-                                    }
-                                    if (mi.oomAdj >= ProcessList.FOREGROUND_APP_ADJ) {
-                                        if (firstLine) {
-                                            stack.append(":");
-                                            firstLine = false;
-                                        }
-                                        stack.append("\n\t at ");
-                                    } else {
-                                        stack.append("$");
-                                    }
-                                } else {
-                                    tag.append(" ");
-                                    stack.append("$");
-                                }
-                                if (mi.oomAdj <= ProcessList.FOREGROUND_APP_ADJ) {
-                                    appendMemBucket(tag, mi.pss, mi.name, false);
-                                }
-                                appendMemBucket(stack, mi.pss, mi.name, true);
-                                if (mi.oomAdj >= ProcessList.FOREGROUND_APP_ADJ
-                                        && ((i+1) >= N || memInfos.get(i+1).oomAdj != lastOomAdj)) {
-                                    stack.append("(");
-                                    for (int k=0; k<DUMP_MEM_OOM_ADJ.length; k++) {
-                                        if (DUMP_MEM_OOM_ADJ[k] == mi.oomAdj) {
-                                            stack.append(DUMP_MEM_OOM_LABEL[k]);
-                                            stack.append(":");
-                                            stack.append(DUMP_MEM_OOM_ADJ[k]);
-                                        }
-                                    }
-                                    stack.append(")");
-                                }
-                            }
-
-                            logBuilder.append("  ");
-                            logBuilder.append(ProcessList.makeOomAdjString(mi.oomAdj));
-                            logBuilder.append(' ');
-                            logBuilder.append(ProcessList.makeProcStateString(mi.procState));
-                            logBuilder.append(' ');
-                            ProcessList.appendRamKb(logBuilder, mi.pss);
-                            logBuilder.append(" kB: ");
-                            logBuilder.append(mi.name);
-                            logBuilder.append(" (");
-                            logBuilder.append(mi.pid);
-                            logBuilder.append(") ");
-                            logBuilder.append(mi.adjType);
-                            logBuilder.append('\n');
-                            if (mi.adjReason != null) {
-                                logBuilder.append("                      ");
-                                logBuilder.append(mi.adjReason);
-                                logBuilder.append('\n');
-                            }
-                        }
-
-                        logBuilder.append("           ");
-                        ProcessList.appendRamKb(logBuilder, totalPss);
-                        logBuilder.append(" kB: TOTAL\n");
-
-                        long[] infos = new long[Debug.MEMINFO_COUNT];
-                        Debug.getMemInfo(infos);
-                        logBuilder.append("  MemInfo: ");
-                        logBuilder.append(infos[Debug.MEMINFO_SLAB]).append(" kB slab, ");
-                        logBuilder.append(infos[Debug.MEMINFO_SHMEM]).append(" kB shmem, ");
-                        logBuilder.append(infos[Debug.MEMINFO_VM_ALLOC_USED]).append(" kB vm alloc, ");
-                        logBuilder.append(infos[Debug.MEMINFO_PAGE_TABLES]).append(" kB page tables ");
-                        logBuilder.append(infos[Debug.MEMINFO_KERNEL_STACK]).append(" kB kernel stack\n");
-                        logBuilder.append("           ");
-                        logBuilder.append(infos[Debug.MEMINFO_BUFFERS]).append(" kB buffers, ");
-                        logBuilder.append(infos[Debug.MEMINFO_CACHED]).append(" kB cached, ");
-                        logBuilder.append(infos[Debug.MEMINFO_MAPPED]).append(" kB mapped, ");
-                        logBuilder.append(infos[Debug.MEMINFO_FREE]).append(" kB free\n");
-                        if (infos[Debug.MEMINFO_ZRAM_TOTAL] != 0) {
-                            logBuilder.append("  ZRAM: ");
-                            logBuilder.append(infos[Debug.MEMINFO_ZRAM_TOTAL]);
-                            logBuilder.append(" kB RAM, ");
-                            logBuilder.append(infos[Debug.MEMINFO_SWAP_TOTAL]);
-                            logBuilder.append(" kB swap total, ");
-                            logBuilder.append(infos[Debug.MEMINFO_SWAP_FREE]);
-                            logBuilder.append(" kB swap free\n");
-                        }
-                        Slog.i(TAG, logBuilder.toString());
-
-                        StringBuilder dropBuilder = new StringBuilder(1024);
-                        /*
-                        StringWriter oomSw = new StringWriter();
-                        PrintWriter oomPw = new FastPrintWriter(oomSw, false, 256);
-                        StringWriter catSw = new StringWriter();
-                        PrintWriter catPw = new FastPrintWriter(catSw, false, 256);
-                        String[] emptyArgs = new String[] { };
-                        dumpApplicationMemoryUsage(null, oomPw, "  ", emptyArgs, true, catPw);
-                        oomPw.flush();
-                        String oomString = oomSw.toString();
-                        */
-                        dropBuilder.append(stack);
-                        dropBuilder.append('\n');
-                        dropBuilder.append('\n');
-                        dropBuilder.append(logBuilder);
-                        dropBuilder.append('\n');
-                        /*
-                        dropBuilder.append(oomString);
-                        dropBuilder.append('\n');
-                        */
-                        StringWriter catSw = new StringWriter();
-                        synchronized (ActivityManagerService.this) {
-                            PrintWriter catPw = new FastPrintWriter(catSw, false, 256);
-                            String[] emptyArgs = new String[] { };
-                            catPw.println();
-                            dumpProcessesLocked(null, catPw, emptyArgs, 0, false, null);
-                            catPw.println();
-                            mServices.dumpServicesLocked(null, catPw, emptyArgs, 0,
-                                    false, false, null);
-                            catPw.println();
-                            dumpActivitiesLocked(null, catPw, emptyArgs, 0, false, false, null);
-                            catPw.flush();
-                        }
-                        dropBuilder.append(catSw.toString());
-                        addErrorToDropBox("lowmem", null, "system_server", null,
-                                null, tag.toString(), dropBuilder.toString(), null, null);
-                        //Slog.i(TAG, "Sent to dropbox:");
-                        //Slog.i(TAG, dropBuilder.toString());
-                        synchronized (ActivityManagerService.this) {
-                            long now = SystemClock.uptimeMillis();
-                            if (mLastMemUsageReportTime < now) {
-                                mLastMemUsageReportTime = now;
-                            }
-                        }
+                        reportMemUsage(memInfos);
                     }
                 };
                 thread.start();
@@ -13927,6 +13737,35 @@
         }
     }
 
+    private static final int KSM_SHARED = 0;
+    private static final int KSM_SHARING = 1;
+    private static final int KSM_UNSHARED = 2;
+    private static final int KSM_VOLATILE = 3;
+
+    private final long[] getKsmInfo() {
+        long[] longOut = new long[4];
+        final int[] SINGLE_LONG_FORMAT = new int[] {
+            Process.PROC_SPACE_TERM|Process.PROC_OUT_LONG
+        };
+        long[] longTmp = new long[1];
+        Process.readProcFile("/sys/kernel/mm/ksm/pages_shared",
+                SINGLE_LONG_FORMAT, null, longTmp, null);
+        longOut[KSM_SHARED] = longTmp[0] * ProcessList.PAGE_SIZE / 1024;
+        longTmp[0] = 0;
+        Process.readProcFile("/sys/kernel/mm/ksm/pages_sharing",
+                SINGLE_LONG_FORMAT, null, longTmp, null);
+        longOut[KSM_SHARING] = longTmp[0] * ProcessList.PAGE_SIZE / 1024;
+        longTmp[0] = 0;
+        Process.readProcFile("/sys/kernel/mm/ksm/pages_unshared",
+                SINGLE_LONG_FORMAT, null, longTmp, null);
+        longOut[KSM_UNSHARED] = longTmp[0] * ProcessList.PAGE_SIZE / 1024;
+        longTmp[0] = 0;
+        Process.readProcFile("/sys/kernel/mm/ksm/pages_volatile",
+                SINGLE_LONG_FORMAT, null, longTmp, null);
+        longOut[KSM_VOLATILE] = longTmp[0] * ProcessList.PAGE_SIZE / 1024;
+        return longOut;
+    }
+
     final void dumpApplicationMemoryUsage(FileDescriptor fd,
             PrintWriter pw, String prefix, String[] args, boolean brief, PrintWriter categoryPw) {
         boolean dumpDetails = false;
@@ -14272,7 +14111,7 @@
                     pw.print(" Free RAM: "); pw.print(cachedPss + memInfo.getCachedSizeKb()
                             + memInfo.getFreeSizeKb()); pw.print(" kB (");
                             pw.print(cachedPss); pw.print(" cached pss + ");
-                            pw.print(memInfo.getCachedSizeKb()); pw.print(" cached + ");
+                            pw.print(memInfo.getCachedSizeKb()); pw.print(" cached kernel + ");
                             pw.print(memInfo.getFreeSizeKb()); pw.println(" free)");
                 } else {
                     pw.print("ram,"); pw.print(memInfo.getTotalSizeKb()); pw.print(",");
@@ -14306,32 +14145,16 @@
                                 pw.println(memInfo.getSwapFreeSizeKb());
                     }
                 }
-                final int[] SINGLE_LONG_FORMAT = new int[] {
-                    Process.PROC_SPACE_TERM|Process.PROC_OUT_LONG
-                };
-                long[] longOut = new long[1];
-                Process.readProcFile("/sys/kernel/mm/ksm/pages_shared",
-                        SINGLE_LONG_FORMAT, null, longOut, null);
-                long shared = longOut[0] * ProcessList.PAGE_SIZE / 1024;
-                longOut[0] = 0;
-                Process.readProcFile("/sys/kernel/mm/ksm/pages_sharing",
-                        SINGLE_LONG_FORMAT, null, longOut, null);
-                long sharing = longOut[0] * ProcessList.PAGE_SIZE / 1024;
-                longOut[0] = 0;
-                Process.readProcFile("/sys/kernel/mm/ksm/pages_unshared",
-                        SINGLE_LONG_FORMAT, null, longOut, null);
-                long unshared = longOut[0] * ProcessList.PAGE_SIZE / 1024;
-                longOut[0] = 0;
-                Process.readProcFile("/sys/kernel/mm/ksm/pages_volatile",
-                        SINGLE_LONG_FORMAT, null, longOut, null);
-                long voltile = longOut[0] * ProcessList.PAGE_SIZE / 1024;
+                final long[] ksm = getKsmInfo();
                 if (!isCompact) {
-                    if (sharing != 0 || shared != 0 || unshared != 0 || voltile != 0) {
-                        pw.print("      KSM: "); pw.print(sharing);
+                    if (ksm[KSM_SHARING] != 0 || ksm[KSM_SHARED] != 0 || ksm[KSM_UNSHARED] != 0
+                            || ksm[KSM_VOLATILE] != 0) {
+                        pw.print("      KSM: "); pw.print(ksm[KSM_SHARING]);
                                 pw.print(" kB saved from shared ");
-                                pw.print(shared); pw.println(" kB");
-                        pw.print("           "); pw.print(unshared); pw.print(" kB unshared; ");
-                                pw.print(voltile); pw.println(" kB volatile");
+                                pw.print(ksm[KSM_SHARED]); pw.println(" kB");
+                        pw.print("           "); pw.print(ksm[KSM_UNSHARED]);
+                                pw.print(" kB unshared; ");
+                                pw.print(ksm[KSM_VOLATILE]); pw.println(" kB volatile");
                     }
                     pw.print("   Tuning: ");
                     pw.print(ActivityManager.staticGetMemoryClass());
@@ -14351,9 +14174,9 @@
                     }
                     pw.println();
                 } else {
-                    pw.print("ksm,"); pw.print(sharing); pw.print(",");
-                    pw.print(shared); pw.print(","); pw.print(unshared); pw.print(",");
-                    pw.println(voltile);
+                    pw.print("ksm,"); pw.print(ksm[KSM_SHARING]); pw.print(",");
+                    pw.print(ksm[KSM_SHARED]); pw.print(","); pw.print(ksm[KSM_UNSHARED]);
+                    pw.print(","); pw.println(ksm[KSM_VOLATILE]);
                     pw.print("tuning,");
                     pw.print(ActivityManager.staticGetMemoryClass());
                     pw.print(',');
@@ -14372,6 +14195,265 @@
         }
     }
 
+    private void appendBasicMemEntry(StringBuilder sb, int oomAdj, int procState, long pss,
+            String name) {
+        sb.append("  ");
+        sb.append(ProcessList.makeOomAdjString(oomAdj));
+        sb.append(' ');
+        sb.append(ProcessList.makeProcStateString(procState));
+        sb.append(' ');
+        ProcessList.appendRamKb(sb, pss);
+        sb.append(" kB: ");
+        sb.append(name);
+    }
+
+    private void appendMemInfo(StringBuilder sb, ProcessMemInfo mi) {
+        appendBasicMemEntry(sb, mi.oomAdj, mi.procState, mi.pss, mi.name);
+        sb.append(" (");
+        sb.append(mi.pid);
+        sb.append(") ");
+        sb.append(mi.adjType);
+        sb.append('\n');
+        if (mi.adjReason != null) {
+            sb.append("                      ");
+            sb.append(mi.adjReason);
+            sb.append('\n');
+        }
+    }
+
+    void reportMemUsage(ArrayList<ProcessMemInfo> memInfos) {
+        final SparseArray<ProcessMemInfo> infoMap = new SparseArray<>(memInfos.size());
+        for (int i=0, N=memInfos.size(); i<N; i++) {
+            ProcessMemInfo mi = memInfos.get(i);
+            infoMap.put(mi.pid, mi);
+        }
+        updateCpuStatsNow();
+        synchronized (mProcessCpuTracker) {
+            final int N = mProcessCpuTracker.countStats();
+            for (int i=0; i<N; i++) {
+                ProcessCpuTracker.Stats st = mProcessCpuTracker.getStats(i);
+                if (st.vsize > 0) {
+                    long pss = Debug.getPss(st.pid, null);
+                    if (pss > 0) {
+                        if (infoMap.indexOfKey(st.pid) < 0) {
+                            ProcessMemInfo mi = new ProcessMemInfo(st.name, st.pid,
+                                    ProcessList.NATIVE_ADJ, -1, "native", null);
+                            mi.pss = pss;
+                            memInfos.add(mi);
+                        }
+                    }
+                }
+            }
+        }
+
+        long totalPss = 0;
+        for (int i=0, N=memInfos.size(); i<N; i++) {
+            ProcessMemInfo mi = memInfos.get(i);
+            if (mi.pss == 0) {
+                mi.pss = Debug.getPss(mi.pid, null);
+            }
+            totalPss += mi.pss;
+        }
+        Collections.sort(memInfos, new Comparator<ProcessMemInfo>() {
+            @Override public int compare(ProcessMemInfo lhs, ProcessMemInfo rhs) {
+                if (lhs.oomAdj != rhs.oomAdj) {
+                    return lhs.oomAdj < rhs.oomAdj ? -1 : 1;
+                }
+                if (lhs.pss != rhs.pss) {
+                    return lhs.pss < rhs.pss ? 1 : -1;
+                }
+                return 0;
+            }
+        });
+
+        StringBuilder tag = new StringBuilder(128);
+        StringBuilder stack = new StringBuilder(128);
+        tag.append("Low on memory -- ");
+        appendMemBucket(tag, totalPss, "total", false);
+        appendMemBucket(stack, totalPss, "total", true);
+
+        StringBuilder fullNativeBuilder = new StringBuilder(1024);
+        StringBuilder shortNativeBuilder = new StringBuilder(1024);
+        StringBuilder fullJavaBuilder = new StringBuilder(1024);
+
+        boolean firstLine = true;
+        int lastOomAdj = Integer.MIN_VALUE;
+        long extraNativeRam = 0;
+        long cachedPss = 0;
+        for (int i=0, N=memInfos.size(); i<N; i++) {
+            ProcessMemInfo mi = memInfos.get(i);
+
+            if (mi.oomAdj >= ProcessList.CACHED_APP_MIN_ADJ) {
+                cachedPss += mi.pss;
+            }
+
+            if (mi.oomAdj != ProcessList.NATIVE_ADJ
+                    && (mi.oomAdj < ProcessList.SERVICE_ADJ
+                            || mi.oomAdj == ProcessList.HOME_APP_ADJ
+                            || mi.oomAdj == ProcessList.PREVIOUS_APP_ADJ)) {
+                if (lastOomAdj != mi.oomAdj) {
+                    lastOomAdj = mi.oomAdj;
+                    if (mi.oomAdj <= ProcessList.FOREGROUND_APP_ADJ) {
+                        tag.append(" / ");
+                    }
+                    if (mi.oomAdj >= ProcessList.FOREGROUND_APP_ADJ) {
+                        if (firstLine) {
+                            stack.append(":");
+                            firstLine = false;
+                        }
+                        stack.append("\n\t at ");
+                    } else {
+                        stack.append("$");
+                    }
+                } else {
+                    tag.append(" ");
+                    stack.append("$");
+                }
+                if (mi.oomAdj <= ProcessList.FOREGROUND_APP_ADJ) {
+                    appendMemBucket(tag, mi.pss, mi.name, false);
+                }
+                appendMemBucket(stack, mi.pss, mi.name, true);
+                if (mi.oomAdj >= ProcessList.FOREGROUND_APP_ADJ
+                        && ((i+1) >= N || memInfos.get(i+1).oomAdj != lastOomAdj)) {
+                    stack.append("(");
+                    for (int k=0; k<DUMP_MEM_OOM_ADJ.length; k++) {
+                        if (DUMP_MEM_OOM_ADJ[k] == mi.oomAdj) {
+                            stack.append(DUMP_MEM_OOM_LABEL[k]);
+                            stack.append(":");
+                            stack.append(DUMP_MEM_OOM_ADJ[k]);
+                        }
+                    }
+                    stack.append(")");
+                }
+            }
+
+            appendMemInfo(fullNativeBuilder, mi);
+            if (mi.oomAdj == ProcessList.NATIVE_ADJ) {
+                // The short form only has native processes that are >= 1MB.
+                if (mi.pss >= 1000) {
+                    appendMemInfo(shortNativeBuilder, mi);
+                } else {
+                    extraNativeRam += mi.pss;
+                }
+            } else {
+                // Short form has all other details, but if we have collected RAM
+                // from smaller native processes let's dump a summary of that.
+                if (extraNativeRam > 0) {
+                    appendBasicMemEntry(shortNativeBuilder, ProcessList.NATIVE_ADJ,
+                            -1, extraNativeRam, "(Other native)");
+                    shortNativeBuilder.append('\n');
+                    extraNativeRam = 0;
+                }
+                appendMemInfo(fullJavaBuilder, mi);
+            }
+        }
+
+        fullJavaBuilder.append("           ");
+        ProcessList.appendRamKb(fullJavaBuilder, totalPss);
+        fullJavaBuilder.append(" kB: TOTAL\n");
+
+        MemInfoReader memInfo = new MemInfoReader();
+        memInfo.readMemInfo();
+        final long[] infos = memInfo.getRawInfo();
+
+        StringBuilder memInfoBuilder = new StringBuilder(1024);
+        Debug.getMemInfo(infos);
+        memInfoBuilder.append("  MemInfo: ");
+        memInfoBuilder.append(infos[Debug.MEMINFO_SLAB]).append(" kB slab, ");
+        memInfoBuilder.append(infos[Debug.MEMINFO_SHMEM]).append(" kB shmem, ");
+        memInfoBuilder.append(infos[Debug.MEMINFO_VM_ALLOC_USED]).append(" kB vm alloc, ");
+        memInfoBuilder.append(infos[Debug.MEMINFO_PAGE_TABLES]).append(" kB page tables ");
+        memInfoBuilder.append(infos[Debug.MEMINFO_KERNEL_STACK]).append(" kB kernel stack\n");
+        memInfoBuilder.append("           ");
+        memInfoBuilder.append(infos[Debug.MEMINFO_BUFFERS]).append(" kB buffers, ");
+        memInfoBuilder.append(infos[Debug.MEMINFO_CACHED]).append(" kB cached, ");
+        memInfoBuilder.append(infos[Debug.MEMINFO_MAPPED]).append(" kB mapped, ");
+        memInfoBuilder.append(infos[Debug.MEMINFO_FREE]).append(" kB free\n");
+        if (infos[Debug.MEMINFO_ZRAM_TOTAL] != 0) {
+            memInfoBuilder.append("  ZRAM: ");
+            memInfoBuilder.append(infos[Debug.MEMINFO_ZRAM_TOTAL]);
+            memInfoBuilder.append(" kB RAM, ");
+            memInfoBuilder.append(infos[Debug.MEMINFO_SWAP_TOTAL]);
+            memInfoBuilder.append(" kB swap total, ");
+            memInfoBuilder.append(infos[Debug.MEMINFO_SWAP_FREE]);
+            memInfoBuilder.append(" kB swap free\n");
+        }
+        final long[] ksm = getKsmInfo();
+        if (ksm[KSM_SHARING] != 0 || ksm[KSM_SHARED] != 0 || ksm[KSM_UNSHARED] != 0
+                || ksm[KSM_VOLATILE] != 0) {
+            memInfoBuilder.append("  KSM: "); memInfoBuilder.append(ksm[KSM_SHARING]);
+            memInfoBuilder.append(" kB saved from shared ");
+            memInfoBuilder.append(ksm[KSM_SHARED]); memInfoBuilder.append(" kB\n");
+            memInfoBuilder.append("       "); memInfoBuilder.append(ksm[KSM_UNSHARED]);
+            memInfoBuilder.append(" kB unshared; ");
+            memInfoBuilder.append(ksm[KSM_VOLATILE]); memInfoBuilder.append(" kB volatile\n");
+        }
+        memInfoBuilder.append("  Free RAM: ");
+        memInfoBuilder.append(cachedPss + memInfo.getCachedSizeKb()
+                + memInfo.getFreeSizeKb());
+        memInfoBuilder.append(" kB\n");
+        memInfoBuilder.append("  Used RAM: ");
+        memInfoBuilder.append(totalPss - cachedPss + memInfo.getKernelUsedSizeKb());
+        memInfoBuilder.append(" kB\n");
+        memInfoBuilder.append("  Lost RAM: ");
+        memInfoBuilder.append(memInfo.getTotalSizeKb()
+                - totalPss - memInfo.getFreeSizeKb() - memInfo.getCachedSizeKb()
+                - memInfo.getKernelUsedSizeKb());
+        memInfoBuilder.append(" kB\n");
+        Slog.i(TAG, "Low on memory:");
+        Slog.i(TAG, shortNativeBuilder.toString());
+        Slog.i(TAG, fullJavaBuilder.toString());
+        Slog.i(TAG, memInfoBuilder.toString());
+
+        StringBuilder dropBuilder = new StringBuilder(1024);
+        /*
+        StringWriter oomSw = new StringWriter();
+        PrintWriter oomPw = new FastPrintWriter(oomSw, false, 256);
+        StringWriter catSw = new StringWriter();
+        PrintWriter catPw = new FastPrintWriter(catSw, false, 256);
+        String[] emptyArgs = new String[] { };
+        dumpApplicationMemoryUsage(null, oomPw, "  ", emptyArgs, true, catPw);
+        oomPw.flush();
+        String oomString = oomSw.toString();
+        */
+        dropBuilder.append("Low on memory:");
+        dropBuilder.append(stack);
+        dropBuilder.append('\n');
+        dropBuilder.append(fullNativeBuilder);
+        dropBuilder.append(fullJavaBuilder);
+        dropBuilder.append('\n');
+        dropBuilder.append(memInfoBuilder);
+        dropBuilder.append('\n');
+        /*
+        dropBuilder.append(oomString);
+        dropBuilder.append('\n');
+        */
+        StringWriter catSw = new StringWriter();
+        synchronized (ActivityManagerService.this) {
+            PrintWriter catPw = new FastPrintWriter(catSw, false, 256);
+            String[] emptyArgs = new String[] { };
+            catPw.println();
+            dumpProcessesLocked(null, catPw, emptyArgs, 0, false, null);
+            catPw.println();
+            mServices.dumpServicesLocked(null, catPw, emptyArgs, 0,
+                    false, false, null);
+            catPw.println();
+            dumpActivitiesLocked(null, catPw, emptyArgs, 0, false, false, null);
+            catPw.flush();
+        }
+        dropBuilder.append(catSw.toString());
+        addErrorToDropBox("lowmem", null, "system_server", null,
+                null, tag.toString(), dropBuilder.toString(), null, null);
+        //Slog.i(TAG, "Sent to dropbox:");
+        //Slog.i(TAG, dropBuilder.toString());
+        synchronized (ActivityManagerService.this) {
+            long now = SystemClock.uptimeMillis();
+            if (mLastMemUsageReportTime < now) {
+                mLastMemUsageReportTime = now;
+            }
+        }
+    }
+
     /**
      * Searches array of arguments for the specified string
      * @param args array of argument strings
diff --git a/services/core/java/com/android/server/am/UserSwitchingDialog.java b/services/core/java/com/android/server/am/UserSwitchingDialog.java
index dfc8df5..36263ec 100644
--- a/services/core/java/com/android/server/am/UserSwitchingDialog.java
+++ b/services/core/java/com/android/server/am/UserSwitchingDialog.java
@@ -17,17 +17,11 @@
 package com.android.server.am;
 
 import android.app.AlertDialog;
-import android.app.Service;
-import android.content.ActivityNotFoundException;
 import android.content.Context;
-import android.content.DialogInterface;
-import android.content.Intent;
 import android.content.res.Resources;
-import android.os.Handler;
-import android.os.Message;
-import android.util.Slog;
 import android.view.LayoutInflater;
 import android.view.View;
+import android.view.ViewTreeObserver;
 import android.view.WindowManager;
 import android.widget.TextView;
 
@@ -39,11 +33,10 @@
  * in the background rather than just freeze the screen and not know if the user-switch affordance
  * was being handled.
  */
-final class UserSwitchingDialog extends AlertDialog {
+final class UserSwitchingDialog extends AlertDialog
+        implements ViewTreeObserver.OnWindowShownListener {
     private static final String TAG = "ActivityManagerUserSwitchingDialog";
 
-    private static final int MSG_START_USER = 1;
-
     private final ActivityManagerService mService;
     private final int mUserId;
 
@@ -74,19 +67,21 @@
 
     @Override
     public void show() {
+        // Slog.v(TAG, "show called");
         super.show();
-        // TODO: Instead of just an arbitrary delay, wait for a signal that the window was fully
-        // displayed by the window manager
-        mHandler.sendMessageDelayed(mHandler.obtainMessage(MSG_START_USER), 250);
+        final View decorView = getWindow().getDecorView();
+        if (decorView != null) {
+            decorView.getViewTreeObserver().addOnWindowShownListener(this);
+        }
     }
 
-    private final Handler mHandler = new Handler() {
-        public void handleMessage(Message msg) {
-            switch (msg.what) {
-                case MSG_START_USER:
-                    mService.startUserInForeground(mUserId, UserSwitchingDialog.this);
-                    break;
-            }
+    @Override
+    public void onWindowShown() {
+        // Slog.v(TAG, "onWindowShown called");
+        mService.startUserInForeground(mUserId, this);
+        final View decorView = getWindow().getDecorView();
+        if (decorView != null) {
+            decorView.getViewTreeObserver().removeOnWindowShownListener(this);
         }
-    };
+    }
 }
diff --git a/services/core/java/com/android/server/connectivity/Nat464Xlat.java b/services/core/java/com/android/server/connectivity/Nat464Xlat.java
index c7a2ce1..576556b 100644
--- a/services/core/java/com/android/server/connectivity/Nat464Xlat.java
+++ b/services/core/java/com/android/server/connectivity/Nat464Xlat.java
@@ -17,6 +17,7 @@
 package com.android.server.connectivity;
 
 import static android.net.ConnectivityManager.TYPE_MOBILE;
+import static android.net.ConnectivityManager.TYPE_WIFI;
 
 import java.net.Inet4Address;
 
@@ -53,7 +54,7 @@
     // ConnectivityService Handler for LinkProperties updates.
     private final Handler mHandler;
 
-    // The network we're running on.
+    // The network we're running on, and its type.
     private final NetworkAgentInfo mNetwork;
 
     // Internal state variables.
@@ -90,8 +91,9 @@
         final boolean connected = nai.networkInfo.isConnected();
         final boolean hasIPv4Address =
                 (nai.linkProperties != null) ? nai.linkProperties.hasIPv4Address() : false;
-        // Only support clat on mobile for now.
-        return netType == TYPE_MOBILE && connected && !hasIPv4Address;
+        // Only support clat on mobile and wifi for now, because these are the only IPv6-only
+        // networks we can connect to.
+        return connected && !hasIPv4Address && (netType == TYPE_MOBILE || netType == TYPE_WIFI);
     }
 
     /**
@@ -211,23 +213,41 @@
         return stacked;
     }
 
+    private LinkAddress getLinkAddress(String iface) {
+        try {
+            InterfaceConfiguration config = mNMService.getInterfaceConfig(iface);
+            return config.getLinkAddress();
+        } catch(RemoteException|IllegalStateException e) {
+            Slog.e(TAG, "Error getting link properties: " + e);
+            return null;
+        }
+    }
+
+    private void maybeSetIpv6NdOffload(String iface, boolean on) {
+        if (mNetwork.networkInfo.getType() != TYPE_WIFI) {
+            return;
+        }
+        try {
+            Slog.d(TAG, (on ? "En" : "Dis") + "abling ND offload on " + iface);
+            mNMService.setInterfaceIpv6NdOffload(iface, on);
+        } catch(RemoteException|IllegalStateException e) {
+            Slog.w(TAG, "Changing IPv6 ND offload on " + iface + "failed: " + e);
+        }
+    }
+
     @Override
     public void interfaceAdded(String iface) {
         // Called by the InterfaceObserver on its own thread, so can race with stop().
         if (isStarted() && mIface.equals(iface)) {
             Slog.i(TAG, "interface " + iface + " added, mIsRunning " + mIsRunning + "->true");
 
-            LinkAddress clatAddress;
-            try {
-                InterfaceConfiguration config = mNMService.getInterfaceConfig(iface);
-                clatAddress = config.getLinkAddress();
-            } catch(RemoteException e) {
-                Slog.e(TAG, "Error getting link properties: " + e);
-                return;
-            }
-
             if (!mIsRunning) {
+                LinkAddress clatAddress = getLinkAddress(iface);
+                if (clatAddress == null) {
+                    return;
+                }
                 mIsRunning = true;
+                maybeSetIpv6NdOffload(mBaseIface, false);
                 LinkProperties lp = new LinkProperties(mNetwork.linkProperties);
                 lp.addStackedLink(makeLinkProperties(clatAddress));
                 Slog.i(TAG, "Adding stacked link " + mIface + " on top of " + mBaseIface);
@@ -255,6 +275,7 @@
                 } catch (RemoteException|IllegalStateException e) {
                     // Well, we tried.
                 }
+                maybeSetIpv6NdOffload(mBaseIface, true);
                 LinkProperties lp = new LinkProperties(mNetwork.linkProperties);
                 lp.removeStackedLink(mIface);
                 clear();
diff --git a/services/core/java/com/android/server/connectivity/PacManager.java b/services/core/java/com/android/server/connectivity/PacManager.java
index 07fe7ba..7d1da01 100644
--- a/services/core/java/com/android/server/connectivity/PacManager.java
+++ b/services/core/java/com/android/server/connectivity/PacManager.java
@@ -265,14 +265,9 @@
         }
         Intent intent = new Intent();
         intent.setClassName(PAC_PACKAGE, PAC_SERVICE);
-        // Already bound no need to bind again.
         if ((mProxyConnection != null) && (mConnection != null)) {
-            if (mLastPort != -1) {
-                sendPacBroadcast(new ProxyInfo(mPacUrl, mLastPort));
-            } else {
-                Log.e(TAG, "Received invalid port from Local Proxy,"
-                        + " PAC will not be operational");
-            }
+            // Already bound no need to bind again, just download the new file.
+            IoThread.getHandler().post(mPacDownloader);
             return;
         }
         mConnection = new ServiceConnection() {
diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java
index e9d19aa..42a8551 100644
--- a/services/core/java/com/android/server/notification/NotificationManagerService.java
+++ b/services/core/java/com/android/server/notification/NotificationManagerService.java
@@ -41,6 +41,7 @@
 import android.content.Intent;
 import android.content.IntentFilter;
 import android.content.pm.ApplicationInfo;
+import android.content.pm.IPackageManager;
 import android.content.pm.PackageInfo;
 import android.content.pm.PackageManager;
 import android.content.pm.PackageManager.NameNotFoundException;
@@ -657,7 +658,7 @@
         }
     };
 
-    private BroadcastReceiver mIntentReceiver = new BroadcastReceiver() {
+    private final BroadcastReceiver mPackageIntentReceiver = new BroadcastReceiver() {
         @Override
         public void onReceive(Context context, Intent intent) {
             String action = intent.getAction();
@@ -673,6 +674,8 @@
                     || (packageChanged=action.equals(Intent.ACTION_PACKAGE_CHANGED))
                     || (queryRestart=action.equals(Intent.ACTION_QUERY_PACKAGE_RESTART))
                     || action.equals(Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE)) {
+                int changeUserId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE,
+                        UserHandle.USER_ALL);
                 String pkgList[] = null;
                 boolean queryReplace = queryRemove &&
                         intent.getBooleanExtra(Intent.EXTRA_REPLACING, false);
@@ -693,8 +696,10 @@
                     if (packageChanged) {
                         // We cancel notifications for packages which have just been disabled
                         try {
-                            final int enabled = getContext().getPackageManager()
-                                    .getApplicationEnabledSetting(pkgName);
+                            final IPackageManager pm = AppGlobals.getPackageManager();
+                            final int enabled = pm.getApplicationEnabledSetting(pkgName,
+                                    changeUserId != UserHandle.USER_ALL ? changeUserId :
+                                    UserHandle.USER_OWNER);
                             if (enabled == PackageManager.COMPONENT_ENABLED_STATE_ENABLED
                                     || enabled == PackageManager.COMPONENT_ENABLED_STATE_DEFAULT) {
                                 cancelNotifications = false;
@@ -705,6 +710,8 @@
                             if (DBG) {
                                 Slog.i(TAG, "Exception trying to look up app enabled setting", e);
                             }
+                        } catch (RemoteException e) {
+                            // Failed to talk to PackageManagerService Should never happen!
                         }
                     }
                     pkgList = new String[]{pkgName};
@@ -714,13 +721,22 @@
                     for (String pkgName : pkgList) {
                         if (cancelNotifications) {
                             cancelAllNotificationsInt(MY_UID, MY_PID, pkgName, 0, 0, !queryRestart,
-                                    UserHandle.USER_ALL, REASON_PACKAGE_CHANGED, null);
+                                    changeUserId, REASON_PACKAGE_CHANGED, null);
                         }
                     }
                 }
                 mListeners.onPackagesChanged(queryReplace, pkgList);
                 mConditionProviders.onPackagesChanged(queryReplace, pkgList);
-            } else if (action.equals(Intent.ACTION_SCREEN_ON)) {
+            }
+        }
+    };
+
+    private final BroadcastReceiver mIntentReceiver = new BroadcastReceiver() {
+        @Override
+        public void onReceive(Context context, Intent intent) {
+            String action = intent.getAction();
+
+            if (action.equals(Intent.ACTION_SCREEN_ON)) {
                 // Keep track of screen on/off state, but do not turn off the notification light
                 // until user passes through the lock screen or views the notification.
                 mScreenOn = true;
@@ -903,6 +919,7 @@
         filter.addAction(Intent.ACTION_USER_SWITCHED);
         filter.addAction(Intent.ACTION_USER_ADDED);
         getContext().registerReceiver(mIntentReceiver, filter);
+
         IntentFilter pkgFilter = new IntentFilter();
         pkgFilter.addAction(Intent.ACTION_PACKAGE_ADDED);
         pkgFilter.addAction(Intent.ACTION_PACKAGE_REMOVED);
@@ -910,9 +927,12 @@
         pkgFilter.addAction(Intent.ACTION_PACKAGE_RESTARTED);
         pkgFilter.addAction(Intent.ACTION_QUERY_PACKAGE_RESTART);
         pkgFilter.addDataScheme("package");
-        getContext().registerReceiver(mIntentReceiver, pkgFilter);
+        getContext().registerReceiverAsUser(mPackageIntentReceiver, UserHandle.ALL, pkgFilter, null,
+                null);
+
         IntentFilter sdFilter = new IntentFilter(Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE);
-        getContext().registerReceiver(mIntentReceiver, sdFilter);
+        getContext().registerReceiverAsUser(mPackageIntentReceiver, UserHandle.ALL, sdFilter, null,
+                null);
 
         mSettingsObserver = new SettingsObserver(mHandler);
 
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index de6e82b..f9a85df 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -333,6 +333,7 @@
     final DisplayMetrics mMetrics;
     final int mDefParseFlags;
     final String[] mSeparateProcesses;
+    final boolean mIsUpgrade;
 
     // This is where all application persistent data goes.
     final File mAppDataDir;
@@ -1760,7 +1761,8 @@
 
             // If this is first boot after an OTA, and a normal boot, then
             // we need to clear code cache directories.
-            if (!Build.FINGERPRINT.equals(mSettings.mFingerprint) && !onlyCore) {
+            mIsUpgrade = !Build.FINGERPRINT.equals(mSettings.mFingerprint);
+            if (mIsUpgrade && !onlyCore) {
                 Slog.i(TAG, "Build fingerprint changed; clearing code caches");
                 for (String pkgName : mSettings.mPackages.keySet()) {
                     deleteCodeCacheDirsLI(pkgName);
@@ -1800,6 +1802,11 @@
         return mOnlyCore;
     }
 
+    @Override
+    public boolean isUpgrade() {
+        return mIsUpgrade;
+    }
+
     private String getRequiredVerifierLPr() {
         final Intent verification = new Intent(Intent.ACTION_PACKAGE_NEEDS_VERIFICATION);
         final List<ResolveInfo> receivers = queryIntentReceivers(verification, PACKAGE_MIME_TYPE,
@@ -3259,7 +3266,7 @@
                         if (DEBUG_PREFERRED) {
                             Slog.v(TAG, "Preferred activity bookkeeping changed; writing restrictions");
                         }
-                        mSettings.writePackageRestrictionsLPr(userId);
+                        scheduleWritePackageRestrictionsLocked(userId);
                     }
                 }
             }
@@ -11559,7 +11566,7 @@
                     + userId + ":");
             filter.dump(new LogPrinter(Log.INFO, TAG), "  ");
             pir.addFilter(new PreferredActivity(filter, match, set, activity, always));
-            mSettings.writePackageRestrictionsLPr(userId);
+            scheduleWritePackageRestrictionsLocked(userId);
         }
     }
 
@@ -11675,8 +11682,7 @@
 
             int user = UserHandle.getCallingUserId();
             if (clearPackagePreferredActivitiesLPw(packageName, user)) {
-                mSettings.writePackageRestrictionsLPr(user);
-                scheduleWriteSettingsLocked();
+                scheduleWritePackageRestrictionsLocked(user);
             }
         }
     }
@@ -11726,8 +11732,7 @@
             int user = UserHandle.getCallingUserId();
             clearPackagePreferredActivitiesLPw(null, user);
             mSettings.readDefaultPreferredAppsLPw(this, user);
-            mSettings.writePackageRestrictionsLPr(user);
-            scheduleWriteSettingsLocked();
+            scheduleWritePackageRestrictionsLocked(user);
         }
     }
 
@@ -11779,7 +11784,7 @@
             filter.dump(new LogPrinter(Log.INFO, TAG), "  ");
             mSettings.editPersistentPreferredActivitiesLPw(userId).addFilter(
                     new PersistentPreferredActivity(filter, activity));
-            mSettings.writePackageRestrictionsLPr(userId);
+            scheduleWritePackageRestrictionsLocked(userId);
         }
     }
 
@@ -11821,7 +11826,7 @@
             }
 
             if (changed) {
-                mSettings.writePackageRestrictionsLPr(userId);
+                scheduleWritePackageRestrictionsLocked(userId);
             }
         }
     }
@@ -11842,7 +11847,7 @@
             CrossProfileIntentFilter filter = new CrossProfileIntentFilter(intentFilter,
                     ownerPackage, UserHandle.getUserId(callingUid), targetUserId, flags);
             mSettings.editCrossProfileIntentResolverLPw(sourceUserId).addFilter(filter);
-            mSettings.writePackageRestrictionsLPr(sourceUserId);
+            scheduleWritePackageRestrictionsLocked(sourceUserId);
         }
     }
 
@@ -11866,7 +11871,7 @@
                     resolver.removeFilter(filter);
                 }
             }
-            mSettings.writePackageRestrictionsLPr(sourceUserId);
+            scheduleWritePackageRestrictionsLocked(sourceUserId);
         }
     }
 
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index 0e55c1c..96e56e9 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -2487,7 +2487,9 @@
                 }
             }
 
-            win.mWinAnimator.mEnterAnimationPending = true;
+            final WindowStateAnimator winAnimator = win.mWinAnimator;
+            winAnimator.mEnterAnimationPending = true;
+            winAnimator.mEnteringAnimation = true;
 
             if (displayContent.isDefaultDisplay) {
                 mPolicy.getContentInsetHintLw(attrs, outContentInsets);
@@ -3099,6 +3101,7 @@
                 if (oldVisibility == View.GONE) {
                     winAnimator.mEnterAnimationPending = true;
                 }
+                winAnimator.mEnteringAnimation = true;
                 if (toBeDisplayed) {
                     if (win.isDrawnLw() && okToDisplay()) {
                         winAnimator.applyEnterAnimationLocked();
@@ -3167,6 +3170,7 @@
                 }
             } else {
                 winAnimator.mEnterAnimationPending = false;
+                winAnimator.mEnteringAnimation = false;
                 if (winAnimator.mSurfaceControl != null) {
                     if (DEBUG_VISIBILITY) Slog.i(TAG, "Relayout invis " + win
                             + ": mExiting=" + win.mExiting);
@@ -6049,6 +6053,10 @@
 
         while (true) {
             if (retryCount++ > 0) {
+                // Reset max/min layers on retries so we don't accidentally take a screenshot of a
+                // layer based on the previous try.
+                maxLayer = 0;
+                minLayer = Integer.MAX_VALUE;
                 try {
                     Thread.sleep(100);
                 } catch (InterruptedException e) {
@@ -6071,7 +6079,17 @@
                             continue;
                         }
                     } else if (ws.mIsWallpaper) {
-                        // Fall through.
+                        if (appWin == null) {
+                            // We have not ran across the target window yet, so it is probably
+                            // behind the wallpaper. This can happen when the keyguard is up and
+                            // all windows are moved behind the wallpaper. We don't want to
+                            // include the wallpaper layer in the screenshot as it will coverup
+                            // the layer of the target window.
+                            continue;
+                        }
+                        // Fall through. The target window is in front of the wallpaper. For this
+                        // case we want to include the wallpaper layer in the screenshot because
+                        // the target window might have some transparent areas.
                     } else if (appToken != null) {
                         if (ws.mAppToken == null || ws.mAppToken.token != appToken) {
                             // This app window is of no interest if it is not associated with the
diff --git a/services/core/java/com/android/server/wm/WindowStateAnimator.java b/services/core/java/com/android/server/wm/WindowStateAnimator.java
index 0c727f3..fc3f2c2 100644
--- a/services/core/java/com/android/server/wm/WindowStateAnimator.java
+++ b/services/core/java/com/android/server/wm/WindowStateAnimator.java
@@ -40,6 +40,7 @@
 import android.graphics.RectF;
 import android.graphics.Region;
 import android.os.Debug;
+import android.os.RemoteException;
 import android.os.UserHandle;
 import android.util.Slog;
 import android.view.Display;
@@ -141,6 +142,11 @@
     // an enter animation.
     boolean mEnterAnimationPending;
 
+    /** Used to indicate that this window is undergoing an enter animation. Used for system
+     * windows to make the callback to View.dispatchOnWindowShownCallback(). Set when the
+     * window is first added or shown, cleared when the callback has been made. */
+    boolean mEnteringAnimation;
+
     boolean keyguardGoingAwayAnimation;
 
     /** This is set when there is no Surface */
@@ -428,6 +434,14 @@
             mWin.mChildWindows.get(i).mWinAnimator.finishExit();
         }
 
+        if (mEnteringAnimation && mWin.mAppToken == null) {
+            try {
+                mEnteringAnimation = false;
+                mWin.mClient.dispatchWindowShown();
+            } catch (RemoteException e) {
+            }
+        }
+
         if (!mWin.mExiting) {
             return;
         }
diff --git a/services/usage/java/com/android/server/usage/UsageStatsDatabase.java b/services/usage/java/com/android/server/usage/UsageStatsDatabase.java
index cfa4436..11da380 100644
--- a/services/usage/java/com/android/server/usage/UsageStatsDatabase.java
+++ b/services/usage/java/com/android/server/usage/UsageStatsDatabase.java
@@ -39,6 +39,7 @@
 
     private static final String TAG = "UsageStatsDatabase";
     private static final boolean DEBUG = UsageStatsService.DEBUG;
+    private static final String BAK_SUFFIX = ".bak";
 
     private final Object mLock = new Object();
     private final File[] mIntervalDirs;
@@ -95,11 +96,71 @@
         }
     }
 
+    public interface CheckinAction {
+        boolean checkin(IntervalStats stats);
+    }
+
+    /**
+     * Calls {@link CheckinAction#checkin(IntervalStats)} on the given {@link CheckinAction}
+     * for all {@link IntervalStats} that haven't been checked-in.
+     * If any of the calls to {@link CheckinAction#checkin(IntervalStats)} returns false or throws
+     * an exception, the check-in will be aborted.
+     *
+     * @param checkinAction The callback to run when checking-in {@link IntervalStats}.
+     * @return true if the check-in succeeded.
+     */
+    public boolean checkinDailyFiles(CheckinAction checkinAction) {
+        synchronized (mLock) {
+            final TimeSparseArray<AtomicFile> files =
+                    mSortedStatFiles[UsageStatsManager.INTERVAL_DAILY];
+            final int fileCount = files.size();
+            int start = 0;
+            while (start < fileCount - 1) {
+                if (!files.valueAt(start).getBaseFile().getName().endsWith("-c")) {
+                    break;
+                }
+            }
+
+            if (start == fileCount - 1) {
+                return true;
+            }
+
+            try {
+                IntervalStats stats = new IntervalStats();
+                for (int i = start; i < fileCount - 1; i++) {
+                    UsageStatsXml.read(files.valueAt(i), stats);
+                    if (!checkinAction.checkin(stats)) {
+                        return false;
+                    }
+                }
+            } catch (IOException e) {
+                Slog.e(TAG, "Failed to check-in", e);
+                return false;
+            }
+
+            // We have successfully checked-in the stats, so rename the files so that they
+            // are marked as checked-in.
+            for (int i = start; i < fileCount - 1; i++) {
+                final AtomicFile file = files.valueAt(i);
+                final File checkedInFile = new File(file.getBaseFile().getParent(),
+                        file.getBaseFile().getName() + "-c");
+                if (!file.getBaseFile().renameTo(checkedInFile)) {
+                    // We must return success, as we've already marked some files as checked-in.
+                    // It's better to repeat ourselves than to lose data.
+                    Slog.e(TAG, "Failed to mark file " + file.getBaseFile().getPath()
+                            + " as checked-in");
+                    return true;
+                }
+            }
+        }
+        return true;
+    }
+
     private void indexFilesLocked() {
         final FilenameFilter backupFileFilter = new FilenameFilter() {
             @Override
             public boolean accept(File dir, String name) {
-                return !name.endsWith(".bak");
+                return !name.endsWith(BAK_SUFFIX);
             }
         };
 
@@ -383,10 +444,10 @@
         if (files != null) {
             for (File f : files) {
                 String path = f.getPath();
-                if (path.endsWith(".bak")) {
-                    f = new File(path.substring(0, path.length() - 4));
+                if (path.endsWith(BAK_SUFFIX)) {
+                    f = new File(path.substring(0, path.length() - BAK_SUFFIX.length()));
                 }
-                long beginTime = Long.parseLong(f.getName());
+                long beginTime = UsageStatsXml.parseBeginTime(f);
                 if (beginTime < expiryTime) {
                     new AtomicFile(f).delete();
                 }
diff --git a/services/usage/java/com/android/server/usage/UsageStatsService.java b/services/usage/java/com/android/server/usage/UsageStatsService.java
index 7ff246a..485b2a2 100644
--- a/services/usage/java/com/android/server/usage/UsageStatsService.java
+++ b/services/usage/java/com/android/server/usage/UsageStatsService.java
@@ -33,7 +33,6 @@
 import android.content.pm.UserInfo;
 import android.content.res.Configuration;
 import android.os.Binder;
-import android.os.Debug;
 import android.os.Environment;
 import android.os.Handler;
 import android.os.Looper;
@@ -48,9 +47,12 @@
 import android.util.SparseArray;
 
 import com.android.internal.os.BackgroundThread;
+import com.android.internal.util.IndentingPrintWriter;
 import com.android.server.SystemService;
 
 import java.io.File;
+import java.io.FileDescriptor;
+import java.io.PrintWriter;
 import java.util.Arrays;
 import java.util.List;
 
@@ -177,7 +179,7 @@
             long currentTimeMillis) {
         UserUsageStatsService service = mUserState.get(userId);
         if (service == null) {
-            service = new UserUsageStatsService(userId,
+            service = new UserUsageStatsService(getContext(), userId,
                     new File(mUsageStatsDir, Integer.toString(userId)), this);
             service.init(currentTimeMillis);
             mUserState.put(userId, service);
@@ -320,6 +322,30 @@
         mHandler.removeMessages(MSG_FLUSH_TO_DISK);
     }
 
+    /**
+     * Called by the Binder stub.
+     */
+    void dump(String[] args, PrintWriter pw) {
+        synchronized (mLock) {
+            IndentingPrintWriter idpw = new IndentingPrintWriter(pw, "  ");
+            ArraySet<String> argSet = new ArraySet<>();
+            argSet.addAll(Arrays.asList(args));
+
+            final int userCount = mUserState.size();
+            for (int i = 0; i < userCount; i++) {
+                idpw.printPair("user", mUserState.keyAt(i));
+                idpw.println();
+                idpw.increaseIndent();
+                if (argSet.contains("--checkin")) {
+                    mUserState.valueAt(i).checkin(idpw);
+                } else {
+                    mUserState.valueAt(i).dump(idpw);
+                }
+                idpw.decreaseIndent();
+            }
+        }
+    }
+
     class H extends Handler {
         public H(Looper looper) {
             super(looper);
@@ -422,6 +448,18 @@
                 Binder.restoreCallingIdentity(token);
             }
         }
+
+        @Override
+        protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
+            if (getContext().checkCallingOrSelfPermission(android.Manifest.permission.DUMP)
+                    != PackageManager.PERMISSION_GRANTED) {
+                pw.println("Permission Denial: can't dump UsageStats from pid="
+                        + Binder.getCallingPid() + ", uid=" + Binder.getCallingUid()
+                        + " without permission " + android.Manifest.permission.DUMP);
+                return;
+            }
+            UsageStatsService.this.dump(args, pw);
+        }
     }
 
     /**
diff --git a/services/usage/java/com/android/server/usage/UsageStatsXml.java b/services/usage/java/com/android/server/usage/UsageStatsXml.java
index 9ce6d63..26148ce 100644
--- a/services/usage/java/com/android/server/usage/UsageStatsXml.java
+++ b/services/usage/java/com/android/server/usage/UsageStatsXml.java
@@ -24,21 +24,26 @@
 import org.xmlpull.v1.XmlPullParser;
 import org.xmlpull.v1.XmlPullParserException;
 
-import java.io.FileInputStream;
-import java.io.FileNotFoundException;
-import java.io.FileOutputStream;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.OutputStream;
+import java.io.*;
 
 public class UsageStatsXml {
     private static final String TAG = "UsageStatsXml";
     private static final int CURRENT_VERSION = 1;
     private static final String USAGESTATS_TAG = "usagestats";
     private static final String VERSION_ATTR = "version";
+    private static final String CHECKED_IN_SUFFIX = "-c";
 
     public static long parseBeginTime(AtomicFile file) {
-        return Long.parseLong(file.getBaseFile().getName());
+        return parseBeginTime(file.getBaseFile());
+    }
+
+    public static long parseBeginTime(File file) {
+        final String name = file.getName();
+        if (name.endsWith(CHECKED_IN_SUFFIX)) {
+            return Long.parseLong(
+                    name.substring(0, name.length() - CHECKED_IN_SUFFIX.length()));
+        }
+        return Long.parseLong(name);
     }
 
     public static void read(AtomicFile file, IntervalStats statsOut) throws IOException {
diff --git a/services/usage/java/com/android/server/usage/UserUsageStatsService.java b/services/usage/java/com/android/server/usage/UserUsageStatsService.java
index 4916ec2..6596781 100644
--- a/services/usage/java/com/android/server/usage/UserUsageStatsService.java
+++ b/services/usage/java/com/android/server/usage/UserUsageStatsService.java
@@ -23,9 +23,13 @@
 import android.app.usage.UsageStatsManager;
 import android.content.res.Configuration;
 import android.os.SystemClock;
+import android.content.Context;
+import android.text.format.DateUtils;
+import android.util.ArrayMap;
 import android.util.ArraySet;
 import android.util.Slog;
 
+import com.android.internal.util.IndentingPrintWriter;
 import com.android.server.usage.UsageStatsDatabase.StatCombiner;
 
 import java.io.File;
@@ -43,7 +47,13 @@
     private static final String TAG = "UsageStatsService";
     private static final boolean DEBUG = UsageStatsService.DEBUG;
     private static final SimpleDateFormat sDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
+    private static final int sDateFormatFlags =
+            DateUtils.FORMAT_SHOW_DATE
+            | DateUtils.FORMAT_SHOW_TIME
+            | DateUtils.FORMAT_SHOW_YEAR
+            | DateUtils.FORMAT_NUMERIC_DATE;
 
+    private final Context mContext;
     private final UsageStatsDatabase mDatabase;
     private final IntervalStats[] mCurrentStats;
     private boolean mStatsChanged = false;
@@ -55,7 +65,8 @@
         void onStatsUpdated();
     }
 
-    UserUsageStatsService(int userId, File usageStatsDir, StatsUpdatedListener listener) {
+    UserUsageStatsService(Context context, int userId, File usageStatsDir, StatsUpdatedListener listener) {
+        mContext = context;
         mDailyExpiryDate = new UnixCalendar(0);
         mDatabase = new UsageStatsDatabase(usageStatsDir);
         mCurrentStats = new IntervalStats[UsageStatsManager.INTERVAL_COUNT];
@@ -433,6 +444,117 @@
                 tempCal.getTimeInMillis() + ")");
     }
 
+    //
+    // -- DUMP related methods --
+    //
+
+    void checkin(final IndentingPrintWriter pw) {
+        mDatabase.checkinDailyFiles(new UsageStatsDatabase.CheckinAction() {
+            @Override
+            public boolean checkin(IntervalStats stats) {
+                printIntervalStats(pw, stats, false);
+                return true;
+            }
+        });
+    }
+
+    void dump(IndentingPrintWriter pw) {
+        // This is not a check-in, only dump in-memory stats.
+        for (int interval = 0; interval < mCurrentStats.length; interval++) {
+            pw.print("In-memory ");
+            pw.print(intervalToString(interval));
+            pw.println(" stats");
+            printIntervalStats(pw, mCurrentStats[interval], true);
+        }
+    }
+
+    private String formatDateTime(long dateTime, boolean pretty) {
+        if (pretty) {
+            return "\"" + DateUtils.formatDateTime(mContext, dateTime, sDateFormatFlags) + "\"";
+        }
+        return Long.toString(dateTime);
+    }
+
+    private String formatElapsedTime(long elapsedTime, boolean pretty) {
+        if (pretty) {
+            return "\"" + DateUtils.formatElapsedTime(elapsedTime / 1000) + "\"";
+        }
+        return Long.toString(elapsedTime);
+    }
+
+    void printIntervalStats(IndentingPrintWriter pw, IntervalStats stats, boolean prettyDates) {
+        if (prettyDates) {
+            pw.printPair("timeRange", "\"" + DateUtils.formatDateRange(mContext,
+                    stats.beginTime, stats.endTime, sDateFormatFlags) + "\"");
+        } else {
+            pw.printPair("beginTime", stats.beginTime);
+            pw.printPair("endTime", stats.endTime);
+        }
+        pw.println();
+        pw.increaseIndent();
+        pw.println("packages");
+        pw.increaseIndent();
+        final ArrayMap<String, UsageStats> pkgStats = stats.packageStats;
+        final int pkgCount = pkgStats.size();
+        for (int i = 0; i < pkgCount; i++) {
+            final UsageStats usageStats = pkgStats.valueAt(i);
+            pw.printPair("package", usageStats.mPackageName);
+            pw.printPair("totalTime", formatElapsedTime(usageStats.mTotalTimeInForeground, prettyDates));
+            pw.printPair("lastTime", formatDateTime(usageStats.mLastTimeUsed, prettyDates));
+            pw.println();
+        }
+        pw.decreaseIndent();
+
+        pw.println("configurations");
+        pw.increaseIndent();
+        final ArrayMap<Configuration, ConfigurationStats> configStats =
+                stats.configurations;
+        final int configCount = configStats.size();
+        for (int i = 0; i < configCount; i++) {
+            final ConfigurationStats config = configStats.valueAt(i);
+            pw.printPair("config", Configuration.resourceQualifierString(config.mConfiguration));
+            pw.printPair("totalTime", formatElapsedTime(config.mTotalTimeActive, prettyDates));
+            pw.printPair("lastTime", formatDateTime(config.mLastTimeActive, prettyDates));
+            pw.printPair("count", config.mActivationCount);
+            pw.println();
+        }
+        pw.decreaseIndent();
+
+        pw.println("events");
+        pw.increaseIndent();
+        final TimeSparseArray<UsageEvents.Event> events = stats.events;
+        final int eventCount = events != null ? events.size() : 0;
+        for (int i = 0; i < eventCount; i++) {
+            final UsageEvents.Event event = events.valueAt(i);
+            pw.printPair("time", formatDateTime(event.mTimeStamp, prettyDates));
+            pw.printPair("type", eventToString(event.mEventType));
+            pw.printPair("package", event.mPackage);
+            if (event.mClass != null) {
+                pw.printPair("class", event.mClass);
+            }
+            if (event.mConfiguration != null) {
+                pw.printPair("config", Configuration.resourceQualifierString(event.mConfiguration));
+            }
+            pw.println();
+        }
+        pw.decreaseIndent();
+        pw.decreaseIndent();
+    }
+
+    private static String intervalToString(int interval) {
+        switch (interval) {
+            case UsageStatsManager.INTERVAL_DAILY:
+                return "daily";
+            case UsageStatsManager.INTERVAL_WEEKLY:
+                return "weekly";
+            case UsageStatsManager.INTERVAL_MONTHLY:
+                return "monthly";
+            case UsageStatsManager.INTERVAL_YEARLY:
+                return "yearly";
+            default:
+                return "?";
+        }
+    }
 
     private static String eventToString(int eventType) {
         switch (eventType) {
diff --git a/telecomm/java/android/telecom/AudioState.java b/telecomm/java/android/telecom/AudioState.java
index d0e2860..43da38f 100644
--- a/telecomm/java/android/telecom/AudioState.java
+++ b/telecomm/java/android/telecom/AudioState.java
@@ -22,7 +22,8 @@
 import java.util.Locale;
 
 /**
- *  Encapsulates all audio states during a call.
+ *  Encapsulates the telecom audio state, including the current audio routing, supported audio
+ *  routing and mute.
  */
 public final class AudioState implements Parcelable {
     /** Direct the audio stream through the device's earpiece. */
@@ -53,10 +54,10 @@
     /** True if the call is muted, false otherwise. */
     public final boolean isMuted;
 
-    /** The route to use for the audio stream. */
+    /** The current audio route being used. */
     public final int route;
 
-    /** Bit vector of all routes supported by this call. */
+    /** Bit mask of all routes supported by this call. */
     public final int supportedRouteMask;
 
     public AudioState(boolean isMuted, int route, int supportedRouteMask) {
diff --git a/telecomm/java/android/telecom/Conference.java b/telecomm/java/android/telecom/Conference.java
index 15cb786..003d5cd 100644
--- a/telecomm/java/android/telecom/Conference.java
+++ b/telecomm/java/android/telecom/Conference.java
@@ -334,6 +334,19 @@
     }
 
     /**
+     * Retrieves the primary connection associated with the conference.  The primary connection is
+     * the connection from which the conference will retrieve its current state.
+     *
+     * @return The primary connection.
+     */
+    public Connection getPrimaryConnection() {
+        if (mUnmodifiableChildConnections == null || mUnmodifiableChildConnections.isEmpty()) {
+            return null;
+        }
+        return mUnmodifiableChildConnections.get(0);
+    }
+
+    /**
      * Inform this Conference that the state of its audio output has been changed externally.
      *
      * @param state The new audio state.
diff --git a/telecomm/java/android/telecom/ConferenceParticipant.aidl b/telecomm/java/android/telecom/ConferenceParticipant.aidl
new file mode 100644
index 0000000..020c923
--- /dev/null
+++ b/telecomm/java/android/telecom/ConferenceParticipant.aidl
@@ -0,0 +1,22 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package android.telecom;
+
+/**
+ * {@hide}
+ */
+parcelable ConferenceParticipant;
diff --git a/telecomm/java/android/telecom/ConferenceParticipant.java b/telecomm/java/android/telecom/ConferenceParticipant.java
new file mode 100644
index 0000000..db0f151
--- /dev/null
+++ b/telecomm/java/android/telecom/ConferenceParticipant.java
@@ -0,0 +1,158 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package android.telecom;
+
+import android.net.Uri;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+/**
+ * Parcelable representation of a participant's state in a conference call.
+ * @hide
+ */
+public class ConferenceParticipant implements Parcelable {
+
+    /**
+     * The conference participant's handle (e.g., phone number).
+     */
+    private final Uri mHandle;
+
+    /**
+     * The display name for the participant.
+     */
+    private final String mDisplayName;
+
+    /**
+     * The endpoint Uri which uniquely identifies this conference participant.  E.g. for an IMS
+     * conference call, this is the endpoint URI for the participant on the IMS conference server.
+     */
+    private final Uri mEndpoint;
+
+    /**
+     * The state of the participant in the conference.
+     *
+     * @see android.telecom.Connection
+     */
+    private final int mState;
+
+    /**
+     * Creates an instance of {@code ConferenceParticipant}.
+     *
+     * @param handle      The conference participant's handle (e.g., phone number).
+     * @param displayName The display name for the participant.
+     * @param endpoint    The enpoint Uri which uniquely identifies this conference participant.
+     * @param state       The state of the participant in the conference.
+     */
+    public ConferenceParticipant(Uri handle, String displayName, Uri endpoint, int state) {
+        mHandle = handle;
+        mDisplayName = displayName;
+        mEndpoint = endpoint;
+        mState = state;
+    }
+
+    /**
+     * Responsible for creating {@code ConferenceParticipant} objects for deserialized Parcels.
+     */
+    public static final Parcelable.Creator<ConferenceParticipant> CREATOR =
+            new Parcelable.Creator<ConferenceParticipant>() {
+
+                @Override
+                public ConferenceParticipant createFromParcel(Parcel source) {
+                    ClassLoader classLoader = ParcelableCall.class.getClassLoader();
+                    Uri handle = source.readParcelable(classLoader);
+                    String displayName = source.readString();
+                    Uri endpoint = source.readParcelable(classLoader);
+                    int state = source.readInt();
+                    return new ConferenceParticipant(handle, displayName, endpoint, state);
+                }
+
+                @Override
+                public ConferenceParticipant[] newArray(int size) {
+                    return new ConferenceParticipant[size];
+                }
+            };
+
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    /**
+     * Writes the {@code ConferenceParticipant} to a parcel.
+     *
+     * @param dest The Parcel in which the object should be written.
+     * @param flags Additional flags about how the object should be written.
+     */
+    @Override
+    public void writeToParcel(Parcel dest, int flags) {
+        dest.writeParcelable(mHandle, 0);
+        dest.writeString(mDisplayName);
+        dest.writeParcelable(mEndpoint, 0);
+        dest.writeInt(mState);
+    }
+
+    /**
+     * Builds a string representation of this instance.
+     *
+     * @return String representing the conference participant.
+     */
+    @Override
+    public String toString() {
+        StringBuilder sb = new StringBuilder();
+        sb.append("[ConferenceParticipant Handle: ");
+        sb.append(mHandle);
+        sb.append(" DisplayName: ");
+        sb.append(mDisplayName);
+        sb.append(" Endpoint: ");
+        sb.append(mEndpoint);
+        sb.append(" State: ");
+        sb.append(mState);
+        sb.append("]");
+        return sb.toString();
+    }
+
+    /**
+     * The conference participant's handle (e.g., phone number).
+     */
+    public Uri getHandle() {
+        return mHandle;
+    }
+
+    /**
+     * The display name for the participant.
+     */
+    public String getDisplayName() {
+        return mDisplayName;
+    }
+
+    /**
+     * The enpoint Uri which uniquely identifies this conference participant.  E.g. for an IMS
+     * conference call, this is the endpoint URI for the participant on the IMS conference server.
+     */
+    public Uri getEndpoint() {
+        return mEndpoint;
+    }
+
+    /**
+     * The state of the participant in the conference.
+     *
+     * @see android.telecom.Connection
+     */
+    public int getState() {
+        return mState;
+    }
+}
diff --git a/telecomm/java/android/telecom/Connection.java b/telecomm/java/android/telecom/Connection.java
index 2932721..9bdbba8 100644
--- a/telecomm/java/android/telecom/Connection.java
+++ b/telecomm/java/android/telecom/Connection.java
@@ -82,6 +82,9 @@
         public void onConferenceableConnectionsChanged(
                 Connection c, List<Connection> conferenceableConnections) {}
         public void onConferenceChanged(Connection c, Conference conference) {}
+        /** @hide */
+        public void onConferenceParticipantChanged(Connection c, ConferenceParticipant participant)
+        {}
     }
 
     /** @hide */
@@ -1117,4 +1120,16 @@
         }
         mConferenceableConnections.clear();
     }
+
+    /**
+     * Notifies listeners of a change to a conference participant.
+     *
+     * @param conferenceParticipant The participant.
+     * @hide
+     */
+    protected final void updateConferenceParticipant(ConferenceParticipant conferenceParticipant) {
+        for (Listener l : mListeners) {
+            l.onConferenceParticipantChanged(this, conferenceParticipant);
+        }
+    }
 }
diff --git a/telecomm/java/android/telecom/ConnectionService.java b/telecomm/java/android/telecom/ConnectionService.java
index 649533e..6e41c33 100644
--- a/telecomm/java/android/telecom/ConnectionService.java
+++ b/telecomm/java/android/telecom/ConnectionService.java
@@ -822,6 +822,40 @@
     }
 
     /**
+     * Adds a connection created by the {@link ConnectionService} and informs telecom of the new
+     * connection.
+     *
+     * @param phoneAccountHandle The phone account handle for the connection.
+     * @param connection The connection to add.
+     */
+    public final void addExistingConnection(PhoneAccountHandle phoneAccountHandle,
+            Connection connection) {
+
+        String id = addExistingConnectionInternal(connection);
+        if (id != null) {
+            List<String> emptyList = new ArrayList<>(0);
+
+            ParcelableConnection parcelableConnection = new ParcelableConnection(
+                    phoneAccountHandle,
+                    connection.getState(),
+                    connection.getCallCapabilities(),
+                    connection.getAddress(),
+                    connection.getAddressPresentation(),
+                    connection.getCallerDisplayName(),
+                    connection.getCallerDisplayNamePresentation(),
+                    connection.getVideoProvider() == null ?
+                            null : connection.getVideoProvider().getInterface(),
+                    connection.getVideoState(),
+                    connection.isRingbackRequested(),
+                    connection.getAudioModeIsVoip(),
+                    connection.getStatusHints(),
+                    connection.getDisconnectCause(),
+                    emptyList);
+            mAdapter.addExistingConnection(id, parcelableConnection);
+        }
+    }
+
+    /**
      * Returns all the active {@code Connection}s for which this {@code ConnectionService}
      * has taken responsibility.
      *
@@ -906,6 +940,12 @@
     public void onRemoteConferenceAdded(RemoteConference conference) {}
 
     /**
+     * Called when an existing connection is added remotely.
+     * @param connection The existing connection which was added.
+     */
+    public void onRemoteExistingConnectionAdded(RemoteConnection connection) {}
+
+    /**
      * @hide
      */
     public boolean containsConference(Conference conference) {
@@ -917,6 +957,11 @@
         onRemoteConferenceAdded(remoteConference);
     }
 
+    /** {@hide} */
+    void addRemoteExistingConnection(RemoteConnection remoteConnection) {
+        onRemoteExistingConnectionAdded(remoteConnection);
+    }
+
     private void onAccountsInitialized() {
         mAreAccountsInitialized = true;
         for (Runnable r : mPreInitializationConnectionRequests) {
@@ -925,6 +970,18 @@
         mPreInitializationConnectionRequests.clear();
     }
 
+    /**
+     * Adds an existing connection to the list of connections, identified by a new UUID.
+     *
+     * @param connection The connection.
+     * @return The UUID of the connection (e.g. the call-id).
+     */
+    private String addExistingConnectionInternal(Connection connection) {
+        String id = UUID.randomUUID().toString();
+        addConnection(id, connection);
+        return id;
+    }
+
     private void addConnection(String callId, Connection connection) {
         mConnectionById.put(callId, connection);
         mIdByConnection.put(connection, callId);
diff --git a/telecomm/java/android/telecom/ConnectionServiceAdapter.java b/telecomm/java/android/telecom/ConnectionServiceAdapter.java
index c676172..e67af8c 100644
--- a/telecomm/java/android/telecom/ConnectionServiceAdapter.java
+++ b/telecomm/java/android/telecom/ConnectionServiceAdapter.java
@@ -344,4 +344,20 @@
             }
         }
     }
+
+    /**
+     * Informs telecom of an existing connection which was added by the {@link ConnectionService}.
+     *
+     * @param callId The unique ID of the call being added.
+     * @param connection The connection.
+     */
+    void addExistingConnection(String callId, ParcelableConnection connection) {
+        Log.v(this, "addExistingConnection: %s", callId);
+        for (IConnectionServiceAdapter adapter : mAdapters) {
+            try {
+                adapter.addExistingConnection(callId, connection);
+            } catch (RemoteException ignored) {
+            }
+        }
+    }
 }
diff --git a/telecomm/java/android/telecom/ConnectionServiceAdapterServant.java b/telecomm/java/android/telecom/ConnectionServiceAdapterServant.java
index 217dbc3..519a400 100644
--- a/telecomm/java/android/telecom/ConnectionServiceAdapterServant.java
+++ b/telecomm/java/android/telecom/ConnectionServiceAdapterServant.java
@@ -57,6 +57,7 @@
     private static final int MSG_SET_ADDRESS = 18;
     private static final int MSG_SET_CALLER_DISPLAY_NAME = 19;
     private static final int MSG_SET_CONFERENCEABLE_CONNECTIONS = 20;
+    private static final int MSG_ADD_EXISTING_CONNECTION = 21;
 
     private final IConnectionServiceAdapter mDelegate;
 
@@ -199,6 +200,16 @@
                     }
                     break;
                 }
+                case MSG_ADD_EXISTING_CONNECTION: {
+                    SomeArgs args = (SomeArgs) msg.obj;
+                    try {
+                        mDelegate.addExistingConnection(
+                                (String) args.arg1, (ParcelableConnection) args.arg2);
+                    } finally {
+                        args.recycle();
+                    }
+                    break;
+                }
             }
         }
     };
@@ -345,6 +356,15 @@
             args.arg2 = conferenceableConnectionIds;
             mHandler.obtainMessage(MSG_SET_CONFERENCEABLE_CONNECTIONS, args).sendToTarget();
         }
+
+        @Override
+        public final void addExistingConnection(
+                String connectionId, ParcelableConnection connection) {
+            SomeArgs args = SomeArgs.obtain();
+            args.arg1 = connectionId;
+            args.arg2 = connection;
+            mHandler.obtainMessage(MSG_ADD_EXISTING_CONNECTION, args).sendToTarget();
+        }
     };
 
     public ConnectionServiceAdapterServant(IConnectionServiceAdapter delegate) {
diff --git a/telecomm/java/android/telecom/DisconnectCause.java b/telecomm/java/android/telecom/DisconnectCause.java
index 9be0138..206046d 100644
--- a/telecomm/java/android/telecom/DisconnectCause.java
+++ b/telecomm/java/android/telecom/DisconnectCause.java
@@ -25,9 +25,10 @@
 
 /**
  * Describes the cause of a disconnected call. This always includes a code describing the generic
- * cause of the disconnect. Optionally, it may include a localized label and/or localized description
- * to display to the user which is provided by the {@link ConnectionService}. It also may contain a
- * reason for the the disconnect, which is intended for logging and not for display to the user.
+ * cause of the disconnect. Optionally, it may include a label and/or description to display to the
+ * user. It is the responsibility of the {@link ConnectionService} to provide localized versions of
+ * the label and description. It also may contain a reason for the disconnect, which is intended for
+ * logging and not for display to the user.
  */
 public final class DisconnectCause implements Parcelable {
 
@@ -85,6 +86,7 @@
 
     /**
      * Creates a new DisconnectCause.
+     *
      * @param label The localized label to show to the user to explain the disconnect.
      * @param code The code for the disconnect cause.
      * @param description The localized description to show to the user to explain the disconnect.
diff --git a/telecomm/java/android/telecom/GatewayInfo.java b/telecomm/java/android/telecom/GatewayInfo.java
index 583c3e2..7105602 100644
--- a/telecomm/java/android/telecom/GatewayInfo.java
+++ b/telecomm/java/android/telecom/GatewayInfo.java
@@ -23,12 +23,16 @@
 import android.text.TextUtils;
 
 /**
- * When calls are made, they may contain gateway information for services which route phone calls
- * through their own service/numbers. The data consists of a number to call and the package name of
- * the service. This data is used in two ways:
+ * Encapsulated gateway address information for outgoing call. When calls are made, the system
+ * provides a facility to specify two addresses for the call: one to display as the address being
+ * dialed and a separate (gateway) address to actually dial. Telecom provides this information to
+ * {@link ConnectionService}s when placing the call as an instance of {@code GatewayInfo}.
+ * <p>
+ * The data consists of an address to call, an address to display and the package name of the
+ * service. This data is used in two ways:
  * <ol>
- * <li> Call the appropriate routing number
- * <li> Display information about how the call is being routed to the user
+ * <li> Call the appropriate gateway address.
+ * <li> Display information about how the call is being routed to the user.
  * </ol>
  */
 public class GatewayInfo implements Parcelable {
@@ -46,31 +50,39 @@
     }
 
     /**
-     * Package name of the gateway provider service. used to place the call with.
+     * Package name of the gateway provider service that provided the gateway information.
+     * This can be used to identify the gateway address source and to load an appropriate icon when
+     * displaying gateway information in the in-call UI.
      */
     public String getGatewayProviderPackageName() {
         return mGatewayProviderPackageName;
     }
 
     /**
-     * Gateway provider address to use when actually placing the call.
+     * Returns the gateway address to dial when placing the call.
      */
     public Uri getGatewayAddress() {
         return mGatewayAddress;
     }
 
     /**
-     * The actual call address that the user is trying to connect to via the gateway.
+     * Returns the address that the user is trying to connect to via the gateway.
      */
     public Uri getOriginalAddress() {
         return mOriginalAddress;
     }
 
+    /**
+     * Indicates whether this {@code GatewayInfo} instance contains any data. A returned value of
+     * false indicates that no gateway number is being used for the call.
+     */
     public boolean isEmpty() {
         return TextUtils.isEmpty(mGatewayProviderPackageName) || mGatewayAddress == null;
     }
 
-    /** Implement the Parcelable interface */
+    /**
+     * The Parcelable interface.
+     * */
     public static final Parcelable.Creator<GatewayInfo> CREATOR =
             new Parcelable.Creator<GatewayInfo> () {
 
diff --git a/telecomm/java/android/telecom/PhoneAccountHandle.java b/telecomm/java/android/telecom/PhoneAccountHandle.java
index 768188b..bc4cc8c 100644
--- a/telecomm/java/android/telecom/PhoneAccountHandle.java
+++ b/telecomm/java/android/telecom/PhoneAccountHandle.java
@@ -23,7 +23,16 @@
 import java.util.Objects;
 
 /**
- * The unique identifier for a {@link PhoneAccount}.
+ * The unique identifier for a {@link PhoneAccount}. A {@code PhoneAccountHandle} is made of two
+ * parts:
+ * <ul>
+ *  <li>The component name of the associated {@link ConnectionService}.</li>
+ *  <li>A string identifier that is unique across {@code PhoneAccountHandle}s with the same
+ *      component name.</li>
+ * </ul>
+ *
+ * See {@link PhoneAccount},
+ * {@link TelecomManager#registerPhoneAccount TelecomManager.registerPhoneAccount}.
  */
 public class PhoneAccountHandle implements Parcelable {
     private ComponentName mComponentName;
diff --git a/telecomm/java/android/telecom/PhoneCapabilities.java b/telecomm/java/android/telecom/PhoneCapabilities.java
index 9c67503..3d3c6bd 100644
--- a/telecomm/java/android/telecom/PhoneCapabilities.java
+++ b/telecomm/java/android/telecom/PhoneCapabilities.java
@@ -17,8 +17,8 @@
 package android.telecom;
 
 /**
- * Defines capabilities a phone call can support, such as conference calling and video telephony.
- * Also defines properties of a phone call, such as whether it is using VoLTE technology.
+ * Defines capabilities for {@link Connection}s and {@link Conference}s such as hold, swap, and
+ * merge.
  */
 public final class PhoneCapabilities {
     /** Call can currently be put on hold or unheld. */
@@ -28,15 +28,22 @@
     public static final int SUPPORT_HOLD       = 0x00000002;
 
     /**
-     * Calls within a conference can be merged. Some connection services create a conference call
-     * only after two calls have been merged.  However, a conference call can also be added the
-     * moment there are more than one call. CDMA calls are implemented in this way because the call
-     * actions are more limited when more than one call exists. This flag allows merge to be exposed
-     * as a capability on the conference call instead of individual calls.
+     * Calls within a conference can be merged. A {@link ConnectionService} has the option to
+     * add a {@link Conference} call before the child {@link Connection}s are merged. This is how
+     * CDMA-based {@link Connection}s are implemented. For these unmerged {@link Conference}s, this
+     * capability allows a merge button to be shown while the conference call is in the foreground
+     * of the in-call UI.
+     * <p>
+     * This is only intended for use by a {@link Conference}.
      */
     public static final int MERGE_CONFERENCE   = 0x00000004;
 
-    /** Calls withing a conference can be swapped between foreground and background. */
+    /**
+     * Calls within a conference can be swapped between foreground and background.
+     * See {@link #MERGE_CONFERENCE} for additional information.
+     * <p>
+     * This is only intended for use by a {@link Conference}.
+     */
     public static final int SWAP_CONFERENCE    = 0x00000008;
 
     /** Call currently supports adding another call to this one. */
@@ -49,8 +56,8 @@
     public static final int MUTE               = 0x00000040;
 
     /**
-     * Call supports conference call management. This capability only applies to conference calls
-     * which can have other calls as children.
+     * Call supports conference call management. This capability only applies to {@link Conference}
+     * calls which can have {@link Connection}s as children.
      */
     public static final int MANAGE_CONFERENCE = 0x00000080;
 
diff --git a/telecomm/java/android/telecom/RemoteConnection.java b/telecomm/java/android/telecom/RemoteConnection.java
index 9a094df..816e2bf 100644
--- a/telecomm/java/android/telecom/RemoteConnection.java
+++ b/telecomm/java/android/telecom/RemoteConnection.java
@@ -407,6 +407,29 @@
     }
 
     /**
+     * @hide
+     */
+    RemoteConnection(String callId, IConnectionService connectionService,
+            ParcelableConnection connection) {
+        mConnectionId = callId;
+        mConnectionService = connectionService;
+        mConnected = true;
+        mState = connection.getState();
+        mDisconnectCause = connection.getDisconnectCause();
+        mRingbackRequested = connection.isRingbackRequested();
+        mCallCapabilities = connection.getCapabilities();
+        mVideoState = connection.getVideoState();
+        mVideoProvider = new RemoteConnection.VideoProvider(connection.getVideoProvider());
+        mIsVoipAudioMode = connection.getIsVoipAudioMode();
+        mStatusHints = connection.getStatusHints();
+        mAddress = connection.getHandle();
+        mAddressPresentation = connection.getHandlePresentation();
+        mCallerDisplayName = connection.getCallerDisplayName();
+        mCallerDisplayNamePresentation = connection.getCallerDisplayNamePresentation();
+        mConference = null;
+    }
+
+    /**
      * Create a RemoteConnection which is used for failed connections. Note that using it for any
      * "real" purpose will almost certainly fail. Callers should note the failure and act
      * accordingly (moving on to another RemoteConnection, for example)
@@ -415,7 +438,7 @@
      * @hide
      */
     RemoteConnection(DisconnectCause disconnectCause) {
-        this("NULL", null, null);
+        mConnectionId = "NULL";
         mConnected = false;
         mState = Connection.STATE_DISCONNECTED;
         mDisconnectCause = disconnectCause;
diff --git a/telecomm/java/android/telecom/RemoteConnectionService.java b/telecomm/java/android/telecom/RemoteConnectionService.java
index af4ee22..4bb78c0 100644
--- a/telecomm/java/android/telecom/RemoteConnectionService.java
+++ b/telecomm/java/android/telecom/RemoteConnectionService.java
@@ -41,8 +41,9 @@
  */
 final class RemoteConnectionService {
 
+    // Note: Casting null to avoid ambiguous constructor reference.
     private static final RemoteConnection NULL_CONNECTION =
-            new RemoteConnection("NULL", null, null);
+            new RemoteConnection("NULL", null, (ConnectionRequest) null);
 
     private static final RemoteConference NULL_CONFERENCE =
             new RemoteConference("NULL", null);
@@ -286,6 +287,15 @@
                         .setConferenceableConnections(conferenceable);
             }
         }
+
+        @Override
+        public void addExistingConnection(String callId, ParcelableConnection connection) {
+            // TODO: add contents of this method
+            RemoteConnection remoteConnction = new RemoteConnection(callId,
+                    mOutgoingConnectionServiceRpc, connection);
+
+            mOurConnectionServiceImpl.addRemoteExistingConnection(remoteConnction);
+        }
     };
 
     private final ConnectionServiceAdapterServant mServant =
diff --git a/telecomm/java/android/telecom/TelecomManager.java b/telecomm/java/android/telecom/TelecomManager.java
index bc51a70..4eac5ac 100644
--- a/telecomm/java/android/telecom/TelecomManager.java
+++ b/telecomm/java/android/telecom/TelecomManager.java
@@ -31,7 +31,17 @@
 import java.util.List;
 
 /**
- * Provides access to Telecom-related functionality.
+ * Provides access to information about active calls and registration/call-management functionality.
+ * Apps can use methods in this class to determine the current call state. Apps can also register new
+ * {@link PhoneAccount}s and get a listing of existing {@link PhoneAccount}s.
+ * <p>
+ * Apps do not instantiate this class directly; instead, they retrieve a reference to an instance
+ * through {@link Context#getSystemService Context.getSystemService(Context.TELECOM_SERVICE)}.
+ * <p>
+ * Note that access to some telecom information is permission-protected. Your app cannot access the
+ * protected information or gain access to protected functionality unless it has the appropriate
+ * permissions declared in its manifest file. Where permissions apply, they are noted in the method
+ * descriptions.
  */
 public class TelecomManager {
 
@@ -583,7 +593,16 @@
     }
 
     /**
-     * Register a {@link PhoneAccount} for use by the system.
+     * Register a {@link PhoneAccount} for use by the system. When registering
+     * {@link PhoneAccount}s, existing registrations will be overwritten if the
+     * {@link PhoneAccountHandle} matches that of a {@link PhoneAccount} which is already
+     * registered. Once registered, the {@link PhoneAccount} is listed to the user as an option
+     * when placing calls. The user may still need to enable the {@link PhoneAccount} within
+     * the phone app settings before the account is usable.
+     * <p>
+     * A {@link SecurityException} will be thrown if an app tries to register a
+     * {@link PhoneAccountHandle} where the package name specified within
+     * {@link PhoneAccountHandle#getComponentName()} does not match the package name of the app.
      *
      * @param account The complete {@link PhoneAccount}.
      */
@@ -876,6 +895,7 @@
      * Processes the specified dial string as an MMI code.
      * MMI codes are any sequence of characters entered into the dialpad that contain a "*" or "#".
      * Some of these sequences launch special behavior through handled by Telephony.
+     * This method uses the default subscription.
      * <p>
      * Requires that the method-caller be set as the system dialer app.
      * </p>
@@ -896,6 +916,31 @@
     }
 
     /**
+     * Processes the specified dial string as an MMI code.
+     * MMI codes are any sequence of characters entered into the dialpad that contain a "*" or "#".
+     * Some of these sequences launch special behavior through handled by Telephony.
+     * <p>
+     * Requires that the method-caller be set as the system dialer app.
+     * </p>
+     *
+     * @param accountHandle The handle for the account the MMI code should apply to.
+     * @param dialString The digits to dial.
+     * @return True if the digits were processed as an MMI code, false otherwise.
+     *
+     */
+    public boolean handleMmi(PhoneAccountHandle accountHandle, String dialString) {
+        ITelecomService service = getTelecomService();
+        if (service != null) {
+            try {
+                return service.handlePinMmiForPhoneAccount(accountHandle, dialString);
+            } catch (RemoteException e) {
+                Log.e(TAG, "Error calling ITelecomService#handlePinMmi", e);
+            }
+        }
+        return false;
+    }
+
+    /**
      * Removes the missed-call notification if one is present.
      * <p>
      * Requires that the method-caller be set as the system dialer app.
diff --git a/telecomm/java/com/android/internal/telecom/IConnectionServiceAdapter.aidl b/telecomm/java/com/android/internal/telecom/IConnectionServiceAdapter.aidl
index 5daa568..0d6b3d9 100644
--- a/telecomm/java/com/android/internal/telecom/IConnectionServiceAdapter.aidl
+++ b/telecomm/java/com/android/internal/telecom/IConnectionServiceAdapter.aidl
@@ -77,4 +77,6 @@
     void setCallerDisplayName(String callId, String callerDisplayName, int presentation);
 
     void setConferenceableConnections(String callId, in List<String> conferenceableCallIds);
+
+    void addExistingConnection(String callId, in ParcelableConnection connection);
 }
diff --git a/telecomm/java/com/android/internal/telecom/ITelecomService.aidl b/telecomm/java/com/android/internal/telecom/ITelecomService.aidl
index 91f44b9..fd47213 100644
--- a/telecomm/java/com/android/internal/telecom/ITelecomService.aidl
+++ b/telecomm/java/com/android/internal/telecom/ITelecomService.aidl
@@ -169,6 +169,11 @@
     boolean handlePinMmi(String dialString);
 
     /**
+     * @see TelecomServiceImpl#handleMmi
+     */
+    boolean handlePinMmiForPhoneAccount(in PhoneAccountHandle accountHandle, String dialString);
+
+    /**
      * @see TelecomServiceImpl#isTtySupported
      */
     boolean isTtySupported();
diff --git a/telephony/java/android/telephony/SignalStrength.java b/telephony/java/android/telephony/SignalStrength.java
index 3363ca6..17db3fb 100644
--- a/telephony/java/android/telephony/SignalStrength.java
+++ b/telephony/java/android/telephony/SignalStrength.java
@@ -20,6 +20,7 @@
 import android.os.Parcel;
 import android.os.Parcelable;
 import android.telephony.Rlog;
+import android.content.res.Resources;
 
 /**
  * Contains phone signal strength related information.
@@ -50,6 +51,11 @@
     //Use int max, as -1 is a valid value in signal strength
     public static final int INVALID = 0x7FFFFFFF;
 
+    private static final int RSRP_THRESH_TYPE_STRICT = 0;
+    private static final int[] RSRP_THRESH_STRICT = new int[] {-140, -115, -105, -95, -85, -44};
+    private static final int[] RSRP_THRESH_LENIENT = new int[] {-140, -128, -118, -108, -98, -44};
+
+
     private int mGsmSignalStrength; // Valid values are (0-31, 99) as defined in TS 27.007 8.5
     private int mGsmBitErrorRate;   // bit error rate (0-7, 99) as defined in TS 27.007 8.5
     private int mCdmaDbm;   // This value is the RSSI value
@@ -745,12 +751,21 @@
          */
         int rssiIconLevel = SIGNAL_STRENGTH_NONE_OR_UNKNOWN, rsrpIconLevel = -1, snrIconLevel = -1;
 
-        if (mLteRsrp > -44) rsrpIconLevel = -1;
-        else if (mLteRsrp >= -85) rsrpIconLevel = SIGNAL_STRENGTH_GREAT;
-        else if (mLteRsrp >= -95) rsrpIconLevel = SIGNAL_STRENGTH_GOOD;
-        else if (mLteRsrp >= -105) rsrpIconLevel = SIGNAL_STRENGTH_MODERATE;
-        else if (mLteRsrp >= -115) rsrpIconLevel = SIGNAL_STRENGTH_POOR;
-        else if (mLteRsrp >= -140) rsrpIconLevel = SIGNAL_STRENGTH_NONE_OR_UNKNOWN;
+        int rsrpThreshType = Resources.getSystem().getInteger(com.android.internal.R.integer.
+                config_LTE_RSRP_threshold_type);
+        int[] threshRsrp;
+        if (rsrpThreshType == RSRP_THRESH_TYPE_STRICT) {
+            threshRsrp = RSRP_THRESH_STRICT;
+        } else {
+            threshRsrp = RSRP_THRESH_LENIENT;
+        }
+
+        if (mLteRsrp > threshRsrp[5]) rsrpIconLevel = -1;
+        else if (mLteRsrp >= threshRsrp[4]) rsrpIconLevel = SIGNAL_STRENGTH_GREAT;
+        else if (mLteRsrp >= threshRsrp[3]) rsrpIconLevel = SIGNAL_STRENGTH_GOOD;
+        else if (mLteRsrp >= threshRsrp[2]) rsrpIconLevel = SIGNAL_STRENGTH_MODERATE;
+        else if (mLteRsrp >= threshRsrp[1]) rsrpIconLevel = SIGNAL_STRENGTH_POOR;
+        else if (mLteRsrp >= threshRsrp[0]) rsrpIconLevel = SIGNAL_STRENGTH_NONE_OR_UNKNOWN;
 
         /*
          * Values are -200 dB to +300 (SNR*10dB) RS_SNR >= 13.0 dB =>4 bars 4.5
@@ -789,6 +804,7 @@
         else if (mLteSignalStrength >= 8) rssiIconLevel = SIGNAL_STRENGTH_GOOD;
         else if (mLteSignalStrength >= 5) rssiIconLevel = SIGNAL_STRENGTH_MODERATE;
         else if (mLteSignalStrength >= 0) rssiIconLevel = SIGNAL_STRENGTH_POOR;
+
         if (DBG) log("getLTELevel - rssi:" + mLteSignalStrength + " rssiIconLevel:"
                 + rssiIconLevel);
         return rssiIconLevel;
diff --git a/telephony/java/android/telephony/TelephonyManager.java b/telephony/java/android/telephony/TelephonyManager.java
index a3546ed..0246a2d 100644
--- a/telephony/java/android/telephony/TelephonyManager.java
+++ b/telephony/java/android/telephony/TelephonyManager.java
@@ -3336,6 +3336,17 @@
 
     /** @hide */
     @SystemApi
+    public boolean handlePinMmiForSubscriber(int subId, String dialString) {
+        try {
+            return getITelephony().handlePinMmiForSubscriber(subId, dialString);
+        } catch (RemoteException e) {
+            Log.e(TAG, "Error calling ITelephony#handlePinMmi", e);
+        }
+        return false;
+    }
+
+    /** @hide */
+    @SystemApi
     public void toggleRadioOnOff() {
         try {
             getITelephony().toggleRadioOnOff();
diff --git a/telephony/java/com/android/ims/ImsConferenceState.java b/telephony/java/com/android/ims/ImsConferenceState.java
index f708d5b..c57ef98 100644
--- a/telephony/java/com/android/ims/ImsConferenceState.java
+++ b/telephony/java/com/android/ims/ImsConferenceState.java
@@ -24,6 +24,8 @@
 import android.os.Bundle;
 import android.os.Parcel;
 import android.os.Parcelable;
+import android.telecom.Call;
+import android.telecom.Connection;
 
 /**
  * Provides the conference information (defined in RFC 4575) for IMS conference call.
@@ -139,4 +141,30 @@
             return new ImsConferenceState[size];
         }
     };
+
+    /**
+     * Translates an {@code ImsConferenceState} status type to a telecom connection state.
+     *
+     * @param status The status type.
+     * @return The corresponding {@link android.telecom.Connection} state.
+     */
+    public static int getConnectionStateForStatus(String status) {
+        if (status.equals(STATUS_PENDING)) {
+            return Connection.STATE_INITIALIZING;
+        } else if (status.equals(STATUS_DIALING_IN)) {
+            return Connection.STATE_RINGING;
+        } else if (status.equals(STATUS_ALERTING) ||
+                status.equals(STATUS_DIALING_OUT)) {
+            return Connection.STATE_DIALING;
+        } else if (status.equals(STATUS_ON_HOLD)) {
+            return Connection.STATE_HOLDING;
+        } else if (status.equals(STATUS_CONNECTED) ||
+                status.equals(STATUS_MUTED_VIA_FOCUS) ||
+                status.equals(STATUS_DISCONNECTING)) {
+            return Connection.STATE_ACTIVE;
+        } else if (status.equals(STATUS_DISCONNECTED)) {
+            return Connection.STATE_DISCONNECTED;
+        }
+        return Call.STATE_ACTIVE;
+    }
 }
diff --git a/test-runner/src/android/test/mock/MockPackageManager.java b/test-runner/src/android/test/mock/MockPackageManager.java
index 7f1dc71..7531d7b 100644
--- a/test-runner/src/android/test/mock/MockPackageManager.java
+++ b/test-runner/src/android/test/mock/MockPackageManager.java
@@ -733,6 +733,14 @@
      * @hide
      */
     @Override
+    public boolean isUpgrade() {
+        throw new UnsupportedOperationException();
+    }
+
+    /**
+     * @hide
+     */
+    @Override
     public void installPackage(Uri packageURI, PackageInstallObserver observer,
             int flags, String installerPackageName) {
         throw new UnsupportedOperationException();
diff --git a/tools/layoutlib/bridge/src/android/animation/AnimatorInflater_Delegate.java b/tools/layoutlib/bridge/src/android/animation/AnimatorInflater_Delegate.java
new file mode 100644
index 0000000..d8a6ffc
--- /dev/null
+++ b/tools/layoutlib/bridge/src/android/animation/AnimatorInflater_Delegate.java
@@ -0,0 +1,59 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.animation;
+
+import com.android.tools.layoutlib.annotations.LayoutlibDelegate;
+
+import android.content.Context;
+import android.content.res.Resources;
+import android.content.res.Resources.NotFoundException;
+import android.content.res.Resources.Theme;
+import android.util.AttributeSet;
+
+/**
+ * Delegate providing alternate implementation to static methods in {@link AnimatorInflater}.
+ */
+public class AnimatorInflater_Delegate {
+
+    @LayoutlibDelegate
+    /*package*/ static Animator loadAnimator(Context context, int id)
+            throws NotFoundException {
+        return loadAnimator(context.getResources(), context.getTheme(), id);
+    }
+
+    @LayoutlibDelegate
+    /*package*/ static Animator loadAnimator(Resources resources, Theme theme, int id)
+            throws NotFoundException {
+        return loadAnimator(resources, theme, id, 1);
+    }
+
+    @LayoutlibDelegate
+    /*package*/ static Animator loadAnimator(Resources resources, Theme theme, int id,
+            float pathErrorScale) throws NotFoundException {
+        // This is a temporary fix to http://b.android.com/77865. This skips loading the
+        // animation altogether.
+        // TODO: Remove this override when Path.approximate() is supported.
+        return new FakeAnimator();
+    }
+
+    @LayoutlibDelegate
+    /*package*/ static ValueAnimator loadAnimator(Resources res, Theme theme,
+            AttributeSet attrs, ValueAnimator anim, float pathErrorScale)
+            throws NotFoundException {
+        return anim;
+    }
+}
diff --git a/tools/layoutlib/bridge/src/android/animation/FakeAnimator.java b/tools/layoutlib/bridge/src/android/animation/FakeAnimator.java
new file mode 100644
index 0000000..78aedc5
--- /dev/null
+++ b/tools/layoutlib/bridge/src/android/animation/FakeAnimator.java
@@ -0,0 +1,52 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.animation;
+
+/**
+ * A fake implementation of Animator which doesn't do anything.
+ */
+public class FakeAnimator extends Animator {
+    @Override
+    public long getStartDelay() {
+        return 0;
+    }
+
+    @Override
+    public void setStartDelay(long startDelay) {
+
+    }
+
+    @Override
+    public Animator setDuration(long duration) {
+        return this;
+    }
+
+    @Override
+    public long getDuration() {
+        return 0;
+    }
+
+    @Override
+    public void setInterpolator(TimeInterpolator value) {
+
+    }
+
+    @Override
+    public boolean isRunning() {
+        return false;
+    }
+}
diff --git a/tools/layoutlib/bridge/src/android/content/res/AssetManager_Delegate.java b/tools/layoutlib/bridge/src/android/content/res/AssetManager_Delegate.java
index 914a359..e0d3b8c 100644
--- a/tools/layoutlib/bridge/src/android/content/res/AssetManager_Delegate.java
+++ b/tools/layoutlib/bridge/src/android/content/res/AssetManager_Delegate.java
@@ -38,8 +38,4 @@
         Resources_Theme_Delegate.getDelegateManager().removeJavaReferenceFor(theme);
     }
 
-    @LayoutlibDelegate
-    /*package*/ static void applyThemeStyle(long theme, int styleRes, boolean force) {
-        Resources_Theme_Delegate.getDelegateManager().getDelegate(theme).force = force;
-    }
 }
diff --git a/tools/layoutlib/bridge/src/android/content/res/BridgeResources.java b/tools/layoutlib/bridge/src/android/content/res/BridgeResources.java
index dd573be..66126af 100644
--- a/tools/layoutlib/bridge/src/android/content/res/BridgeResources.java
+++ b/tools/layoutlib/bridge/src/android/content/res/BridgeResources.java
@@ -163,7 +163,7 @@
         Pair<String, ResourceValue> value = getResourceValue(id, mPlatformResourceFlag);
 
         if (value != null) {
-            return ResourceHelper.getDrawable(value.getSecond(), mContext);
+            return ResourceHelper.getDrawable(value.getSecond(), mContext, theme);
         }
 
         // id was not found or not resolved. Throw a NotFoundException.
diff --git a/tools/layoutlib/bridge/src/android/content/res/BridgeTypedArray.java b/tools/layoutlib/bridge/src/android/content/res/BridgeTypedArray.java
index 28a109d..a2bd6d7 100644
--- a/tools/layoutlib/bridge/src/android/content/res/BridgeTypedArray.java
+++ b/tools/layoutlib/bridge/src/android/content/res/BridgeTypedArray.java
@@ -32,6 +32,7 @@
 import org.xmlpull.v1.XmlPullParser;
 import org.xmlpull.v1.XmlPullParserException;
 
+import android.content.res.Resources.Theme;
 import android.graphics.drawable.Drawable;
 import android.util.DisplayMetrics;
 import android.util.TypedValue;
@@ -116,6 +117,13 @@
     }
 
     /**
+     * Set the theme to be used for inflating drawables.
+     */
+    public void setTheme(Theme theme) {
+        mTheme = theme;
+    }
+
+    /**
      * Return the number of values in this array.
      */
     @Override
@@ -663,7 +671,7 @@
         }
 
         ResourceValue value = mResourceData[index];
-        return ResourceHelper.getDrawable(value, mContext);
+        return ResourceHelper.getDrawable(value, mContext, mTheme);
     }
 
 
diff --git a/tools/layoutlib/bridge/src/android/content/res/Resources_Theme_Delegate.java b/tools/layoutlib/bridge/src/android/content/res/Resources_Theme_Delegate.java
index f4a9f52..4bd83e9 100644
--- a/tools/layoutlib/bridge/src/android/content/res/Resources_Theme_Delegate.java
+++ b/tools/layoutlib/bridge/src/android/content/res/Resources_Theme_Delegate.java
@@ -39,9 +39,6 @@
  */
 public class Resources_Theme_Delegate {
 
-    // Whether to use the Theme.mThemeResId as primary theme.
-    boolean force;
-
     // ---- delegate manager ----
 
     private static final DelegateManager<Resources_Theme_Delegate> sManager =
@@ -58,7 +55,8 @@
             Resources thisResources, Theme thisTheme,
             int[] attrs) {
         boolean changed = setupResources(thisTheme);
-        TypedArray ta = RenderSessionImpl.getCurrentContext().obtainStyledAttributes(attrs);
+        BridgeTypedArray ta = RenderSessionImpl.getCurrentContext().obtainStyledAttributes(attrs);
+        ta.setTheme(thisTheme);
         restoreResources(changed);
         return ta;
     }
@@ -69,7 +67,9 @@
             int resid, int[] attrs)
             throws NotFoundException {
         boolean changed = setupResources(thisTheme);
-        TypedArray ta = RenderSessionImpl.getCurrentContext().obtainStyledAttributes(resid, attrs);
+        BridgeTypedArray ta = RenderSessionImpl.getCurrentContext().obtainStyledAttributes(resid,
+                attrs);
+        ta.setTheme(thisTheme);
         restoreResources(changed);
         return ta;
     }
@@ -79,8 +79,9 @@
             Resources thisResources, Theme thisTheme,
             AttributeSet set, int[] attrs, int defStyleAttr, int defStyleRes) {
         boolean changed = setupResources(thisTheme);
-        TypedArray ta = RenderSessionImpl.getCurrentContext().obtainStyledAttributes(set, attrs,
-                defStyleAttr, defStyleRes);
+        BridgeTypedArray ta = RenderSessionImpl.getCurrentContext().obtainStyledAttributes(set,
+                attrs, defStyleAttr, defStyleRes);
+        ta.setTheme(thisTheme);
         restoreResources(changed);
         return ta;
     }
@@ -91,8 +92,8 @@
             int resid, TypedValue outValue,
             boolean resolveRefs) {
         boolean changed = setupResources(thisTheme);
-        boolean found =  RenderSessionImpl.getCurrentContext().resolveThemeAttribute(
-                resid, outValue, resolveRefs);
+        boolean found =  RenderSessionImpl.getCurrentContext().resolveThemeAttribute(resid,
+                outValue, resolveRefs);
         restoreResources(changed);
         return found;
     }
@@ -107,14 +108,29 @@
     // ---- private helper methods ----
 
     private static boolean setupResources(Theme thisTheme) {
-        Resources_Theme_Delegate themeDelegate = sManager.getDelegate(thisTheme.getNativeTheme());
-        StyleResourceValue style = resolveStyle(thisTheme.getAppliedStyleResId());
-        if (style != null) {
-            RenderSessionImpl.getCurrentContext().getRenderResources()
-                    .applyStyle(style, themeDelegate.force);
-            return true;
+        // Key is a space-separated list of theme ids applied that have been merged into the
+        // BridgeContext's theme to make thisTheme.
+        String[] appliedStyles = thisTheme.getKey().split(" ");
+        boolean changed = false;
+        for (String s : appliedStyles) {
+            if (s.isEmpty()) {
+                continue;
+            }
+            // See the definition of force parameter in Theme.applyStyle().
+            boolean force = false;
+            if (s.charAt(s.length() - 1) == '!') {
+                force = true;
+                s = s.substring(0, s.length() - 1);
+            }
+            int styleId = Integer.parseInt(s, 16);
+            StyleResourceValue style = resolveStyle(styleId);
+            if (style != null) {
+                RenderSessionImpl.getCurrentContext().getRenderResources().applyStyle(style, force);
+                changed = true;
+            }
+
         }
-        return false;
+        return changed;
     }
 
     private static void restoreResources(boolean changed) {
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeContext.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeContext.java
index 04a52ea..d804230 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeContext.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeContext.java
@@ -115,7 +115,7 @@
     private int mDynamicIdGenerator = 0x02030000; // Base id for R.style in custom namespace
 
     // cache for TypedArray generated from IStyleResourceValue object
-    private Map<int[], Map<Integer, TypedArray>> mTypedArrayCache;
+    private Map<int[], Map<Integer, BridgeTypedArray>> mTypedArrayCache;
     private BridgeInflater mBridgeInflater;
 
     private BridgeContentResolver mContentResolver;
@@ -467,7 +467,7 @@
 
 
     @Override
-    public final TypedArray obtainStyledAttributes(int[] attrs) {
+    public final BridgeTypedArray obtainStyledAttributes(int[] attrs) {
         // No style is specified here, so create the typed array based on the default theme
         // and the styles already applied to it. A null value of style indicates that the default
         // theme should be used.
@@ -475,7 +475,7 @@
     }
 
     @Override
-    public final TypedArray obtainStyledAttributes(int resid, int[] attrs)
+    public final BridgeTypedArray obtainStyledAttributes(int resid, int[] attrs)
             throws Resources.NotFoundException {
         // get the StyleResourceValue based on the resId;
         StyleResourceValue style = getStyleByDynamicId(resid);
@@ -485,9 +485,9 @@
         }
 
         if (mTypedArrayCache == null) {
-            mTypedArrayCache = new HashMap<int[], Map<Integer,TypedArray>>();
+            mTypedArrayCache = new HashMap<int[], Map<Integer,BridgeTypedArray>>();
 
-            Map<Integer, TypedArray> map = new HashMap<Integer, TypedArray>();
+            Map<Integer, BridgeTypedArray> map = new HashMap<Integer, BridgeTypedArray>();
             mTypedArrayCache.put(attrs, map);
 
             BridgeTypedArray ta = createStyleBasedTypedArray(style, attrs);
@@ -497,14 +497,14 @@
         }
 
         // get the 2nd map
-        Map<Integer, TypedArray> map = mTypedArrayCache.get(attrs);
+        Map<Integer, BridgeTypedArray> map = mTypedArrayCache.get(attrs);
         if (map == null) {
-            map = new HashMap<Integer, TypedArray>();
+            map = new HashMap<Integer, BridgeTypedArray>();
             mTypedArrayCache.put(attrs, map);
         }
 
         // get the array from the 2nd map
-        TypedArray ta = map.get(resid);
+        BridgeTypedArray ta = map.get(resid);
 
         if (ta == null) {
             ta = createStyleBasedTypedArray(style, attrs);
@@ -515,12 +515,12 @@
     }
 
     @Override
-    public final TypedArray obtainStyledAttributes(AttributeSet set, int[] attrs) {
+    public final BridgeTypedArray obtainStyledAttributes(AttributeSet set, int[] attrs) {
         return obtainStyledAttributes(set, attrs, 0, 0);
     }
 
     @Override
-    public TypedArray obtainStyledAttributes(AttributeSet set, int[] attrs,
+    public BridgeTypedArray obtainStyledAttributes(AttributeSet set, int[] attrs,
             int defStyleAttr, int defStyleRes) {
 
         Map<String, String> defaultPropMap = null;
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeWindow.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeWindow.java
index 997b199..4c4454d 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeWindow.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeWindow.java
@@ -95,6 +95,10 @@
     }
 
     @Override
+    public void dispatchWindowShown() {
+    }
+
+    @Override
     public IBinder asBinder() {
         // pass for now.
         return null;
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/ResourceHelper.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/ResourceHelper.java
index 22f8e1c..677c744 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/ResourceHelper.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/ResourceHelper.java
@@ -32,6 +32,7 @@
 import org.xmlpull.v1.XmlPullParserException;
 
 import android.content.res.ColorStateList;
+import android.content.res.Resources.Theme;
 import android.graphics.Bitmap;
 import android.graphics.Bitmap_Delegate;
 import android.graphics.NinePatch_Delegate;
@@ -166,6 +167,17 @@
      * @param context the current context
      */
     public static Drawable getDrawable(ResourceValue value, BridgeContext context) {
+        return getDrawable(value, context, null);
+    }
+
+    /**
+     * Returns a drawable from the given value.
+     * @param value The value that contains a path to a 9 patch, a bitmap or a xml based drawable,
+     * or an hexadecimal color
+     * @param context the current context
+     * @param theme the theme to be used to inflate the drawable.
+     */
+    public static Drawable getDrawable(ResourceValue value, BridgeContext context, Theme theme) {
         if (value == null) {
             return null;
         }
@@ -209,7 +221,7 @@
                     BridgeXmlBlockParser blockParser = new BridgeXmlBlockParser(
                             parser, context, value.isFramework());
                     try {
-                        return Drawable.createFromXml(context.getResources(), blockParser);
+                        return Drawable.createFromXml(context.getResources(), blockParser, theme);
                     } finally {
                         blockParser.ensurePopped();
                     }
diff --git a/tools/layoutlib/create/src/com/android/tools/layoutlib/create/CreateInfo.java b/tools/layoutlib/create/src/com/android/tools/layoutlib/create/CreateInfo.java
index f20b890..2fcdf34 100644
--- a/tools/layoutlib/create/src/com/android/tools/layoutlib/create/CreateInfo.java
+++ b/tools/layoutlib/create/src/com/android/tools/layoutlib/create/CreateInfo.java
@@ -137,13 +137,13 @@
      * The list of methods to rewrite as delegates.
      */
     public final static String[] DELEGATE_METHODS = new String[] {
+        "android.animation.AnimatorInflater#loadAnimator",  // TODO: remove when Path.approximate() is supported.
         "android.app.Fragment#instantiate", //(Landroid/content/Context;Ljava/lang/String;Landroid/os/Bundle;)Landroid/app/Fragment;",
         "android.content.res.Resources$Theme#obtainStyledAttributes",
         "android.content.res.Resources$Theme#resolveAttribute",
         "android.content.res.Resources$Theme#resolveAttributes",
         "android.content.res.AssetManager#newTheme",
         "android.content.res.AssetManager#deleteTheme",
-        "android.content.res.AssetManager#applyThemeStyle",
         "android.content.res.TypedArray#getValueAt",
         "android.content.res.TypedArray#obtain",
         "android.graphics.BitmapFactory#finishDecode",