Merge "Improve low on RAM reporting." into lmp-mr1-dev
diff --git a/api/current.txt b/api/current.txt
index 0f35a7b..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
@@ -28093,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();
@@ -28182,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);
@@ -28191,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";
   }
 
@@ -28389,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);
@@ -32152,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);
@@ -33607,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();
@@ -33883,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);
@@ -35162,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();
@@ -35232,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);
@@ -38429,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/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/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/provider/Settings.java b/core/java/android/provider/Settings.java
index 369efac..c54a5ba 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -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 d42ed03..74d4245 100644
--- a/core/java/android/util/TypedValue.java
+++ b/core/java/android/util/TypedValue.java
@@ -312,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 e4f95a4..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;
@@ -3888,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;
@@ -5611,6 +5627,7 @@
             if (rootView == null) {
                 rootView = this;
             }
+
             View label = rootView.findLabelForView(this, mID);
             if (label != null) {
                 info.setLabeledBy(label);
@@ -5639,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());
@@ -6043,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.
      *
@@ -6061,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);
     }
 
     /**
diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java
index 27f78b6..f0d5252 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -3089,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
@@ -3138,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);
         }
@@ -3366,6 +3369,9 @@
                     invalidateWorld(mView);
                 }
             } break;
+            case MSG_DISPATCH_WINDOW_SHOWN: {
+                handleDispatchWindowShown();
+            }
             }
         }
     }
@@ -5212,6 +5218,10 @@
         }
     }
 
+    public void handleDispatchWindowShown() {
+        mAttachInfo.mTreeObserver.dispatchOnWindowShown();
+    }
+
     public void getLastTouchPoint(Point outLocation) {
         outLocation.x = (int) mLastTouchPoint.x;
         outLocation.y = (int) mLastTouchPoint.y;
@@ -6072,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;
@@ -6582,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/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 6c107a2..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) {
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/com/android/internal/app/AlertController.java b/core/java/com/android/internal/app/AlertController.java
index 3630cc7..35e03c3 100644
--- a/core/java/com/android/internal/app/AlertController.java
+++ b/core/java/com/android/internal/app/AlertController.java
@@ -37,6 +37,7 @@
 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;
@@ -589,9 +590,10 @@
             mScrollView.removeView(mMessageView);
 
             if (mListView != null) {
-                final int childIndex = mScrollView.indexOfChild(mScrollView);
-                contentPanel.removeViewAt(childIndex);
-                contentPanel.addView(mListView, childIndex,
+                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);
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/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/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/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/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 c4131b3..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
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 c0b7fd0..c0a5ab2 100644
--- a/core/res/res/values/public.xml
+++ b/core/res/res/values/public.xml
@@ -2597,5 +2597,7 @@
 
     <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/symbols.xml b/core/res/res/values/symbols.xml
index 0432425..afe7c78 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -2094,4 +2094,7 @@
   <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/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/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/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 6a69517..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);
 
@@ -5634,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);
@@ -5668,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/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/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/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/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/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/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 0cf2d05..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;
@@ -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/StackScrollState.java b/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackScrollState.java
index 026c2f3..4611370 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackScrollState.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackScrollState.java
@@ -234,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/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/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/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/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/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index 13fb96f..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);
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/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/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/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 b771879..4eac5ac 100644
--- a/telecomm/java/android/telecom/TelecomManager.java
+++ b/telecomm/java/android/telecom/TelecomManager.java
@@ -895,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>
@@ -915,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/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;