Merge "Even, Even more telecom javadoc." into lmp-mr1-dev
diff --git a/api/current.txt b/api/current.txt
index 95f743b..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
@@ -28392,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);
@@ -32155,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);
@@ -33610,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();
@@ -33886,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);
@@ -35165,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();
@@ -35235,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);
@@ -38432,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/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/hardware/display/DisplayManagerInternal.java b/core/java/android/hardware/display/DisplayManagerInternal.java
index 8447dde..bb162153 100644
--- a/core/java/android/hardware/display/DisplayManagerInternal.java
+++ b/core/java/android/hardware/display/DisplayManagerInternal.java
@@ -172,9 +172,12 @@
         // If true, enables automatic brightness control.
         public boolean useAutoBrightness;
 
-        //If true, scales the brightness to half of desired.
+        // If true, scales the brightness to half of desired.
         public boolean lowPowerMode;
 
+        // If true, applies a brightness boost.
+        public boolean boostScreenBrightness;
+
         // If true, prevents the screen from completely turning on if it is currently off.
         // The display does not enter a "ready" state if this flag is true and screen on is
         // blocked.  The window manager policy blocks screen on while it prepares the keyguard to
@@ -216,6 +219,7 @@
             useAutoBrightness = other.useAutoBrightness;
             blockScreenOn = other.blockScreenOn;
             lowPowerMode = other.lowPowerMode;
+            boostScreenBrightness = other.boostScreenBrightness;
             dozeScreenBrightness = other.dozeScreenBrightness;
             dozeScreenState = other.dozeScreenState;
         }
@@ -235,6 +239,7 @@
                     && useAutoBrightness == other.useAutoBrightness
                     && blockScreenOn == other.blockScreenOn
                     && lowPowerMode == other.lowPowerMode
+                    && boostScreenBrightness == other.boostScreenBrightness
                     && dozeScreenBrightness == other.dozeScreenBrightness
                     && dozeScreenState == other.dozeScreenState;
         }
@@ -253,6 +258,7 @@
                     + ", useAutoBrightness=" + useAutoBrightness
                     + ", blockScreenOn=" + blockScreenOn
                     + ", lowPowerMode=" + lowPowerMode
+                    + ", boostScreenBrightness=" + boostScreenBrightness
                     + ", dozeScreenBrightness=" + dozeScreenBrightness
                     + ", dozeScreenState=" + Display.stateToString(dozeScreenState);
         }
diff --git a/core/java/android/net/PskKeyManager.java b/core/java/android/net/PskKeyManager.java
index d162282..f82e635 100644
--- a/core/java/android/net/PskKeyManager.java
+++ b/core/java/android/net/PskKeyManager.java
@@ -81,6 +81,13 @@
  * Subclasses should normally provide their own implementation of {@code getKey} because the default
  * implementation returns no key, which aborts the handshake.
  *
+ * <h3>Known issues</h3>
+ * The implementation of {@code ECDHE_PSK} cipher suites in API Level 21 contains a bug which breaks
+ * compatibility with other implementations. {@code ECDHE_PSK} cipher suites are enabled by default
+ * on platforms with API Level 21 when an {@code SSLContext} is initialized with a
+ * {@code PskKeyManager}. A workaround is to disable {@code ECDHE_PSK} cipher suites on platforms
+ * with API Level 21.
+ *
  * <h3>Example</h3>
  * The following example illustrates how to create an {@code SSLContext} which enables the use of
  * TLS-PSK in {@code SSLSocket}, {@code SSLServerSocket} and {@code SSLEngine} instances obtained
diff --git a/core/java/android/os/IPowerManager.aidl b/core/java/android/os/IPowerManager.aidl
index 182dbee..ec30684 100644
--- a/core/java/android/os/IPowerManager.aidl
+++ b/core/java/android/os/IPowerManager.aidl
@@ -50,6 +50,7 @@
 
     void setStayOnSetting(int val);
     void setMaximumScreenOffTimeoutFromDeviceAdmin(int timeMs);
+    void boostScreenBrightness(long time);
 
     // temporarily overrides the screen brightness settings to allow the user to
     // see the effect of a settings change without applying it immediately
diff --git a/core/java/android/os/PowerManager.java b/core/java/android/os/PowerManager.java
index 3b6ce53..8307d9b 100644
--- a/core/java/android/os/PowerManager.java
+++ b/core/java/android/os/PowerManager.java
@@ -669,6 +669,28 @@
     }
 
     /**
+     * Boosts the brightness of the screen to maximum for a predetermined
+     * period of time.  This is used to make the screen more readable in bright
+     * daylight for a short duration.
+     * <p>
+     * Requires the {@link android.Manifest.permission#DEVICE_POWER} permission.
+     * </p>
+     *
+     * @param time The time when the request to boost was issued, in the
+     * {@link SystemClock#uptimeMillis()} time base.  This timestamp is used to correctly
+     * order the boost request with other power management functions.  It should be set
+     * to the timestamp of the input event that caused the request to boost.
+     *
+     * @hide Requires signature permission.
+     */
+    public void boostScreenBrightness(long time) {
+        try {
+            mService.boostScreenBrightness(time);
+        } catch (RemoteException e) {
+        }
+    }
+
+    /**
      * Sets the brightness of the backlights (screen, keyboard, button).
      * <p>
      * Requires the {@link android.Manifest.permission#DEVICE_POWER} permission.
diff --git a/core/java/android/print/IPrintDocumentAdapter.aidl b/core/java/android/print/IPrintDocumentAdapter.aidl
index 9d384fb..8f33e0b 100644
--- a/core/java/android/print/IPrintDocumentAdapter.aidl
+++ b/core/java/android/print/IPrintDocumentAdapter.aidl
@@ -37,4 +37,5 @@
     void write(in PageRange[] pages, in ParcelFileDescriptor fd,
             IWriteResultCallback callback, int sequence);
     void finish();
+    void kill(String reason);
 }
diff --git a/core/java/android/print/PrintManager.java b/core/java/android/print/PrintManager.java
index bf8ac65..3fb812e 100644
--- a/core/java/android/print/PrintManager.java
+++ b/core/java/android/print/PrintManager.java
@@ -634,6 +634,17 @@
         }
 
         @Override
+        public void kill(String reason) {
+            synchronized (mLock) {
+                // If destroyed the handler is null.
+                if (!isDestroyedLocked()) {
+                    mHandler.obtainMessage(MyHandler.MSG_ON_KILL,
+                            reason).sendToTarget();
+                }
+            }
+        }
+
+        @Override
         public void onActivityPaused(Activity activity) {
             /* do nothing */
         }
@@ -719,6 +730,7 @@
             public static final int MSG_ON_LAYOUT = 2;
             public static final int MSG_ON_WRITE = 3;
             public static final int MSG_ON_FINISH = 4;
+            public static final int MSG_ON_KILL = 5;
 
             public MyHandler(Looper looper) {
                 super(looper, null, true);
@@ -794,6 +806,15 @@
                         }
                     } break;
 
+                    case MSG_ON_KILL: {
+                        if (DEBUG) {
+                            Log.i(LOG_TAG, "onKill()");
+                        }
+
+                        String reason = (String) message.obj;
+                        throw new RuntimeException(reason);
+                    }
+
                     default: {
                         throw new IllegalArgumentException("Unknown message: "
                                 + message.what);
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/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/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/OverScroller.java b/core/java/android/widget/OverScroller.java
index 7b3dd31..a40d4f8 100644
--- a/core/java/android/widget/OverScroller.java
+++ b/core/java/android/widget/OverScroller.java
@@ -904,6 +904,10 @@
             final long time = AnimationUtils.currentAnimationTimeMillis();
             final long currentTime = time - mStartTime;
 
+            if (currentTime == 0) {
+                // Skip work but report that we're still going if we have a nonzero duration.
+                return mDuration > 0;
+            }
             if (currentTime > mDuration) {
                 return false;
             }
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/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/util/MemInfoReader.java b/core/java/com/android/internal/util/MemInfoReader.java
index 1dd9464..b71fa06 100644
--- a/core/java/com/android/internal/util/MemInfoReader.java
+++ b/core/java/com/android/internal/util/MemInfoReader.java
@@ -106,4 +106,8 @@
     public long getZramTotalSizeKb() {
         return mInfos[Debug.MEMINFO_ZRAM_TOTAL];
     }
+
+    public long[] getRawInfo() {
+        return mInfos;
+    }
 }
diff --git a/core/java/com/android/internal/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..ed6f1d6 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;
@@ -72,8 +89,17 @@
 
     if (!document) {
         const long error = FPDF_GetLastError();
-        jniThrowException(env, "java/io/IOException",
-                "cannot create document. Error:" + error);
+        switch (error) {
+            case FPDF_ERR_PASSWORD:
+            case FPDF_ERR_SECURITY: {
+                jniThrowException(env, "java/lang/SecurityException",
+                        "cannot create document. Error:" + error);
+            } break;
+            default: {
+                jniThrowException(env, "java/io/IOException",
+                        "cannot create document. Error:" + error);
+            } break;
+        }
         destroyLibraryIfNeeded();
         return -1;
     }
@@ -144,18 +170,201 @@
     }
 }
 
+static void nativeSetTransformAndClip(JNIEnv* env, jclass thiz, jlong documentPtr, jint pageIndex,
+        jlong transformPtr, jint clipLeft, jint clipTop, jint clipRight, jint clipBottom) {
+    FPDF_DOCUMENT document = reinterpret_cast<FPDF_DOCUMENT>(documentPtr);
+
+    CPDF_Page* page = (CPDF_Page*) FPDF_LoadPage(document, pageIndex);
+    if (!page) {
+        jniThrowException(env, "java/lang/IllegalStateException",
+                "cannot open page");
+        return;
+    }
+
+    double width = 0;
+    double height = 0;
+
+    const int result = FPDF_GetPageSizeByIndex(document, pageIndex, &width, &height);
+    if (!result) {
+        jniThrowException(env, "java/lang/IllegalStateException",
+                    "cannot get page size");
+        return;
+    }
+
+    CFX_AffineMatrix matrix;
+
+    SkMatrix* skTransform = reinterpret_cast<SkMatrix*>(transformPtr);
+
+    SkScalar transformValues[6];
+    skTransform->asAffine(transformValues);
+
+    // PDF's coordinate system origin is left-bottom while in graphics it
+    // is the top-left. So, translate the PDF coordinates to ours.
+    matrix.Set(1, 0, 0, -1, 0, page->GetPageHeight());
+
+    // Apply the transformation what was created in our coordinates.
+    matrix.Concat(transformValues[SkMatrix::kAScaleX], transformValues[SkMatrix::kASkewY],
+            transformValues[SkMatrix::kASkewX], transformValues[SkMatrix::kAScaleY],
+            transformValues[SkMatrix::kATransX], transformValues[SkMatrix::kATransY]);
+
+    // Translate the result back to PDF coordinates.
+    matrix.Concat(1, 0, 0, -1, 0, page->GetPageHeight());
+
+    FS_MATRIX transform = {matrix.a, matrix.b, matrix.c, matrix.d, matrix.e, matrix.f};
+    FS_RECTF clip = {(float) clipLeft, (float) clipTop, (float) clipRight, (float) clipBottom};
+
+    FPDFPage_TransFormWithClip(page, &transform, &clip);
+
+    FPDF_ClosePage(page);
+}
+
+static void nativeGetPageSize(JNIEnv* env, jclass thiz, jlong documentPtr,
+        jint pageIndex, jobject outSize) {
+    FPDF_DOCUMENT document = reinterpret_cast<FPDF_DOCUMENT>(documentPtr);
+
+    FPDF_PAGE page = FPDF_LoadPage(document, pageIndex);
+    if (!page) {
+        jniThrowException(env, "java/lang/IllegalStateException",
+                "cannot open page");
+        return;
+    }
+
+    double width = 0;
+    double height = 0;
+
+    const int result = FPDF_GetPageSizeByIndex(document, pageIndex, &width, &height);
+    if (!result) {
+        jniThrowException(env, "java/lang/IllegalStateException",
+                    "cannot get page size");
+        return;
+    }
+
+    env->SetIntField(outSize, gPointClassInfo.x, width);
+    env->SetIntField(outSize, gPointClassInfo.y, height);
+
+    FPDF_ClosePage(page);
+}
+
+static jboolean nativeScaleForPrinting(JNIEnv* env, jclass thiz, jlong documentPtr) {
+    FPDF_DOCUMENT document = reinterpret_cast<FPDF_DOCUMENT>(documentPtr);
+    FPDF_BOOL success = FPDF_VIEWERREF_GetPrintScaling(document);
+    return success ? JNI_TRUE : JNI_FALSE;
+}
+
+static bool nativeGetPageBox(JNIEnv* env, jclass thiz, jlong documentPtr, jint pageIndex,
+        PageBox pageBox, jobject outBox) {
+    FPDF_DOCUMENT document = reinterpret_cast<FPDF_DOCUMENT>(documentPtr);
+
+    FPDF_PAGE page = FPDF_LoadPage(document, pageIndex);
+    if (!page) {
+        jniThrowException(env, "java/lang/IllegalStateException",
+                "cannot open page");
+        return false;
+    }
+
+    float left;
+    float top;
+    float right;
+    float bottom;
+
+    const FPDF_BOOL success = (pageBox == PAGE_BOX_MEDIA)
+        ? FPDFPage_GetMediaBox(page, &left, &top, &right, &bottom)
+        : FPDFPage_GetCropBox(page, &left, &top, &right, &bottom);
+
+    FPDF_ClosePage(page);
+
+    if (!success) {
+        return false;
+    }
+
+    env->SetIntField(outBox, gRectClassInfo.left, (int) left);
+    env->SetIntField(outBox, gRectClassInfo.top, (int) top);
+    env->SetIntField(outBox, gRectClassInfo.right, (int) right);
+    env->SetIntField(outBox, gRectClassInfo.bottom, (int) bottom);
+
+    return true;
+}
+
+static jboolean nativeGetPageMediaBox(JNIEnv* env, jclass thiz, jlong documentPtr, jint pageIndex,
+        jobject outMediaBox) {
+    const bool success = nativeGetPageBox(env, thiz, documentPtr, pageIndex, PAGE_BOX_MEDIA,
+            outMediaBox);
+    return success ? JNI_TRUE : JNI_FALSE;
+}
+
+static jboolean nativeGetPageCropBox(JNIEnv* env, jclass thiz, jlong documentPtr, jint pageIndex,
+        jobject outMediaBox) {
+    const bool success = nativeGetPageBox(env, thiz, documentPtr, pageIndex, PAGE_BOX_CROP,
+         outMediaBox);
+    return success ? JNI_TRUE : JNI_FALSE;
+}
+
+static void nativeSetPageBox(JNIEnv* env, jclass thiz, jlong documentPtr, jint pageIndex,
+        PageBox pageBox, jobject box) {
+    FPDF_DOCUMENT document = reinterpret_cast<FPDF_DOCUMENT>(documentPtr);
+
+    FPDF_PAGE page = FPDF_LoadPage(document, pageIndex);
+    if (!page) {
+        jniThrowException(env, "java/lang/IllegalStateException",
+                "cannot open page");
+        return;
+    }
+
+    const int left = env->GetIntField(box, gRectClassInfo.left);
+    const int top = env->GetIntField(box, gRectClassInfo.top);
+    const int right = env->GetIntField(box, gRectClassInfo.right);
+    const int bottom = env->GetIntField(box, gRectClassInfo.bottom);
+
+    if (pageBox == PAGE_BOX_MEDIA) {
+        FPDFPage_SetMediaBox(page, left, top, right, bottom);
+    } else {
+        FPDFPage_SetCropBox(page, left, top, right, bottom);
+    }
+
+    FPDF_ClosePage(page);
+}
+
+static void nativeSetPageMediaBox(JNIEnv* env, jclass thiz, jlong documentPtr, jint pageIndex,
+        jobject mediaBox) {
+    nativeSetPageBox(env, thiz, documentPtr, pageIndex, PAGE_BOX_MEDIA, mediaBox);
+}
+
+static void nativeSetPageCropBox(JNIEnv* env, jclass thiz, jlong documentPtr, jint pageIndex,
+        jobject mediaBox) {
+    nativeSetPageBox(env, thiz, documentPtr, pageIndex, PAGE_BOX_CROP, mediaBox);
+}
+
 static JNINativeMethod gPdfEditor_Methods[] = {
     {"nativeOpen", "(IJ)J", (void*) nativeOpen},
     {"nativeClose", "(J)V", (void*) nativeClose},
     {"nativeGetPageCount", "(J)I", (void*) nativeGetPageCount},
     {"nativeRemovePage", "(JI)I", (void*) nativeRemovePage},
-    {"nativeWrite", "(JI)V", (void*) nativeWrite}
+    {"nativeWrite", "(JI)V", (void*) nativeWrite},
+    {"nativeSetTransformAndClip", "(JIJIIII)V", (void*) nativeSetTransformAndClip},
+    {"nativeGetPageSize", "(JILandroid/graphics/Point;)V", (void*) nativeGetPageSize},
+    {"nativeScaleForPrinting", "(J)Z", (void*) nativeScaleForPrinting},
+    {"nativeGetPageMediaBox", "(JILandroid/graphics/Rect;)Z", (void*) nativeGetPageMediaBox},
+    {"nativeSetPageMediaBox", "(JILandroid/graphics/Rect;)V", (void*) nativeSetPageMediaBox},
+    {"nativeGetPageCropBox", "(JILandroid/graphics/Rect;)Z", (void*) nativeGetPageCropBox},
+    {"nativeSetPageCropBox", "(JILandroid/graphics/Rect;)V", (void*) nativeSetPageCropBox}
 };
 
 int register_android_graphics_pdf_PdfEditor(JNIEnv* env) {
-    return android::AndroidRuntime::registerNativeMethods(
+    const int result = android::AndroidRuntime::registerNativeMethods(
             env, "android/graphics/pdf/PdfEditor", gPdfEditor_Methods,
             NELEM(gPdfEditor_Methods));
+
+    jclass pointClass = env->FindClass("android/graphics/Point");
+    gPointClassInfo.x = env->GetFieldID(pointClass, "x", "I");
+    gPointClassInfo.y = env->GetFieldID(pointClass, "y", "I");
+
+    jclass rectClass = env->FindClass("android/graphics/Rect");
+    gRectClassInfo.left = env->GetFieldID(rectClass, "left", "I");
+    gRectClassInfo.top = env->GetFieldID(rectClass, "top", "I");
+    gRectClassInfo.right = env->GetFieldID(rectClass, "right", "I");
+    gRectClassInfo.bottom = env->GetFieldID(rectClass, "bottom", "I");
+
+    return result;
 };
 
 };
diff --git a/core/jni/android/graphics/pdf/PdfRenderer.cpp b/core/jni/android/graphics/pdf/PdfRenderer.cpp
index 303ddea..357d3c0 100644
--- a/core/jni/android/graphics/pdf/PdfRenderer.cpp
+++ b/core/jni/android/graphics/pdf/PdfRenderer.cpp
@@ -82,8 +82,17 @@
 
     if (!document) {
         const long error = FPDF_GetLastError();
-        jniThrowException(env, "java/io/IOException",
-                "cannot create document. Error:" + error);
+        switch (error) {
+            case FPDF_ERR_PASSWORD:
+            case FPDF_ERR_SECURITY: {
+                jniThrowException(env, "java/lang/SecurityException",
+                        "cannot create document. Error:" + error);
+            } break;
+            default: {
+                jniThrowException(env, "java/io/IOException",
+                        "cannot create document. Error:" + error);
+            } break;
+        }
         destroyLibraryIfNeeded();
         return -1;
     }
diff --git a/core/jni/android_view_GLES20Canvas.cpp b/core/jni/android_view_GLES20Canvas.cpp
index 2e2b23f..9bdc6b5 100644
--- a/core/jni/android_view_GLES20Canvas.cpp
+++ b/core/jni/android_view_GLES20Canvas.cpp
@@ -43,6 +43,7 @@
 #include <RenderNode.h>
 #include <CanvasProperty.h>
 #include <Paint.h>
+#include <renderthread/RenderProxy.h>
 
 #include "MinikinUtils.h"
 
@@ -861,7 +862,7 @@
 android_app_ActivityThread_dumpGraphics(JNIEnv* env, jobject clazz, jobject javaFileDescriptor) {
 #ifdef USE_OPENGL_RENDERER
     int fd = jniGetFDFromFileDescriptor(env, javaFileDescriptor);
-    android::uirenderer::RenderNode::outputLogBuffer(fd);
+    android::uirenderer::renderthread::RenderProxy::outputLogBuffer(fd);
 #endif // USE_OPENGL_RENDERER
 }
 
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..1534b49 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -586,6 +586,7 @@
             0 - Nothing
             1 - Global actions menu
             2 - Power off (with confirmation)
+            3 - Power off (without confirmation)
     -->
     <integer name="config_longPressOnPowerBehavior">1</integer>
 
@@ -597,6 +598,20 @@
     -->
     <integer name="config_shortPressOnPowerBehavior">1</integer>
 
+    <!-- Control the behavior when the user double presses the power button.
+            0 - Nothing
+            1 - Toggle theater mode setting
+            2 - Brightness boost
+    -->
+    <integer name="config_doublePressOnPowerBehavior">0</integer>
+
+    <!-- Control the behavior when the user triple presses the power button.
+            0 - Nothing
+            1 - Toggle theater mode setting
+            2 - Brightness boost
+    -->
+    <integer name="config_triplePressOnPowerBehavior">0</integer>
+
     <!-- Package name for default keyguard appwidget [DO NOT TRANSLATE] -->
     <string name="widget_default_package_name"></string>
 
@@ -1885,4 +1900,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..3835d8b 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -340,6 +340,7 @@
   <java-symbol type="integer" name="config_bluetooth_max_advertisers" />
   <java-symbol type="integer" name="config_bluetooth_max_scan_filters" />
   <java-symbol type="integer" name="config_cursorWindowSize" />
+  <java-symbol type="integer" name="config_doublePressOnPowerBehavior" />
   <java-symbol type="integer" name="config_extraFreeKbytesAdjust" />
   <java-symbol type="integer" name="config_extraFreeKbytesAbsolute" />
   <java-symbol type="integer" name="config_immersive_mode_confirmation_panic" />
@@ -354,6 +355,7 @@
   <java-symbol type="integer" name="config_ntpTimeout" />
   <java-symbol type="integer" name="config_shortPressOnPowerBehavior" />
   <java-symbol type="integer" name="config_toastDefaultGravity" />
+  <java-symbol type="integer" name="config_triplePressOnPowerBehavior" />
   <java-symbol type="integer" name="config_wifi_framework_scan_interval" />
   <java-symbol type="integer" name="config_wifi_supplicant_scan_interval" />
   <java-symbol type="integer" name="config_wifi_scan_interval_p2p_connected" />
@@ -2094,4 +2096,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/design/wear/patterns.jd b/docs/html/design/wear/patterns.jd
index 30fdc24..e56ac2d 100644
--- a/docs/html/design/wear/patterns.jd
+++ b/docs/html/design/wear/patterns.jd
@@ -76,6 +76,13 @@
 <li>The cue card can be invoked to continue specifying the action. For example in a messaging application, tapping a “Reply” action button invokes the Cue Card and prompts for voice input. In this case the prompt label (such as “Speak your message…”) and a set of sample voice suggestions can be specified by developers.</li>
 </ol>
 
+<a class="notice-developers left" href="{@docRoot}training/wearables/ui/confirm.html">
+  <div>
+    <h3>Developer Docs</h3>
+    <p>Showing Confirmations</p>
+  </div>
+</a>
+
 
 <h2 id="Continuing" style="clear:both">Continuing activities on phone</h2>
 
@@ -100,6 +107,13 @@
 
 <p>Good examples of using an action on card include: play and pause music, toggle light switch on and off, navigate to an address, and call a phone number.</p>
 
+<a class="notice-developers left" href="{@docRoot}training/wearables/ui/cards.html">
+  <div>
+    <h3>Developer Docs</h3>
+    <p>Creating Cards</p>
+  </div>
+</a>
+
 
 <h2 id="Stacks" style="clear:both">Card stacks</h2>
   <img src="{@docRoot}design/media/wear/expandable_stacks.png" width="147" height="147" style="float:right;margin:0 0 20px 40px">
@@ -124,6 +138,13 @@
 
 <p>More information about how to use the 2D Picker pattern is provided in the <a href="{@docRoot}design/wear/structure.html#2DPicker">App Structure</a> guide.</p>
 
+<a class="notice-developers left" href="{@docRoot}training/wearables/ui/2d-picker.html">
+  <div>
+    <h3>Developer Docs</h3>
+    <p>Creating a 2D Picker</p>
+  </div>
+</a>
+
 
 <h2 id="Voice" style="clear:both">Voice commands</h2>
 
@@ -148,3 +169,10 @@
 
 
 <p>Of course, it is possible for Android Wear apps to extend themselves beyond the familiarities of these patterns. For a deeper look at the options available, see the <a href="{@docRoot}design/wear/structure.html">App Structure</a> guide.</p>
+
+<a class="notice-developers left" href="{@docRoot}training/wearables/ui/lists.html">
+  <div>
+    <h3>Developer Docs</h3>
+    <p>Creating Lists</p>
+  </div>
+</a>
diff --git a/docs/html/design/wear/structure.jd b/docs/html/design/wear/structure.jd
index b77ccc2..95d5c1a 100644
--- a/docs/html/design/wear/structure.jd
+++ b/docs/html/design/wear/structure.jd
@@ -84,12 +84,18 @@
 <img src="{@docRoot}design/media/wear/1D_picker.png" alt="" width="499px" />
 <p class="img-caption">This pattern can be used to present a single vertical list, or a “1D Picker”</p>
 
-<img src="{@docRoot}design/media/wear/2D_picker.png" alt="" width:760px" />
+<img src="{@docRoot}design/media/wear/2D_picker.png" alt="" width="760px" />
 <p class="img-caption">It can also be used as a 2D matrix of options, as a way of presenting categorized options.</p>
 
 
 
 <h3>Actions</h3>
+<a class="notice-developers" style="clear:none" href="{@docRoot}training/wearables/ui/2d-picker.html">
+  <div>
+    <h3>Developer Docs</h3>
+    <p>Creating a 2D Picker</p>
+  </div>
+</a>
 <p>For actions on each card, use the <a href="{@docRoot}design/wear/patterns.html#Actions">Action cards pattern</a>.</p>
 
 <h3>Making it fast</h3>
@@ -155,6 +161,6 @@
 <h3>Manually exiting</h3>
 
 <p>Even with logical exit points like these, some cases may exist where the user may want to immediately exit. This may be common in apps that are used for a longer while. In all cases, you should treat long-press as the user's intent to exit, using
-<a href="{@docRoot}training/wearables/apps/layouts.html#UiLibrary"><code>DismissOverlayView</code></a>.</p>
+<a href="{@docRoot}training/wearables/ui/exit.html"><code>DismissOverlayView</code></a>.</p>
 
 
diff --git a/docs/html/distribute/tools/promote/badges.jd b/docs/html/distribute/tools/promote/badges.jd
index 4bea8be..eb09333 100644
--- a/docs/html/distribute/tools/promote/badges.jd
+++ b/docs/html/distribute/tools/promote/badges.jd
@@ -66,7 +66,7 @@
 var APP_LANGS = ['it','pt-br','pt-pt','nl','ko','ja','fr','es','es-419','en','de'];
 
 // variables for creating 'try it out' demo button
-var imagePath = "{@docRoot}images/brand/"
+var imagePath = "https://developer.android.com/images/brand/"
 var linkStart = "<a href=\"https://play.google.com/store/";
 var imageStart = "\">\n"
         + "  <img alt=\"";
@@ -99,7 +99,7 @@
     $("#button-preview").html(linkStart + "apps/details?id=" + packageName
             + imageStart + altText + imageSrc
             + selectedValue + imageEnd);
-            
+
     // Send the event to Analytics
     ga('send', 'event', 'Distribute', 'Create Google Play Badge', 'Package ' + selectedValue);
   } else if (form["publisher"].value != "Example, Inc.") {
@@ -111,7 +111,7 @@
     $("#button-preview").html(linkStart + "search?q=pub:" + publisherName
             + imageStart + altText + imageSrc
             + selectedValue + imageEnd);
-   
+
     // Send the event to Analytics
     ga('send', 'event', 'Distribute', 'Create Google Play Badge', 'Publisher ' + selectedValue);
   } else {
@@ -159,7 +159,7 @@
 /** Switch the badge urls for selected language */
 function changeBadgeLang() {
   var lang = $('#locale option:selected').val();
-  
+
   // check if we have the 'app' badge for this lang and show notice if not
   $("div.button-row.error").remove();  // remove any existing instance of error message
   if ($.inArray(lang,APP_LANGS) == -1) {
@@ -173,7 +173,7 @@
   } else {
     $("div.button-row.app").show(); // show the 'app' badge row
   }
-  
+
   $('.button-row img').each(function() {
     var id = $(this).parent().attr('for');
     var imgName = lang + $('input#'+id).attr('value') + '.png';
@@ -356,7 +356,7 @@
 style="font-family:monospace;background-color:#efefef;padding:5px;display:none;margin-bottom:1em">
   </textarea >
 
-<p>Try it out:</p>
+<p>Test your badge:</p>
 <div id="button-preview" style="margin-top:1em"></div>
 </div>
 
diff --git a/docs/html/images/tools/studio-build-variant.png b/docs/html/images/tools/studio-build-variant.png
new file mode 100644
index 0000000..a400ad4
--- /dev/null
+++ b/docs/html/images/tools/studio-build-variant.png
Binary files differ
diff --git a/docs/html/images/ui/notifications/heads-up.png b/docs/html/images/ui/notifications/heads-up.png
index 42fbbcd..75cc95e 100644
--- a/docs/html/images/ui/notifications/heads-up.png
+++ b/docs/html/images/ui/notifications/heads-up.png
Binary files differ
diff --git a/docs/html/sdk/installing/adding-packages.jd b/docs/html/sdk/installing/adding-packages.jd
index 22d055c..b8d8925 100644
--- a/docs/html/sdk/installing/adding-packages.jd
+++ b/docs/html/sdk/installing/adding-packages.jd
@@ -1,6 +1,6 @@
 page.title=Adding SDK Packages
 
-page.tags=studio, sdk tools, eclipse adt, sdk manager, google play services, support library
+page.tags=sdk manager
 helpoutsWidget=true
 
 @jd:body
diff --git a/docs/html/sdk/installing/index.jd b/docs/html/sdk/installing/index.jd
index 6a99952..68f4eb7 100644
--- a/docs/html/sdk/installing/index.jd
+++ b/docs/html/sdk/installing/index.jd
@@ -1,6 +1,6 @@
 page.title=Installing the Android SDK
 
-page.tags=studio, sdk tools, eclipse adt
+page.tags=sdk tools
 helpoutsWidget=true
 
 @jd:body
@@ -74,9 +74,9 @@
 <!-- ################    STUDIO    ##################### -->
 <div id="studio" heading="Installing Android Studio" style="display:none">
 
-<p>Android Studio provides everything you need to start developing apps, including
-the Android SDK tools and the Android Studio IDE (powered by IntelliJ) to
-streamline your Android app development.</p>
+<p>Android Studio provides the tools you need to start developing apps, including
+the Android Studio IDE (powered by IntelliJ) and guides you to install
+the Android SDK tools to streamline your Android app development.</p>
 
 <p>If you didn't download Android Studio, go <a href="{@docRoot}sdk/installing/studio.html"
 ><b>download Android Studio now</b></a>, or switch to the
@@ -103,8 +103,9 @@
 
 <p><b>To set up Android Studio on Windows:</b></p>
   <ol>
-    <li>Launch the downloaded EXE file, {@code android-studio-bundle-&lt;version&gt;.exe}.</li>
-    <li>Follow the setup wizard to install Android Studio.
+    <li>Unzip the file, {@code android-studio-ide-&lt;version&gt;-windows.zip} and launch the
+        <code>studio.exe</code> file.</li>
+    <li>Follow the setup wizard to install Android Studio and the SDK Tools.
 
     <p>On some Windows systems, the launcher script does not find where Java is installed.
       If you encounter this problem,
@@ -119,11 +120,10 @@
   </ol>
 
 
-<p>The individual tools and
-other SDK packages are saved within the Android Studio application directory.
-If you need to access the tools directly, use a terminal to navigate into the application and locate
-the {@code sdk/} directory. For example:</p>
-<p><code>\Users\&lt;user&gt;\AppData\Local\Android\android-studio\sdk\</code></p>
+<p>The individual tools and other SDK packages are saved outside the Android Studio application
+directory. If you need to access the tools directly, use a terminal to navigate to the location
+where they are installed. For example:</p>
+<p><code>\Users\&lt;user&gt;\sdk\</code></p>
 
 
 
@@ -134,7 +134,7 @@
 
 <p><b>To set up Android Studio on Mac OSX:</b></p>
   <ol>
-    <li>Open the downloaded DMG file, {@code android-studio-bundle-&lt;version&gt;.dmg}.</li>
+    <li>Unzip the downloaded zip file, {@code android-studio-ide-&lt;version&gt;-mac.zip}.</li>
     <li>Drag and drop Android Studio into the Applications folder.
       <p>
       Depending on your security settings, when you attempt to open Android Studio, you might
@@ -143,13 +143,13 @@
       <strong>Allow applications downloaded from</strong>, select <strong>Anywhere</strong>.
       Then open Android Studio again.</p>
     </li>
+    <li>Follow the links to install the SDK outside of the Android Studio directories.</li>
   </ol>
 
-<p>The individual tools and
-other SDK packages are saved within the Android Studio application directory.
-If you need access the tools directly, use a terminal to navigate into the application and locate
-the {@code sdk/} directory. For example:</p>
-<p><code>/Applications/Android\ Studio.app/sdk/</code></p>
+<p>The individual tools and other SDK packages are saved outside the Android Studio application
+directory. If you need access the tools directly, use a terminal to navigate into the location
+where they are installed. For example:</p>
+<p><code>/Applications/sdk/</code></p>
 
 
 </div><!-- end mac -->
@@ -160,13 +160,14 @@
 <p><b>To set up Android Studio on Linux:</b></p>
 
   <ol>
-    <li>Unpack the downloaded Tar file, {@code android-studio-bundle-&lt;version&gt;.tgz}, into an appropriate
-    location for your applications.
+    <li>Unpack the downloaded Tar file, {@code android-studio-ide-&lt;version&gt;-linux.zip}, into an 
+        appropriate location for your applications.
     <li>To launch Android Studio, navigate to the {@code android-studio/bin/} directory
     in a terminal and execute {@code studio.sh}.
       <p>You may want to add {@code android-studio/bin/} to your PATH environmental
       variable so that you can start Android Studio from any directory.</p>
     </li>
+    <li>Follow the links to install the SDK outside of the Android Studio directories.</li>
   </ol>
 
 </div><!-- end linux -->
@@ -217,11 +218,12 @@
 
 <p>Your download package is an executable file that starts an installer. The installer checks your machine
   for required tools, such as the proper Java SE Development Kit (JDK) and installs it if necessary.
-  The installer then saves the Android SDK Tools into a default location (or you can specify the location).</p>
+  The installer then saves the Android SDK Tools to a specified the location outside of the Android
+  Studio directories.</p>
 
 <ol>
 <li>Double-click the executable ({@code .exe} file) to start the install.</li>
-<li>Make a note of the name and location in which it saves the SDK on your system&mdash;you will need to
+<li>Make a note of the name and location where you save the SDK on your system&mdash;you will need to
 refer to the SDK directory later when using
 the SDK tools from the command line.</li>
 <li>Once the installation completes, the installer starts the Android SDK Manager.
@@ -237,8 +239,8 @@
 <p><b>To get started on Mac OSX:</b></p>
 
 <p>Unpack the ZIP file you've downloaded. By default, it's unpacked
-into a directory named <code>android-sdk-mac_x86</code>. Move it to an appropriate location on your machine,
-such as a "Development" directory in your home directory.</p>
+into a directory named <code>android-sdk-mac_x86</code>. Move it to an appropriate location on your 
+machine, such as a "Development" directory in your home directory.</p>
 
 <p>Make a note of the name and location of the SDK directory on your system&mdash;you will need to
 refer to the SDK directory later when using
@@ -253,9 +255,8 @@
 
 <p><b>To get started on Linux:</b></p>
 
-<p>Unpack the {@code .tgz} file you've downloaded. By default, the SDK files are unpacked
-into a directory named <code>android-sdk-linux_x86</code>. Move it to an appropriate location on your machine,
-such as a "Development" directory in your home directory.</p>
+<p>Unpack the {@code .zip} file you've downloaded. The SDK files are download separately to a 
+user-specified directory. </p>
 
 <p>Make a note of the name and location of the SDK directory on your system&mdash;you will need to
 refer to the SDK directory later when using
diff --git a/docs/html/sdk/installing/studio.jd b/docs/html/sdk/installing/studio.jd
index b0567e7..6991dea 100644
--- a/docs/html/sdk/installing/studio.jd
+++ b/docs/html/sdk/installing/studio.jd
@@ -194,12 +194,12 @@
 href="" style="display:none;width:368px;margin:0 auto;display:block;font-size:18px" ></a>
 <div style="margin:20px 0 0 0">
 
-<p style="margin-bottom:8px">This download includes:</p>
+<p style="margin-bottom:8px">This installation includes:</p>
 <ul style="margin-bottom:20px">
-<li>Android Studio Beta</li>
-<li>All the Android SDK Tools to design, test, and debug your app</li>
-<li>A version of the Android platform to compile your app</li>
-<li>A version of the Android system image to run your app in the emulator</li>
+  <li>Android Studio Beta</li>
+  <li>All the Android SDK Tools to design, test, and debug your app</li>
+  <li>A version of the Android platform to compile your app</li>
+  <li>A version of the Android system image to run your app in the emulator</li>
 </ul>
 
 </div>
@@ -244,43 +244,41 @@
       <th>Platform</th>
       <th>Package</th>
       <th>Size</th>
-      <th>MD5 Checksum</th>
+      <th>SHA Sum</th>
   </tr>
 
   <tr>
     <td>Windows</td>
     <td>
   <a onclick="return onDownload(this)" id="win-studio"
-      href="https://dl.google.com/android/studio/install/0.8.6/android-studio-bundle-135.1339820-windows.exe">
-      android-studio-bundle-135.1339820-windows.exe
+      href="https://dl.google.com/dl/android/studio/ide-zips/0.8.14/android-studio-ide-135.1538390-windows.zip">android-studio-ide-135.1538390-windows.zip
       </a>
     </td>
-    <td>379497130 bytes</td>
-    <td>024e002b8c8fa7dcd2ff69fd69e06e56</td>
+    <td>177343814 bytes</td>
+    <td>b533480200ba893616c73b32477e66ebb357a1b3</td>
   </tr>
 
   <tr>
     <td><nobr>Mac OS X</nobr></td>
     <td>
   <a onclick="return onDownload(this)" id="mac-studio"
-    href="https://dl.google.com/android/studio/install/0.8.6/android-studio-bundle-135.1339820-mac.dmg">
-    android-studio-bundle-135.1339820-mac.dmg
+    href="https://dl.google.com/dl/android/studio/ide-zips/0.8.14/android-studio-ide-135.1538390-mac.zip">
+    android-studio-ide-135.1538390-mac.zip
     </a>
     </td>
-    <td>368507143 bytes</td>
-    <td>4143f2aa556634eae91701965d88899b</td>
+    <td>176745627 bytes</td>
+    <td>4070e6f6a44d042266f46f1f2f9ca3448ac23f8cd</td>
   </tr>
 
   <tr>
     <td>Linux</td>
     <td>
   <a onclick="return onDownload(this)" id="linux-studio"
-    href="https://dl.google.com/android/studio/install/0.8.6/android-studio-bundle-135.1339820-linux.tgz">
-    android-studio-bundle-135.1339820-linux.tgz
+    href="https://dl.google.com/dl/android/studio/ide-zips/0.8.14/android-studio-ide-135.1538390-linux.zip">android-studio-ide-135.1538390-linux.zip
     </a>
     </td>
-    <td>417631443 bytes</td>
-    <td>fa403762ecd0a5da87acbeff485f81cc</td>
+    <td>176358193 bytes</td>
+    <td>718356b49254f6c4e55c64b99164d311995205dd</td>
   </tr>
   </table>
 
@@ -301,44 +299,48 @@
 <tr>
 <td>
 <ul>
-  <li>Microsoft Windows 8, 7, Vista, 2003, or XP (32 or 64 bit)</li>
-  <li>1 GB of RAM minimum, 2 GB recommended</li>
-  <li>400 MB of disk space</li>
-  <li>At least 1 GB of additional disk space for the Android SDK, emulator system images, and caches</li>
+  <li>Microsoft Windows 8/7/Vista/2003 (32 or 64 bit)</li>
+  <li>2 GB RAM minimum, 4 GB RAM recommended</li>
+  <li>400 MB disk space </li>
+  <li>At least 1 GB for Android SDK, emulator system images, and caches</li>
   <li>1280x800 minimum screen resolution</li>
-  <li>Java Development Kit (JDK) 6 or higher</li>
+  <li>Java Development Kit (JDK) 7 or higher</li>
+  <li>(Optional for accelerated emulator: Intel processor with support for Intel VT-x, Intel
+   EM64T (Intel 64), and Execute Disable (XD) Bit functionality)</li>
 </ul>
 </td>
 <td>
 <ul>
   <li>Mac OS X 10.8.5 or higher, up to 10.9 (Mavericks)</li>
-  <li>1 GB of RAM minimum, 2 GB recommended</li>
-  <li>400 MB of disk space</li>
-  <li>At least 1 GB of additional disk space for the Android SDK, emulator system images, and caches</li>
+  <li>2 GB RAM minimum, 4 GB RAM recommended</li>
+  <li>400 MB disk space</li>
+  <li>At least 1 GB for Android SDK, emulator system images, and caches</li>
   <li>1280x800 minimum screen resolution</li>
-  <li>Java Runtime Environment (JRE) 6 *</li>
-  <li>Java Development Kit (JDK) 6 or JDK 7</li>
+  <li>Java Runtime Environment (JRE) 6</li>
+  <li>Java Development Kit (JDK) 7 or higher
+    <p>On Mac OS, run Android Studio with Java Runtime Environment (JRE) 6 for optimized font
+    rendering. You can then configure your project to use Java Development Kit (JDK) JDK 7.</p></li>
+  <li>(Optional for accelerated emulator: Intel processor with support for Intel VT-x, Intel
+    EM64T (Intel 64), and Execute Disable (XD) Bit functionality)</li>
 </ul>
-<p>* On Mac OS, run Android Studio with Java Runtime Environment (JRE) 6 for optimized font
-rendering. You can then configure your project to use Java Development Kit (JDK) 6 or JDK 7.</p>
+
 </td>
 <td>
 <ul>
-  <li>64-bit distribution capable of running 32-bit applications</li>
+  <li>GNOME or KDE desktop.</li>
+  <li>Tested on Ubuntu 12.04, Precise Pangolin (64-bit distribution capable of running 32-bit
+      applications)</li>
   <li>GNU C Library (glibc) 2.11 or later is required.</li>
-  <li>Tested on Ubuntu 12.04, Precise Pangolin</li>
-  <li>GNOME or KDE desktop</li>
-  <li>1 GB of RAM minimum, 2 GB recommended</li>
-  <li>400 MB of disk space</li>
-  <li>At least 1 GB of additional disk space for the Android SDK, emulator system images, and caches</li>
+  <li>2 GB RAM minimum, 4 GB RAM recommended</li>
+  <li>400 MB disk space</li>
+  <li>At least 1 GB for Android SDK, emulator system images, and caches</li>
   <li>1280x800 minimum screen resolution</li>
-  <li>Oracle Java Development Kit (JDK) 6 or JDK 7</li>
+  <li>Java Development Kit (JDK) 7 or higher</li>
 </ul>
 </td>
 </tr>
 </table>
-<p class="note"><strong>Note:</strong> Java Development Kit (JDK) 7 is required if you're targeting
-the Android L Developer Preview.</p>
+<p class="note"><strong>Note:</strong> The full SDK/NDK requires 13 GB of disk space.</p>
 </div><!-- end pax -->
 
 
@@ -425,7 +427,7 @@
 <p><strong>Caution:</strong> Replacing your existing installation of
 Android Studio will remove any additional SDK packages you've installed, such as target
 platforms, system images, and sample apps. To preserve these, copy them from your current
-SDK directory under Android Studio to a temporary location
+SDK directory to a temporary location
 before installing the update. Then move them back once the update is complete.
 If you fail to copy these packages, then you can instead download them again through
 the Android SDK Manager.</p>
@@ -453,6 +455,17 @@
 <div class="toggle-content opened">
   <p><a href="#" onclick="return toggleContent(this)">
     <img src="{@docRoot}assets/images/triangle-opened.png" class="toggle-content-img"
+      alt=""/>Android Studio v0.8.14</a> <em>(October 2014)</em>
+  </p>
+
+  <div class="toggle-content-toggleme">
+    <p>See <a href="http://tools.android.com/recent">tools.android.com</a> for a full list of changes.</p>
+  </div>
+</div>
+
+<div class="toggle-content closed">
+  <p><a href="#" onclick="return toggleContent(this)">
+    <img src="{@docRoot}assets/images/triangle-closed.png" class="toggle-content-img"
       alt=""/>Android Studio v0.8.6</a> <em>(August 2014)</em>
   </p>
 
@@ -650,7 +663,7 @@
   if (os) {
     /* set up primary ACE download button */
     $('#download-ide-button').show();
-    $('#download-ide-button').append("Download Android Studio Beta <span class='small'>v0.8.6</span>"
+    $('#download-ide-button').append("Download Android Studio Beta <span class='small'>v0.8.14</span>"
         + "<br/> <span class='small'>with the Android SDK for " + os + "</span>");
     $('#download-ide-button').click(function() {return onDownload(this,true);}).attr('href', bundlename);
 
diff --git a/docs/html/tools/building/multidex.jd b/docs/html/tools/building/multidex.jd
new file mode 100644
index 0000000..49cde8c
--- /dev/null
+++ b/docs/html/tools/building/multidex.jd
@@ -0,0 +1,458 @@
+page.title=Building Apps with Over 65K Methods
+page.tags="65536","references","max","65k","dex","64k","multidex","multi-dex","methods"</p>
+
+@jd:body
+
+<div id="qv-wrapper">
+  <div id="qv">
+    <h2>In this document</h2>
+    <ol>
+      <li><a href="#about">
+        About the 65K Reference Limit</a>
+        <ol>
+          <li><a href="#mdex-pre-l">Multidex support prior to Android 5.0</a></li>
+          <li><a href="#mdex-on-l">Multidex support for Android 5.0 and higher</a></li>
+        </ol>
+      </li>
+      <li><a href="#avoid">
+        Avoiding the 65K Limit</a></li>
+      <li><a href="#mdex-gradle">
+        Configuring Your App for Multidex with Gradle</a>
+        <ol>
+          <li><a href="#limitations">
+            Limitations of the multidex support library</a></li>
+        </ol>
+      </li>
+      <li><a href="#dev-build">
+        Optimizing Multidex Development Builds</a>
+        <ol>
+          <li><a href="#variants-studio">
+            Using Build Variants in Android Studio</a></li>
+        </ol>
+      </li>
+      <li><a href="#testing">
+        Testing Multidex Apps</a></li>
+    </ol>
+
+    <h2>See Also</h2>
+    <ol>
+      <li><a href="{@docRoot}tools/help/proguard.html">ProGuard</a>
+      </li>
+    </ol>
+  </div>
+</div>
+
+
+<p>
+  As the Android platform has continued to grow, so has the size of Android apps. When your
+  application and the libraries it references reach a certain size, you encounter build errors that
+  indicate your app has reached a limit of the Android app build architecture. Earlier versions of
+  the build system report this error as follows:
+</p>
+
+<pre>
+Conversion to Dalvik format failed:
+Unable to execute dex: method ID not in [0, 0xffff]: 65536
+</pre>
+
+<p>
+  More recent versions of the Android build system display a different error, which is an
+  indication of the same problem:
+</p>
+
+<pre>
+trouble writing output:
+Too many field references: 131000; max is 65536.
+You may try using --multi-dex option.
+</pre>
+
+<p>
+  Both these error conditions display a common number: 65,536. This number is significant in that
+  it represents the total number of references that can be invoked by the code within a single
+  Dalvik Executable (dex) bytecode file. If you have built an Android app and received this error,
+  then congratulations, you have a lot of code! This document explains how to move past this
+  limitation and continue building your app.
+</p>
+
+<p class="note">
+  <strong>Note:</strong> The guidance provided in this document supersedes the guidance given in
+  the Android Developers blog post <a href=
+  "http://android-developers.blogspot.com/2011/07/custom-class-loading-in-dalvik.html">Custom Class
+  Loading in Dalvik</a>.
+</p>
+
+
+<h2 id="about">About the 65K Reference Limit</h2>
+
+<p>
+  Android application (APK) files contain executable bytecode files in the form of <a href=
+  "https://source.android.com/devices/tech/dalvik/">Dalvik</a> Executable (DEX) files, which
+  contain the compiled code used to run your app. The Dalvik Executable specification limits the
+  total number of methods that can be referenced within a single DEX file to 65,536, including
+  Android framework methods, library methods, and methods in your own code. Getting past this limit
+  requires that you configure your app build process to generate more than one DEX file, known as a
+  <em>multidex</em> configuration.
+</p>
+
+
+<h3 id="mdex-pre-l">Multidex support prior to Android 5.0</h3>
+
+<p>
+  Versions of the platform prior to Android 5.0 use the Dalvik runtime for executing app code. By
+  default, Dalvik limits apps to a single classes.dex bytecode file per APK. In order to get around
+  this limitation, you can use the <a href="{@docRoot}tools/support-library/features.html#multidex">
+  multidex support library</a>, which becomes part of the primary DEX file of your app and then
+  manages access to the additional DEX files and the code they contain.
+</p>
+
+
+<h3 id="mdex-on-l">Multidex support for Android 5.0 and higher</h3>
+
+<p>
+  Android 5.0 and higher uses a runtime called ART which natively supports loading multiple dex
+  files from application APK files. ART performs pre-compilation at application install time which
+  scans for classes(..N).dex files and compiles them into a single .oat file for execution by the
+  Android device. For more information on the Android 5.0 runtime, see <a href=
+  "https://source.android.com/devices/tech/dalvik/art.html">Introducing ART</a>.
+</p>
+
+
+<h2 id="avoid">Avoiding the 65K Limit</h2>
+
+<p>
+  Before configuring your app to enable use of 65K or more method references, you should take steps
+  to reduce the total number of references called by your app code, including methods defined by
+  your app code or included libraries. The following strategies can help you avoid hitting the dex
+  reference limit:
+</p>
+
+<ul>
+  <li>
+    <strong>Review your app's direct and transitive dependencies</strong> - Ensure any large library
+    dependency you include in your app is used in a manner that outweighs the amount of code
+    being added to the application. A common anti-pattern is to include a very large library
+    because a few utility methods were useful. Reducing your app code dependencies can often help
+    you avoid the dex reference limit.
+  </li>
+  <li>
+    <strong>Remove unused code with ProGuard</strong> - Configure the <a href=
+    "{@docRoot}tools/help/proguard.html">ProGuard</a> settings for your app to run ProGuard and
+    ensure you have shrinking enabled for release builds. Enabling shrinking ensures you
+    are not shipping unused code with your APKs.
+  </li>
+</ul>
+
+
+<p>
+  Using these techniques can help you avoid the build configuration changes required to enable more
+  method references in your app. These steps can also decrease the size of your APKs, which is
+  particularly important for markets where bandwidth costs are high.
+</p>
+
+
+<h2 id="mdex-gradle">Configuring Your App for Multidex with Gradle</h2>
+
+<p>
+  The Android plugin for Gradle available in Android SDK Build Tools 21.1 and higher supports
+  multidex as part of your build configuration. Make sure you update the Android SDK Build Tools
+  tools and the Android Support Repository to the latest version using the <a href=
+  "{@docRoot}tools/help/sdk-manager.html">SDK Manager</a> before attempting to configure your app
+  for multidex.
+</p>
+
+<p>
+  Setting up your app development project to use a multidex configuration requires that you make a
+  few modifications to your app development project. In particular you need to perform the
+  following steps:
+</p>
+
+<ul>
+  <li>Change your Gradle build configuration to enable multidex</li>
+  <li>Modify your manifest to reference the {@link android.support.multidex.MultiDexApplication}
+    class</li>
+</ul>
+
+<p>
+  Modify your app Gradle build file configuration to include the support library and enable
+  multidex output, as shown in the following Gradle build file snippet:
+</p>
+
+<pre>
+android {
+    compileSdkVersion 21
+    buildToolsVersion "21.1.0"
+
+    defaultConfig {
+        ...
+        minSdkVersion 14
+        targetSdkVersion 21
+        ...
+
+        // Enabling multidex support.
+        multiDexEnabled true
+    }
+    ...
+}
+
+dependencies {
+  compile 'com.android.support:multidex:1.0.0'
+}
+</pre>
+
+<p class="note">
+  <strong>Note:</strong> You can specify the <code>multiDexEnabled</code> setting in the
+  <code>defaultConfig,</code> <code>buildType</code>, or <code>productFlavor</code> sections of
+  your Gradle build file.
+</p>
+
+
+<p>
+  In your manifest add the {@link android.support.multidex.MultiDexApplication} class from the
+  multidex support library to the application element.
+</p>
+
+<pre>
+&lt;?xml version="1.0" encoding="utf-8"?&gt;
+&lt;manifest xmlns:android="http://schemas.android.com/apk/res/android"
+    package="com.example.android.multidex.myapplication"&gt;
+    &lt;application
+        ...
+        android:name="android.support.multidex.MultiDexApplication"&gt;
+        ...
+    &lt;/application&gt;
+&lt;/manifest&gt;
+</pre>
+
+<p>
+  When these configuration settings are added to an app, the Android build tools construct a
+  primary dex (classes.dex) and supporting (classes2.dex, classes3.dex) as needed. The build system
+  will then package them into an APK file for distribution.
+</p>
+
+<p class="note">
+  <strong>Note:</strong> If your app uses extends the {@link android.app.Application} class, you
+  can override the attachBaseContext() method and call MultiDex.install(this) to enable multidex.
+  For more information, see the {@link android.support.multidex.MultiDexApplication} reference
+  documentation.
+</p>
+
+<h3 id="limitations">Limitations of the multidex support library</h3>
+
+<p>
+  The multidex support library has some known limitations that you should be aware of and test for
+  when you incorporate it into your app build configuration:
+</p>
+
+<ul>
+  <li>The installation of .dex files during startup onto a device's data partition is complex and
+  can result in Application Not Responding (ANR) errors if the secondary dex files are large. In
+  this case, you should apply code shrinking techniques with ProGuard to minimize the size of dex
+  files and remove unused portions of code.
+  </li>
+
+  <li>Applications that use multidex may not start on devices that run versions of the platform
+  earlier than Android 4.0 (API level 14) due to a Dalvik linearAlloc bug (Issue <a href=
+  "http://b.android.com/22586">22586</a>). If you are targeting API levels earlier than 14, make
+  sure to perform testing with these versions of the platform as your application can have issues
+  at startup or when particular groups of classes are loaded. Code shrinking can reduce or possibly
+  eliminate these potential issues.
+  </li>
+
+  <li>Applications using a multidex configuration that make very large memory allocation
+  requests may crash during run time due to a Dalvik linearAlloc limit (Issue <a href=
+  "http://b.android.com/78035">78035</a>). The allocation limit was increased in Android 4.0 (API
+  level 14), but apps may still run into this limit on Android versions prior to
+  Android 5.0 (API level 21).
+  </li>
+
+  <li>There are complex requirements regarding what classes are needed in the primary dex file when
+  executing in the Dalvik runtime. The Android build tooling updates handle the Android
+  requirements, but it is possible that other included libraries have additional dependency
+  requirements including the use of introspection or invocation of Java methods from native code.
+  Some libraries may not be able to be used until the multidex build tools are updated to allow you
+  to specify classes that must be included in the primary dex file.
+  </li>
+</ul>
+
+
+<h2 id="dev-build">Optimizing Multidex Development Builds</h2>
+
+<p>
+  A multidex configuration requires significantly increased build processing time because the build
+  system must make complex decisions about what classes must be included in the primary DEX file
+  and what classes can be included in secondary DEX files. This means that routine builds performed
+  as part of the development process with multidex typically take longer and can potentially slow
+  your development process.
+</p>
+
+<p>
+  In order to mitigate the typically longer build times for multidex output, you should create two
+  variations on your build output using the Android plugin for Gradle
+  <a href="http://tools.android.com/tech-docs/new-build-system/user-guide#TOC-Product-flavors">
+  {@code productFlavors}</a>: a development flavor and a production flavor.
+</p>
+
+<p>
+  For the development flavor, set a minimum SDK version of 21. This setting generates multidex
+  output much faster using the ART-supported format. For the release flavor, set a minimum SDK
+  version which matches your actual minimum support level. This setting generates a multidex APK
+  that is compatible with more devices, but takes longer to build.
+</p>
+
+<p>
+  The following build configuration sample demonstrates the how to set up these flavors in a Gradle
+  build file:
+</p>
+
+<pre>
+android {
+    productFlavors {
+        // Define separate dev and prod product flavors.
+        dev {
+            // dev utilizes minSDKVersion = 21 to allow the Android gradle plugin
+            // to pre-dex each module and produce an APK that can be tested on
+            // Android Lollipop without time consuming dex merging processes.
+            minSdkVersion 21
+        }
+        prod {
+            // The actual minSdkVersion for the application.
+            minSdkVersion 14
+        }
+    }
+          ...
+    buildTypes {
+        release {
+            runProguard true
+            proguardFiles getDefaultProguardFile('proguard-android.txt'),
+                                                 'proguard-rules.pro'
+        }
+    }
+}
+dependencies {
+  compile 'com.android.support:multidex:1.0.0'
+}
+</pre>
+
+<p>
+  After you have completed this configuration change, you can use the <code>devDebug</code> variant
+  of your app, which combines the attributes of the <code>dev</code> productFlavor and the
+  <code>debug</code> buildType. Using this target creates a debug app with proguard disabled,
+  multidex enabled, and minSdkVersion set to Android API level 21. These settings cause the Android
+  gradle plugin to do the following:
+</p>
+
+<ol>
+  <li>Build each module of the application (including dependencies) as separate dex files. This is
+  commonly referred to as pre-dexing.
+  </li>
+
+  <li>Include each dex file in the APK without modification.
+  </li>
+
+  <li>Most importantly, the module dex files will not be combined, and so the long-running
+  calculation to determine the contents of the primary dex file is avoided.
+  </li>
+</ol>
+
+<p>
+  These settings result in fast, incremental builds, because only the dex files of modified modules
+  are recomputed and repackaged into the APK file. The APK that results from these builds can be
+  used to test on Android 5.0 devices only. However, by implementing the configuration as a flavor,
+  you preserve the ability to perform normal builds with the release-appropriate minimum SDK level
+  and proguard settings.
+</p>
+
+<p>
+  You can also build the other variants, including a <code>prodDebug</code> variant
+  build, which takes longer to build, but can be used for testing outside of development.
+  Within the configuration shown, the <code>prodRelease</code> variant would be the final testing
+  and release version. If you are executing gradle tasks from the command line, you can use
+  standard commands with <code>DevDebug</code> appended to the end (such as <code>./gradlew
+  installDevDebug</code>). For more information about using flavors with Gradle tasks, see the
+  <a href="http://tools.android.com/tech-docs/new-build-system/user-guide">Gradle Plugin User
+  Guide</a>.
+</p>
+
+<p>
+  <strong>Tip:</strong> You can also provide a custom manifest, or a custom application class for each
+  flavor, allowing you to use the support library MultiDexApplication class, or calling
+  MultiDex.install() only for the variants that need it.
+</p>
+
+
+<h3 id="variants-studio">Using Build Variants in Android Studio</h3>
+
+<p>
+  Build variants can be very useful for managing the build process when using multidex. Android
+  Studio allows you to select these build variants in the user interface.
+</p>
+
+<p>
+  To have Android Studio build the "devDebug" variant of your app:
+</p>
+
+<ol>
+  <li>Open the <em>Build Variants</em> window from the left-sidebar. The option is located next to
+  <em>Favorites</em>.
+  </li>
+
+  <li>Click the name of the build variant to select a different variant, as shown in Figure 1.
+  </li>
+</ol>
+
+<img src="{@docRoot}images/tools/studio-build-variant.png" alt="" height="XXX" id="figure1">
+<p class="img-caption">
+  <strong>Figure 1.</strong> Screen shot of the Android Studio left panel showing a build variant.
+</p>
+
+<p class="note">
+  <strong>Note</strong>: The option to open this window is only available after you have
+  successfully synchronized Android Studio with your Gradle build file using the <strong>Tools &gt;
+  Android &gt; Sync Project with Gradle Files</strong> command.
+</p>
+
+
+<h2 id="testing">Testing Multidex Apps</h2>
+
+<p>
+  Testing apps that use multidex configuration require some additional steps and configuration.
+  Since the location of code for classes is not within a single DEX file, instrumentation tests do
+  not run properly unless configured for multidex.
+</p>
+
+<p>
+  When testing a multidex app with instrumentation tests, use
+  <a href="{@docRoot}reference/com/android/test/runner/MultiDexTestRunner.html">
+  MultiDexTestRunner</a> from the multidex testing support library. The following sample
+  {@code build.gradle} file, demonstrates how to configure your build to use this test runner:
+</p>
+
+<pre>
+android {
+  defaultConfig {
+      ...
+      testInstrumentationRunner "android.support.multidex.MultiDexTestRunner"
+  }
+}
+
+dependencies {
+    androidTestCompile 'com.android.support:multidex-instrumentation:1.0.0'
+}
+</pre>
+
+<p>
+  You may use the instrumentation test runner class directly or extend it to fit your testing
+  needs. Alternatively, you can override onCreate in existing instrumentations like this:
+</p>
+
+<pre>
+public void onCreate(Bundle arguments) {
+    MultiDex.install(getTargetContext());
+    super.onCreate(arguments);
+    ...
+}
+</pre>
+
+<p class="note">
+  <strong>Note:</strong> Use of multidex for creating a test APK is not currently supported.
+</p>
\ No newline at end of file
diff --git a/docs/html/tools/revisions/build-tools.jd b/docs/html/tools/revisions/build-tools.jd
index 6f07755..ec88efc 100644
--- a/docs/html/tools/revisions/build-tools.jd
+++ b/docs/html/tools/revisions/build-tools.jd
@@ -77,6 +77,18 @@
 <div class="toggle-content opened">
   <p><a href="#" onclick="return toggleContent(this)">
     <img src="{@docRoot}assets/images/triangle-opened.png" class="toggle-content-img"
+      alt=""/>Build Tools, Revision 21.1</a> <em>(October 2014)</em>
+  </p>
+  <div class="toggle-content-toggleme">
+    <p>Added multidex file support for APKs and Jack suppport to address the 64K method reference
+    limit.</p>
+  </div>
+</div>
+
+
+<div class="toggle-content closed">
+  <p><a href="#" onclick="return toggleContent(this)">
+    <img src="{@docRoot}assets/images/triangle-closed.png" class="toggle-content-img"
       alt=""/>Build Tools, Revision 21.0.2</a> <em>(October 2014)</em>
   </p>
   <div class="toggle-content-toggleme">
diff --git a/docs/html/tools/revisions/platforms.jd b/docs/html/tools/revisions/platforms.jd
index 85b9c5e..ef8575a 100644
--- a/docs/html/tools/revisions/platforms.jd
+++ b/docs/html/tools/revisions/platforms.jd
@@ -88,7 +88,7 @@
 
   <div class="toggle-content-toggleme">
 
-    <p>Added location APIs support for Wear.</p>
+    <p>Updated the rendering library.  </p>
 
     <p>Dependencies:</p>
     <ul>
diff --git a/docs/html/tools/support-library/features.jd b/docs/html/tools/support-library/features.jd
index 44c5045..3ebfc89 100644
--- a/docs/html/tools/support-library/features.jd
+++ b/docs/html/tools/support-library/features.jd
@@ -8,6 +8,7 @@
     <h2>In this document</h2>
     <ol>
       <li><a href="#v4">v4 Support Library</a></li>
+      <li><a href="#multidex">Multidex Support Library</a></li>
       <li><a href="#v7">v7 Support Libraries</a>
         <ol>
           <li><a href="#v7-appcompat">v7 appcompat library</a></li>
@@ -145,6 +146,34 @@
 <p>This dependency notation specifies the release version 21.0.0 or higher.</p>
 
 
+<h2 id="multidex">Multidex Support Library</h2>
+
+<p>
+  This library provides support for building apps with multiple Dalvik Executable (DEX) files.
+  Apps that reference more than 65536 methods are required to use multidex configurations. For
+  more information about using multidex, see <a href="{@docRoot}tools/building/multidex.html">
+  Building Apps with Over 65K Methods</a>.
+</p>
+
+<p>
+  This library is located in the {@code &lt;sdk&gt;/extras/android/support/multidex/} directory
+  after you download the Android Support Libraries. The library does not contain user interface
+  resources. To include it in your application project, follow the instructions for <a href=
+  "{@docRoot}tools/support-library/setup.html#libs-without-res">Adding libraries without
+  resources</a>.
+</p>
+
+<p>
+  The Gradle build script dependency identifier for this library is as follows:
+</p>
+
+<pre>
+com.android.support:multidex:1.0.+
+</pre>
+
+<p>This dependency notation specifies the release version 1.0.0 or higher.</p>
+
+
 <h2 id="v7">v7 Support Libraries</h2>
 
 <p>There are several libraries designed to be used with Android 2.1 (API level 7) and higher.
diff --git a/docs/html/tools/testing/activity_testing.jd b/docs/html/tools/testing/activity_testing.jd
index 88ac9b2..8baa35d 100644
--- a/docs/html/tools/testing/activity_testing.jd
+++ b/docs/html/tools/testing/activity_testing.jd
@@ -242,7 +242,7 @@
     This changes when you run tests against the application. With instrumentation-based classes,
     you can invoke methods against the UI of the application under test. The other test classes
     don't allow this. To run an entire test method on the UI thread, you can annotate the thread
-    with <code>@UIThreadTest</code>. Notice that this will run <em>all</em> of the method statements
+    with <code>@UiThreadTest</code>. Notice that this will run <em>all</em> of the method statements
     on the UI thread.  Methods that do not interact with the UI are not allowed; for example, you
     can't invoke <code>Instrumentation.waitForIdleSync()</code>.
 </p>
diff --git a/docs/html/tools/tools_toc.cs b/docs/html/tools/tools_toc.cs
index 8eb9cbf..ac33185 100644
--- a/docs/html/tools/tools_toc.cs
+++ b/docs/html/tools/tools_toc.cs
@@ -66,10 +66,17 @@
 
 
       <li class="nav-section">
-        <div class="nav-section-header"><a href="<?cs var:toroot ?>tools/building/index.html"><span class="en">Building and Running</span></a></div>
+        <div class="nav-section-header">
+          <a href="<?cs var:toroot ?>tools/building/index.html">
+          <span class="en">Building and Running</span></a>
+        </div>
         <ul>
-          <li><a href="<?cs var:toroot ?>tools/building/building-eclipse.html"><span class="en">From Eclipse with ADT</span></a></li>
-          <li><a href="<?cs var:toroot ?>tools/building/building-cmdline.html"><span class="en">From the Command Line</span></a></li>
+          <li><a href="<?cs var:toroot ?>tools/building/building-eclipse.html">
+            <span class="en">From Eclipse with ADT</span></a></li>
+          <li><a href="<?cs var:toroot ?>tools/building/building-cmdline.html">
+            <span class="en">From the Command Line</span></a></li>
+          <li><a href="<?cs var:toroot ?>tools/building/multidex.html">
+            <span class="en">Apps Over 65K Methods</span></a></li>
         </ul>
       </li>
 
diff --git a/docs/html/training/basics/firstapp/building-ui.jd b/docs/html/training/basics/firstapp/building-ui.jd
index c082642..0430cdd 100644
--- a/docs/html/training/basics/firstapp/building-ui.jd
+++ b/docs/html/training/basics/firstapp/building-ui.jd
@@ -1,7 +1,7 @@
 page.title=Building a Simple User Interface
 trainingnavtop=true
 
-page.tags=ui, views, layouts, widgets, string resources
+page.tags=ui
 helpoutsWidget=true
 
 @jd:body
diff --git a/docs/html/training/basics/firstapp/creating-project.jd b/docs/html/training/basics/firstapp/creating-project.jd
index 418eb68..2e06103 100644
--- a/docs/html/training/basics/firstapp/creating-project.jd
+++ b/docs/html/training/basics/firstapp/creating-project.jd
@@ -1,6 +1,6 @@
 page.title=Creating an Android Project
 
-page.tags=eclipse adt, sdk tools, project setup
+page.tags=project setup
 helpoutsWidget=true
 
 trainingnavtop=true
diff --git a/docs/html/training/basics/firstapp/starting-activity.jd b/docs/html/training/basics/firstapp/starting-activity.jd
index f9dcba4..71f66dd 100644
--- a/docs/html/training/basics/firstapp/starting-activity.jd
+++ b/docs/html/training/basics/firstapp/starting-activity.jd
@@ -4,7 +4,7 @@
 
 trainingnavtop=true
 
-page.tags=input events, intents, activity lifecycle
+page.tags=intents
 helpoutsWidget=true
 
 @jd:body
diff --git a/docs/html/training/wearables/apps/layouts.jd b/docs/html/training/wearables/apps/layouts.jd
index e62d3e5..a35acb0 100644
--- a/docs/html/training/wearables/apps/layouts.jd
+++ b/docs/html/training/wearables/apps/layouts.jd
@@ -90,9 +90,10 @@
 </ol>
 <h2 id="UiLibrary">Create Layouts with the Wearable UI Library</h2>
 <p>
-There's an unofficial UI library that is automatically included when you create your wearable
-app with the Android Studio Project Wizard. You can also add the library to your <code>build.gradle</code>
+The Wearable UI Library is automatically included when you create your wearable
+app with the Android Studio Project Wizard. You can also add this library to your <code>build.gradle</code>
 file with the following dependency declaration:
+</p>
 
 <pre>
 dependencies {
@@ -101,8 +102,11 @@
     compile 'com.google.android.gms:play-services-wearable:+'
 }
 </pre>
-This library helps you build UIs that are designed for wearables. Here are some of the major classes:
-</p>
+
+<p>This library helps you build UIs that are designed for wearables. For more information, see
+<a href="{@docRoot}training/wearables/ui/index.html">Creating Custom UIs for Wear Devices</a>.</p>
+
+<p>Here are some of the major classes in the Wearable UI Library:</p>
 
 <ul>
     <li><code>BoxInsetLayout</code> - A FrameLayout that's aware of screen shape and can box its
diff --git a/docs/html/training/wearables/data-layer/index.jd b/docs/html/training/wearables/data-layer/index.jd
index 39d6561..6ef3fc7 100644
--- a/docs/html/training/wearables/data-layer/index.jd
+++ b/docs/html/training/wearables/data-layer/index.jd
@@ -8,7 +8,7 @@
     <h2>Dependencies and prerequisites</h2>
     <ul>
       <li>Android 4.3 (API Level 18) or higher on the handset device</li>
-      <li>The latest version of <a href="{@docRoot}google/play">Google Play services</a></li>
+      <li>The latest version of <a href="{@docRoot}google/play-services/index.html">Google Play services</a></li>
       <li>An Android Wear device or Wear AVD</li>
     </ul>
   </div>
diff --git a/docs/html/training/wearables/notifications/voice-input.jd b/docs/html/training/wearables/notifications/voice-input.jd
index 4a27826..3ce1c80 100644
--- a/docs/html/training/wearables/notifications/voice-input.jd
+++ b/docs/html/training/wearables/notifications/voice-input.jd
@@ -37,7 +37,7 @@
 
 <h2 id="VoiceInput">Define the Voice Input</h2>
 
-<p>To create an action that supports voice input, create an instance of 
+<p>To create an action that supports voice input, create an instance of
   {@link android.support.v4.app.RemoteInput.Builder} that you can add to your notification action.
   This class's constructor accepts a string that the system uses as
   the key for the voice input, which you'll later use to retrieve the text of the
@@ -166,9 +166,8 @@
 
 private CharSequence getMessageText(Intent intent) {
     Bundle remoteInput = RemoteInput.getResultsFromIntent(intent);
-        if (remoteInput != null) {
-            return remoteInput.getCharSequence(EXTRA_VOICE_REPLY);
-        }
+    if (remoteInput != null) {
+        return remoteInput.getCharSequence(EXTRA_VOICE_REPLY);
     }
     return null;
 }
diff --git a/graphics/java/android/graphics/pdf/PdfEditor.java b/graphics/java/android/graphics/pdf/PdfEditor.java
index 9837139..2b70b6a 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;
@@ -55,6 +59,10 @@
      *
      * @param input Seekable file descriptor to read from.
      *
+     * @throws java.io.IOException If an error occurs while reading the file.
+     * @throws java.lang.SecurityException If the file requires a password or
+     *         the security scheme is not supported.
+     *
      * @see #close()
      */
     public PdfEditor(@NonNull ParcelFileDescriptor input) throws IOException {
@@ -98,6 +106,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 +265,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/graphics/java/android/graphics/pdf/PdfRenderer.java b/graphics/java/android/graphics/pdf/PdfRenderer.java
index 359c294..79934da 100644
--- a/graphics/java/android/graphics/pdf/PdfRenderer.java
+++ b/graphics/java/android/graphics/pdf/PdfRenderer.java
@@ -131,6 +131,10 @@
      * </p>
      *
      * @param input Seekable file descriptor to read from.
+     *
+     * @throws java.io.IOException If an error occurs while reading the file.
+     * @throws java.lang.SecurityException If the file requires a password or
+     *         the security scheme is not supported.
      */
     public PdfRenderer(@NonNull ParcelFileDescriptor input) throws IOException {
         if (input == null) {
diff --git a/libs/hwui/Caches.cpp b/libs/hwui/Caches.cpp
index f0bf7b2..ad50894 100644
--- a/libs/hwui/Caches.cpp
+++ b/libs/hwui/Caches.cpp
@@ -265,14 +265,27 @@
 }
 
 void Caches::dumpMemoryUsage(String8 &log) {
+    uint32_t total = 0;
     log.appendFormat("Current memory usage / total memory usage (bytes):\n");
     log.appendFormat("  TextureCache         %8d / %8d\n",
             textureCache.getSize(), textureCache.getMaxSize());
     log.appendFormat("  LayerCache           %8d / %8d (numLayers = %zu)\n",
             layerCache.getSize(), layerCache.getMaxSize(), layerCache.getCount());
-    log.appendFormat("  Garbage layers       %8zu\n", mLayerGarbage.size());
-    log.appendFormat("  Active layers        %8zu\n",
-            mRenderState ? mRenderState->mActiveLayers.size() : 0);
+    if (mRenderState) {
+        int memused = 0;
+        for (std::set<const Layer*>::iterator it = mRenderState->mActiveLayers.begin();
+                it != mRenderState->mActiveLayers.end(); it++) {
+            const Layer* layer = *it;
+            log.appendFormat("    Layer size %dx%d; isTextureLayer()=%d; texid=%u fbo=%u; refs=%d\n",
+                    layer->getWidth(), layer->getHeight(),
+                    layer->isTextureLayer(), layer->getTexture(),
+                    layer->getFbo(), layer->getStrongCount());
+            memused = layer->getWidth() * layer->getHeight() * 4;
+        }
+        log.appendFormat("  Layers total   %8d (numLayers = %zu)\n",
+                memused, mRenderState->mActiveLayers.size());
+        total += memused;
+    }
     log.appendFormat("  RenderBufferCache    %8d / %8d\n",
             renderBufferCache.getSize(), renderBufferCache.getMaxSize());
     log.appendFormat("  GradientCache        %8d / %8d\n",
@@ -297,9 +310,7 @@
     log.appendFormat("  FboCache             %8d / %8d\n",
             fboCache.getSize(), fboCache.getMaxSize());
 
-    uint32_t total = 0;
     total += textureCache.getSize();
-    total += layerCache.getSize();
     total += renderBufferCache.getSize();
     total += gradientCache.getSize();
     total += pathCache.getSize();
@@ -323,27 +334,6 @@
     textureCache.clearGarbage();
     pathCache.clearGarbage();
     patchCache.clearGarbage();
-
-    Vector<Layer*> layers;
-
-    { // scope for the lock
-        Mutex::Autolock _l(mGarbageLock);
-        layers = mLayerGarbage;
-        mLayerGarbage.clear();
-    }
-
-    size_t count = layers.size();
-    for (size_t i = 0; i < count; i++) {
-        Layer* layer = layers.itemAt(i);
-        delete layer;
-    }
-    layers.clear();
-}
-
-void Caches::deleteLayerDeferred(Layer* layer) {
-    Mutex::Autolock _l(mGarbageLock);
-    layer->state = Layer::kState_InGarbageList;
-    mLayerGarbage.push(layer);
 }
 
 void Caches::flush(FlushMode mode) {
diff --git a/libs/hwui/DeferredLayerUpdater.cpp b/libs/hwui/DeferredLayerUpdater.cpp
index a6d7e78..d02455c 100644
--- a/libs/hwui/DeferredLayerUpdater.cpp
+++ b/libs/hwui/DeferredLayerUpdater.cpp
@@ -24,25 +24,6 @@
 namespace android {
 namespace uirenderer {
 
-class DeleteLayerTask : public renderthread::RenderTask {
-public:
-    DeleteLayerTask(renderthread::EglManager& eglManager, Layer* layer)
-        : mEglManager(eglManager)
-        , mLayer(layer)
-    {}
-
-    virtual void run() {
-        mEglManager.requireGlContext();
-        LayerRenderer::destroyLayer(mLayer);
-        mLayer = 0;
-        delete this;
-    }
-
-private:
-    renderthread::EglManager& mEglManager;
-    Layer* mLayer;
-};
-
 DeferredLayerUpdater::DeferredLayerUpdater(renderthread::RenderThread& thread, Layer* layer)
         : mSurfaceTexture(0)
         , mTransform(0)
@@ -62,7 +43,7 @@
 DeferredLayerUpdater::~DeferredLayerUpdater() {
     SkSafeUnref(mColorFilter);
     setTransform(0);
-    mRenderThread.queue(new DeleteLayerTask(mRenderThread.eglManager(), mLayer));
+    mLayer->postDecStrong();
     mLayer = 0;
 }
 
diff --git a/libs/hwui/DisplayList.cpp b/libs/hwui/DisplayList.cpp
index d8932ce..4a927cf 100644
--- a/libs/hwui/DisplayList.cpp
+++ b/libs/hwui/DisplayList.cpp
@@ -61,10 +61,6 @@
         caches.resourceCache.decrementRefcountLocked(sourcePaths.itemAt(i));
     }
 
-    for (size_t i = 0; i < layers.size(); i++) {
-        caches.resourceCache.decrementRefcountLocked(layers.itemAt(i));
-    }
-
     caches.resourceCache.unlock();
 
     for (size_t i = 0; i < paints.size(); i++) {
@@ -86,7 +82,6 @@
     paints.clear();
     regions.clear();
     paths.clear();
-    layers.clear();
 }
 
 size_t DisplayListData::addChild(DrawRenderNodeOp* op) {
diff --git a/libs/hwui/DisplayList.h b/libs/hwui/DisplayList.h
index dea109c..cb8a8d1 100644
--- a/libs/hwui/DisplayList.h
+++ b/libs/hwui/DisplayList.h
@@ -147,7 +147,6 @@
     Vector<const SkPath*> paths;
     SortedVector<const SkPath*> sourcePaths;
     Vector<const SkRegion*> regions;
-    Vector<Layer*> layers;
     Vector<Functor*> functors;
 
     const Vector<Chunk>& getChunks() const {
@@ -157,11 +156,7 @@
     size_t addChild(DrawRenderNodeOp* childOp);
     const Vector<DrawRenderNodeOp*>& children() { return mChildren; }
 
-    void refProperty(CanvasPropertyPrimitive* prop) {
-        mReferenceHolders.push(prop);
-    }
-
-    void refProperty(CanvasPropertyPaint* prop) {
+    void ref(VirtualLightRefBase* prop) {
         mReferenceHolders.push(prop);
     }
 
diff --git a/libs/hwui/DisplayListRenderer.cpp b/libs/hwui/DisplayListRenderer.cpp
index 1f70921..c17dd09 100644
--- a/libs/hwui/DisplayListRenderer.cpp
+++ b/libs/hwui/DisplayListRenderer.cpp
@@ -189,7 +189,7 @@
 }
 
 status_t DisplayListRenderer::drawLayer(Layer* layer, float x, float y) {
-    layer = refLayer(layer);
+    mDisplayListData->ref(layer);
     addDrawOp(new (alloc()) DrawLayerOp(layer, x, y));
     return DrawGlInfo::kStatusDone;
 }
@@ -280,13 +280,13 @@
         CanvasPropertyPrimitive* right, CanvasPropertyPrimitive* bottom,
         CanvasPropertyPrimitive* rx, CanvasPropertyPrimitive* ry,
         CanvasPropertyPaint* paint) {
-    mDisplayListData->refProperty(left);
-    mDisplayListData->refProperty(top);
-    mDisplayListData->refProperty(right);
-    mDisplayListData->refProperty(bottom);
-    mDisplayListData->refProperty(rx);
-    mDisplayListData->refProperty(ry);
-    mDisplayListData->refProperty(paint);
+    mDisplayListData->ref(left);
+    mDisplayListData->ref(top);
+    mDisplayListData->ref(right);
+    mDisplayListData->ref(bottom);
+    mDisplayListData->ref(rx);
+    mDisplayListData->ref(ry);
+    mDisplayListData->ref(paint);
     addDrawOp(new (alloc()) DrawRoundRectPropsOp(&left->value, &top->value,
             &right->value, &bottom->value, &rx->value, &ry->value, &paint->value));
     return DrawGlInfo::kStatusDone;
@@ -300,10 +300,10 @@
 
 status_t DisplayListRenderer::drawCircle(CanvasPropertyPrimitive* x, CanvasPropertyPrimitive* y,
         CanvasPropertyPrimitive* radius, CanvasPropertyPaint* paint) {
-    mDisplayListData->refProperty(x);
-    mDisplayListData->refProperty(y);
-    mDisplayListData->refProperty(radius);
-    mDisplayListData->refProperty(paint);
+    mDisplayListData->ref(x);
+    mDisplayListData->ref(y);
+    mDisplayListData->ref(radius);
+    mDisplayListData->ref(paint);
     addDrawOp(new (alloc()) DrawCirclePropsOp(&x->value, &y->value,
             &radius->value, &paint->value));
     return DrawGlInfo::kStatusDone;
diff --git a/libs/hwui/DisplayListRenderer.h b/libs/hwui/DisplayListRenderer.h
index 3a3fc3a..901e8f0 100644
--- a/libs/hwui/DisplayListRenderer.h
+++ b/libs/hwui/DisplayListRenderer.h
@@ -267,12 +267,6 @@
         return regionCopy;
     }
 
-    inline Layer* refLayer(Layer* layer) {
-        mDisplayListData->layers.add(layer);
-        mCaches.resourceCache.incrementRefcount(layer);
-        return layer;
-    }
-
     inline const SkBitmap* refBitmap(const SkBitmap* bitmap) {
         // Note that this assumes the bitmap is immutable. There are cases this won't handle
         // correctly, such as creating the bitmap from scratch, drawing with it, changing its
diff --git a/libs/hwui/Layer.cpp b/libs/hwui/Layer.cpp
index b5089aa..b95636b 100644
--- a/libs/hwui/Layer.cpp
+++ b/libs/hwui/Layer.cpp
@@ -35,6 +35,9 @@
         , renderState(renderState)
         , texture(caches)
         , type(layerType) {
+    // TODO: This is a violation of Android's typical ref counting, but it
+    // preserves the old inc/dec ref locations. This should be changed...
+    incStrong(0);
     mesh = NULL;
     meshElementCount = 0;
     cacheable = true;
@@ -53,20 +56,14 @@
     forceFilter = false;
     deferredList = NULL;
     convexMask = NULL;
-    caches.resourceCache.incrementRefcount(this);
     rendererLightPosDirty = true;
     wasBuildLayered = false;
-    if (!isTextureLayer()) {
-        // track only non-texture layer lifecycles in renderstate,
-        // because texture layers are destroyed via finalizer
-        renderState.registerLayer(this);
-    }
+    renderState.registerLayer(this);
 }
 
 Layer::~Layer() {
-    if (!isTextureLayer()) {
-        renderState.unregisterLayer(this);
-    }
+    renderState.requireGLContext();
+    renderState.unregisterLayer(this);
     SkSafeUnref(colorFilter);
     removeFbo();
     deleteTexture();
@@ -292,5 +289,9 @@
     renderNode = NULL;
 }
 
+void Layer::postDecStrong() {
+    renderState.postDecStrong(this);
+}
+
 }; // namespace uirenderer
 }; // namespace android
diff --git a/libs/hwui/Layer.h b/libs/hwui/Layer.h
index a8e1c26..64d1d12 100644
--- a/libs/hwui/Layer.h
+++ b/libs/hwui/Layer.h
@@ -52,7 +52,7 @@
 /**
  * A layer has dimensions and is backed by an OpenGL texture or FBO.
  */
-class Layer {
+class Layer : public VirtualLightRefBase {
 public:
     enum Type {
         kType_Texture,
@@ -280,6 +280,12 @@
     void render(const OpenGLRenderer& rootRenderer);
 
     /**
+     * Posts a decStrong call to the appropriate thread.
+     * Thread-safe.
+     */
+    void postDecStrong();
+
+    /**
      * Bounds of the layer.
      */
     Rect layer;
diff --git a/libs/hwui/LayerCache.cpp b/libs/hwui/LayerCache.cpp
index 833f64b..3033dc6 100644
--- a/libs/hwui/LayerCache.cpp
+++ b/libs/hwui/LayerCache.cpp
@@ -84,7 +84,7 @@
                 layer->getFbo());
         mSize -= layer->getWidth() * layer->getHeight() * 4;
         layer->state = Layer::kState_DeletedFromCache;
-        Caches::getInstance().resourceCache.decrementRefcount(layer);
+        layer->decStrong(0);
     }
 }
 
diff --git a/libs/hwui/LayerRenderer.cpp b/libs/hwui/LayerRenderer.cpp
index 103c843..394c647 100644
--- a/libs/hwui/LayerRenderer.cpp
+++ b/libs/hwui/LayerRenderer.cpp
@@ -212,7 +212,7 @@
 
         // Creating a new layer always increment its refcount by 1, this allows
         // us to destroy the layer object if one was created for us
-        Caches::getInstance().resourceCache.decrementRefcount(layer);
+        layer->decStrong(0);
 
         return NULL;
     }
@@ -240,7 +240,7 @@
         if (glGetError() != GL_NO_ERROR) {
             ALOGE("Could not allocate texture for layer (fbo=%d %dx%d)", fbo, width, height);
             renderState.bindFramebuffer(previousFbo);
-            caches.resourceCache.decrementRefcount(layer);
+            layer->decStrong(0);
             return NULL;
         }
     }
@@ -316,7 +316,7 @@
 
         if (!Caches::getInstance().layerCache.put(layer)) {
             LAYER_RENDERER_LOGD("  Destroyed!");
-            Caches::getInstance().resourceCache.decrementRefcount(layer);
+            layer->decStrong(0);
         } else {
             LAYER_RENDERER_LOGD("  Cached!");
 #if DEBUG_LAYER_RENDERER
@@ -328,14 +328,6 @@
     }
 }
 
-void LayerRenderer::destroyLayerDeferred(Layer* layer) {
-    if (layer) {
-        LAYER_RENDERER_LOGD("Deferring layer destruction, fbo = %d", layer->getFbo());
-
-        Caches::getInstance().deleteLayerDeferred(layer);
-    }
-}
-
 void LayerRenderer::flushLayer(RenderState& renderState, Layer* layer) {
 #ifdef GL_EXT_discard_framebuffer
     if (!layer) return;
diff --git a/libs/hwui/LayerRenderer.h b/libs/hwui/LayerRenderer.h
index bf7828c..4d8620b 100644
--- a/libs/hwui/LayerRenderer.h
+++ b/libs/hwui/LayerRenderer.h
@@ -60,7 +60,6 @@
     static void updateTextureLayer(Layer* layer, uint32_t width, uint32_t height,
             bool isOpaque, bool forceFilter, GLenum renderTarget, float* textureTransform);
     static void destroyLayer(Layer* layer);
-    ANDROID_API static void destroyLayerDeferred(Layer* layer);
     static bool copyLayer(RenderState& renderState, Layer* layer, SkBitmap* bitmap);
 
     static void flushLayer(RenderState& renderState, Layer* layer);
diff --git a/libs/hwui/OpenGLRenderer.cpp b/libs/hwui/OpenGLRenderer.cpp
index 19fc9a3..d570b0d 100755
--- a/libs/hwui/OpenGLRenderer.cpp
+++ b/libs/hwui/OpenGLRenderer.cpp
@@ -509,11 +509,8 @@
 
         // Note: it is very important to update the layers in order
         for (int i = 0; i < count; i++) {
-            Layer* layer = mLayerUpdates.itemAt(i);
+            Layer* layer = mLayerUpdates.itemAt(i).get();
             updateLayer(layer, false);
-            if (CC_UNLIKELY(mCaches.drawDeferDisabled)) {
-                mCaches.resourceCache.decrementRefcount(layer);
-            }
         }
 
         if (CC_UNLIKELY(mCaches.drawDeferDisabled)) {
@@ -532,7 +529,7 @@
 
         // Note: it is very important to update the layers in order
         for (int i = 0; i < count; i++) {
-            Layer* layer = mLayerUpdates.itemAt(i);
+            Layer* layer = mLayerUpdates.itemAt(i).get();
 
             sprintf(layerName, "Layer #%d", i);
             startMark(layerName);
@@ -542,8 +539,6 @@
 
             ATRACE_END();
             endMark();
-
-            mCaches.resourceCache.decrementRefcount(layer);
         }
 
         mLayerUpdates.clear();
@@ -565,7 +560,6 @@
             }
         }
         mLayerUpdates.push_back(layer);
-        mCaches.resourceCache.incrementRefcount(layer);
     }
 }
 
@@ -574,25 +568,12 @@
         for (int i = mLayerUpdates.size() - 1; i >= 0; i--) {
             if (mLayerUpdates.itemAt(i) == layer) {
                 mLayerUpdates.removeAt(i);
-                mCaches.resourceCache.decrementRefcount(layer);
                 break;
             }
         }
     }
 }
 
-void OpenGLRenderer::clearLayerUpdates() {
-    size_t count = mLayerUpdates.size();
-    if (count > 0) {
-        mCaches.resourceCache.lock();
-        for (size_t i = 0; i < count; i++) {
-            mCaches.resourceCache.decrementRefcountLocked(mLayerUpdates.itemAt(i));
-        }
-        mCaches.resourceCache.unlock();
-        mLayerUpdates.clear();
-    }
-}
-
 void OpenGLRenderer::flushLayerUpdates() {
     ATRACE_CALL();
     syncState();
@@ -956,7 +937,7 @@
     layer->setConvexMask(NULL);
     if (!mCaches.layerCache.put(layer)) {
         LAYER_LOGD("Deleting layer");
-        Caches::getInstance().resourceCache.decrementRefcount(layer);
+        layer->decStrong(0);
     }
 }
 
diff --git a/libs/hwui/OpenGLRenderer.h b/libs/hwui/OpenGLRenderer.h
index c2c0b0e..e1c3d10 100755
--- a/libs/hwui/OpenGLRenderer.h
+++ b/libs/hwui/OpenGLRenderer.h
@@ -140,7 +140,6 @@
 
     void pushLayerUpdate(Layer* layer);
     void cancelLayerUpdate(Layer* layer);
-    void clearLayerUpdates();
     void flushLayerUpdates();
     void markLayersAsBuildLayers();
 
@@ -982,7 +981,7 @@
     // List of rectangles to clear after saveLayer() is invoked
     Vector<Rect*> mLayers;
     // List of layers to update at the beginning of a frame
-    Vector<Layer*> mLayerUpdates;
+    Vector< sp<Layer> > mLayerUpdates;
 
     // The following fields are used to setup drawing
     // Used to describe the shaders to generate
diff --git a/libs/hwui/RenderNode.cpp b/libs/hwui/RenderNode.cpp
index 40cd13e..c9ed9a7 100644
--- a/libs/hwui/RenderNode.cpp
+++ b/libs/hwui/RenderNode.cpp
@@ -87,7 +87,11 @@
 RenderNode::~RenderNode() {
     deleteDisplayListData();
     delete mStagingDisplayListData;
-    LayerRenderer::destroyLayerDeferred(mLayer);
+    if (mLayer) {
+        ALOGW("Memory Warning: Layer %p missed its detachment, held on to for far too long!", mLayer);
+        mLayer->postDecStrong();
+        mLayer = 0;
+    }
 }
 
 void RenderNode::setStagingDisplayList(DisplayListData* data) {
@@ -201,6 +205,7 @@
     info.damageAccumulator->peekAtDirty(&dirty);
 
     if (!mLayer) {
+        Caches::getInstance().dumpMemoryUsage();
         if (info.errorHandler) {
             std::string msg = "Unable to create layer for ";
             msg += getName();
diff --git a/libs/hwui/RenderNode.h b/libs/hwui/RenderNode.h
index f329283..2ce7cb7 100644
--- a/libs/hwui/RenderNode.h
+++ b/libs/hwui/RenderNode.h
@@ -101,7 +101,7 @@
         kReplayFlag_ClipChildren = 0x1
     };
 
-    ANDROID_API static void outputLogBuffer(int fd);
+    static void outputLogBuffer(int fd);
     void debugDumpLayers(const char* prefix);
 
     ANDROID_API void setStagingDisplayList(DisplayListData* newData);
diff --git a/libs/hwui/RenderState.cpp b/libs/hwui/RenderState.cpp
index 86bd7dd..a8cf26f 100644
--- a/libs/hwui/RenderState.cpp
+++ b/libs/hwui/RenderState.cpp
@@ -16,15 +16,18 @@
 #include "RenderState.h"
 
 #include "renderthread/CanvasContext.h"
+#include "renderthread/EglManager.h"
 
 namespace android {
 namespace uirenderer {
 
-RenderState::RenderState()
-        : mCaches(NULL)
+RenderState::RenderState(renderthread::RenderThread& thread)
+        : mRenderThread(thread)
+        , mCaches(NULL)
         , mViewportWidth(0)
         , mViewportHeight(0)
         , mFramebuffer(0) {
+    mThreadId = pthread_self();
 }
 
 RenderState::~RenderState() {
@@ -39,7 +42,6 @@
 
 void RenderState::onGLContextDestroyed() {
 /*
-    AutoMutex _lock(mLayerLock);
     size_t size = mActiveLayers.size();
     if (CC_UNLIKELY(size != 0)) {
         ALOGE("Crashing, have %d contexts and %d layers at context destruction. isempty %d",
@@ -146,5 +148,34 @@
     }
 }
 
+void RenderState::requireGLContext() {
+    assertOnGLThread();
+    mRenderThread.eglManager().requireGlContext();
+}
+
+void RenderState::assertOnGLThread() {
+    pthread_t curr = pthread_self();
+    LOG_ALWAYS_FATAL_IF(!pthread_equal(mThreadId, curr), "Wrong thread!");
+}
+
+
+class DecStrongTask : public renderthread::RenderTask {
+public:
+    DecStrongTask(VirtualLightRefBase* object) : mObject(object) {}
+
+    virtual void run() {
+        mObject->decStrong(0);
+        mObject = 0;
+        delete this;
+    }
+
+private:
+    VirtualLightRefBase* mObject;
+};
+
+void RenderState::postDecStrong(VirtualLightRefBase* object) {
+    mRenderThread.queue(new DecStrongTask(object));
+}
+
 } /* namespace uirenderer */
 } /* namespace android */
diff --git a/libs/hwui/RenderState.h b/libs/hwui/RenderState.h
index cbe7cfc..afeef95 100644
--- a/libs/hwui/RenderState.h
+++ b/libs/hwui/RenderState.h
@@ -53,16 +53,10 @@
     void debugOverdraw(bool enable, bool clear);
 
     void registerLayer(const Layer* layer) {
-        /*
-        AutoMutex _lock(mLayerLock);
         mActiveLayers.insert(layer);
-        */
     }
     void unregisterLayer(const Layer* layer) {
-        /*
-        AutoMutex _lock(mLayerLock);
         mActiveLayers.erase(layer);
-        */
     }
 
     void registerCanvasContext(renderthread::CanvasContext* context) {
@@ -73,16 +67,24 @@
         mRegisteredContexts.erase(context);
     }
 
+    void requireGLContext();
+
+    // TODO: This system is a little clunky feeling, this could use some
+    // more thinking...
+    void postDecStrong(VirtualLightRefBase* object);
+
 private:
     friend class renderthread::RenderThread;
     friend class Caches;
 
     void interruptForFunctorInvoke();
     void resumeFromFunctorInvoke();
+    void assertOnGLThread();
 
-    RenderState();
+    RenderState(renderthread::RenderThread& thread);
     ~RenderState();
 
+    renderthread::RenderThread& mRenderThread;
     Caches* mCaches;
     std::set<const Layer*> mActiveLayers;
     std::set<renderthread::CanvasContext*> mRegisteredContexts;
@@ -90,7 +92,8 @@
     GLsizei mViewportWidth;
     GLsizei mViewportHeight;
     GLuint mFramebuffer;
-    Mutex mLayerLock;
+
+    pthread_t mThreadId;
 };
 
 } /* namespace uirenderer */
diff --git a/libs/hwui/ResourceCache.cpp b/libs/hwui/ResourceCache.cpp
index 8b553d1..329d92f 100644
--- a/libs/hwui/ResourceCache.cpp
+++ b/libs/hwui/ResourceCache.cpp
@@ -75,10 +75,6 @@
     incrementRefcount((void*) patchResource, kNinePatch);
 }
 
-void ResourceCache::incrementRefcount(Layer* layerResource) {
-    incrementRefcount((void*) layerResource, kLayer);
-}
-
 void ResourceCache::incrementRefcountLocked(void* resource, ResourceType resourceType) {
     ssize_t index = mCache->indexOfKey(resource);
     ResourceReference* ref = index >= 0 ? mCache->valueAt(index) : NULL;
@@ -103,10 +99,6 @@
     incrementRefcountLocked((void*) patchResource, kNinePatch);
 }
 
-void ResourceCache::incrementRefcountLocked(Layer* layerResource) {
-    incrementRefcountLocked((void*) layerResource, kLayer);
-}
-
 void ResourceCache::decrementRefcount(void* resource) {
     Mutex::Autolock _l(mLock);
     decrementRefcountLocked(resource);
@@ -126,10 +118,6 @@
     decrementRefcount((void*) patchResource);
 }
 
-void ResourceCache::decrementRefcount(Layer* layerResource) {
-    decrementRefcount((void*) layerResource);
-}
-
 void ResourceCache::decrementRefcountLocked(void* resource) {
     ssize_t index = mCache->indexOfKey(resource);
     ResourceReference* ref = index >= 0 ? mCache->valueAt(index) : NULL;
@@ -157,10 +145,6 @@
     decrementRefcountLocked((void*) patchResource);
 }
 
-void ResourceCache::decrementRefcountLocked(Layer* layerResource) {
-    decrementRefcountLocked((void*) layerResource);
-}
-
 void ResourceCache::destructor(SkPath* resource) {
     Mutex::Autolock _l(mLock);
     destructorLocked(resource);
@@ -274,7 +258,7 @@
     if (ref->recycled && ref->resourceType == kBitmap) {
         ((SkBitmap*) resource)->setPixels(NULL, NULL);
     }
-    if (ref->destroyed || ref->resourceType == kLayer) {
+    if (ref->destroyed) {
         switch (ref->resourceType) {
             case kBitmap: {
                 SkBitmap* bitmap = (SkBitmap*) resource;
@@ -305,11 +289,6 @@
                 }
             }
             break;
-            case kLayer: {
-                Layer* layer = (Layer*) resource;
-                Caches::getInstance().deleteLayerDeferred(layer);
-            }
-            break;
         }
     }
     mCache->removeItem(resource);
diff --git a/libs/hwui/ResourceCache.h b/libs/hwui/ResourceCache.h
index 3864d4b..8539d12 100644
--- a/libs/hwui/ResourceCache.h
+++ b/libs/hwui/ResourceCache.h
@@ -36,8 +36,7 @@
 enum ResourceType {
     kBitmap,
     kNinePatch,
-    kPath,
-    kLayer
+    kPath
 };
 
 class ResourceReference {
@@ -69,22 +68,18 @@
     void incrementRefcount(const SkPath* resource);
     void incrementRefcount(const SkBitmap* resource);
     void incrementRefcount(const Res_png_9patch* resource);
-    void incrementRefcount(Layer* resource);
 
     void incrementRefcountLocked(const SkPath* resource);
     void incrementRefcountLocked(const SkBitmap* resource);
     void incrementRefcountLocked(const Res_png_9patch* resource);
-    void incrementRefcountLocked(Layer* resource);
 
     void decrementRefcount(const SkBitmap* resource);
     void decrementRefcount(const SkPath* resource);
     void decrementRefcount(const Res_png_9patch* resource);
-    void decrementRefcount(Layer* resource);
 
     void decrementRefcountLocked(const SkBitmap* resource);
     void decrementRefcountLocked(const SkPath* resource);
     void decrementRefcountLocked(const Res_png_9patch* resource);
-    void decrementRefcountLocked(Layer* resource);
 
     void destructor(SkPath* resource);
     void destructor(const SkBitmap* resource);
diff --git a/libs/hwui/renderthread/CanvasContext.cpp b/libs/hwui/renderthread/CanvasContext.cpp
index 9d2ae8b..b499dd0 100644
--- a/libs/hwui/renderthread/CanvasContext.cpp
+++ b/libs/hwui/renderthread/CanvasContext.cpp
@@ -236,6 +236,8 @@
 
     if (status & DrawGlInfo::kStatusDrew) {
         swapBuffers();
+    } else {
+        mEglManager.cancelFrame();
     }
 
     profiler().finishFrame();
diff --git a/libs/hwui/renderthread/EglManager.cpp b/libs/hwui/renderthread/EglManager.cpp
index e37aafc..9bd6f41 100644
--- a/libs/hwui/renderthread/EglManager.cpp
+++ b/libs/hwui/renderthread/EglManager.cpp
@@ -73,7 +73,8 @@
         , mAllowPreserveBuffer(load_dirty_regions_property())
         , mCurrentSurface(EGL_NO_SURFACE)
         , mAtlasMap(NULL)
-        , mAtlasMapSize(0) {
+        , mAtlasMapSize(0)
+        , mInFrame(false) {
     mCanSetPreserveBuffer = mAllowPreserveBuffer;
     ALOGD("Use EGL_SWAP_BEHAVIOR_PRESERVED: %s", mAllowPreserveBuffer ? "true" : "false");
 }
@@ -105,10 +106,12 @@
 void EglManager::requireGlContext() {
     LOG_ALWAYS_FATAL_IF(mEglDisplay == EGL_NO_DISPLAY, "No EGL context");
 
-    // We can't be certain about the state of the current surface (whether
-    // or not it is destroyed, for example), so err on the side of using
-    // the pbuffer surface which we fully control
-    usePBufferSurface();
+    if (!mInFrame) {
+        // We can't be certain about the state of the current surface (whether
+        // or not it is destroyed, for example), so err on the side of using
+        // the pbuffer surface which we fully control
+        usePBufferSurface();
+    }
 }
 
 void EglManager::loadConfig() {
@@ -251,9 +254,11 @@
         eglQuerySurface(mEglDisplay, surface, EGL_HEIGHT, height);
     }
     eglBeginFrame(mEglDisplay, surface);
+    mInFrame = true;
 }
 
 bool EglManager::swapBuffers(EGLSurface surface) {
+    mInFrame = false;
     eglSwapBuffers(mEglDisplay, surface);
     EGLint err = eglGetError();
     if (CC_LIKELY(err == EGL_SUCCESS)) {
@@ -272,6 +277,10 @@
     return false;
 }
 
+void EglManager::cancelFrame() {
+    mInFrame = false;
+}
+
 bool EglManager::setPreserveBuffer(EGLSurface surface, bool preserve) {
     if (CC_UNLIKELY(!mAllowPreserveBuffer)) return false;
 
diff --git a/libs/hwui/renderthread/EglManager.h b/libs/hwui/renderthread/EglManager.h
index ae03ea1..e12db3a 100644
--- a/libs/hwui/renderthread/EglManager.h
+++ b/libs/hwui/renderthread/EglManager.h
@@ -48,6 +48,7 @@
     bool makeCurrent(EGLSurface surface);
     void beginFrame(EGLSurface surface, EGLint* width, EGLint* height);
     bool swapBuffers(EGLSurface surface);
+    void cancelFrame();
 
     // Returns true iff the surface is now preserving buffers.
     bool setPreserveBuffer(EGLSurface surface, bool preserve);
@@ -80,6 +81,12 @@
     sp<GraphicBuffer> mAtlasBuffer;
     int64_t* mAtlasMap;
     size_t mAtlasMapSize;
+
+    // Whether or not we are in the middle of drawing a frame. This is used
+    // to avoid switching surfaces mid-frame if requireGlContext() is called
+    // TODO: Need to be better about surface/context management so that this isn't
+    // necessary
+    bool mInFrame;
 };
 
 } /* namespace renderthread */
diff --git a/libs/hwui/renderthread/RenderProxy.cpp b/libs/hwui/renderthread/RenderProxy.cpp
index 8f99b4e..5d55ea6 100644
--- a/libs/hwui/renderthread/RenderProxy.cpp
+++ b/libs/hwui/renderthread/RenderProxy.cpp
@@ -235,12 +235,7 @@
         // waitForCompletion = true is expected to be fairly rare and only
         // happen in destruction. Thus it should be fine to temporarily
         // create a Mutex
-        Mutex mutex;
-        Condition condition;
-        SignalingRenderTask syncTask(task, &mutex, &condition);
-        AutoMutex _lock(mutex);
-        thread.queue(&syncTask);
-        condition.wait(mutex);
+        staticPostAndWait(task);
     } else {
         thread.queue(task);
     }
@@ -258,17 +253,6 @@
     postAndWait(task);
 }
 
-CREATE_BRIDGE1(destroyLayer, Layer* layer) {
-    LayerRenderer::destroyLayer(args->layer);
-    return NULL;
-}
-
-void RenderProxy::enqueueDestroyLayer(Layer* layer) {
-    SETUP_TASK(destroyLayer);
-    args->layer = layer;
-    RenderThread::getInstance().queue(task);
-}
-
 CREATE_BRIDGE2(createTextureLayer, RenderThread* thread, CanvasContext* context) {
     Layer* layer = args->context->createTextureLayer();
     if (!layer) return 0;
@@ -400,6 +384,17 @@
     postAndWait(task);
 }
 
+CREATE_BRIDGE1(outputLogBuffer, int fd) {
+    RenderNode::outputLogBuffer(args->fd);
+    return NULL;
+}
+
+void RenderProxy::outputLogBuffer(int fd) {
+    SETUP_TASK(outputLogBuffer);
+    args->fd = fd;
+    staticPostAndWait(task);
+}
+
 CREATE_BRIDGE4(setTextureAtlas, RenderThread* thread, GraphicBuffer* buffer, int64_t* map, size_t size) {
     CanvasContext::setTextureAtlas(*args->thread, args->buffer, args->map, args->size);
     args->buffer->decStrong(0);
@@ -430,6 +425,19 @@
     return retval;
 }
 
+void* RenderProxy::staticPostAndWait(MethodInvokeRenderTask* task) {
+    RenderThread& thread = RenderThread::getInstance();
+    void* retval;
+    task->setReturnPtr(&retval);
+    Mutex mutex;
+    Condition condition;
+    SignalingRenderTask syncTask(task, &mutex, &condition);
+    AutoMutex _lock(mutex);
+    thread.queue(&syncTask);
+    condition.wait(mutex);
+    return retval;
+}
+
 } /* namespace renderthread */
 } /* namespace uirenderer */
 } /* namespace android */
diff --git a/libs/hwui/renderthread/RenderProxy.h b/libs/hwui/renderthread/RenderProxy.h
index dddf0c7..4989b14 100644
--- a/libs/hwui/renderthread/RenderProxy.h
+++ b/libs/hwui/renderthread/RenderProxy.h
@@ -81,7 +81,6 @@
 
     ANDROID_API void runWithGlContext(RenderTask* task);
 
-    static void enqueueDestroyLayer(Layer* layer);
     ANDROID_API DeferredLayerUpdater* createTextureLayer();
     ANDROID_API void buildLayer(RenderNode* node);
     ANDROID_API bool copyLayerInto(DeferredLayerUpdater* layer, SkBitmap* bitmap);
@@ -97,6 +96,7 @@
     ANDROID_API void notifyFramePending();
 
     ANDROID_API void dumpProfileInfo(int fd);
+    ANDROID_API static void outputLogBuffer(int fd);
 
     ANDROID_API void setTextureAtlas(const sp<GraphicBuffer>& buffer, int64_t* map, size_t size);
 
@@ -114,6 +114,8 @@
     void post(RenderTask* task);
     void* postAndWait(MethodInvokeRenderTask* task);
 
+    static void* staticPostAndWait(MethodInvokeRenderTask* task);
+
     // Friend class to help with bridging
     friend class RenderProxyBridge;
 };
diff --git a/libs/hwui/renderthread/RenderThread.cpp b/libs/hwui/renderthread/RenderThread.cpp
index 403e164..f887103 100644
--- a/libs/hwui/renderthread/RenderThread.cpp
+++ b/libs/hwui/renderthread/RenderThread.cpp
@@ -168,7 +168,7 @@
 void RenderThread::initThreadLocals() {
     initializeDisplayEventReceiver();
     mEglManager = new EglManager(*this);
-    mRenderState = new RenderState();
+    mRenderState = new RenderState(*this);
 }
 
 int RenderThread::displayEventReceiverCallback(int fd, int events, void* data) {
diff --git a/media/java/android/media/tv/TvContract.java b/media/java/android/media/tv/TvContract.java
index 691df77..5b92266 100644
--- a/media/java/android/media/tv/TvContract.java
+++ b/media/java/android/media/tv/TvContract.java
@@ -856,6 +856,9 @@
         /**
          * The start time of this TV program, in milliseconds since the epoch.
          * <p>
+         * The value should be equal to or larger than {@link #COLUMN_END_TIME_UTC_MILLIS} of the
+         * previous program in the same channel.
+         * </p><p>
          * Type: INTEGER (long)
          * </p>
          */
@@ -864,6 +867,9 @@
         /**
          * The end time of this TV program, in milliseconds since the epoch.
          * <p>
+         * The value should be equal to or less than {@link #COLUMN_START_TIME_UTC_MILLIS} of the
+         * next program in the same channel.
+         * </p><p>
          * Type: INTEGER (long)
          * </p>
          */
diff --git a/packages/PrintSpooler/src/com/android/printspooler/model/OpenDocumentCallback.java b/packages/PrintSpooler/src/com/android/printspooler/model/OpenDocumentCallback.java
new file mode 100644
index 0000000..50f424a
--- /dev/null
+++ b/packages/PrintSpooler/src/com/android/printspooler/model/OpenDocumentCallback.java
@@ -0,0 +1,37 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.printspooler.model;
+
+/**
+ * Callbacks interface for opening a file.
+ */
+public interface OpenDocumentCallback {
+    public static final int ERROR_MALFORMED_PDF_FILE = -1;
+    public static final int ERROR_SECURE_PDF_FILE = -2;
+
+    /**
+     * Called after the file is opened.
+     */
+    public void onSuccess();
+
+    /**
+     * Called after opening the file failed.
+     *
+     * @param error The error.
+     */
+    public void onFailure(int error);
+}
diff --git a/packages/PrintSpooler/src/com/android/printspooler/model/PageContentRepository.java b/packages/PrintSpooler/src/com/android/printspooler/model/PageContentRepository.java
index 35930cd..882b364 100644
--- a/packages/PrintSpooler/src/com/android/printspooler/model/PageContentRepository.java
+++ b/packages/PrintSpooler/src/com/android/printspooler/model/PageContentRepository.java
@@ -78,13 +78,8 @@
         public void onPageContentAvailable(BitmapDrawable content);
     }
 
-    public interface OnMalformedPdfFileListener {
-        public void onMalformedPdfFile();
-    }
-
-    public PageContentRepository(Context context,
-            OnMalformedPdfFileListener malformedPdfFileListener) {
-        mRenderer = new AsyncRenderer(context, malformedPdfFileListener);
+    public PageContentRepository(Context context) {
+        mRenderer = new AsyncRenderer(context);
         mState = STATE_CLOSED;
         if (DEBUG) {
             Log.i(LOG_TAG, "STATE_CLOSED");
@@ -92,7 +87,7 @@
         mCloseGuard.open("destroy");
     }
 
-    public void open(ParcelFileDescriptor source, final Runnable callback) {
+    public void open(ParcelFileDescriptor source, final OpenDocumentCallback callback) {
         throwIfNotClosed();
         mState = STATE_OPENED;
         if (DEBUG) {
@@ -412,8 +407,6 @@
 
         private final ArrayMap<Integer, RenderPageTask> mPageToRenderTaskMap = new ArrayMap<>();
 
-        private final OnMalformedPdfFileListener mOnMalformedPdfFileListener;
-
         private int mPageCount = PrintDocumentInfo.PAGE_COUNT_UNKNOWN;
 
         @GuardedBy("mLock")
@@ -422,9 +415,8 @@
         private boolean mBoundToService;
         private boolean mDestroyed;
 
-        public AsyncRenderer(Context context, OnMalformedPdfFileListener malformedPdfFileListener) {
+        public AsyncRenderer(Context context) {
             mContext = context;
-            mOnMalformedPdfFileListener = malformedPdfFileListener;
 
             ActivityManager activityManager = (ActivityManager)
                     mContext.getSystemService(Context.ACTIVITY_SERVICE);
@@ -447,7 +439,7 @@
             }
         }
 
-        public void open(final ParcelFileDescriptor source, final Runnable callback) {
+        public void open(final ParcelFileDescriptor source, final OpenDocumentCallback callback) {
             // Opening a new document invalidates the cache as it has pages
             // from the last document. We keep the cache even when the document
             // is closed to show pages while the other side is writing the new
@@ -483,7 +475,7 @@
                             return mRenderer.openDocument(source);
                         } catch (RemoteException re) {
                             Log.e(LOG_TAG, "Cannot open PDF document");
-                            return PdfManipulationService.MALFORMED_PDF_FILE_ERROR;
+                            return PdfManipulationService.ERROR_MALFORMED_PDF_FILE;
                         } finally {
                             // Close the fd as we passed it to another process
                             // which took ownership.
@@ -494,14 +486,25 @@
 
                 @Override
                 public void onPostExecute(Integer pageCount) {
-                    if (pageCount == PdfManipulationService.MALFORMED_PDF_FILE_ERROR) {
-                        mOnMalformedPdfFileListener.onMalformedPdfFile();
-                        mPageCount = PrintDocumentInfo.PAGE_COUNT_UNKNOWN;
-                    } else {
-                        mPageCount = pageCount;
-                    }
-                    if (callback != null) {
-                        callback.run();
+                    switch (pageCount) {
+                        case PdfManipulationService.ERROR_MALFORMED_PDF_FILE: {
+                            mPageCount = PrintDocumentInfo.PAGE_COUNT_UNKNOWN;
+                            if (callback != null) {
+                                callback.onFailure(OpenDocumentCallback.ERROR_MALFORMED_PDF_FILE);
+                            }
+                        } break;
+                        case PdfManipulationService.ERROR_SECURE_PDF_FILE: {
+                            mPageCount = PrintDocumentInfo.PAGE_COUNT_UNKNOWN;
+                            if (callback != null) {
+                                callback.onFailure(OpenDocumentCallback.ERROR_SECURE_PDF_FILE);
+                            }
+                        } break;
+                        default: {
+                            mPageCount = pageCount;
+                            if (callback != null) {
+                                callback.onSuccess();
+                            }
+                        } break;
                     }
                 }
             }.executeOnExecutor(AsyncTask.SERIAL_EXECUTOR);
diff --git a/packages/PrintSpooler/src/com/android/printspooler/model/RemotePrintDocument.java b/packages/PrintSpooler/src/com/android/printspooler/model/RemotePrintDocument.java
index f6ace41..1b6e9ce 100644
--- a/packages/PrintSpooler/src/com/android/printspooler/model/RemotePrintDocument.java
+++ b/packages/PrintSpooler/src/com/android/printspooler/model/RemotePrintDocument.java
@@ -304,6 +304,18 @@
         disconnectFromRemoteDocument();
     }
 
+    public void kill(String reason) {
+        if (DEBUG) {
+            Log.i(LOG_TAG, "[CALLED] kill()");
+        }
+
+        try {
+            mPrintDocumentAdapter.kill(reason);
+        } catch (RemoteException re) {
+            Log.e(LOG_TAG, "Error calling kill()", re);
+        }
+    }
+
     public boolean isUpdating() {
         return mState == STATE_UPDATING || mState == STATE_CANCELING;
     }
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..7db2074 100644
--- a/packages/PrintSpooler/src/com/android/printspooler/renderer/PdfManipulationService.java
+++ b/packages/PrintSpooler/src/com/android/printspooler/renderer/PdfManipulationService.java
@@ -47,7 +47,9 @@
     public static final String ACTION_GET_EDITOR =
             "com.android.printspooler.renderer.ACTION_GET_EDITOR";
 
-    public static final int MALFORMED_PDF_FILE_ERROR = -2;
+    public static final int ERROR_MALFORMED_PDF_FILE = -2;
+
+    public static final int ERROR_SECURE_PDF_FILE = -3;
 
     private static final String LOG_TAG = "PdfManipulationService";
     private static final boolean DEBUG = false;
@@ -87,10 +89,14 @@
                     }
                     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;
+                    return ERROR_MALFORMED_PDF_FILE;
+                } catch (SecurityException e) {
+                    IoUtils.closeQuietly(source);
+                    Log.e(LOG_TAG, "Cannot open file", e);
+                    return ERROR_SECURE_PDF_FILE;
                 }
             }
         }
@@ -217,7 +223,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 +252,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/PageAdapter.java b/packages/PrintSpooler/src/com/android/printspooler/ui/PageAdapter.java
index aa79568..0d2e736 100644
--- a/packages/PrintSpooler/src/com/android/printspooler/ui/PageAdapter.java
+++ b/packages/PrintSpooler/src/com/android/printspooler/ui/PageAdapter.java
@@ -37,6 +37,7 @@
 import android.view.View.MeasureSpec;
 import android.widget.TextView;
 import com.android.printspooler.R;
+import com.android.printspooler.model.OpenDocumentCallback;
 import com.android.printspooler.model.PageContentRepository;
 import com.android.printspooler.model.PageContentRepository.PageContentProvider;
 import com.android.printspooler.util.PageRangeUtils;
@@ -51,8 +52,7 @@
 /**
  * This class represents the adapter for the pages in the print preview list.
  */
-public final class PageAdapter extends Adapter implements
-        PageContentRepository.OnMalformedPdfFileListener {
+public final class PageAdapter extends Adapter {
     private static final String LOG_TAG = "PageAdapter";
 
     private static final int MAX_PREVIEW_PAGES_BATCH = 50;
@@ -113,6 +113,7 @@
     public interface ContentCallbacks {
         public void onRequestContentUpdate();
         public void onMalformedPdfFile();
+        public void onSecurePdfFile();
     }
 
     public interface PreviewArea {
@@ -127,7 +128,7 @@
         mCallbacks = callbacks;
         mLayoutInflater = (LayoutInflater) context.getSystemService(
                 Context.LAYOUT_INFLATER_SERVICE);
-        mPageContentRepository = new PageContentRepository(context, this);
+        mPageContentRepository = new PageContentRepository(context);
 
         mPreviewPageMargin = mContext.getResources().getDimensionPixelSize(
                 R.dimen.preview_page_margin);
@@ -156,11 +157,6 @@
         }
     }
 
-    @Override
-    public void onMalformedPdfFile() {
-        mCallbacks.onMalformedPdfFile();
-    }
-
     public void onOrientationChanged() {
         mColumnCount = mContext.getResources().getInteger(
                 R.integer.preview_page_per_row_count);
@@ -181,12 +177,25 @@
         if (DEBUG) {
             Log.i(LOG_TAG, "STATE_OPENED");
         }
-        mPageContentRepository.open(source, new Runnable() {
+        mPageContentRepository.open(source, new OpenDocumentCallback() {
             @Override
-            public void run() {
+            public void onSuccess() {
                 notifyDataSetChanged();
                 callback.run();
             }
+
+            @Override
+            public void onFailure(int error) {
+                switch (error) {
+                    case OpenDocumentCallback.ERROR_MALFORMED_PDF_FILE: {
+                        mCallbacks.onMalformedPdfFile();
+                    } break;
+
+                    case OpenDocumentCallback.ERROR_SECURE_PDF_FILE: {
+                        mCallbacks.onSecurePdfFile();
+                    } break;
+                }
+            }
         });
     }
 
diff --git a/packages/PrintSpooler/src/com/android/printspooler/ui/PrintActivity.java b/packages/PrintSpooler/src/com/android/printspooler/ui/PrintActivity.java
index 15ea9a7..b76a9cd 100644
--- a/packages/PrintSpooler/src/com/android/printspooler/ui/PrintActivity.java
+++ b/packages/PrintSpooler/src/com/android/printspooler/ui/PrintActivity.java
@@ -378,7 +378,7 @@
             return true;
         }
 
-        if (mState == STATE_PRINT_CANCELED ||mState == STATE_PRINT_CONFIRMED
+        if (mState == STATE_PRINT_CANCELED || mState == STATE_PRINT_CONFIRMED
                 || mState == STATE_PRINT_COMPLETED) {
             return true;
         }
@@ -405,12 +405,23 @@
 
     @Override
     public void onMalformedPdfFile() {
+        onPrintDocumentError("Cannot print a malformed PDF file");
+    }
+
+    @Override
+    public void onSecurePdfFile() {
+        onPrintDocumentError("Cannot print a password protected PDF file");
+    }
+
+    private void onPrintDocumentError(String message) {
         mProgressMessageController.cancel();
         ensureErrorUiShown(null, PrintErrorFragment.ACTION_RETRY);
 
         setState(STATE_UPDATE_FAILED);
 
         updateOptionsUi();
+
+        mPrintedDocument.kill(message);
     }
 
     @Override
@@ -592,7 +603,7 @@
             mDestinationSpinner.post(new Runnable() {
                 @Override
                 public void run() {
-                    shredPagesAndFinish(uri);
+                    transformDocumentAndFinish(uri);
                 }
             });
         } else if (resultCode == RESULT_CANCELED) {
@@ -922,7 +933,7 @@
         if (mCurrentPrinter == mDestinationSpinnerAdapter.getPdfPrinter()) {
             startCreateDocumentActivity();
         } else {
-            shredPagesAndFinish(null);
+            transformDocumentAndFinish(null);
         }
     }
 
@@ -1597,8 +1608,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 +1620,7 @@
                 }
                 doFinish();
             }
-        }).shred();
+        }).transform();
     }
 
     private void doFinish() {
@@ -2329,7 +2343,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 +2355,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 +2394,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 +2412,7 @@
             /* do nothing */
         }
 
-        private void shredPages(IPdfEditor editor) {
+        private void doTransform(IPdfEditor editor) {
             File tempFile = null;
             ParcelFileDescriptor src = null;
             ParcelFileDescriptor dst = null;
@@ -2413,6 +2431,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_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/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/ExpandableNotificationRow.java b/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java
index 62dfeeb..a4e5e74 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java
@@ -154,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/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/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java b/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
index fb2a17b..1195ac8 100644
--- a/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
+++ b/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
@@ -136,8 +136,9 @@
     static final String TAG = "WindowManager";
     static final boolean DEBUG = false;
     static final boolean localLOGV = false;
-    static final boolean DEBUG_LAYOUT = false;
     static final boolean DEBUG_INPUT = false;
+    static final boolean DEBUG_KEYGUARD = false;
+    static final boolean DEBUG_LAYOUT = false;
     static final boolean DEBUG_STARTING_WINDOW = false;
     static final boolean DEBUG_WAKEUP = false;
     static final boolean SHOW_STARTING_ANIMATIONS = true;
@@ -158,6 +159,10 @@
     static final int LONG_PRESS_POWER_SHUT_OFF = 2;
     static final int LONG_PRESS_POWER_SHUT_OFF_NO_CONFIRM = 3;
 
+    static final int MULTI_PRESS_POWER_NOTHING = 0;
+    static final int MULTI_PRESS_POWER_THEATER_MODE = 1;
+    static final int MULTI_PRESS_POWER_BRIGHTNESS_BOOST = 2;
+
     // These need to match the documentation/constant in
     // core/res/res/values/config.xml
     static final int LONG_PRESS_HOME_NOTHING = 0;
@@ -300,12 +305,21 @@
     };
 
     GlobalActions mGlobalActions;
-    volatile boolean mPowerKeyHandled; // accessed from input reader and handler thread
-    boolean mPendingPowerKeyUpCanceled;
     Handler mHandler;
     WindowState mLastInputMethodWindow = null;
     WindowState mLastInputMethodTargetWindow = null;
 
+    // FIXME This state is shared between the input reader and handler thread.
+    // Technically it's broken and buggy but it has been like this for many years
+    // and we have not yet seen any problems.  Someday we'll rewrite this logic
+    // so that only one thread is involved in handling input policy.  Unfortunately
+    // it's on a critical path for power management so we can't just post the work to the
+    // handler thread.  We'll need to resolve this someday by teaching the input dispatcher
+    // to hold wakelocks during dispatch and eliminating the critical path.
+    volatile boolean mPowerKeyHandled;
+    volatile int mPowerKeyPressCounter;
+    volatile boolean mEndCallKeyHandled;
+
     boolean mRecentsVisible;
     int mRecentAppsHeldModifiers;
     boolean mLanguageSwitchKeyPressed;
@@ -345,8 +359,10 @@
     int mLidKeyboardAccessibility;
     int mLidNavigationAccessibility;
     boolean mLidControlsSleep;
-    int mShortPressOnPowerBehavior = -1;
-    int mLongPressOnPowerBehavior = -1;
+    int mShortPressOnPowerBehavior;
+    int mLongPressOnPowerBehavior;
+    int mDoublePressOnPowerBehavior;
+    int mTriplePressOnPowerBehavior;
     boolean mAwake;
     boolean mScreenOnEarly;
     boolean mScreenOnFully;
@@ -517,12 +533,12 @@
     // Increase the chord delay when taking a screenshot from the keyguard
     private static final float KEYGUARD_SCREENSHOT_CHORD_DELAY_MULTIPLIER = 2.5f;
     private boolean mScreenshotChordEnabled;
-    private boolean mVolumeDownKeyTriggered;
-    private long mVolumeDownKeyTime;
-    private boolean mVolumeDownKeyConsumedByScreenshotChord;
-    private boolean mVolumeUpKeyTriggered;
-    private boolean mPowerKeyTriggered;
-    private long mPowerKeyTime;
+    private boolean mScreenshotChordVolumeDownKeyTriggered;
+    private long mScreenshotChordVolumeDownKeyTime;
+    private boolean mScreenshotChordVolumeDownKeyConsumed;
+    private boolean mScreenshotChordVolumeUpKeyTriggered;
+    private boolean mScreenshotChordPowerKeyTriggered;
+    private long mScreenshotChordPowerKeyTime;
 
     /* The number of steps between min and max brightness */
     private static final int BRIGHTNESS_STEPS = 10;
@@ -530,6 +546,7 @@
     SettingsObserver mSettingsObserver;
     ShortcutManager mShortcutManager;
     PowerManager.WakeLock mBroadcastWakeLock;
+    PowerManager.WakeLock mPowerKeyWakeLock;
     boolean mHavePendingMediaKeyRepeatWithWakeLock;
 
     private int mCurrentUserId;
@@ -555,6 +572,8 @@
     private static final int MSG_DISPATCH_SHOW_GLOBAL_ACTIONS = 10;
     private static final int MSG_HIDE_BOOT_MESSAGE = 11;
     private static final int MSG_LAUNCH_VOICE_ASSIST_WITH_WAKE_LOCK = 12;
+    private static final int MSG_POWER_DELAYED_PRESS = 13;
+    private static final int MSG_POWER_LONG_PRESS = 14;
 
     private class PolicyHandler extends Handler {
         @Override
@@ -596,6 +615,13 @@
                 case MSG_LAUNCH_VOICE_ASSIST_WITH_WAKE_LOCK:
                     launchVoiceAssistWithWakeLock(msg.arg1 != 0);
                     break;
+                case MSG_POWER_DELAYED_PRESS:
+                    powerPress((Long)msg.obj, msg.arg1 != 0, msg.arg2);
+                    finishPowerKeyPress();
+                    break;
+                case MSG_POWER_LONG_PRESS:
+                    powerLongPress();
+                    break;
             }
         }
     }
@@ -789,38 +815,239 @@
         }
     }
 
-    private void interceptPowerKeyDown(boolean handled) {
-        mPowerKeyHandled = handled;
-        if (!handled) {
-            mHandler.postDelayed(mPowerLongPress,
-                    ViewConfiguration.get(mContext).getDeviceGlobalActionKeyTimeout());
+    private void interceptPowerKeyDown(KeyEvent event, boolean interactive) {
+        // Hold a wake lock until the power key is released.
+        if (!mPowerKeyWakeLock.isHeld()) {
+            mPowerKeyWakeLock.acquire();
+        }
+
+        // Cancel multi-press detection timeout.
+        if (mPowerKeyPressCounter != 0) {
+            mHandler.removeMessages(MSG_POWER_DELAYED_PRESS);
+        }
+
+        // Detect user pressing the power button in panic when an application has
+        // taken over the whole screen.
+        boolean panic = mImmersiveModeConfirmation.onPowerKeyDown(interactive,
+                event.getDownTime(), isImmersiveMode(mLastSystemUiFlags));
+        if (panic) {
+            mHandler.post(mRequestTransientNav);
+        }
+
+        // Latch power key state to detect screenshot chord.
+        if (interactive && !mScreenshotChordPowerKeyTriggered
+                && (event.getFlags() & KeyEvent.FLAG_FALLBACK) == 0) {
+            mScreenshotChordPowerKeyTriggered = true;
+            mScreenshotChordPowerKeyTime = event.getDownTime();
+            interceptScreenshotChord();
+        }
+
+        // Stop ringing or end call if configured to do so when power is pressed.
+        TelecomManager telecomManager = getTelecommService();
+        boolean hungUp = false;
+        if (telecomManager != null) {
+            if (telecomManager.isRinging()) {
+                // Pressing Power while there's a ringing incoming
+                // call should silence the ringer.
+                telecomManager.silenceRinger();
+            } else if ((mIncallPowerBehavior
+                    & Settings.Secure.INCALL_POWER_BUTTON_BEHAVIOR_HANGUP) != 0
+                    && telecomManager.isInCall() && interactive) {
+                // Otherwise, if "Power button ends call" is enabled,
+                // the Power button will hang up any current active call.
+                hungUp = telecomManager.endCall();
+            }
+        }
+
+        // If the power key has still not yet been handled, then detect short
+        // press, long press, or multi press and decide what to do.
+        mPowerKeyHandled = hungUp || mScreenshotChordVolumeDownKeyTriggered
+                || mScreenshotChordVolumeUpKeyTriggered;
+        if (!mPowerKeyHandled) {
+            if (interactive) {
+                // When interactive, we're already awake.
+                // Wait for a long press or for the button to be released to decide what to do.
+                if (hasLongPressOnPowerBehavior()) {
+                    Message msg = mHandler.obtainMessage(MSG_POWER_LONG_PRESS);
+                    msg.setAsynchronous(true);
+                    mHandler.sendMessageDelayed(msg,
+                            ViewConfiguration.get(mContext).getDeviceGlobalActionKeyTimeout());
+                }
+            } else {
+                // When non-interactive, we ordinarily wake up immediately and
+                // consume the key.  However on some devices we need to support multi-press
+                // without waking so we will delay handling for later in that case
+                // (at the cost of increased latency).
+                final int maxCount = getMaxMultiPressPowerCount();
+                if (maxCount <= 1) {
+                    // No other actions.  We can wake immediately.
+                    wakeUpFromPowerKey(event.getDownTime());
+                    mPowerKeyHandled = true;
+                }
+            }
         }
     }
 
-    private boolean interceptPowerKeyUp(boolean canceled) {
-        if (!mPowerKeyHandled) {
-            mHandler.removeCallbacks(mPowerLongPress);
-            return !canceled;
+    private void interceptPowerKeyUp(KeyEvent event, boolean interactive, boolean canceled) {
+        final boolean handled = canceled || mPowerKeyHandled;
+        mScreenshotChordPowerKeyTriggered = false;
+        cancelPendingScreenshotChordAction();
+        cancelPendingPowerKeyAction();
+
+        if (!handled) {
+            // Figure out how to handle the key now that it has been released.
+            mPowerKeyPressCounter += 1;
+
+            final int maxCount = getMaxMultiPressPowerCount();
+            final long eventTime = event.getDownTime();
+            if (mPowerKeyPressCounter < maxCount) {
+                // This could be a multi-press.  Wait a little bit longer to confirm.
+                // Continue holding the wake lock.
+                Message msg = mHandler.obtainMessage(MSG_POWER_DELAYED_PRESS,
+                        interactive ? 1 : 0, mPowerKeyPressCounter, eventTime);
+                msg.setAsynchronous(true);
+                mHandler.sendMessageDelayed(msg, ViewConfiguration.getDoubleTapTimeout());
+                return;
+            }
+
+            // No other actions.  Handle it immediately.
+            powerPress(eventTime, interactive, mPowerKeyPressCounter);
         }
-        return false;
+
+        // Done.  Reset our state.
+        finishPowerKeyPress();
+    }
+
+    private void finishPowerKeyPress() {
+        mPowerKeyPressCounter = 0;
+        if (mPowerKeyWakeLock.isHeld()) {
+            mPowerKeyWakeLock.release();
+        }
     }
 
     private void cancelPendingPowerKeyAction() {
         if (!mPowerKeyHandled) {
-            mHandler.removeCallbacks(mPowerLongPress);
+            mPowerKeyHandled = true;
+            mHandler.removeMessages(MSG_POWER_LONG_PRESS);
         }
-        if (mPowerKeyTriggered) {
-            mPendingPowerKeyUpCanceled = true;
+    }
+
+    private void powerPress(long eventTime, boolean interactive, int count) {
+        if (mScreenOnEarly && !mScreenOnFully) {
+            Slog.i(TAG, "Suppressed redundant power key press while "
+                    + "already in the process of turning the screen on.");
+            return;
         }
+
+        if (count == 2) {
+            powerMultiPressAction(eventTime, interactive, mDoublePressOnPowerBehavior);
+        } else if (count == 3) {
+            powerMultiPressAction(eventTime, interactive, mTriplePressOnPowerBehavior);
+        } else if (!interactive) {
+            wakeUpFromPowerKey(eventTime);
+        } else {
+            switch (mShortPressOnPowerBehavior) {
+                case SHORT_PRESS_POWER_NOTHING:
+                    break;
+                case SHORT_PRESS_POWER_GO_TO_SLEEP:
+                    mPowerManager.goToSleep(eventTime,
+                            PowerManager.GO_TO_SLEEP_REASON_POWER_BUTTON, 0);
+                    break;
+                case SHORT_PRESS_POWER_REALLY_GO_TO_SLEEP:
+                    mPowerManager.goToSleep(eventTime,
+                            PowerManager.GO_TO_SLEEP_REASON_POWER_BUTTON,
+                            PowerManager.GO_TO_SLEEP_FLAG_NO_DOZE);
+                    break;
+                case SHORT_PRESS_POWER_REALLY_GO_TO_SLEEP_AND_GO_HOME:
+                    mPowerManager.goToSleep(eventTime,
+                            PowerManager.GO_TO_SLEEP_REASON_POWER_BUTTON,
+                            PowerManager.GO_TO_SLEEP_FLAG_NO_DOZE);
+                    launchHomeFromHotKey();
+                    break;
+            }
+        }
+    }
+
+    private void powerMultiPressAction(long eventTime, boolean interactive, int behavior) {
+        switch (behavior) {
+            case MULTI_PRESS_POWER_NOTHING:
+                break;
+            case MULTI_PRESS_POWER_THEATER_MODE:
+                if (isTheaterModeEnabled()) {
+                    Slog.i(TAG, "Toggling theater mode off.");
+                    Settings.Global.putInt(mContext.getContentResolver(),
+                            Settings.Global.THEATER_MODE_ON, 0);
+                    if (!interactive) {
+                        wakeUpFromPowerKey(eventTime);
+                    }
+                } else {
+                    Slog.i(TAG, "Toggling theater mode on.");
+                    Settings.Global.putInt(mContext.getContentResolver(),
+                            Settings.Global.THEATER_MODE_ON, 1);
+                    if (interactive) {
+                        mPowerManager.goToSleep(eventTime,
+                                PowerManager.GO_TO_SLEEP_REASON_POWER_BUTTON, 0);
+                    }
+                }
+                break;
+            case MULTI_PRESS_POWER_BRIGHTNESS_BOOST:
+                mPowerManager.boostScreenBrightness(eventTime);
+                break;
+        }
+    }
+
+    private int getMaxMultiPressPowerCount() {
+        if (mTriplePressOnPowerBehavior != MULTI_PRESS_POWER_NOTHING) {
+            return 3;
+        }
+        if (mDoublePressOnPowerBehavior != MULTI_PRESS_POWER_NOTHING) {
+            return 2;
+        }
+        return 1;
+    }
+
+    private void powerLongPress() {
+        final int behavior = getResolvedLongPressOnPowerBehavior();
+        switch (behavior) {
+        case LONG_PRESS_POWER_NOTHING:
+            break;
+        case LONG_PRESS_POWER_GLOBAL_ACTIONS:
+            mPowerKeyHandled = true;
+            if (!performHapticFeedbackLw(null, HapticFeedbackConstants.LONG_PRESS, false)) {
+                performAuditoryFeedbackForAccessibilityIfNeed();
+            }
+            showGlobalActionsInternal();
+            break;
+        case LONG_PRESS_POWER_SHUT_OFF:
+        case LONG_PRESS_POWER_SHUT_OFF_NO_CONFIRM:
+            mPowerKeyHandled = true;
+            performHapticFeedbackLw(null, HapticFeedbackConstants.LONG_PRESS, false);
+            sendCloseSystemWindows(SYSTEM_DIALOG_REASON_GLOBAL_ACTIONS);
+            mWindowManagerFuncs.shutdown(behavior == LONG_PRESS_POWER_SHUT_OFF);
+            break;
+        }
+    }
+
+    private int getResolvedLongPressOnPowerBehavior() {
+        if (FactoryTest.isLongPressOnPowerOffEnabled()) {
+            return LONG_PRESS_POWER_SHUT_OFF_NO_CONFIRM;
+        }
+        return mLongPressOnPowerBehavior;
+    }
+
+    private boolean hasLongPressOnPowerBehavior() {
+        return getResolvedLongPressOnPowerBehavior() != LONG_PRESS_POWER_NOTHING;
     }
 
     private void interceptScreenshotChord() {
         if (mScreenshotChordEnabled
-                && mVolumeDownKeyTriggered && mPowerKeyTriggered && !mVolumeUpKeyTriggered) {
+                && mScreenshotChordVolumeDownKeyTriggered && mScreenshotChordPowerKeyTriggered
+                && !mScreenshotChordVolumeUpKeyTriggered) {
             final long now = SystemClock.uptimeMillis();
-            if (now <= mVolumeDownKeyTime + SCREENSHOT_CHORD_DEBOUNCE_DELAY_MILLIS
-                    && now <= mPowerKeyTime + SCREENSHOT_CHORD_DEBOUNCE_DELAY_MILLIS) {
-                mVolumeDownKeyConsumedByScreenshotChord = true;
+            if (now <= mScreenshotChordVolumeDownKeyTime + SCREENSHOT_CHORD_DEBOUNCE_DELAY_MILLIS
+                    && now <= mScreenshotChordPowerKeyTime
+                            + SCREENSHOT_CHORD_DEBOUNCE_DELAY_MILLIS) {
+                mScreenshotChordVolumeDownKeyConsumed = true;
                 cancelPendingPowerKeyAction();
 
                 mHandler.postDelayed(mScreenshotRunnable, getScreenshotChordLongPressDelay());
@@ -841,64 +1068,14 @@
         mHandler.removeCallbacks(mScreenshotRunnable);
     }
 
-    private void powerShortPress(long eventTime) {
-        if (mShortPressOnPowerBehavior < 0) {
-            mShortPressOnPowerBehavior = mContext.getResources().getInteger(
-                    com.android.internal.R.integer.config_shortPressOnPowerBehavior);
-        }
-
-        switch (mShortPressOnPowerBehavior) {
-            case SHORT_PRESS_POWER_NOTHING:
-                break;
-            case SHORT_PRESS_POWER_GO_TO_SLEEP:
-                mPowerManager.goToSleep(eventTime,
-                        PowerManager.GO_TO_SLEEP_REASON_POWER_BUTTON, 0);
-                break;
-            case SHORT_PRESS_POWER_REALLY_GO_TO_SLEEP:
-                mPowerManager.goToSleep(eventTime,
-                        PowerManager.GO_TO_SLEEP_REASON_POWER_BUTTON,
-                        PowerManager.GO_TO_SLEEP_FLAG_NO_DOZE);
-                break;
-            case SHORT_PRESS_POWER_REALLY_GO_TO_SLEEP_AND_GO_HOME:
-                mPowerManager.goToSleep(eventTime,
-                        PowerManager.GO_TO_SLEEP_REASON_POWER_BUTTON,
-                        PowerManager.GO_TO_SLEEP_FLAG_NO_DOZE);
-                launchHomeFromHotKey();
-                break;
-        }
-    }
-
-    private final Runnable mPowerLongPress = new Runnable() {
+    private final Runnable mEndCallLongPress = new Runnable() {
         @Override
         public void run() {
-            // The context isn't read
-            if (mLongPressOnPowerBehavior < 0) {
-                mLongPressOnPowerBehavior = mContext.getResources().getInteger(
-                        com.android.internal.R.integer.config_longPressOnPowerBehavior);
+            mEndCallKeyHandled = true;
+            if (!performHapticFeedbackLw(null, HapticFeedbackConstants.LONG_PRESS, false)) {
+                performAuditoryFeedbackForAccessibilityIfNeed();
             }
-            int resolvedBehavior = mLongPressOnPowerBehavior;
-            if (FactoryTest.isLongPressOnPowerOffEnabled()) {
-                resolvedBehavior = LONG_PRESS_POWER_SHUT_OFF_NO_CONFIRM;
-            }
-
-            switch (resolvedBehavior) {
-            case LONG_PRESS_POWER_NOTHING:
-                break;
-            case LONG_PRESS_POWER_GLOBAL_ACTIONS:
-                mPowerKeyHandled = true;
-                if (!performHapticFeedbackLw(null, HapticFeedbackConstants.LONG_PRESS, false)) {
-                    performAuditoryFeedbackForAccessibilityIfNeed();
-                }
-                showGlobalActionsInternal();
-                break;
-            case LONG_PRESS_POWER_SHUT_OFF:
-            case LONG_PRESS_POWER_SHUT_OFF_NO_CONFIRM:
-                mPowerKeyHandled = true;
-                performHapticFeedbackLw(null, HapticFeedbackConstants.LONG_PRESS, false);
-                sendCloseSystemWindows(SYSTEM_DIALOG_REASON_GLOBAL_ACTIONS);
-                mWindowManagerFuncs.shutdown(resolvedBehavior == LONG_PRESS_POWER_SHUT_OFF);
-                break;
-            }
+            showGlobalActionsInternal();
         }
     };
 
@@ -939,6 +1116,18 @@
                 Settings.Secure.USER_SETUP_COMPLETE, 0, UserHandle.USER_CURRENT) != 0;
     }
 
+    private void handleShortPressOnHome() {
+        // If there's a dream running then use home to escape the dream
+        // but don't actually go home.
+        if (mDreamManagerInternal != null && mDreamManagerInternal.isDreaming()) {
+            mDreamManagerInternal.stopDream(false /*immediate*/);
+            return;
+        }
+
+        // Go home!
+        launchHomeFromHotKey();
+    }
+
     private void handleLongPressOnHome() {
         if (mLongPressOnHomeBehavior != LONG_PRESS_HOME_NOTHING) {
             mHomeConsumed = true;
@@ -964,7 +1153,7 @@
         public void run() {
             if (mHomeDoubleTapPending) {
                 mHomeDoubleTapPending = false;
-                launchHomeFromHotKey();
+                handleShortPressOnHome();
             }
         }
     };
@@ -1007,6 +1196,8 @@
         mPowerManager = (PowerManager)context.getSystemService(Context.POWER_SERVICE);
         mBroadcastWakeLock = mPowerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK,
                 "PhoneWindowManager.mBroadcastWakeLock");
+        mPowerKeyWakeLock = mPowerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK,
+                "PhoneWindowManager.mPowerKeyWakeLock");
         mEnableShiftMenuBugReports = "1".equals(SystemProperties.get("ro.debuggable"));
         mSupportAutoRotation = mContext.getResources().getBoolean(
                 com.android.internal.R.bool.config_supportAutoRotation);
@@ -1045,6 +1236,15 @@
         mAllowTheaterModeWakeFromWakeGesture = mContext.getResources().getBoolean(
                 com.android.internal.R.bool.config_allowTheaterModeWakeFromGesture);
 
+        mShortPressOnPowerBehavior = mContext.getResources().getInteger(
+                com.android.internal.R.integer.config_shortPressOnPowerBehavior);
+        mLongPressOnPowerBehavior = mContext.getResources().getInteger(
+                com.android.internal.R.integer.config_longPressOnPowerBehavior);
+        mDoublePressOnPowerBehavior = mContext.getResources().getInteger(
+                com.android.internal.R.integer.config_doublePressOnPowerBehavior);
+        mTriplePressOnPowerBehavior = mContext.getResources().getInteger(
+                com.android.internal.R.integer.config_triplePressOnPowerBehavior);
+
         readConfigurationDependentBehaviors();
 
         mAccessibilityManager = (AccessibilityManager) context.getSystemService(
@@ -2188,17 +2388,18 @@
         // but we're not sure, then tell the dispatcher to wait a little while and
         // try again later before dispatching.
         if (mScreenshotChordEnabled && (flags & KeyEvent.FLAG_FALLBACK) == 0) {
-            if (mVolumeDownKeyTriggered && !mPowerKeyTriggered) {
+            if (mScreenshotChordVolumeDownKeyTriggered && !mScreenshotChordPowerKeyTriggered) {
                 final long now = SystemClock.uptimeMillis();
-                final long timeoutTime = mVolumeDownKeyTime + SCREENSHOT_CHORD_DEBOUNCE_DELAY_MILLIS;
+                final long timeoutTime = mScreenshotChordVolumeDownKeyTime
+                        + SCREENSHOT_CHORD_DEBOUNCE_DELAY_MILLIS;
                 if (now < timeoutTime) {
                     return timeoutTime - now;
                 }
             }
             if (keyCode == KeyEvent.KEYCODE_VOLUME_DOWN
-                    && mVolumeDownKeyConsumedByScreenshotChord) {
+                    && mScreenshotChordVolumeDownKeyConsumed) {
                 if (!down) {
-                    mVolumeDownKeyConsumedByScreenshotChord = false;
+                    mScreenshotChordVolumeDownKeyConsumed = false;
                 }
                 return -1;
             }
@@ -2241,15 +2442,7 @@
                     return -1;
                 }
 
-                // If there's a dream running then use home to escape the dream
-                // but don't actually go home.
-                if (mDreamManagerInternal != null && mDreamManagerInternal.isDreaming()) {
-                    mDreamManagerInternal.stopDream(false /*immediate*/);
-                    return -1;
-                }
-
-                // Go home!
-                launchHomeFromHotKey();
+                handleShortPressOnHome();
                 return -1;
             }
 
@@ -2523,7 +2716,8 @@
             return -1;
         }
 
-        if (mGlobalKeyManager.handleGlobalKey(mContext, keyCode, event)) {
+        if (isValidGlobalKey(keyCode)
+                && mGlobalKeyManager.handleGlobalKey(mContext, keyCode, event)) {
             return -1;
         }
 
@@ -4289,10 +4483,10 @@
 
         // If the key would be handled globally, just return the result, don't worry about special
         // key processing.
-        if (mGlobalKeyManager.shouldHandleGlobalKey(keyCode, event)) {
+        if (isValidGlobalKey(keyCode)
+                && mGlobalKeyManager.shouldHandleGlobalKey(keyCode, event)) {
             if (isWakeKey) {
-                wakeUp(event.getEventTime(), keyCode == KeyEvent.KEYCODE_POWER
-                        ? mAllowTheaterModeWakeFromPowerKey : mAllowTheaterModeWakeFromKey);
+                wakeUp(event.getEventTime(), mAllowTheaterModeWakeFromKey);
             }
             return result;
         }
@@ -4308,28 +4502,28 @@
             case KeyEvent.KEYCODE_VOLUME_MUTE: {
                 if (keyCode == KeyEvent.KEYCODE_VOLUME_DOWN) {
                     if (down) {
-                        if (interactive && !mVolumeDownKeyTriggered
+                        if (interactive && !mScreenshotChordVolumeDownKeyTriggered
                                 && (event.getFlags() & KeyEvent.FLAG_FALLBACK) == 0) {
-                            mVolumeDownKeyTriggered = true;
-                            mVolumeDownKeyTime = event.getDownTime();
-                            mVolumeDownKeyConsumedByScreenshotChord = false;
+                            mScreenshotChordVolumeDownKeyTriggered = true;
+                            mScreenshotChordVolumeDownKeyTime = event.getDownTime();
+                            mScreenshotChordVolumeDownKeyConsumed = false;
                             cancelPendingPowerKeyAction();
                             interceptScreenshotChord();
                         }
                     } else {
-                        mVolumeDownKeyTriggered = false;
+                        mScreenshotChordVolumeDownKeyTriggered = false;
                         cancelPendingScreenshotChordAction();
                     }
                 } else if (keyCode == KeyEvent.KEYCODE_VOLUME_UP) {
                     if (down) {
-                        if (interactive && !mVolumeUpKeyTriggered
+                        if (interactive && !mScreenshotChordVolumeUpKeyTriggered
                                 && (event.getFlags() & KeyEvent.FLAG_FALLBACK) == 0) {
-                            mVolumeUpKeyTriggered = true;
+                            mScreenshotChordVolumeUpKeyTriggered = true;
                             cancelPendingPowerKeyAction();
                             cancelPendingScreenshotChordAction();
                         }
                     } else {
-                        mVolumeUpKeyTriggered = false;
+                        mScreenshotChordVolumeUpKeyTriggered = false;
                         cancelPendingScreenshotChordAction();
                     }
                 }
@@ -4386,20 +4580,29 @@
                     if (telecomManager != null) {
                         hungUp = telecomManager.endCall();
                     }
-                    interceptPowerKeyDown(!interactive || hungUp);
+                    if (interactive && !hungUp) {
+                        mEndCallKeyHandled = false;
+                        mHandler.postDelayed(mEndCallLongPress,
+                                ViewConfiguration.get(mContext).getDeviceGlobalActionKeyTimeout());
+                    } else {
+                        mEndCallKeyHandled = true;
+                    }
                 } else {
-                    if (interceptPowerKeyUp(canceled)) {
-                        if ((mEndcallBehavior
-                                & Settings.System.END_BUTTON_BEHAVIOR_HOME) != 0) {
-                            if (goHome()) {
-                                break;
+                    if (!mEndCallKeyHandled) {
+                        mHandler.removeCallbacks(mEndCallLongPress);
+                        if (!canceled) {
+                            if ((mEndcallBehavior
+                                    & Settings.System.END_BUTTON_BEHAVIOR_HOME) != 0) {
+                                if (goHome()) {
+                                    break;
+                                }
                             }
-                        }
-                        if ((mEndcallBehavior
-                                & Settings.System.END_BUTTON_BEHAVIOR_SLEEP) != 0) {
-                            mPowerManager.goToSleep(event.getEventTime(),
-                                    PowerManager.GO_TO_SLEEP_REASON_POWER_BUTTON, 0);
-                            isWakeKey = false;
+                            if ((mEndcallBehavior
+                                    & Settings.System.END_BUTTON_BEHAVIOR_SLEEP) != 0) {
+                                mPowerManager.goToSleep(event.getEventTime(),
+                                        PowerManager.GO_TO_SLEEP_REASON_POWER_BUTTON, 0);
+                                isWakeKey = false;
+                            }
                         }
                     }
                 }
@@ -4408,49 +4611,11 @@
 
             case KeyEvent.KEYCODE_POWER: {
                 result &= ~ACTION_PASS_TO_USER;
+                isWakeKey = false; // wake-up will be handled separately
                 if (down) {
-                    boolean panic = mImmersiveModeConfirmation.onPowerKeyDown(interactive,
-                            event.getDownTime(), isImmersiveMode(mLastSystemUiFlags));
-                    if (panic) {
-                        mHandler.post(mRequestTransientNav);
-                    }
-                    if (interactive && !mPowerKeyTriggered
-                            && (event.getFlags() & KeyEvent.FLAG_FALLBACK) == 0) {
-                        mPowerKeyTriggered = true;
-                        mPowerKeyTime = event.getDownTime();
-                        interceptScreenshotChord();
-                    }
-
-                    TelecomManager telecomManager = getTelecommService();
-                    boolean hungUp = false;
-                    if (telecomManager != null) {
-                        if (telecomManager.isRinging()) {
-                            // Pressing Power while there's a ringing incoming
-                            // call should silence the ringer.
-                            telecomManager.silenceRinger();
-                        } else if ((mIncallPowerBehavior
-                                & Settings.Secure.INCALL_POWER_BUTTON_BEHAVIOR_HANGUP) != 0
-                                && telecomManager.isInCall() && interactive) {
-                            // Otherwise, if "Power button ends call" is enabled,
-                            // the Power button will hang up any current active call.
-                            hungUp = telecomManager.endCall();
-                        }
-                    }
-                    interceptPowerKeyDown(!interactive || hungUp
-                            || mVolumeDownKeyTriggered || mVolumeUpKeyTriggered);
+                    interceptPowerKeyDown(event, interactive);
                 } else {
-                    mPowerKeyTriggered = false;
-                    cancelPendingScreenshotChordAction();
-                    if (interceptPowerKeyUp(canceled || mPendingPowerKeyUpCanceled)) {
-                        if (mScreenOnEarly && !mScreenOnFully) {
-                            Slog.i(TAG, "Suppressed redundant power key press while "
-                                    + "already in the process of turning the screen on.");
-                        } else {
-                            powerShortPress(event.getEventTime());
-                        }
-                        isWakeKey = false;
-                    }
-                    mPendingPowerKeyUpCanceled = false;
+                    interceptPowerKeyUp(event, interactive, canceled);
                 }
                 break;
             }
@@ -4541,14 +4706,29 @@
         }
 
         if (isWakeKey) {
-            wakeUp(event.getEventTime(), keyCode == KeyEvent.KEYCODE_POWER
-                    ? mAllowTheaterModeWakeFromPowerKey : mAllowTheaterModeWakeFromKey);
+            wakeUp(event.getEventTime(), mAllowTheaterModeWakeFromKey);
         }
 
         return result;
     }
 
     /**
+     * Returns true if the key can have global actions attached to it.
+     * We reserve all power management keys for the system since they require
+     * very careful handling.
+     */
+    private static boolean isValidGlobalKey(int keyCode) {
+        switch (keyCode) {
+            case KeyEvent.KEYCODE_POWER:
+            case KeyEvent.KEYCODE_WAKEUP:
+            case KeyEvent.KEYCODE_SLEEP:
+                return false;
+            default:
+                return true;
+        }
+    }
+
+    /**
      * When the screen is off we ignore some keys that might otherwise typically
      * be considered wake keys.  We filter them out here.
      *
@@ -4765,6 +4945,10 @@
         }
     }
 
+    private void wakeUpFromPowerKey(long eventTime) {
+        wakeUp(eventTime, mAllowTheaterModeWakeFromPowerKey);
+    }
+
     private void wakeUp(long wakeTime, boolean wakeInTheaterMode) {
         if (!wakeInTheaterMode && isTheaterModeEnabled()) {
             return;
@@ -4981,6 +5165,7 @@
     @Override
     public void dismissKeyguardLw() {
         if (mKeyguardDelegate != null && mKeyguardDelegate.isShowing()) {
+            if (DEBUG_KEYGUARD) Slog.d(TAG, "PWM.dismissKeyguardLw");
             mHandler.post(new Runnable() {
                 @Override
                 public void run() {
@@ -5012,6 +5197,7 @@
     @Override
     public void startKeyguardExitAnimation(long startTime, long fadeoutDuration) {
         if (mKeyguardDelegate != null) {
+            if (DEBUG_KEYGUARD) Slog.d(TAG, "PWM.startKeyguardExitAnimation");
             mKeyguardDelegate.startKeyguardExitAnimation(startTime, fadeoutDuration);
         }
     }
@@ -5983,6 +6169,9 @@
         pw.print(prefix);
                 pw.print("mShortPressOnPowerBehavior="); pw.print(mShortPressOnPowerBehavior);
                 pw.print(" mLongPressOnPowerBehavior="); pw.println(mLongPressOnPowerBehavior);
+        pw.print(prefix);
+                pw.print("mDoublePressOnPowerBehavior="); pw.print(mDoublePressOnPowerBehavior);
+                pw.print(" mTriplePressOnPowerBehavior="); pw.println(mTriplePressOnPowerBehavior);
         pw.print(prefix); pw.print("mHasSoftInput="); pw.println(mHasSoftInput);
         pw.print(prefix); pw.print("mAwake="); pw.println(mAwake);
         pw.print(prefix); pw.print("mScreenOnEarly="); pw.print(mScreenOnEarly);
diff --git a/services/core/java/com/android/server/TextServicesManagerService.java b/services/core/java/com/android/server/TextServicesManagerService.java
index d4c436f..5add88e 100644
--- a/services/core/java/com/android/server/TextServicesManagerService.java
+++ b/services/core/java/com/android/server/TextServicesManagerService.java
@@ -16,6 +16,7 @@
 
 package com.android.server;
 
+import com.android.internal.annotations.GuardedBy;
 import com.android.internal.content.PackageMonitor;
 import com.android.internal.textservice.ISpellCheckerService;
 import com.android.internal.textservice.ISpellCheckerSession;
@@ -28,14 +29,18 @@
 import android.app.ActivityManagerNative;
 import android.app.AppGlobals;
 import android.app.IUserSwitchObserver;
+import android.content.BroadcastReceiver;
 import android.content.ComponentName;
 import android.content.ContentResolver;
 import android.content.Context;
 import android.content.Intent;
+import android.content.IntentFilter;
 import android.content.ServiceConnection;
+import android.content.pm.ApplicationInfo;
 import android.content.pm.PackageManager;
 import android.content.pm.ResolveInfo;
 import android.content.pm.ServiceInfo;
+import android.content.pm.UserInfo;
 import android.os.Binder;
 import android.os.Bundle;
 import android.os.IBinder;
@@ -43,6 +48,7 @@
 import android.os.Process;
 import android.os.RemoteException;
 import android.os.UserHandle;
+import android.os.UserManager;
 import android.provider.Settings;
 import android.service.textservice.SpellCheckerService;
 import android.text.TextUtils;
@@ -84,6 +90,12 @@
     public TextServicesManagerService(Context context) {
         mSystemReady = false;
         mContext = context;
+
+        final IntentFilter broadcastFilter = new IntentFilter();
+        broadcastFilter.addAction(Intent.ACTION_USER_ADDED);
+        broadcastFilter.addAction(Intent.ACTION_USER_REMOVED);
+        mContext.registerReceiver(new TextServicesBroadcastReceiver(), broadcastFilter);
+
         int userId = UserHandle.USER_OWNER;
         try {
             ActivityManagerNative.getDefault().registerUserSwitchObserver(
@@ -119,6 +131,7 @@
 
     private void switchUserLocked(int userId) {
         mSettings.setCurrentUserId(userId);
+        updateCurrentProfileIds();
         unbindServiceLocked();
         buildSpellCheckerMapLocked(mContext, mSpellCheckerList, mSpellCheckerMap, mSettings);
         SpellCheckerInfo sci = getCurrentSpellChecker(null);
@@ -133,6 +146,16 @@
         }
     }
 
+    void updateCurrentProfileIds() {
+        List<UserInfo> profiles =
+                UserManager.get(mContext).getProfiles(mSettings.getCurrentUserId());
+        int[] currentProfileIds = new int[profiles.size()]; // profiles will not be null
+        for (int i = 0; i < currentProfileIds.length; i++) {
+            currentProfileIds[i] = profiles.get(i).id;
+        }
+        mSettings.setCurrentProfileIds(currentProfileIds);
+    }
+
     private class TextServicesMonitor extends PackageMonitor {
         private boolean isChangingPackagesOfCurrentUser() {
             final int userId = getChangingUserId();
@@ -171,6 +194,19 @@
         }
     }
 
+    class TextServicesBroadcastReceiver extends BroadcastReceiver {
+        @Override
+        public void onReceive(Context context, Intent intent) {
+            final String action = intent.getAction();
+            if (Intent.ACTION_USER_ADDED.equals(action)
+                    || Intent.ACTION_USER_REMOVED.equals(action)) {
+                updateCurrentProfileIds();
+                return;
+            }
+            Slog.w(TAG, "Unexpected intent " + intent);
+        }
+    }
+
     private static void buildSpellCheckerMapLocked(Context context,
             ArrayList<SpellCheckerInfo> list, HashMap<String, SpellCheckerInfo> map,
             TextServicesSettings settings) {
@@ -223,7 +259,7 @@
             Slog.d(TAG, "--- calledFromForegroundUserOrSystemProcess ? "
                     + "calling uid = " + uid + " system uid = " + Process.SYSTEM_UID
                     + " calling userId = " + userId + ", foreground user id = "
-                    + mSettings.getCurrentUserId());
+                    + mSettings.getCurrentUserId() + ", calling pid = " + Binder.getCallingPid());
             try {
                 final String[] packageNames = AppGlobals.getPackageManager().getPackagesForUid(uid);
                 for (int i = 0; i < packageNames.length; ++i) {
@@ -237,10 +273,40 @@
 
         if (uid == Process.SYSTEM_UID || userId == mSettings.getCurrentUserId()) {
             return true;
-        } else {
-            Slog.w(TAG, "--- IPC called from background users. Ignore. \n" + getStackTrace());
-            return false;
         }
+
+        // Permits current profile to use TSFM as long as the current text service is the system's
+        // one. This is a tentative solution and should be replaced with fully functional multiuser
+        // support.
+        // TODO: Implement multiuser support in TSMS.
+        final boolean isCurrentProfile = mSettings.isCurrentProfile(userId);
+        if (DBG) {
+            Slog.d(TAG, "--- userId = "+ userId + " isCurrentProfile = " + isCurrentProfile);
+        }
+        if (mSettings.isCurrentProfile(userId)) {
+            final SpellCheckerInfo spellCheckerInfo = getCurrentSpellCheckerWithoutVerification();
+            if (spellCheckerInfo != null) {
+                final ServiceInfo serviceInfo = spellCheckerInfo.getServiceInfo();
+                final boolean isSystemSpellChecker =
+                        (serviceInfo.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) != 0;
+                if (DBG) {
+                    Slog.d(TAG, "--- current spell checker = "+ spellCheckerInfo.getPackageName()
+                            + " isSystem = " + isSystemSpellChecker);
+                }
+                if (isSystemSpellChecker) {
+                    return true;
+                }
+            }
+        }
+
+        // Unlike InputMethodManagerService#calledFromValidUser, INTERACT_ACROSS_USERS_FULL isn't
+        // taken into account here.  Anyway this method is supposed to be removed once multiuser
+        // support is implemented.
+        if (DBG) {
+            Slog.d(TAG, "--- IPC from userId:" + userId + " is being ignored. \n"
+                    + getStackTrace());
+        }
+        return false;
     }
 
     private boolean bindCurrentSpellCheckerService(
@@ -292,6 +358,10 @@
         if (!calledFromValidUser()) {
             return null;
         }
+        return getCurrentSpellCheckerWithoutVerification();
+    }
+
+    private SpellCheckerInfo getCurrentSpellCheckerWithoutVerification() {
         synchronized (mSpellCheckerMap) {
             final String curSpellCheckerId = mSettings.getSelectedSpellChecker();
             if (DBG) {
@@ -914,6 +984,10 @@
     private static class TextServicesSettings {
         private final ContentResolver mResolver;
         private int mCurrentUserId;
+        @GuardedBy("mLock")
+        private int[] mCurrentProfileIds = new int[0];
+        private Object mLock = new Object();
+
         public TextServicesSettings(ContentResolver resolver, int userId) {
             mResolver = resolver;
             mCurrentUserId = userId;
@@ -928,6 +1002,22 @@
             mCurrentUserId = userId;
         }
 
+        public void setCurrentProfileIds(int[] currentProfileIds) {
+            synchronized (mLock) {
+                mCurrentProfileIds = currentProfileIds;
+            }
+        }
+
+        public boolean isCurrentProfile(int userId) {
+            synchronized (mLock) {
+                if (userId == mCurrentUserId) return true;
+                for (int i = 0; i < mCurrentProfileIds.length; i++) {
+                    if (userId == mCurrentProfileIds[i]) return true;
+                }
+                return false;
+            }
+        }
+
         public int getCurrentUserId() {
             return mCurrentUserId;
         }
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index 9f1ce0b..9179cc4 100755
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -1606,197 +1606,7 @@
                 final ArrayList<ProcessMemInfo> memInfos = (ArrayList<ProcessMemInfo>)msg.obj;
                 Thread thread = new Thread() {
                     @Override public void run() {
-                        final SparseArray<ProcessMemInfo> infoMap
-                                = new SparseArray<ProcessMemInfo>(memInfos.size());
-                        for (int i=0, N=memInfos.size(); i<N; i++) {
-                            ProcessMemInfo mi = memInfos.get(i);
-                            infoMap.put(mi.pid, mi);
-                        }
-                        updateCpuStatsNow();
-                        synchronized (mProcessCpuTracker) {
-                            final int N = mProcessCpuTracker.countStats();
-                            for (int i=0; i<N; i++) {
-                                ProcessCpuTracker.Stats st = mProcessCpuTracker.getStats(i);
-                                if (st.vsize > 0) {
-                                    long pss = Debug.getPss(st.pid, null);
-                                    if (pss > 0) {
-                                        if (infoMap.indexOfKey(st.pid) < 0) {
-                                            ProcessMemInfo mi = new ProcessMemInfo(st.name, st.pid,
-                                                    ProcessList.NATIVE_ADJ, -1, "native", null);
-                                            mi.pss = pss;
-                                            memInfos.add(mi);
-                                        }
-                                    }
-                                }
-                            }
-                        }
-
-                        long totalPss = 0;
-                        for (int i=0, N=memInfos.size(); i<N; i++) {
-                            ProcessMemInfo mi = memInfos.get(i);
-                            if (mi.pss == 0) {
-                                mi.pss = Debug.getPss(mi.pid, null);
-                            }
-                            totalPss += mi.pss;
-                        }
-                        Collections.sort(memInfos, new Comparator<ProcessMemInfo>() {
-                            @Override public int compare(ProcessMemInfo lhs, ProcessMemInfo rhs) {
-                                if (lhs.oomAdj != rhs.oomAdj) {
-                                    return lhs.oomAdj < rhs.oomAdj ? -1 : 1;
-                                }
-                                if (lhs.pss != rhs.pss) {
-                                    return lhs.pss < rhs.pss ? 1 : -1;
-                                }
-                                return 0;
-                            }
-                        });
-
-                        StringBuilder tag = new StringBuilder(128);
-                        StringBuilder stack = new StringBuilder(128);
-                        tag.append("Low on memory -- ");
-                        appendMemBucket(tag, totalPss, "total", false);
-                        appendMemBucket(stack, totalPss, "total", true);
-
-                        StringBuilder logBuilder = new StringBuilder(1024);
-                        logBuilder.append("Low on memory:\n");
-
-                        boolean firstLine = true;
-                        int lastOomAdj = Integer.MIN_VALUE;
-                        for (int i=0, N=memInfos.size(); i<N; i++) {
-                            ProcessMemInfo mi = memInfos.get(i);
-
-                            if (mi.oomAdj != ProcessList.NATIVE_ADJ
-                                    && (mi.oomAdj < ProcessList.SERVICE_ADJ
-                                            || mi.oomAdj == ProcessList.HOME_APP_ADJ
-                                            || mi.oomAdj == ProcessList.PREVIOUS_APP_ADJ)) {
-                                if (lastOomAdj != mi.oomAdj) {
-                                    lastOomAdj = mi.oomAdj;
-                                    if (mi.oomAdj <= ProcessList.FOREGROUND_APP_ADJ) {
-                                        tag.append(" / ");
-                                    }
-                                    if (mi.oomAdj >= ProcessList.FOREGROUND_APP_ADJ) {
-                                        if (firstLine) {
-                                            stack.append(":");
-                                            firstLine = false;
-                                        }
-                                        stack.append("\n\t at ");
-                                    } else {
-                                        stack.append("$");
-                                    }
-                                } else {
-                                    tag.append(" ");
-                                    stack.append("$");
-                                }
-                                if (mi.oomAdj <= ProcessList.FOREGROUND_APP_ADJ) {
-                                    appendMemBucket(tag, mi.pss, mi.name, false);
-                                }
-                                appendMemBucket(stack, mi.pss, mi.name, true);
-                                if (mi.oomAdj >= ProcessList.FOREGROUND_APP_ADJ
-                                        && ((i+1) >= N || memInfos.get(i+1).oomAdj != lastOomAdj)) {
-                                    stack.append("(");
-                                    for (int k=0; k<DUMP_MEM_OOM_ADJ.length; k++) {
-                                        if (DUMP_MEM_OOM_ADJ[k] == mi.oomAdj) {
-                                            stack.append(DUMP_MEM_OOM_LABEL[k]);
-                                            stack.append(":");
-                                            stack.append(DUMP_MEM_OOM_ADJ[k]);
-                                        }
-                                    }
-                                    stack.append(")");
-                                }
-                            }
-
-                            logBuilder.append("  ");
-                            logBuilder.append(ProcessList.makeOomAdjString(mi.oomAdj));
-                            logBuilder.append(' ');
-                            logBuilder.append(ProcessList.makeProcStateString(mi.procState));
-                            logBuilder.append(' ');
-                            ProcessList.appendRamKb(logBuilder, mi.pss);
-                            logBuilder.append(" kB: ");
-                            logBuilder.append(mi.name);
-                            logBuilder.append(" (");
-                            logBuilder.append(mi.pid);
-                            logBuilder.append(") ");
-                            logBuilder.append(mi.adjType);
-                            logBuilder.append('\n');
-                            if (mi.adjReason != null) {
-                                logBuilder.append("                      ");
-                                logBuilder.append(mi.adjReason);
-                                logBuilder.append('\n');
-                            }
-                        }
-
-                        logBuilder.append("           ");
-                        ProcessList.appendRamKb(logBuilder, totalPss);
-                        logBuilder.append(" kB: TOTAL\n");
-
-                        long[] infos = new long[Debug.MEMINFO_COUNT];
-                        Debug.getMemInfo(infos);
-                        logBuilder.append("  MemInfo: ");
-                        logBuilder.append(infos[Debug.MEMINFO_SLAB]).append(" kB slab, ");
-                        logBuilder.append(infos[Debug.MEMINFO_SHMEM]).append(" kB shmem, ");
-                        logBuilder.append(infos[Debug.MEMINFO_VM_ALLOC_USED]).append(" kB vm alloc, ");
-                        logBuilder.append(infos[Debug.MEMINFO_PAGE_TABLES]).append(" kB page tables ");
-                        logBuilder.append(infos[Debug.MEMINFO_KERNEL_STACK]).append(" kB kernel stack\n");
-                        logBuilder.append("           ");
-                        logBuilder.append(infos[Debug.MEMINFO_BUFFERS]).append(" kB buffers, ");
-                        logBuilder.append(infos[Debug.MEMINFO_CACHED]).append(" kB cached, ");
-                        logBuilder.append(infos[Debug.MEMINFO_MAPPED]).append(" kB mapped, ");
-                        logBuilder.append(infos[Debug.MEMINFO_FREE]).append(" kB free\n");
-                        if (infos[Debug.MEMINFO_ZRAM_TOTAL] != 0) {
-                            logBuilder.append("  ZRAM: ");
-                            logBuilder.append(infos[Debug.MEMINFO_ZRAM_TOTAL]);
-                            logBuilder.append(" kB RAM, ");
-                            logBuilder.append(infos[Debug.MEMINFO_SWAP_TOTAL]);
-                            logBuilder.append(" kB swap total, ");
-                            logBuilder.append(infos[Debug.MEMINFO_SWAP_FREE]);
-                            logBuilder.append(" kB swap free\n");
-                        }
-                        Slog.i(TAG, logBuilder.toString());
-
-                        StringBuilder dropBuilder = new StringBuilder(1024);
-                        /*
-                        StringWriter oomSw = new StringWriter();
-                        PrintWriter oomPw = new FastPrintWriter(oomSw, false, 256);
-                        StringWriter catSw = new StringWriter();
-                        PrintWriter catPw = new FastPrintWriter(catSw, false, 256);
-                        String[] emptyArgs = new String[] { };
-                        dumpApplicationMemoryUsage(null, oomPw, "  ", emptyArgs, true, catPw);
-                        oomPw.flush();
-                        String oomString = oomSw.toString();
-                        */
-                        dropBuilder.append(stack);
-                        dropBuilder.append('\n');
-                        dropBuilder.append('\n');
-                        dropBuilder.append(logBuilder);
-                        dropBuilder.append('\n');
-                        /*
-                        dropBuilder.append(oomString);
-                        dropBuilder.append('\n');
-                        */
-                        StringWriter catSw = new StringWriter();
-                        synchronized (ActivityManagerService.this) {
-                            PrintWriter catPw = new FastPrintWriter(catSw, false, 256);
-                            String[] emptyArgs = new String[] { };
-                            catPw.println();
-                            dumpProcessesLocked(null, catPw, emptyArgs, 0, false, null);
-                            catPw.println();
-                            mServices.dumpServicesLocked(null, catPw, emptyArgs, 0,
-                                    false, false, null);
-                            catPw.println();
-                            dumpActivitiesLocked(null, catPw, emptyArgs, 0, false, false, null);
-                            catPw.flush();
-                        }
-                        dropBuilder.append(catSw.toString());
-                        addErrorToDropBox("lowmem", null, "system_server", null,
-                                null, tag.toString(), dropBuilder.toString(), null, null);
-                        //Slog.i(TAG, "Sent to dropbox:");
-                        //Slog.i(TAG, dropBuilder.toString());
-                        synchronized (ActivityManagerService.this) {
-                            long now = SystemClock.uptimeMillis();
-                            if (mLastMemUsageReportTime < now) {
-                                mLastMemUsageReportTime = now;
-                            }
-                        }
+                        reportMemUsage(memInfos);
                     }
                 };
                 thread.start();
@@ -13927,6 +13737,35 @@
         }
     }
 
+    private static final int KSM_SHARED = 0;
+    private static final int KSM_SHARING = 1;
+    private static final int KSM_UNSHARED = 2;
+    private static final int KSM_VOLATILE = 3;
+
+    private final long[] getKsmInfo() {
+        long[] longOut = new long[4];
+        final int[] SINGLE_LONG_FORMAT = new int[] {
+            Process.PROC_SPACE_TERM|Process.PROC_OUT_LONG
+        };
+        long[] longTmp = new long[1];
+        Process.readProcFile("/sys/kernel/mm/ksm/pages_shared",
+                SINGLE_LONG_FORMAT, null, longTmp, null);
+        longOut[KSM_SHARED] = longTmp[0] * ProcessList.PAGE_SIZE / 1024;
+        longTmp[0] = 0;
+        Process.readProcFile("/sys/kernel/mm/ksm/pages_sharing",
+                SINGLE_LONG_FORMAT, null, longTmp, null);
+        longOut[KSM_SHARING] = longTmp[0] * ProcessList.PAGE_SIZE / 1024;
+        longTmp[0] = 0;
+        Process.readProcFile("/sys/kernel/mm/ksm/pages_unshared",
+                SINGLE_LONG_FORMAT, null, longTmp, null);
+        longOut[KSM_UNSHARED] = longTmp[0] * ProcessList.PAGE_SIZE / 1024;
+        longTmp[0] = 0;
+        Process.readProcFile("/sys/kernel/mm/ksm/pages_volatile",
+                SINGLE_LONG_FORMAT, null, longTmp, null);
+        longOut[KSM_VOLATILE] = longTmp[0] * ProcessList.PAGE_SIZE / 1024;
+        return longOut;
+    }
+
     final void dumpApplicationMemoryUsage(FileDescriptor fd,
             PrintWriter pw, String prefix, String[] args, boolean brief, PrintWriter categoryPw) {
         boolean dumpDetails = false;
@@ -14272,7 +14111,7 @@
                     pw.print(" Free RAM: "); pw.print(cachedPss + memInfo.getCachedSizeKb()
                             + memInfo.getFreeSizeKb()); pw.print(" kB (");
                             pw.print(cachedPss); pw.print(" cached pss + ");
-                            pw.print(memInfo.getCachedSizeKb()); pw.print(" cached + ");
+                            pw.print(memInfo.getCachedSizeKb()); pw.print(" cached kernel + ");
                             pw.print(memInfo.getFreeSizeKb()); pw.println(" free)");
                 } else {
                     pw.print("ram,"); pw.print(memInfo.getTotalSizeKb()); pw.print(",");
@@ -14306,32 +14145,16 @@
                                 pw.println(memInfo.getSwapFreeSizeKb());
                     }
                 }
-                final int[] SINGLE_LONG_FORMAT = new int[] {
-                    Process.PROC_SPACE_TERM|Process.PROC_OUT_LONG
-                };
-                long[] longOut = new long[1];
-                Process.readProcFile("/sys/kernel/mm/ksm/pages_shared",
-                        SINGLE_LONG_FORMAT, null, longOut, null);
-                long shared = longOut[0] * ProcessList.PAGE_SIZE / 1024;
-                longOut[0] = 0;
-                Process.readProcFile("/sys/kernel/mm/ksm/pages_sharing",
-                        SINGLE_LONG_FORMAT, null, longOut, null);
-                long sharing = longOut[0] * ProcessList.PAGE_SIZE / 1024;
-                longOut[0] = 0;
-                Process.readProcFile("/sys/kernel/mm/ksm/pages_unshared",
-                        SINGLE_LONG_FORMAT, null, longOut, null);
-                long unshared = longOut[0] * ProcessList.PAGE_SIZE / 1024;
-                longOut[0] = 0;
-                Process.readProcFile("/sys/kernel/mm/ksm/pages_volatile",
-                        SINGLE_LONG_FORMAT, null, longOut, null);
-                long voltile = longOut[0] * ProcessList.PAGE_SIZE / 1024;
+                final long[] ksm = getKsmInfo();
                 if (!isCompact) {
-                    if (sharing != 0 || shared != 0 || unshared != 0 || voltile != 0) {
-                        pw.print("      KSM: "); pw.print(sharing);
+                    if (ksm[KSM_SHARING] != 0 || ksm[KSM_SHARED] != 0 || ksm[KSM_UNSHARED] != 0
+                            || ksm[KSM_VOLATILE] != 0) {
+                        pw.print("      KSM: "); pw.print(ksm[KSM_SHARING]);
                                 pw.print(" kB saved from shared ");
-                                pw.print(shared); pw.println(" kB");
-                        pw.print("           "); pw.print(unshared); pw.print(" kB unshared; ");
-                                pw.print(voltile); pw.println(" kB volatile");
+                                pw.print(ksm[KSM_SHARED]); pw.println(" kB");
+                        pw.print("           "); pw.print(ksm[KSM_UNSHARED]);
+                                pw.print(" kB unshared; ");
+                                pw.print(ksm[KSM_VOLATILE]); pw.println(" kB volatile");
                     }
                     pw.print("   Tuning: ");
                     pw.print(ActivityManager.staticGetMemoryClass());
@@ -14351,9 +14174,9 @@
                     }
                     pw.println();
                 } else {
-                    pw.print("ksm,"); pw.print(sharing); pw.print(",");
-                    pw.print(shared); pw.print(","); pw.print(unshared); pw.print(",");
-                    pw.println(voltile);
+                    pw.print("ksm,"); pw.print(ksm[KSM_SHARING]); pw.print(",");
+                    pw.print(ksm[KSM_SHARED]); pw.print(","); pw.print(ksm[KSM_UNSHARED]);
+                    pw.print(","); pw.println(ksm[KSM_VOLATILE]);
                     pw.print("tuning,");
                     pw.print(ActivityManager.staticGetMemoryClass());
                     pw.print(',');
@@ -14372,6 +14195,265 @@
         }
     }
 
+    private void appendBasicMemEntry(StringBuilder sb, int oomAdj, int procState, long pss,
+            String name) {
+        sb.append("  ");
+        sb.append(ProcessList.makeOomAdjString(oomAdj));
+        sb.append(' ');
+        sb.append(ProcessList.makeProcStateString(procState));
+        sb.append(' ');
+        ProcessList.appendRamKb(sb, pss);
+        sb.append(" kB: ");
+        sb.append(name);
+    }
+
+    private void appendMemInfo(StringBuilder sb, ProcessMemInfo mi) {
+        appendBasicMemEntry(sb, mi.oomAdj, mi.procState, mi.pss, mi.name);
+        sb.append(" (");
+        sb.append(mi.pid);
+        sb.append(") ");
+        sb.append(mi.adjType);
+        sb.append('\n');
+        if (mi.adjReason != null) {
+            sb.append("                      ");
+            sb.append(mi.adjReason);
+            sb.append('\n');
+        }
+    }
+
+    void reportMemUsage(ArrayList<ProcessMemInfo> memInfos) {
+        final SparseArray<ProcessMemInfo> infoMap = new SparseArray<>(memInfos.size());
+        for (int i=0, N=memInfos.size(); i<N; i++) {
+            ProcessMemInfo mi = memInfos.get(i);
+            infoMap.put(mi.pid, mi);
+        }
+        updateCpuStatsNow();
+        synchronized (mProcessCpuTracker) {
+            final int N = mProcessCpuTracker.countStats();
+            for (int i=0; i<N; i++) {
+                ProcessCpuTracker.Stats st = mProcessCpuTracker.getStats(i);
+                if (st.vsize > 0) {
+                    long pss = Debug.getPss(st.pid, null);
+                    if (pss > 0) {
+                        if (infoMap.indexOfKey(st.pid) < 0) {
+                            ProcessMemInfo mi = new ProcessMemInfo(st.name, st.pid,
+                                    ProcessList.NATIVE_ADJ, -1, "native", null);
+                            mi.pss = pss;
+                            memInfos.add(mi);
+                        }
+                    }
+                }
+            }
+        }
+
+        long totalPss = 0;
+        for (int i=0, N=memInfos.size(); i<N; i++) {
+            ProcessMemInfo mi = memInfos.get(i);
+            if (mi.pss == 0) {
+                mi.pss = Debug.getPss(mi.pid, null);
+            }
+            totalPss += mi.pss;
+        }
+        Collections.sort(memInfos, new Comparator<ProcessMemInfo>() {
+            @Override public int compare(ProcessMemInfo lhs, ProcessMemInfo rhs) {
+                if (lhs.oomAdj != rhs.oomAdj) {
+                    return lhs.oomAdj < rhs.oomAdj ? -1 : 1;
+                }
+                if (lhs.pss != rhs.pss) {
+                    return lhs.pss < rhs.pss ? 1 : -1;
+                }
+                return 0;
+            }
+        });
+
+        StringBuilder tag = new StringBuilder(128);
+        StringBuilder stack = new StringBuilder(128);
+        tag.append("Low on memory -- ");
+        appendMemBucket(tag, totalPss, "total", false);
+        appendMemBucket(stack, totalPss, "total", true);
+
+        StringBuilder fullNativeBuilder = new StringBuilder(1024);
+        StringBuilder shortNativeBuilder = new StringBuilder(1024);
+        StringBuilder fullJavaBuilder = new StringBuilder(1024);
+
+        boolean firstLine = true;
+        int lastOomAdj = Integer.MIN_VALUE;
+        long extraNativeRam = 0;
+        long cachedPss = 0;
+        for (int i=0, N=memInfos.size(); i<N; i++) {
+            ProcessMemInfo mi = memInfos.get(i);
+
+            if (mi.oomAdj >= ProcessList.CACHED_APP_MIN_ADJ) {
+                cachedPss += mi.pss;
+            }
+
+            if (mi.oomAdj != ProcessList.NATIVE_ADJ
+                    && (mi.oomAdj < ProcessList.SERVICE_ADJ
+                            || mi.oomAdj == ProcessList.HOME_APP_ADJ
+                            || mi.oomAdj == ProcessList.PREVIOUS_APP_ADJ)) {
+                if (lastOomAdj != mi.oomAdj) {
+                    lastOomAdj = mi.oomAdj;
+                    if (mi.oomAdj <= ProcessList.FOREGROUND_APP_ADJ) {
+                        tag.append(" / ");
+                    }
+                    if (mi.oomAdj >= ProcessList.FOREGROUND_APP_ADJ) {
+                        if (firstLine) {
+                            stack.append(":");
+                            firstLine = false;
+                        }
+                        stack.append("\n\t at ");
+                    } else {
+                        stack.append("$");
+                    }
+                } else {
+                    tag.append(" ");
+                    stack.append("$");
+                }
+                if (mi.oomAdj <= ProcessList.FOREGROUND_APP_ADJ) {
+                    appendMemBucket(tag, mi.pss, mi.name, false);
+                }
+                appendMemBucket(stack, mi.pss, mi.name, true);
+                if (mi.oomAdj >= ProcessList.FOREGROUND_APP_ADJ
+                        && ((i+1) >= N || memInfos.get(i+1).oomAdj != lastOomAdj)) {
+                    stack.append("(");
+                    for (int k=0; k<DUMP_MEM_OOM_ADJ.length; k++) {
+                        if (DUMP_MEM_OOM_ADJ[k] == mi.oomAdj) {
+                            stack.append(DUMP_MEM_OOM_LABEL[k]);
+                            stack.append(":");
+                            stack.append(DUMP_MEM_OOM_ADJ[k]);
+                        }
+                    }
+                    stack.append(")");
+                }
+            }
+
+            appendMemInfo(fullNativeBuilder, mi);
+            if (mi.oomAdj == ProcessList.NATIVE_ADJ) {
+                // The short form only has native processes that are >= 1MB.
+                if (mi.pss >= 1000) {
+                    appendMemInfo(shortNativeBuilder, mi);
+                } else {
+                    extraNativeRam += mi.pss;
+                }
+            } else {
+                // Short form has all other details, but if we have collected RAM
+                // from smaller native processes let's dump a summary of that.
+                if (extraNativeRam > 0) {
+                    appendBasicMemEntry(shortNativeBuilder, ProcessList.NATIVE_ADJ,
+                            -1, extraNativeRam, "(Other native)");
+                    shortNativeBuilder.append('\n');
+                    extraNativeRam = 0;
+                }
+                appendMemInfo(fullJavaBuilder, mi);
+            }
+        }
+
+        fullJavaBuilder.append("           ");
+        ProcessList.appendRamKb(fullJavaBuilder, totalPss);
+        fullJavaBuilder.append(" kB: TOTAL\n");
+
+        MemInfoReader memInfo = new MemInfoReader();
+        memInfo.readMemInfo();
+        final long[] infos = memInfo.getRawInfo();
+
+        StringBuilder memInfoBuilder = new StringBuilder(1024);
+        Debug.getMemInfo(infos);
+        memInfoBuilder.append("  MemInfo: ");
+        memInfoBuilder.append(infos[Debug.MEMINFO_SLAB]).append(" kB slab, ");
+        memInfoBuilder.append(infos[Debug.MEMINFO_SHMEM]).append(" kB shmem, ");
+        memInfoBuilder.append(infos[Debug.MEMINFO_VM_ALLOC_USED]).append(" kB vm alloc, ");
+        memInfoBuilder.append(infos[Debug.MEMINFO_PAGE_TABLES]).append(" kB page tables ");
+        memInfoBuilder.append(infos[Debug.MEMINFO_KERNEL_STACK]).append(" kB kernel stack\n");
+        memInfoBuilder.append("           ");
+        memInfoBuilder.append(infos[Debug.MEMINFO_BUFFERS]).append(" kB buffers, ");
+        memInfoBuilder.append(infos[Debug.MEMINFO_CACHED]).append(" kB cached, ");
+        memInfoBuilder.append(infos[Debug.MEMINFO_MAPPED]).append(" kB mapped, ");
+        memInfoBuilder.append(infos[Debug.MEMINFO_FREE]).append(" kB free\n");
+        if (infos[Debug.MEMINFO_ZRAM_TOTAL] != 0) {
+            memInfoBuilder.append("  ZRAM: ");
+            memInfoBuilder.append(infos[Debug.MEMINFO_ZRAM_TOTAL]);
+            memInfoBuilder.append(" kB RAM, ");
+            memInfoBuilder.append(infos[Debug.MEMINFO_SWAP_TOTAL]);
+            memInfoBuilder.append(" kB swap total, ");
+            memInfoBuilder.append(infos[Debug.MEMINFO_SWAP_FREE]);
+            memInfoBuilder.append(" kB swap free\n");
+        }
+        final long[] ksm = getKsmInfo();
+        if (ksm[KSM_SHARING] != 0 || ksm[KSM_SHARED] != 0 || ksm[KSM_UNSHARED] != 0
+                || ksm[KSM_VOLATILE] != 0) {
+            memInfoBuilder.append("  KSM: "); memInfoBuilder.append(ksm[KSM_SHARING]);
+            memInfoBuilder.append(" kB saved from shared ");
+            memInfoBuilder.append(ksm[KSM_SHARED]); memInfoBuilder.append(" kB\n");
+            memInfoBuilder.append("       "); memInfoBuilder.append(ksm[KSM_UNSHARED]);
+            memInfoBuilder.append(" kB unshared; ");
+            memInfoBuilder.append(ksm[KSM_VOLATILE]); memInfoBuilder.append(" kB volatile\n");
+        }
+        memInfoBuilder.append("  Free RAM: ");
+        memInfoBuilder.append(cachedPss + memInfo.getCachedSizeKb()
+                + memInfo.getFreeSizeKb());
+        memInfoBuilder.append(" kB\n");
+        memInfoBuilder.append("  Used RAM: ");
+        memInfoBuilder.append(totalPss - cachedPss + memInfo.getKernelUsedSizeKb());
+        memInfoBuilder.append(" kB\n");
+        memInfoBuilder.append("  Lost RAM: ");
+        memInfoBuilder.append(memInfo.getTotalSizeKb()
+                - totalPss - memInfo.getFreeSizeKb() - memInfo.getCachedSizeKb()
+                - memInfo.getKernelUsedSizeKb());
+        memInfoBuilder.append(" kB\n");
+        Slog.i(TAG, "Low on memory:");
+        Slog.i(TAG, shortNativeBuilder.toString());
+        Slog.i(TAG, fullJavaBuilder.toString());
+        Slog.i(TAG, memInfoBuilder.toString());
+
+        StringBuilder dropBuilder = new StringBuilder(1024);
+        /*
+        StringWriter oomSw = new StringWriter();
+        PrintWriter oomPw = new FastPrintWriter(oomSw, false, 256);
+        StringWriter catSw = new StringWriter();
+        PrintWriter catPw = new FastPrintWriter(catSw, false, 256);
+        String[] emptyArgs = new String[] { };
+        dumpApplicationMemoryUsage(null, oomPw, "  ", emptyArgs, true, catPw);
+        oomPw.flush();
+        String oomString = oomSw.toString();
+        */
+        dropBuilder.append("Low on memory:");
+        dropBuilder.append(stack);
+        dropBuilder.append('\n');
+        dropBuilder.append(fullNativeBuilder);
+        dropBuilder.append(fullJavaBuilder);
+        dropBuilder.append('\n');
+        dropBuilder.append(memInfoBuilder);
+        dropBuilder.append('\n');
+        /*
+        dropBuilder.append(oomString);
+        dropBuilder.append('\n');
+        */
+        StringWriter catSw = new StringWriter();
+        synchronized (ActivityManagerService.this) {
+            PrintWriter catPw = new FastPrintWriter(catSw, false, 256);
+            String[] emptyArgs = new String[] { };
+            catPw.println();
+            dumpProcessesLocked(null, catPw, emptyArgs, 0, false, null);
+            catPw.println();
+            mServices.dumpServicesLocked(null, catPw, emptyArgs, 0,
+                    false, false, null);
+            catPw.println();
+            dumpActivitiesLocked(null, catPw, emptyArgs, 0, false, false, null);
+            catPw.flush();
+        }
+        dropBuilder.append(catSw.toString());
+        addErrorToDropBox("lowmem", null, "system_server", null,
+                null, tag.toString(), dropBuilder.toString(), null, null);
+        //Slog.i(TAG, "Sent to dropbox:");
+        //Slog.i(TAG, dropBuilder.toString());
+        synchronized (ActivityManagerService.this) {
+            long now = SystemClock.uptimeMillis();
+            if (mLastMemUsageReportTime < now) {
+                mLastMemUsageReportTime = now;
+            }
+        }
+    }
+
     /**
      * Searches array of arguments for the specified string
      * @param args array of argument strings
diff --git a/services/core/java/com/android/server/am/ActivityStackSupervisor.java b/services/core/java/com/android/server/am/ActivityStackSupervisor.java
index c1bf955..eaff6be 100644
--- a/services/core/java/com/android/server/am/ActivityStackSupervisor.java
+++ b/services/core/java/com/android/server/am/ActivityStackSupervisor.java
@@ -444,10 +444,6 @@
         return mService.startHomeActivityLocked(mCurrentUser);
     }
 
-    void keyguardWaitingForActivityDrawn() {
-        mWindowManager.keyguardWaitingForActivityDrawn();
-    }
-
     TaskRecord anyTaskForIdLocked(int id) {
         int numDisplays = mActivityDisplays.size();
         for (int displayNdx = 0; displayNdx < numDisplays; ++displayNdx) {
diff --git a/services/core/java/com/android/server/display/DisplayPowerController.java b/services/core/java/com/android/server/display/DisplayPowerController.java
index 2d5b99e..1d8003b 100644
--- a/services/core/java/com/android/server/display/DisplayPowerController.java
+++ b/services/core/java/com/android/server/display/DisplayPowerController.java
@@ -570,8 +570,11 @@
         state = mPowerState.getScreenState();
 
         // Use zero brightness when screen is off.
+        // Use full brightness when screen brightness is boosted.
         if (state == Display.STATE_OFF) {
             brightness = PowerManager.BRIGHTNESS_OFF;
+        } else if (mPowerRequest.boostScreenBrightness) {
+            brightness = PowerManager.BRIGHTNESS_ON;
         }
 
         // Use default brightness when dozing unless overridden.
diff --git a/services/core/java/com/android/server/location/GpsLocationProvider.java b/services/core/java/com/android/server/location/GpsLocationProvider.java
index 0198e46..c2cb4b1 100644
--- a/services/core/java/com/android/server/location/GpsLocationProvider.java
+++ b/services/core/java/com/android/server/location/GpsLocationProvider.java
@@ -473,14 +473,7 @@
                 checkSmsSuplInit(intent);
             } else if (action.equals(Intents.WAP_PUSH_RECEIVED_ACTION)) {
                 checkWapSuplInit(intent);
-            } else if (action.equals(ConnectivityManager.CONNECTIVITY_ACTION)) {
-                int networkState;
-                if (intent.getBooleanExtra(ConnectivityManager.EXTRA_NO_CONNECTIVITY, false)) {
-                    networkState = LocationProvider.TEMPORARILY_UNAVAILABLE;
-                } else {
-                    networkState = LocationProvider.AVAILABLE;
-                }
-
+            } else if (action.equals(ConnectivityManager.CONNECTIVITY_ACTION_IMMEDIATE)) {
                 // retrieve NetworkInfo result for this UID
                 NetworkInfo info =
                         intent.getParcelableExtra(ConnectivityManager.EXTRA_NETWORK_INFO);
@@ -488,6 +481,15 @@
                         mContext.getSystemService(Context.CONNECTIVITY_SERVICE);
                 info = connManager.getNetworkInfo(info.getType());
 
+                int networkState;
+                if (intent.getBooleanExtra(ConnectivityManager.EXTRA_NO_CONNECTIVITY, false) ||
+                    !info.isConnected()) {
+                    networkState = LocationProvider.TEMPORARILY_UNAVAILABLE;
+                } else {
+                    networkState = LocationProvider.AVAILABLE;
+                }
+
+
                 updateNetworkState(networkState, info);
             } else if (PowerManager.ACTION_POWER_SAVE_MODE_CHANGED.equals(action)
                     || Intent.ACTION_SCREEN_OFF.equals(action)
@@ -715,7 +717,7 @@
         intentFilter = new IntentFilter();
         intentFilter.addAction(ALARM_WAKEUP);
         intentFilter.addAction(ALARM_TIMEOUT);
-        intentFilter.addAction(ConnectivityManager.CONNECTIVITY_ACTION);
+        intentFilter.addAction(ConnectivityManager.CONNECTIVITY_ACTION_IMMEDIATE);
         intentFilter.addAction(PowerManager.ACTION_POWER_SAVE_MODE_CHANGED);
         intentFilter.addAction(Intent.ACTION_SCREEN_OFF);
         intentFilter.addAction(Intent.ACTION_SCREEN_ON);
diff --git a/services/core/java/com/android/server/power/PowerManagerService.java b/services/core/java/com/android/server/power/PowerManagerService.java
index 5e95dfe..8682f5c 100644
--- a/services/core/java/com/android/server/power/PowerManagerService.java
+++ b/services/core/java/com/android/server/power/PowerManagerService.java
@@ -88,6 +88,8 @@
     private static final int MSG_USER_ACTIVITY_TIMEOUT = 1;
     // Message: Sent when the device enters or exits a dreaming or dozing state.
     private static final int MSG_SANDMAN = 2;
+    // Message: Sent when the screen brightness boost expires.
+    private static final int MSG_SCREEN_BRIGHTNESS_BOOST_TIMEOUT = 3;
 
     // Dirty bit: mWakeLocks changed
     private static final int DIRTY_WAKE_LOCKS = 1 << 0;
@@ -111,6 +113,8 @@
     private static final int DIRTY_PROXIMITY_POSITIVE = 1 << 9;
     // Dirty bit: dock state changed
     private static final int DIRTY_DOCK_STATE = 1 << 10;
+    // Dirty bit: brightness boost changed
+    private static final int DIRTY_SCREEN_BRIGHTNESS_BOOST = 1 << 11;
 
     // Wakefulness: The device is asleep and can only be awoken by a call to wakeUp().
     // The screen should be off or in the process of being turned off by the display controller.
@@ -149,6 +153,11 @@
     private static final int DEFAULT_SCREEN_OFF_TIMEOUT = 15 * 1000;
     private static final int DEFAULT_SLEEP_TIMEOUT = -1;
 
+    // Screen brightness boost timeout.
+    // Hardcoded for now until we decide what the right policy should be.
+    // This should perhaps be a setting.
+    private static final int SCREEN_BRIGHTNESS_BOOST_TIMEOUT = 5 * 1000;
+
     // Power hints defined in hardware/libhardware/include/hardware/power.h.
     private static final int POWER_HINT_INTERACTION = 2;
     private static final int POWER_HINT_LOW_POWER = 5;
@@ -215,6 +224,10 @@
     // Timestamp of last interactive power hint.
     private long mLastInteractivePowerHintTime;
 
+    // Timestamp of the last screen brightness boost.
+    private long mLastScreenBrightnessBoostTime;
+    private boolean mScreenBrightnessBoostInProgress;
+
     // A bitfield that summarizes the effect of the user activity timer.
     private int mUserActivitySummary;
 
@@ -1812,9 +1825,13 @@
         final boolean oldDisplayReady = mDisplayReady;
         if ((dirty & (DIRTY_WAKE_LOCKS | DIRTY_USER_ACTIVITY | DIRTY_WAKEFULNESS
                 | DIRTY_ACTUAL_DISPLAY_POWER_STATE_UPDATED | DIRTY_BOOT_COMPLETED
-                | DIRTY_SETTINGS)) != 0) {
+                | DIRTY_SETTINGS | DIRTY_SCREEN_BRIGHTNESS_BOOST)) != 0) {
             mDisplayPowerRequest.policy = getDesiredScreenPolicyLocked();
 
+            // Handle screen brightness boost timeout.
+            updateScreenBrightnessBoostLocked();
+
+            // Determine appropriate screen brightness and auto-brightness adjustments.
             int screenBrightness = mScreenBrightnessSettingDefault;
             float screenAutoBrightnessAdjustment = 0.0f;
             boolean autoBrightness = (mScreenBrightnessModeSetting ==
@@ -1842,14 +1859,15 @@
                     mScreenBrightnessSettingMaximum), mScreenBrightnessSettingMinimum);
             screenAutoBrightnessAdjustment = Math.max(Math.min(
                     screenAutoBrightnessAdjustment, 1.0f), -1.0f);
+
+            // Update display power request.
             mDisplayPowerRequest.screenBrightness = screenBrightness;
             mDisplayPowerRequest.screenAutoBrightnessAdjustment =
                     screenAutoBrightnessAdjustment;
             mDisplayPowerRequest.useAutoBrightness = autoBrightness;
-
             mDisplayPowerRequest.useProximitySensor = shouldUseProximitySensorLocked();
-
             mDisplayPowerRequest.lowPowerMode = mLowPowerModeEnabled;
+            mDisplayPowerRequest.boostScreenBrightness = mScreenBrightnessBoostInProgress;
 
             if (mDisplayPowerRequest.policy == DisplayPowerRequest.POLICY_DOZE) {
                 mDisplayPowerRequest.dozeScreenState = mDozeScreenStateOverrideFromDreamManager;
@@ -1861,21 +1879,40 @@
             }
 
             mDisplayReady = mDisplayManagerInternal.requestPowerState(mDisplayPowerRequest,
-                    mRequestWaitForNegativeProximity);
+                    mRequestWaitForNegativeProximity) && !mScreenBrightnessBoostInProgress;
             mRequestWaitForNegativeProximity = false;
 
             if (DEBUG_SPEW) {
-                Slog.d(TAG, "updateScreenStateLocked: mDisplayReady=" + mDisplayReady
+                Slog.d(TAG, "updateDisplayPowerStateLocked: mDisplayReady=" + mDisplayReady
                         + ", policy=" + mDisplayPowerRequest.policy
                         + ", mWakefulness=" + mWakefulness
                         + ", mWakeLockSummary=0x" + Integer.toHexString(mWakeLockSummary)
                         + ", mUserActivitySummary=0x" + Integer.toHexString(mUserActivitySummary)
-                        + ", mBootCompleted=" + mBootCompleted);
+                        + ", mBootCompleted=" + mBootCompleted
+                        + ", mScreenBrightnessBoostInProgress="
+                                + mScreenBrightnessBoostInProgress);
             }
         }
         return mDisplayReady && !oldDisplayReady;
     }
 
+    private void updateScreenBrightnessBoostLocked() {
+        if (mScreenBrightnessBoostInProgress) {
+            mHandler.removeMessages(MSG_SCREEN_BRIGHTNESS_BOOST_TIMEOUT);
+            if (mLastScreenBrightnessBoostTime > mLastSleepTime) {
+                final long boostTimeout = mLastScreenBrightnessBoostTime +
+                        SCREEN_BRIGHTNESS_BOOST_TIMEOUT;
+                if (boostTimeout > SystemClock.uptimeMillis()) {
+                    Message msg = mHandler.obtainMessage(MSG_SCREEN_BRIGHTNESS_BOOST_TIMEOUT);
+                    msg.setAsynchronous(true);
+                    mHandler.sendMessageAtTime(msg, boostTimeout);
+                    return;
+                }
+            }
+            mScreenBrightnessBoostInProgress = false;
+        }
+    }
+
     private static boolean isValidBrightness(int value) {
         return value >= 0 && value <= 255;
     }
@@ -2223,6 +2260,41 @@
         light.setFlashing(color, Light.LIGHT_FLASH_HARDWARE, (on ? 3 : 0), 0);
     }
 
+    private void boostScreenBrightnessInternal(long eventTime, int uid) {
+        synchronized (mLock) {
+            if (!mSystemReady || mWakefulness == WAKEFULNESS_ASLEEP
+                    || eventTime < mLastScreenBrightnessBoostTime) {
+                return;
+            }
+
+            Slog.i(TAG, "Brightness boost activated (uid " + uid +")...");
+            mLastScreenBrightnessBoostTime = eventTime;
+            mScreenBrightnessBoostInProgress = true;
+            mDirty |= DIRTY_SCREEN_BRIGHTNESS_BOOST;
+
+            userActivityNoUpdateLocked(eventTime,
+                    PowerManager.USER_ACTIVITY_EVENT_OTHER, 0, uid);
+            updatePowerStateLocked();
+        }
+    }
+
+    /**
+     * Called when a screen brightness boost timeout has occurred.
+     *
+     * This function must have no other side-effects besides setting the dirty
+     * bit and calling update power state.
+     */
+    private void handleScreenBrightnessBoostTimeout() { // runs on handler thread
+        synchronized (mLock) {
+            if (DEBUG_SPEW) {
+                Slog.d(TAG, "handleScreenBrightnessBoostTimeout");
+            }
+
+            mDirty |= DIRTY_SCREEN_BRIGHTNESS_BOOST;
+            updatePowerStateLocked();
+        }
+    }
+
     private void setScreenBrightnessOverrideFromWindowManagerInternal(int brightness) {
         synchronized (mLock) {
             if (mScreenBrightnessOverrideFromWindowManager != brightness) {
@@ -2366,6 +2438,10 @@
                     + TimeUtils.formatUptime(mLastUserActivityTimeNoChangeLights));
             pw.println("  mLastInteractivePowerHintTime="
                     + TimeUtils.formatUptime(mLastInteractivePowerHintTime));
+            pw.println("  mLastScreenBrightnessBoostTime="
+                    + TimeUtils.formatUptime(mLastScreenBrightnessBoostTime));
+            pw.println("  mScreenBrightnessBoostInProgress="
+                    + mScreenBrightnessBoostInProgress);
             pw.println("  mDisplayReady=" + mDisplayReady);
             pw.println("  mHoldingWakeLockSuspendBlocker=" + mHoldingWakeLockSuspendBlocker);
             pw.println("  mHoldingDisplaySuspendBlocker=" + mHoldingDisplaySuspendBlocker);
@@ -2562,6 +2638,9 @@
                 case MSG_SANDMAN:
                     handleSandman();
                     break;
+                case MSG_SCREEN_BRIGHTNESS_BOOST_TIMEOUT:
+                    handleScreenBrightnessBoostTimeout();
+                    break;
             }
         }
     }
@@ -3143,6 +3222,24 @@
         }
 
         @Override // Binder call
+        public void boostScreenBrightness(long eventTime) {
+            if (eventTime > SystemClock.uptimeMillis()) {
+                throw new IllegalArgumentException("event time must not be in the future");
+            }
+
+            mContext.enforceCallingOrSelfPermission(
+                    android.Manifest.permission.DEVICE_POWER, null);
+
+            final int uid = Binder.getCallingUid();
+            final long ident = Binder.clearCallingIdentity();
+            try {
+                boostScreenBrightnessInternal(eventTime, uid);
+            } finally {
+                Binder.restoreCallingIdentity(ident);
+            }
+        }
+
+        @Override // Binder call
         protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
             if (mContext.checkCallingOrSelfPermission(Manifest.permission.DUMP)
                     != PackageManager.PERMISSION_GRANTED) {
diff --git a/services/core/java/com/android/server/wm/WindowAnimator.java b/services/core/java/com/android/server/wm/WindowAnimator.java
index 69d3191..61ea1e8 100644
--- a/services/core/java/com/android/server/wm/WindowAnimator.java
+++ b/services/core/java/com/android/server/wm/WindowAnimator.java
@@ -20,6 +20,7 @@
 import static android.view.WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED;
 
 import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_KEYGUARD;
+import static com.android.server.wm.WindowManagerService.DEBUG_KEYGUARD;
 import static com.android.server.wm.WindowManagerService.LayoutFields.SET_UPDATE_ROTATION;
 import static com.android.server.wm.WindowManagerService.LayoutFields.SET_WALLPAPER_MAY_CHANGE;
 import static com.android.server.wm.WindowManagerService.LayoutFields.SET_FORCE_HIDING_CHANGED;
@@ -29,7 +30,6 @@
 import android.content.Context;
 import android.os.Debug;
 import android.os.SystemClock;
-import android.util.Log;
 import android.util.Slog;
 import android.util.SparseArray;
 import android.util.SparseIntArray;
@@ -233,12 +233,17 @@
                 final WindowStateAnimator winAnimator = win.mWinAnimator;
                 if ((win.mAttrs.privateFlags & PRIVATE_FLAG_KEYGUARD) != 0) {
                     if (!winAnimator.mAnimating) {
+                        if (DEBUG_KEYGUARD) Slog.d(TAG,
+                                "updateWindowsLocked: creating delay animation");
+
                         // Create a new animation to delay until keyguard is gone on its own.
                         winAnimator.mAnimation = new AlphaAnimation(1.0f, 1.0f);
                         winAnimator.mAnimation.setDuration(KEYGUARD_ANIM_TIMEOUT_MS);
                         winAnimator.mAnimationIsEntrance = false;
                     }
                 } else {
+                    if (DEBUG_KEYGUARD) Slog.d(TAG,
+                            "updateWindowsLocked: StatusBar is no longer keyguard");
                     mKeyguardGoingAway = false;
                     winAnimator.clearAnimation();
                 }
@@ -282,7 +287,7 @@
 
                 if (mPolicy.isForceHiding(win.mAttrs)) {
                     if (!wasAnimating && nowAnimating) {
-                        if (WindowManagerService.DEBUG_ANIM ||
+                        if (DEBUG_KEYGUARD || WindowManagerService.DEBUG_ANIM ||
                                 WindowManagerService.DEBUG_VISIBILITY) Slog.v(TAG,
                                 "Animation started that could impact force hide: " + win);
                         mBulkUpdateParams |= SET_FORCE_HIDING_CHANGED;
@@ -310,7 +315,7 @@
                             mForceHiding = win.isDrawnLw() ? KEYGUARD_SHOWN : KEYGUARD_NOT_SHOWN;
                         }
                     }
-                    if (WindowManagerService.DEBUG_VISIBILITY) Slog.v(TAG,
+                    if (DEBUG_KEYGUARD || WindowManagerService.DEBUG_VISIBILITY) Slog.v(TAG,
                             "Force hide " + forceHidingToString()
                             + " hasSurface=" + win.mHasSurface
                             + " policyVis=" + win.mPolicyVisibility
@@ -327,12 +332,12 @@
                                 && (!winAnimator.isAnimating() || hideWhenLocked))
                             || ((mForceHiding == KEYGUARD_SHOWN) && hideWhenLocked)) {
                         changed = win.hideLw(false, false);
-                        if (WindowManagerService.DEBUG_VISIBILITY && changed) Slog.v(TAG,
-                                "Now policy hidden: " + win);
+                        if ((DEBUG_KEYGUARD || WindowManagerService.DEBUG_VISIBILITY)
+                                && changed) Slog.v(TAG, "Now policy hidden: " + win);
                     } else {
                         changed = win.showLw(false, false);
-                        if (WindowManagerService.DEBUG_VISIBILITY && changed) Slog.v(TAG,
-                                "Now policy shown: " + win);
+                        if ((DEBUG_KEYGUARD || WindowManagerService.DEBUG_VISIBILITY)
+                                && changed) Slog.v(TAG, "Now policy shown: " + win);
                         if (changed) {
                             if ((mBulkUpdateParams & SET_FORCE_HIDING_CHANGED) != 0
                                     && win.isVisibleNow() /*w.isReadyForDisplay()*/) {
@@ -404,6 +409,11 @@
                 if (!mKeyguardGoingAwayDisableWindowAnimations) {
                     a = mPolicy.createForceHideEnterAnimation(wallpaperInUnForceHiding,
                             mKeyguardGoingAwayToNotificationShade);
+                    if (DEBUG_KEYGUARD) Slog.d(TAG, "updateWindowsLocked: created anim=" + a
+                            + " for win=" + unForceHiding.get(i));
+                } else {
+                    if (DEBUG_KEYGUARD) Slog.d(TAG, "updateWindowsLocked: skipping anim for win="
+                            + unForceHiding.get(i));
                 }
                 if (a != null) {
                     final WindowStateAnimator winAnimator = unForceHiding.get(i);
@@ -422,6 +432,7 @@
             // Wallpaper is going away in un-force-hide motion, animate it as well.
             if (!wallpaperInUnForceHiding && wallpaper != null
                     && !mKeyguardGoingAwayDisableWindowAnimations) {
+                if (DEBUG_KEYGUARD) Slog.d(TAG, "updateWindowsLocked: wallpaper animating away");
                 Animation a = mPolicy.createForceHideWallpaperExitAnimation(
                         mKeyguardGoingAwayToNotificationShade);
                 if (a != null) {
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index 96e56e9..a48d39f 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -166,6 +166,7 @@
     static final boolean DEBUG_FOCUS = false;
     static final boolean DEBUG_FOCUS_LIGHT = DEBUG_FOCUS || false;
     static final boolean DEBUG_ANIM = false;
+    static final boolean DEBUG_KEYGUARD = false;
     static final boolean DEBUG_LAYOUT = false;
     static final boolean DEBUG_RESIZE = false;
     static final boolean DEBUG_LAYERS = false;
@@ -5363,6 +5364,8 @@
                 != PackageManager.PERMISSION_GRANTED) {
             throw new SecurityException("Requires DISABLE_KEYGUARD permission");
         }
+        if (DEBUG_KEYGUARD) Slog.d(TAG, "keyguardGoingAway: disableWinAnim="
+                + disableWindowAnimations + " kgToNotifShade=" + keyguardGoingToNotificationShade);
         synchronized (mWindowMap) {
             mAnimator.mKeyguardGoingAway = true;
             mAnimator.mKeyguardGoingAwayToNotificationShade = keyguardGoingToNotificationShade;
@@ -5372,12 +5375,15 @@
     }
 
     public void keyguardWaitingForActivityDrawn() {
+        if (DEBUG_KEYGUARD) Slog.d(TAG, "keyguardWaitingForActivityDrawn");
         synchronized (mWindowMap) {
             mKeyguardWaitingForActivityDrawn = true;
         }
     }
 
     public void notifyActivityDrawnForKeyguard() {
+        if (DEBUG_KEYGUARD) Slog.d(TAG, "notifyActivityDrawnForKeyguard: waiting="
+                + mKeyguardWaitingForActivityDrawn);
         synchronized (mWindowMap) {
             if (mKeyguardWaitingForActivityDrawn) {
                 mPolicy.notifyActivityDrawnForKeyguardLw();
diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java
index e5cf764..f9efc80 100644
--- a/services/core/java/com/android/server/wm/WindowState.java
+++ b/services/core/java/com/android/server/wm/WindowState.java
@@ -29,6 +29,7 @@
 import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_NO_MOVE_ANIMATION;
 import static android.view.WindowManager.LayoutParams.TYPE_INPUT_METHOD;
 import static android.view.WindowManager.LayoutParams.TYPE_INPUT_METHOD_DIALOG;
+import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_STARTING;
 import static android.view.WindowManager.LayoutParams.TYPE_WALLPAPER;
 
 import android.app.AppOpsManager;
@@ -902,7 +903,8 @@
      */
     boolean isVisibleNow() {
         return mHasSurface && mPolicyVisibility && !mAttachedHidden
-                && !mRootToken.hidden && !mExiting && !mDestroying;
+                && (!mRootToken.hidden || mAttrs.type == TYPE_APPLICATION_STARTING)
+                && !mExiting && !mDestroying;
     }
 
     /**
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/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/BridgePowerManager.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgePowerManager.java
index 22265a3..05a6fd6 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgePowerManager.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgePowerManager.java
@@ -145,4 +145,9 @@
     public void wakeUp(long time) throws RemoteException {
         // pass for now.
     }
+
+    @Override
+    public void boostScreenBrightness(long time) throws RemoteException {
+        // pass for now.
+    }
 }