Merge "QS edit mode fixes." into pi-dev
diff --git a/api/current.txt b/api/current.txt
index 999a6fb..6ea38cc 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -1378,7 +1378,7 @@
     field public static final int textEditSidePasteWindowLayout = 16843614; // 0x101035e
     field public static final int textEditSuggestionItemLayout = 16843636; // 0x1010374
     field public static final int textFilterEnabled = 16843007; // 0x10100ff
-    field public static final int textFontWeight = 16844166; // 0x1010586
+    field public static final int textFontWeight = 16844165; // 0x1010585
     field public static final int textIsSelectable = 16843542; // 0x1010316
     field public static final int textOff = 16843045; // 0x1010125
     field public static final int textOn = 16843044; // 0x1010124
@@ -1469,7 +1469,6 @@
     field public static final deprecated int unfocusedMonthDateColor = 16843588; // 0x1010344
     field public static final int unselectedAlpha = 16843278; // 0x101020e
     field public static final int updatePeriodMillis = 16843344; // 0x1010250
-    field public static final int urlBarResourceId = 16844164; // 0x1010584
     field public static final int use32bitAbi = 16844053; // 0x1010515
     field public static final int useDefaultMargins = 16843641; // 0x1010379
     field public static final int useIntrinsicSizeAsMinimum = 16843536; // 0x1010310
@@ -1549,7 +1548,7 @@
     field public static final int windowHideAnimation = 16842935; // 0x10100b7
     field public static final int windowIsFloating = 16842839; // 0x1010057
     field public static final int windowIsTranslucent = 16842840; // 0x1010058
-    field public static final int windowLayoutInDisplayCutoutMode = 16844167; // 0x1010587
+    field public static final int windowLayoutInDisplayCutoutMode = 16844166; // 0x1010586
     field public static final int windowLightNavigationBar = 16844140; // 0x101056c
     field public static final int windowLightStatusBar = 16844000; // 0x10104e0
     field public static final int windowMinWidthMajor = 16843606; // 0x1010356
@@ -11167,6 +11166,7 @@
     method public abstract android.content.res.Resources getResourcesForApplication(java.lang.String) throws android.content.pm.PackageManager.NameNotFoundException;
     method public abstract android.content.pm.ServiceInfo getServiceInfo(android.content.ComponentName, int) throws android.content.pm.PackageManager.NameNotFoundException;
     method public abstract java.util.List<android.content.pm.SharedLibraryInfo> getSharedLibraries(int);
+    method public android.os.PersistableBundle getSuspendedPackageAppExtras();
     method public abstract android.content.pm.FeatureInfo[] getSystemAvailableFeatures();
     method public abstract java.lang.String[] getSystemSharedLibraryNames();
     method public abstract java.lang.CharSequence getText(java.lang.String, int, android.content.pm.ApplicationInfo);
@@ -11180,6 +11180,7 @@
     method public abstract boolean hasSystemFeature(java.lang.String, int);
     method public abstract boolean isInstantApp();
     method public abstract boolean isInstantApp(java.lang.String);
+    method public boolean isPackageSuspended();
     method public abstract boolean isPermissionRevokedByPolicy(java.lang.String, java.lang.String);
     method public abstract boolean isSafeMode();
     method public abstract java.util.List<android.content.pm.ResolveInfo> queryBroadcastReceivers(android.content.Intent, int);
@@ -13645,12 +13646,14 @@
     field public static final int ALLOCATOR_HARDWARE = 3; // 0x3
     field public static final int ALLOCATOR_SHARED_MEMORY = 2; // 0x2
     field public static final int ALLOCATOR_SOFTWARE = 1; // 0x1
-    field public static final int ERROR_SOURCE_ERROR = 3; // 0x3
-    field public static final int ERROR_SOURCE_EXCEPTION = 1; // 0x1
-    field public static final int ERROR_SOURCE_INCOMPLETE = 2; // 0x2
   }
 
-  public static abstract class ImageDecoder.Error implements java.lang.annotation.Annotation {
+  public static final class ImageDecoder.DecodeException extends java.io.IOException {
+    method public int getError();
+    method public android.graphics.ImageDecoder.Source getSource();
+    field public static final int SOURCE_EXCEPTION = 1; // 0x1
+    field public static final int SOURCE_INCOMPLETE = 2; // 0x2
+    field public static final int SOURCE_MALFORMED_DATA = 3; // 0x3
   }
 
   public static class ImageDecoder.ImageInfo {
@@ -13659,16 +13662,12 @@
     method public boolean isAnimated();
   }
 
-  public static class ImageDecoder.IncompleteException extends java.io.IOException {
-    ctor public ImageDecoder.IncompleteException();
-  }
-
   public static abstract interface ImageDecoder.OnHeaderDecodedListener {
     method public abstract void onHeaderDecoded(android.graphics.ImageDecoder, android.graphics.ImageDecoder.ImageInfo, android.graphics.ImageDecoder.Source);
   }
 
   public static abstract interface ImageDecoder.OnPartialImageListener {
-    method public abstract boolean onPartialImage(int, android.graphics.ImageDecoder.Source);
+    method public abstract boolean onPartialImage(android.graphics.ImageDecoder.DecodeException);
   }
 
   public static abstract class ImageDecoder.Source {
diff --git a/api/removed.txt b/api/removed.txt
index a5370f4..1228fd1 100644
--- a/api/removed.txt
+++ b/api/removed.txt
@@ -155,6 +155,13 @@
   public final class ImageDecoder implements java.lang.AutoCloseable {
     method public deprecated boolean getAsAlphaMask();
     method public deprecated android.graphics.ImageDecoder setAsAlphaMask(boolean);
+    field public static final deprecated int ERROR_SOURCE_ERROR = 3; // 0x3
+    field public static final deprecated int ERROR_SOURCE_EXCEPTION = 1; // 0x1
+    field public static final deprecated int ERROR_SOURCE_INCOMPLETE = 2; // 0x2
+  }
+
+  public static deprecated class ImageDecoder.IncompleteException extends java.io.IOException {
+    ctor public ImageDecoder.IncompleteException();
   }
 
   public deprecated class LayerRasterizer extends android.graphics.Rasterizer {
diff --git a/api/system-current.txt b/api/system-current.txt
index a056115..d472b06 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -181,6 +181,7 @@
     field public static final java.lang.String STATUS_BAR = "android.permission.STATUS_BAR";
     field public static final java.lang.String STOP_APP_SWITCHES = "android.permission.STOP_APP_SWITCHES";
     field public static final java.lang.String SUBSTITUTE_NOTIFICATION_APP_NAME = "android.permission.SUBSTITUTE_NOTIFICATION_APP_NAME";
+    field public static final java.lang.String SUSPEND_APPS = "android.permission.SUSPEND_APPS";
     field public static final java.lang.String TETHER_PRIVILEGED = "android.permission.TETHER_PRIVILEGED";
     field public static final java.lang.String TV_INPUT_HARDWARE = "android.permission.TV_INPUT_HARDWARE";
     field public static final java.lang.String TV_VIRTUAL_REMOTE_CONTROLLER = "android.permission.TV_VIRTUAL_REMOTE_CONTROLLER";
@@ -207,7 +208,7 @@
     field public static final int isVrOnly = 16844152; // 0x1010578
     field public static final int requiredSystemPropertyName = 16844133; // 0x1010565
     field public static final int requiredSystemPropertyValue = 16844134; // 0x1010566
-    field public static final int userRestriction = 16844165; // 0x1010585
+    field public static final int userRestriction = 16844164; // 0x1010584
   }
 
   public static final class R.raw {
@@ -283,6 +284,7 @@
     field public static final java.lang.String OPSTR_GET_ACCOUNTS = "android:get_accounts";
     field public static final java.lang.String OPSTR_GPS = "android:gps";
     field public static final java.lang.String OPSTR_INSTANT_APP_START_FOREGROUND = "android:instant_app_start_foreground";
+    field public static final java.lang.String OPSTR_MANAGE_IPSEC_TUNNELS = "android:manage_ipsec_tunnels";
     field public static final java.lang.String OPSTR_MUTE_MICROPHONE = "android:mute_microphone";
     field public static final java.lang.String OPSTR_NEIGHBORING_CELLS = "android:neighboring_cells";
     field public static final java.lang.String OPSTR_PLAY_AUDIO = "android:play_audio";
@@ -1016,15 +1018,19 @@
     method public abstract java.util.List<android.content.pm.IntentFilterVerificationInfo> getIntentFilterVerifications(java.lang.String);
     method public abstract int getIntentVerificationStatusAsUser(java.lang.String, int);
     method public abstract int getPermissionFlags(java.lang.String, java.lang.String, android.os.UserHandle);
+    method public android.os.PersistableBundle getSuspendedPackageAppExtras(java.lang.String);
     method public abstract void grantRuntimePermission(java.lang.String, java.lang.String, android.os.UserHandle);
     method public abstract int installExistingPackage(java.lang.String) throws android.content.pm.PackageManager.NameNotFoundException;
     method public abstract int installExistingPackage(java.lang.String, int) throws android.content.pm.PackageManager.NameNotFoundException;
+    method public boolean isPackageSuspended(java.lang.String);
     method public java.util.List<android.content.pm.ResolveInfo> queryBroadcastReceiversAsUser(android.content.Intent, int, android.os.UserHandle);
     method public abstract void registerDexModule(java.lang.String, android.content.pm.PackageManager.DexModuleRegisterCallback);
     method public abstract void removeOnPermissionsChangeListener(android.content.pm.PackageManager.OnPermissionsChangedListener);
     method public abstract void revokeRuntimePermission(java.lang.String, java.lang.String, android.os.UserHandle);
     method public abstract boolean setDefaultBrowserPackageNameAsUser(java.lang.String, int);
     method public void setHarmfulAppWarning(java.lang.String, java.lang.CharSequence);
+    method public java.lang.String[] setPackagesSuspended(java.lang.String[], boolean, android.os.PersistableBundle, android.os.PersistableBundle, java.lang.String);
+    method public void setSuspendedPackageAppExtras(java.lang.String, android.os.PersistableBundle);
     method public abstract void setUpdateAvailable(java.lang.String, boolean);
     method public abstract boolean updateIntentVerificationStatusAsUser(java.lang.String, int, int);
     method public abstract void updatePermissionFlags(java.lang.String, java.lang.String, int, int, android.os.UserHandle);
diff --git a/api/test-current.txt b/api/test-current.txt
index 31e3e7c..81cebf0 100644
--- a/api/test-current.txt
+++ b/api/test-current.txt
@@ -79,6 +79,7 @@
     field public static final java.lang.String OPSTR_GET_ACCOUNTS = "android:get_accounts";
     field public static final java.lang.String OPSTR_GPS = "android:gps";
     field public static final java.lang.String OPSTR_INSTANT_APP_START_FOREGROUND = "android:instant_app_start_foreground";
+    field public static final java.lang.String OPSTR_MANAGE_IPSEC_TUNNELS = "android:manage_ipsec_tunnels";
     field public static final java.lang.String OPSTR_MUTE_MICROPHONE = "android:mute_microphone";
     field public static final java.lang.String OPSTR_NEIGHBORING_CELLS = "android:neighboring_cells";
     field public static final java.lang.String OPSTR_PLAY_AUDIO = "android:play_audio";
@@ -294,6 +295,14 @@
 
 }
 
+package android.graphics {
+
+  public final class ImageDecoder implements java.lang.AutoCloseable {
+    method public static android.graphics.ImageDecoder.Source createSource(android.content.res.Resources, java.io.InputStream, int);
+  }
+
+}
+
 package android.graphics.drawable {
 
   public class AdaptiveIconDrawable extends android.graphics.drawable.Drawable implements android.graphics.drawable.Drawable.Callback {
diff --git a/cmds/statsd/src/anomaly/DurationAnomalyTracker.cpp b/cmds/statsd/src/anomaly/DurationAnomalyTracker.cpp
index d85157c..79067eb 100644
--- a/cmds/statsd/src/anomaly/DurationAnomalyTracker.cpp
+++ b/cmds/statsd/src/anomaly/DurationAnomalyTracker.cpp
@@ -68,10 +68,10 @@
     if (itr->second != nullptr && timestampNs >= NS_PER_SEC * itr->second->timestampSec) {
         declareAnomaly(timestampNs, dimensionKey);
     }
-    mAlarms.erase(dimensionKey);
     if (mAlarmMonitor != nullptr) {
         mAlarmMonitor->remove(itr->second);
     }
+    mAlarms.erase(dimensionKey);
 }
 
 void DurationAnomalyTracker::cancelAllAlarms() {
diff --git a/cmds/statsd/src/metrics/duration_helper/MaxDurationTracker.cpp b/cmds/statsd/src/metrics/duration_helper/MaxDurationTracker.cpp
index 335ec4c..c9547cf 100644
--- a/cmds/statsd/src/metrics/duration_helper/MaxDurationTracker.cpp
+++ b/cmds/statsd/src/metrics/duration_helper/MaxDurationTracker.cpp
@@ -205,11 +205,12 @@
     bool hasPendingEvent =
             false;  // has either a kStarted or kPaused event across bucket boundaries
     // meaning we need to carry them over to the new bucket.
-    for (auto it = mInfos.begin(); it != mInfos.end(); ++it) {
+    for (auto it = mInfos.begin(); it != mInfos.end();) {
         if (it->second.state == DurationState::kStopped) {
             // No need to keep buckets for events that were stopped before.
-            mInfos.erase(it);
+            it = mInfos.erase(it);
         } else {
+            ++it;
             hasPendingEvent = true;
         }
     }
diff --git a/cmds/statsd/src/packages/UidMap.cpp b/cmds/statsd/src/packages/UidMap.cpp
index 3ba4b7a..1cb20bc 100644
--- a/cmds/statsd/src/packages/UidMap.cpp
+++ b/cmds/statsd/src/packages/UidMap.cpp
@@ -365,7 +365,8 @@
             count++;
             proto->write(FIELD_TYPE_INT64 | FIELD_ID_SNAPSHOT_TIMESTAMP,
                          (long long)record.timestampNs);
-            proto->write(FIELD_TYPE_MESSAGE | FIELD_ID_SNAPSHOT_PACKAGE_INFO, record.bytes.data());
+            proto->write(FIELD_TYPE_MESSAGE | FIELD_ID_SNAPSHOT_PACKAGE_INFO, record.bytes.data(),
+                         record.bytes.size());
             proto->end(snapshotsToken);
         }
     }
diff --git a/config/hiddenapi-light-greylist.txt b/config/hiddenapi-light-greylist.txt
index e4df85b..77c2f8b2 100644
--- a/config/hiddenapi-light-greylist.txt
+++ b/config/hiddenapi-light-greylist.txt
@@ -669,7 +669,6 @@
 Landroid/graphics/GraphicBuffer;-><init>(IIIIJ)V
 Landroid/graphics/GraphicBuffer;->mNativeObject:J
 Landroid/graphics/ImageDecoder;-><init>(JIIZ)V
-Landroid/graphics/ImageDecoder;->onPartialImage(I)Z
 Landroid/graphics/ImageDecoder;->postProcessAndRelease(Landroid/graphics/Canvas;)I
 Landroid/graphics/LinearGradient;->mColors:[I
 Landroid/graphics/Matrix;->native_instance:J
diff --git a/core/java/android/app/AppOpsManager.java b/core/java/android/app/AppOpsManager.java
index 4690211..ea8c71c 100644
--- a/core/java/android/app/AppOpsManager.java
+++ b/core/java/android/app/AppOpsManager.java
@@ -270,8 +270,10 @@
     public static final int OP_BIND_ACCESSIBILITY_SERVICE = 73;
     /** @hide Continue handover of a call from another app */
     public static final int OP_ACCEPT_HANDOVER = 74;
+    /** @hide Create and Manage IPsec Tunnels */
+    public static final int OP_MANAGE_IPSEC_TUNNELS = 75;
     /** @hide */
-    public static final int _NUM_OP = 75;
+    public static final int _NUM_OP = 76;
 
     /** Access to coarse location information. */
     public static final String OPSTR_COARSE_LOCATION = "android:coarse_location";
@@ -507,6 +509,9 @@
     @SystemApi @TestApi
     public static final String OPSTR_BIND_ACCESSIBILITY_SERVICE =
             "android:bind_accessibility_service";
+    /** @hide */
+    @SystemApi @TestApi
+    public static final String OPSTR_MANAGE_IPSEC_TUNNELS = "android:manage_ipsec_tunnels";
 
     // Warning: If an permission is added here it also has to be added to
     // com.android.packageinstaller.permission.utils.EventLogger
@@ -641,6 +646,7 @@
             OP_REQUEST_DELETE_PACKAGES,
             OP_BIND_ACCESSIBILITY_SERVICE,
             OP_ACCEPT_HANDOVER,
+            OP_MANAGE_IPSEC_TUNNELS,
     };
 
     /**
@@ -722,6 +728,7 @@
             OPSTR_REQUEST_DELETE_PACKAGES,
             OPSTR_BIND_ACCESSIBILITY_SERVICE,
             OPSTR_ACCEPT_HANDOVER,
+            OPSTR_MANAGE_IPSEC_TUNNELS,
     };
 
     /**
@@ -804,6 +811,7 @@
             "REQUEST_DELETE_PACKAGES",
             "BIND_ACCESSIBILITY_SERVICE",
             "ACCEPT_HANDOVER",
+            "MANAGE_IPSEC_TUNNELS",
     };
 
     /**
@@ -886,6 +894,7 @@
             Manifest.permission.REQUEST_DELETE_PACKAGES,
             Manifest.permission.BIND_ACCESSIBILITY_SERVICE,
             Manifest.permission.ACCEPT_HANDOVER,
+            null, // no permission for OP_MANAGE_IPSEC_TUNNELS
     };
 
     /**
@@ -969,6 +978,7 @@
             null, // REQUEST_DELETE_PACKAGES
             null, // OP_BIND_ACCESSIBILITY_SERVICE
             null, // ACCEPT_HANDOVER
+            null, // MANAGE_IPSEC_TUNNELS
     };
 
     /**
@@ -1051,6 +1061,7 @@
             false, // OP_REQUEST_DELETE_PACKAGES
             false, // OP_BIND_ACCESSIBILITY_SERVICE
             false, // ACCEPT_HANDOVER
+            false, // MANAGE_IPSEC_HANDOVERS
     };
 
     /**
@@ -1132,6 +1143,7 @@
             AppOpsManager.MODE_ALLOWED,  // REQUEST_DELETE_PACKAGES
             AppOpsManager.MODE_ALLOWED,  // OP_BIND_ACCESSIBILITY_SERVICE
             AppOpsManager.MODE_ALLOWED,  // ACCEPT_HANDOVER
+            AppOpsManager.MODE_ERRORED,  // MANAGE_IPSEC_TUNNELS
     };
 
     /**
@@ -1217,6 +1229,7 @@
             false, // OP_REQUEST_DELETE_PACKAGES
             false, // OP_BIND_ACCESSIBILITY_SERVICE
             false, // ACCEPT_HANDOVER
+            false, // MANAGE_IPSEC_TUNNELS
     };
 
     /**
diff --git a/core/java/android/app/ApplicationPackageManager.java b/core/java/android/app/ApplicationPackageManager.java
index b8c4ef7..fb8ded1 100644
--- a/core/java/android/app/ApplicationPackageManager.java
+++ b/core/java/android/app/ApplicationPackageManager.java
@@ -70,6 +70,7 @@
 import android.os.Handler;
 import android.os.Looper;
 import android.os.Message;
+import android.os.PersistableBundle;
 import android.os.Process;
 import android.os.RemoteException;
 import android.os.SystemProperties;
@@ -2151,16 +2152,42 @@
     }
 
     @Override
-    public String[] setPackagesSuspendedAsUser(String[] packageNames, boolean suspended,
-            int userId) {
+    public String[] setPackagesSuspended(String[] packageNames, boolean suspended,
+            PersistableBundle appExtras, PersistableBundle launcherExtras,
+            String dialogMessage) {
+        // TODO (b/75332201): Pass in the dialogMessage and use it in the interceptor dialog
         try {
-            return mPM.setPackagesSuspendedAsUser(packageNames, suspended, userId);
+            return mPM.setPackagesSuspendedAsUser(packageNames, suspended, appExtras,
+                    launcherExtras, mContext.getOpPackageName(), mContext.getUserId());
         } catch (RemoteException e) {
             throw e.rethrowFromSystemServer();
         }
     }
 
     @Override
+    public PersistableBundle getSuspendedPackageAppExtras(String packageName) {
+        try {
+            return mPM.getPackageSuspendedAppExtras(packageName, mContext.getUserId());
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+    }
+
+    @Override
+    public PersistableBundle getSuspendedPackageAppExtras() {
+        return getSuspendedPackageAppExtras(mContext.getOpPackageName());
+    }
+
+    @Override
+    public void setSuspendedPackageAppExtras(String packageName, PersistableBundle appExtras) {
+        try {
+            mPM.setSuspendedPackageAppExtras(packageName, appExtras, mContext.getUserId());
+        } catch (RemoteException e) {
+            e.rethrowFromSystemServer();
+        }
+    }
+
+    @Override
     public boolean isPackageSuspendedForUser(String packageName, int userId) {
         try {
             return mPM.isPackageSuspendedForUser(packageName, userId);
@@ -2171,6 +2198,17 @@
 
     /** @hide */
     @Override
+    public boolean isPackageSuspended(String packageName) {
+        return isPackageSuspendedForUser(packageName, mContext.getUserId());
+    }
+
+    @Override
+    public boolean isPackageSuspended() {
+        return isPackageSuspendedForUser(mContext.getOpPackageName(), mContext.getUserId());
+    }
+
+    /** @hide */
+    @Override
     public void setApplicationCategoryHint(String packageName, int categoryHint) {
         try {
             mPM.setApplicationCategoryHint(packageName, categoryHint,
diff --git a/core/java/android/content/pm/IPackageManager.aidl b/core/java/android/content/pm/IPackageManager.aidl
index 36a74a4..f4352f9 100644
--- a/core/java/android/content/pm/IPackageManager.aidl
+++ b/core/java/android/content/pm/IPackageManager.aidl
@@ -50,8 +50,8 @@
 import android.content.pm.dex.IArtManager;
 import android.graphics.Bitmap;
 import android.net.Uri;
-import android.os.Bundle;
 import android.os.ParcelFileDescriptor;
+import android.os.PersistableBundle;
 import android.content.IntentSender;
 
 /**
@@ -272,9 +272,17 @@
 
     void clearCrossProfileIntentFilters(int sourceUserId, String ownerPackage);
 
-    String[] setPackagesSuspendedAsUser(in String[] packageNames, boolean suspended, int userId);
+    String[] setPackagesSuspendedAsUser(in String[] packageNames, boolean suspended,
+            in PersistableBundle launcherExtras, in PersistableBundle appExtras,
+            String callingPackage, int userId);
+
     boolean isPackageSuspendedForUser(String packageName, int userId);
 
+    PersistableBundle getPackageSuspendedAppExtras(String pacakgeName, int userId);
+
+    void setSuspendedPackageAppExtras(String packageName, in PersistableBundle appExtras,
+            int userId);
+
     /**
      * Backup/restore support - only the system uid may use these.
      */
diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java
index 3536eea..4d8773c 100644
--- a/core/java/android/content/pm/PackageManager.java
+++ b/core/java/android/content/pm/PackageManager.java
@@ -51,6 +51,7 @@
 import android.os.Build;
 import android.os.Bundle;
 import android.os.Handler;
+import android.os.PersistableBundle;
 import android.os.RemoteException;
 import android.os.UserHandle;
 import android.os.UserManager;
@@ -5510,28 +5511,49 @@
     /**
      * Puts the package in a suspended state, where attempts at starting activities are denied.
      *
-     * <p>It doesn't remove the data or the actual package file. The application notifications
-     * will be hidden, the application will not show up in recents, will not be able to show
-     * toasts or dialogs or ring the device.
+     * <p>It doesn't remove the data or the actual package file. The application's notifications
+     * will be hidden, any of the it's started activities will be stopped and it will not be able to
+     * show toasts or dialogs or ring the device. When the user tries to launch a suspended app, a
+     * system dialog with the given {@code dialogMessage} will be shown instead.</p>
      *
      * <p>The package must already be installed. If the package is uninstalled while suspended
-     * the package will no longer be suspended.
+     * the package will no longer be suspended. </p>
+     *
+     * <p>Optionally, the suspending app can provide extra information in the form of
+     * {@link PersistableBundle} objects to be shared with the apps being suspended and the
+     * launcher to support customization that they might need to handle the suspended state. </p>
+     *
+     * <p>The caller must hold {@link Manifest.permission#SUSPEND_APPS} or
+     * {@link Manifest.permission#MANAGE_USERS} to use this api.</p>
      *
      * @param packageNames The names of the packages to set the suspended status.
      * @param suspended If set to {@code true} than the packages will be suspended, if set to
-     * {@code false} the packages will be unsuspended.
-     * @param userId The user id.
+     * {@code false}, the packages will be unsuspended.
+     * @param appExtras An optional {@link PersistableBundle} that the suspending app can provide
+     *                  which will be shared with the apps being suspended. Ignored if
+     *                  {@code suspended} is false.
+     * @param launcherExtras An optional {@link PersistableBundle} that the suspending app can
+     *                       provide which will be shared with the launcher. Ignored if
+     *                       {@code suspended} is false.
+     * @param dialogMessage The message to be displayed to the user, when they try to launch a
+     *                      suspended app.
      *
      * @return an array of package names for which the suspended status is not set as requested in
      * this method.
      *
      * @hide
      */
-    public abstract String[] setPackagesSuspendedAsUser(
-            String[] packageNames, boolean suspended, @UserIdInt int userId);
+    @SystemApi
+    @RequiresPermission(anyOf = {Manifest.permission.SUSPEND_APPS,
+            Manifest.permission.MANAGE_USERS})
+    public String[] setPackagesSuspended(String[] packageNames, boolean suspended,
+            @Nullable PersistableBundle appExtras, @Nullable PersistableBundle launcherExtras,
+            String dialogMessage) {
+        throw new UnsupportedOperationException("setPackagesSuspended not implemented");
+    }
 
     /**
-     * @see #setPackageSuspendedAsUser(String, boolean, int)
+     * @see #setPackagesSuspended(String[], boolean, PersistableBundle, PersistableBundle, String)
      * @param packageName The name of the package to get the suspended status of.
      * @param userId The user id.
      * @return {@code true} if the package is suspended or {@code false} if the package is not
@@ -5541,6 +5563,86 @@
     public abstract boolean isPackageSuspendedForUser(String packageName, int userId);
 
     /**
+     * Query if an app is currently suspended.
+     *
+     * @return {@code true} if the given package is suspended, {@code false} otherwise
+     *
+     * @see #setPackagesSuspended(String[], boolean, PersistableBundle, PersistableBundle, String)
+     * @hide
+     */
+    @SystemApi
+    public boolean isPackageSuspended(String packageName) {
+        throw new UnsupportedOperationException("isPackageSuspended not implemented");
+    }
+
+    /**
+     * Apps can query this to know if they have been suspended.
+     *
+     * @return {@code true} if the calling package has been suspended, {@code false} otherwise.
+     *
+     * @see #getSuspendedPackageAppExtras()
+     */
+    public boolean isPackageSuspended() {
+        throw new UnsupportedOperationException("isPackageSuspended not implemented");
+    }
+
+    /**
+     * Retrieve the {@link PersistableBundle} that was passed as {@code appExtras} when the given
+     * package was suspended.
+     *
+     * <p> The caller must hold permission {@link Manifest.permission#SUSPEND_APPS} to use this
+     * api.</p>
+     *
+     * @param packageName The package to retrieve extras for.
+     * @return The {@code appExtras} for the suspended package.
+     *
+     * @see #setPackagesSuspended(String[], boolean, PersistableBundle, PersistableBundle, String)
+     * @hide
+     */
+    @SystemApi
+    @RequiresPermission(Manifest.permission.SUSPEND_APPS)
+    public PersistableBundle getSuspendedPackageAppExtras(String packageName) {
+        throw new UnsupportedOperationException("getSuspendedPackageAppExtras not implemented");
+    }
+
+    /**
+     * Set the app extras for a suspended package. This method can be used to update the appExtras
+     * for a package that was earlier suspended using
+     * {@link #setPackagesSuspended(String[], boolean, PersistableBundle, PersistableBundle,
+     * String)}
+     * Does nothing if the given package is not already in a suspended state.
+     *
+     * @param packageName The package for which the appExtras need to be updated
+     * @param appExtras The new appExtras for the given package
+     *
+     * @see #setPackagesSuspended(String[], boolean, PersistableBundle, PersistableBundle, String)
+     *
+     * @hide
+     */
+    @SystemApi
+    @RequiresPermission(Manifest.permission.SUSPEND_APPS)
+    public void setSuspendedPackageAppExtras(String packageName,
+            @Nullable PersistableBundle appExtras) {
+        throw new UnsupportedOperationException("setSuspendedPackageAppExtras not implemented");
+    }
+
+    /**
+     * Returns any extra information supplied as {@code appExtras} to the system when the calling
+     * app was suspended.
+     *
+     * <p> Note: This just returns whatever {@link PersistableBundle} was passed to the system via
+     * {@code setPackagesSuspended(String[], boolean, PersistableBundle, PersistableBundle,
+     * String)} when suspending the package, <em> which might be {@code null}. </em></p>
+     *
+     * @return A {@link PersistableBundle} containing the extras for the app, or {@code null} if the
+     * package is not currently suspended.
+     * @see #isPackageSuspended()
+     */
+    public @Nullable PersistableBundle getSuspendedPackageAppExtras() {
+        throw new UnsupportedOperationException("getSuspendedPackageAppExtras not implemented");
+    }
+
+    /**
      * Provide a hint of what the {@link ApplicationInfo#category} value should
      * be for the given package.
      * <p>
diff --git a/core/java/android/content/pm/PackageUserState.java b/core/java/android/content/pm/PackageUserState.java
index 293beb2..f7b6e09 100644
--- a/core/java/android/content/pm/PackageUserState.java
+++ b/core/java/android/content/pm/PackageUserState.java
@@ -27,6 +27,8 @@
 import static android.content.pm.PackageManager.MATCH_DISABLED_UNTIL_USED_COMPONENTS;
 import static android.content.pm.PackageManager.MATCH_SYSTEM_ONLY;
 
+import android.os.BaseBundle;
+import android.os.PersistableBundle;
 import android.util.ArraySet;
 
 import com.android.internal.util.ArrayUtils;
@@ -44,6 +46,9 @@
     public boolean notLaunched;
     public boolean hidden; // Is the app restricted by owner / admin
     public boolean suspended;
+    public String suspendingPackage;
+    public PersistableBundle suspendedAppExtras;
+    public PersistableBundle suspendedLauncherExtras;
     public boolean instantApp;
     public boolean virtualPreload;
     public int enabled;
@@ -76,6 +81,9 @@
         notLaunched = o.notLaunched;
         hidden = o.hidden;
         suspended = o.suspended;
+        suspendingPackage = o.suspendingPackage;
+        suspendedAppExtras = o.suspendedAppExtras;
+        suspendedLauncherExtras = o.suspendedLauncherExtras;
         instantApp = o.instantApp;
         virtualPreload = o.virtualPreload;
         enabled = o.enabled;
@@ -195,6 +203,20 @@
         if (suspended != oldState.suspended) {
             return false;
         }
+        if (suspended) {
+            if (suspendingPackage == null
+                    || !suspendingPackage.equals(oldState.suspendingPackage)) {
+                return false;
+            }
+            if (!BaseBundle.kindofEquals(suspendedAppExtras,
+                    oldState.suspendedAppExtras)) {
+                return false;
+            }
+            if (!BaseBundle.kindofEquals(suspendedLauncherExtras,
+                    oldState.suspendedLauncherExtras)) {
+                return false;
+            }
+        }
         if (instantApp != oldState.instantApp) {
             return false;
         }
diff --git a/core/java/android/os/BaseBundle.java b/core/java/android/os/BaseBundle.java
index 5312dca..f5a7433 100644
--- a/core/java/android/os/BaseBundle.java
+++ b/core/java/android/os/BaseBundle.java
@@ -357,6 +357,23 @@
     }
 
     /**
+     * Does a loose equality check between two given {@link BaseBundle} objects.
+     * Returns {@code true} if both are {@code null}, or if both are equal as per
+     * {@link #kindofEquals(BaseBundle)}
+     *
+     * @param a A {@link BaseBundle} object
+     * @param b Another {@link BaseBundle} to compare with a
+     * @return {@code true} if both are the same, {@code false} otherwise
+     *
+     * @see #kindofEquals(BaseBundle)
+     *
+     * @hide
+     */
+    public static boolean kindofEquals(BaseBundle a, BaseBundle b) {
+        return (a == b) || (a != null && a.kindofEquals(b));
+    }
+
+    /**
      * @hide This kind-of does an equality comparison.  Kind-of.
      */
     public boolean kindofEquals(BaseBundle other) {
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index 87babc0..86f02e4 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -7762,6 +7762,21 @@
         public static final String BLUETOOTH_ON_WHILE_DRIVING = "bluetooth_on_while_driving";
 
         /**
+         * What behavior should be invoked when the volume hush gesture is triggered
+         * One of VOLUME_HUSH_OFF, VOLUME_HUSH_VIBRATE, VOLUME_HUSH_MUTE.
+         *
+         * @hide
+         */
+        public static final String VOLUME_HUSH_GESTURE = "volume_hush_gesture";
+
+        /** @hide */ public static final int VOLUME_HUSH_OFF = 0;
+        /** @hide */ public static final int VOLUME_HUSH_VIBRATE = 1;
+        /** @hide */ public static final int VOLUME_HUSH_MUTE = 2;
+
+        private static final Validator VOLUME_HUSH_GESTURE_VALIDATOR =
+                NON_NEGATIVE_INTEGER_VALIDATOR;
+
+        /**
          * The number of times (integer) the user has manually enabled battery saver.
          * @hide
          */
@@ -7875,6 +7890,7 @@
             SCREENSAVER_ACTIVATE_ON_SLEEP,
             LOCKDOWN_IN_POWER_MENU,
             SHOW_FIRST_CRASH_DIALOG_DEV_OPTION,
+            VOLUME_HUSH_GESTURE
         };
 
         /**
@@ -8011,6 +8027,7 @@
             VALIDATORS.put(LOCKDOWN_IN_POWER_MENU, LOCKDOWN_IN_POWER_MENU_VALIDATOR);
             VALIDATORS.put(SHOW_FIRST_CRASH_DIALOG_DEV_OPTION,
                     SHOW_FIRST_CRASH_DIALOG_DEV_OPTION_VALIDATOR);
+            VALIDATORS.put(VOLUME_HUSH_GESTURE, VOLUME_HUSH_GESTURE_VALIDATOR);
             VALIDATORS.put(ENABLED_NOTIFICATION_LISTENERS,
                     ENABLED_NOTIFICATION_LISTENERS_VALIDATOR); //legacy restore setting
             VALIDATORS.put(ENABLED_NOTIFICATION_ASSISTANT,
diff --git a/core/java/android/service/autofill/AutofillServiceInfo.java b/core/java/android/service/autofill/AutofillServiceInfo.java
index de23455..b7ec281 100644
--- a/core/java/android/service/autofill/AutofillServiceInfo.java
+++ b/core/java/android/service/autofill/AutofillServiceInfo.java
@@ -198,14 +198,6 @@
                     } else {
                         maxVersionCode = Long.MAX_VALUE;
                     }
-                    if (true) { // TODO(b/74445943): remove block after P DP2 is branched
-                        final String urlBarResourceId = cpAttributes.getString(
-                                R.styleable.AutofillService_CompatibilityPackage_urlBarResourceId);
-                        if (urlBarResourceId != null) {
-                            Log.e(TAG, "Service is using deprecated attribute 'urlBarResourceId'");
-                        }
-                    }
-
                     if (compatibilityPackages == null) {
                         compatibilityPackages = new ArrayMap<>();
                     }
diff --git a/core/java/android/view/SurfaceControl.java b/core/java/android/view/SurfaceControl.java
index 7ff4f21..d4610a5 100644
--- a/core/java/android/view/SurfaceControl.java
+++ b/core/java/android/view/SurfaceControl.java
@@ -353,8 +353,8 @@
         private int mFormat = PixelFormat.OPAQUE;
         private String mName;
         private SurfaceControl mParent;
-        private int mWindowType;
-        private int mOwnerUid;
+        private int mWindowType = -1;
+        private int mOwnerUid = -1;
 
         /**
          * Begin building a SurfaceControl with a given {@link SurfaceSession}.
diff --git a/core/java/com/android/internal/os/BatteryStatsImpl.java b/core/java/com/android/internal/os/BatteryStatsImpl.java
index bbff515..3c150c1 100644
--- a/core/java/com/android/internal/os/BatteryStatsImpl.java
+++ b/core/java/com/android/internal/os/BatteryStatsImpl.java
@@ -138,7 +138,7 @@
     private static final int MAGIC = 0xBA757475; // 'BATSTATS'
 
     // Current on-disk Parcel version
-    private static final int VERSION = 176 + (USE_OLD_HISTORY ? 1000 : 0);
+    private static final int VERSION = 177 + (USE_OLD_HISTORY ? 1000 : 0);
 
     // Maximum number of items we will record in the history.
     private static final int MAX_HISTORY_ITEMS;
@@ -1551,27 +1551,31 @@
         }
     }
 
+    @VisibleForTesting
     public static class LongSamplingCounter extends LongCounter implements TimeBaseObs {
         final TimeBase mTimeBase;
-        long mCount;
-        long mLoadedCount;
-        long mUnpluggedCount;
+        public long mCount;
+        public long mCurrentCount;
+        public long mLoadedCount;
+        public long mUnpluggedCount;
 
-        LongSamplingCounter(TimeBase timeBase, Parcel in) {
+        public LongSamplingCounter(TimeBase timeBase, Parcel in) {
             mTimeBase = timeBase;
             mCount = in.readLong();
+            mCurrentCount = in.readLong();
             mLoadedCount = in.readLong();
             mUnpluggedCount = in.readLong();
             timeBase.add(this);
         }
 
-        LongSamplingCounter(TimeBase timeBase) {
+        public LongSamplingCounter(TimeBase timeBase) {
             mTimeBase = timeBase;
             timeBase.add(this);
         }
 
         public void writeToParcel(Parcel out) {
             out.writeLong(mCount);
+            out.writeLong(mCurrentCount);
             out.writeLong(mLoadedCount);
             out.writeLong(mUnpluggedCount);
         }
@@ -1598,24 +1602,37 @@
         @Override
         public void logState(Printer pw, String prefix) {
             pw.println(prefix + "mCount=" + mCount
+                    + " mCurrentCount=" + mCurrentCount
                     + " mLoadedCount=" + mLoadedCount
                     + " mUnpluggedCount=" + mUnpluggedCount);
         }
 
-        void addCountLocked(long count) {
-            addCountLocked(count, mTimeBase.isRunning());
+        public void addCountLocked(long count) {
+            update(mCurrentCount + count, mTimeBase.isRunning());
         }
 
-        void addCountLocked(long count, boolean isRunning) {
-            if (isRunning) {
-                mCount += count;
+        public void addCountLocked(long count, boolean isRunning) {
+            update(mCurrentCount + count, isRunning);
+        }
+
+        public void update(long count) {
+            update(count, mTimeBase.isRunning());
+        }
+
+        public void update(long count, boolean isRunning) {
+            if (count < mCurrentCount) {
+                mCurrentCount = 0;
             }
+            if (isRunning) {
+                mCount += count - mCurrentCount;
+            }
+            mCurrentCount = count;
         }
 
         /**
          * Clear state of this counter.
          */
-        void reset(boolean detachIfReset) {
+        public void reset(boolean detachIfReset) {
             mCount = 0;
             mLoadedCount = mUnpluggedCount = 0;
             if (detachIfReset) {
@@ -1623,18 +1640,16 @@
             }
         }
 
-        void detach() {
+        public void detach() {
             mTimeBase.remove(this);
         }
 
-        void writeSummaryFromParcelLocked(Parcel out) {
+        public void writeSummaryFromParcelLocked(Parcel out) {
             out.writeLong(mCount);
         }
 
-        void readSummaryFromParcelLocked(Parcel in) {
-            mLoadedCount = in.readLong();
-            mCount = mLoadedCount;
-            mUnpluggedCount = mLoadedCount;
+        public void readSummaryFromParcelLocked(Parcel in) {
+            mCount = mUnpluggedCount= mLoadedCount = in.readLong();
         }
     }
 
@@ -11603,10 +11618,6 @@
         }
     }
 
-    // Cache last value for comparison.
-    private BluetoothActivityEnergyInfo mLastBluetoothActivityEnergyInfo =
-            new BluetoothActivityEnergyInfo(0, 0, 0, 0, 0, 0);
-
     /**
      * Add modem tx power to history
      * Device is said to be in high cellular transmit power when it has spent most of the transmit
@@ -11645,8 +11656,35 @@
         return;
     }
 
+    private final class BluetoothActivityInfoCache {
+        long idleTimeMs;
+        long rxTimeMs;
+        long txTimeMs;
+        long energy;
+
+        SparseLongArray uidRxBytes = new SparseLongArray();
+        SparseLongArray uidTxBytes = new SparseLongArray();
+
+        void set(BluetoothActivityEnergyInfo info) {
+            idleTimeMs = info.getControllerIdleTimeMillis();
+            rxTimeMs = info.getControllerRxTimeMillis();
+            txTimeMs = info.getControllerTxTimeMillis();
+            energy = info.getControllerEnergyUsed();
+            if (info.getUidTraffic() != null) {
+                for (UidTraffic traffic : info.getUidTraffic()) {
+                    uidRxBytes.put(traffic.getUid(), traffic.getRxBytes());
+                    uidTxBytes.put(traffic.getUid(), traffic.getTxBytes());
+                }
+            }
+        }
+    }
+
+    private final BluetoothActivityInfoCache mLastBluetoothActivityInfo
+            = new BluetoothActivityInfoCache();
+
     /**
      * Distribute Bluetooth energy info and network traffic to apps.
+     *
      * @param info The energy information from the bluetooth controller.
      */
     public void updateBluetoothStateLocked(@Nullable final BluetoothActivityEnergyInfo info) {
@@ -11661,12 +11699,13 @@
         mHasBluetoothReporting = true;
 
         final long elapsedRealtimeMs = mClocks.elapsedRealtime();
-        final long rxTimeMs = info.getControllerRxTimeMillis() -
-                mLastBluetoothActivityEnergyInfo.getControllerRxTimeMillis();
-        final long txTimeMs = info.getControllerTxTimeMillis() -
-                mLastBluetoothActivityEnergyInfo.getControllerTxTimeMillis();
-        final long idleTimeMs = info.getControllerIdleTimeMillis() -
-                mLastBluetoothActivityEnergyInfo.getControllerIdleTimeMillis();
+        final long rxTimeMs =
+                info.getControllerRxTimeMillis() - mLastBluetoothActivityInfo.rxTimeMs;
+        final long txTimeMs =
+                info.getControllerTxTimeMillis() - mLastBluetoothActivityInfo.txTimeMs;
+        final long idleTimeMs =
+                info.getControllerIdleTimeMillis() - mLastBluetoothActivityInfo.idleTimeMs;
+
         if (DEBUG_ENERGY) {
             Slog.d(TAG, "------ BEGIN BLE power blaming ------");
             Slog.d(TAG, "  Tx Time:    " + txTimeMs + " ms");
@@ -11738,8 +11777,8 @@
         }
 
         if (DEBUG_ENERGY) {
-            Slog.d(TAG, "Left over time for traffic RX=" + leftOverRxTimeMs
-                    + " TX=" + leftOverTxTimeMs);
+            Slog.d(TAG, "Left over time for traffic RX=" + leftOverRxTimeMs + " TX="
+                    + leftOverTxTimeMs);
         }
 
         //
@@ -11750,70 +11789,56 @@
         long totalRxBytes = 0;
 
         final UidTraffic[] uidTraffic = info.getUidTraffic();
-        final UidTraffic[] lastUidTraffic = mLastBluetoothActivityEnergyInfo.getUidTraffic();
-        final ArrayList<UidTraffic> deltaTraffic = new ArrayList<>();
-        int m = 0, n = 0;
-        for (; m < uidTraffic.length && n < lastUidTraffic.length; m++) {
-            final UidTraffic traffic = uidTraffic[m];
-            final UidTraffic lastTraffic = lastUidTraffic[n];
-            if (traffic.getUid() == lastTraffic.getUid()) {
-                deltaTraffic.add(new UidTraffic(traffic.getUid(),
-                        traffic.getRxBytes() - lastTraffic.getRxBytes(),
-                        traffic.getTxBytes() - lastTraffic.getTxBytes()));
-                n++;
-            }
-        }
-        for (; m < uidTraffic.length; m ++) {
-            deltaTraffic.add(uidTraffic[m]);
-        }
-
-        for (int i = 0, j = 0; i < deltaTraffic.size(); i++) {
-            final UidTraffic traffic = deltaTraffic.get(i);
+        final int numUids = uidTraffic != null ? uidTraffic.length : 0;
+        for (int i = 0; i < numUids; i++) {
+            final UidTraffic traffic = uidTraffic[i];
+            final long rxBytes = traffic.getRxBytes() - mLastBluetoothActivityInfo.uidRxBytes.get(
+                    traffic.getUid());
+            final long txBytes = traffic.getTxBytes() - mLastBluetoothActivityInfo.uidTxBytes.get(
+                    traffic.getUid());
 
             // Add to the global counters.
-            mNetworkByteActivityCounters[NETWORK_BT_RX_DATA].addCountLocked(
-                    traffic.getRxBytes());
-            mNetworkByteActivityCounters[NETWORK_BT_TX_DATA].addCountLocked(
-                    traffic.getTxBytes());
+            mNetworkByteActivityCounters[NETWORK_BT_RX_DATA].addCountLocked(rxBytes);
+            mNetworkByteActivityCounters[NETWORK_BT_TX_DATA].addCountLocked(txBytes);
 
             // Add to the UID counters.
             final Uid u = getUidStatsLocked(mapUid(traffic.getUid()));
-            u.noteNetworkActivityLocked(NETWORK_BT_RX_DATA, traffic.getRxBytes(), 0);
-            u.noteNetworkActivityLocked(NETWORK_BT_TX_DATA, traffic.getTxBytes(), 0);
+            u.noteNetworkActivityLocked(NETWORK_BT_RX_DATA, rxBytes, 0);
+            u.noteNetworkActivityLocked(NETWORK_BT_TX_DATA, txBytes, 0);
 
             // Calculate the total traffic.
-            totalTxBytes += traffic.getTxBytes();
-            totalRxBytes += traffic.getRxBytes();
+            totalRxBytes += rxBytes;
+            totalTxBytes += txBytes;
         }
 
-        if ((totalTxBytes != 0 || totalRxBytes != 0) &&
-                (leftOverRxTimeMs != 0 || leftOverTxTimeMs != 0)) {
-            for (int i = 0; i < deltaTraffic.size(); i++) {
-                final UidTraffic traffic = deltaTraffic.get(i);
+        if ((totalTxBytes != 0 || totalRxBytes != 0) && (leftOverRxTimeMs != 0
+                || leftOverTxTimeMs != 0)) {
+            for (int i = 0; i < numUids; i++) {
+                final UidTraffic traffic = uidTraffic[i];
+                final int uid = traffic.getUid();
+                final long rxBytes =
+                        traffic.getRxBytes() - mLastBluetoothActivityInfo.uidRxBytes.get(uid);
+                final long txBytes =
+                        traffic.getTxBytes() - mLastBluetoothActivityInfo.uidTxBytes.get(uid);
 
-                final Uid u = getUidStatsLocked(mapUid(traffic.getUid()));
+                final Uid u = getUidStatsLocked(mapUid(uid));
                 final ControllerActivityCounterImpl counter =
                         u.getOrCreateBluetoothControllerActivityLocked();
 
-                if (totalRxBytes > 0 && traffic.getRxBytes() > 0) {
-                    final long timeRxMs = (leftOverRxTimeMs * traffic.getRxBytes()) / totalRxBytes;
-
+                if (totalRxBytes > 0 && rxBytes > 0) {
+                    final long timeRxMs = (leftOverRxTimeMs * rxBytes) / totalRxBytes;
                     if (DEBUG_ENERGY) {
-                        Slog.d(TAG, "UID=" + traffic.getUid() + " rx_bytes=" + traffic.getRxBytes()
-                                + " rx_time=" + timeRxMs);
+                        Slog.d(TAG, "UID=" + uid + " rx_bytes=" + rxBytes + " rx_time=" + timeRxMs);
                     }
                     counter.getRxTimeCounter().addCountLocked(timeRxMs);
                     leftOverRxTimeMs -= timeRxMs;
                 }
 
-                if (totalTxBytes > 0 && traffic.getTxBytes() > 0) {
-                    final long timeTxMs = (leftOverTxTimeMs * traffic.getTxBytes()) / totalTxBytes;
-
+                if (totalTxBytes > 0 && txBytes > 0) {
+                    final long timeTxMs = (leftOverTxTimeMs * txBytes) / totalTxBytes;
                     if (DEBUG_ENERGY) {
-                        Slog.d(TAG, "UID=" + traffic.getUid() + " tx_bytes=" + traffic.getTxBytes()
-                                + " tx_time=" + timeTxMs);
+                        Slog.d(TAG, "UID=" + uid + " tx_bytes=" + txBytes + " tx_time=" + timeTxMs);
                     }
-
                     counter.getTxTimeCounters()[0].addCountLocked(timeTxMs);
                     leftOverTxTimeMs -= timeTxMs;
                 }
@@ -11830,10 +11855,10 @@
         if (opVolt != 0) {
             // We store the power drain as mAms.
             mBluetoothActivity.getPowerCounter().addCountLocked(
-                    (long) ((info.getControllerEnergyUsed() -
-                            mLastBluetoothActivityEnergyInfo.getControllerEnergyUsed() )/ opVolt));
+                    (long) ((info.getControllerEnergyUsed() - mLastBluetoothActivityInfo.energy)
+                            / opVolt));
         }
-        mLastBluetoothActivityEnergyInfo = info;
+        mLastBluetoothActivityInfo.set(info);
     }
 
     /**
diff --git a/core/jni/android/graphics/ImageDecoder.cpp b/core/jni/android/graphics/ImageDecoder.cpp
index e2ce1a4..726c450 100644
--- a/core/jni/android/graphics/ImageDecoder.cpp
+++ b/core/jni/android/graphics/ImageDecoder.cpp
@@ -38,48 +38,81 @@
 
 static jclass    gImageDecoder_class;
 static jclass    gSize_class;
-static jclass    gIncomplete_class;
+static jclass    gDecodeException_class;
 static jclass    gCanvas_class;
 static jmethodID gImageDecoder_constructorMethodID;
 static jmethodID gImageDecoder_postProcessMethodID;
 static jmethodID gSize_constructorMethodID;
-static jmethodID gIncomplete_constructorMethodID;
+static jmethodID gDecodeException_constructorMethodID;
 static jmethodID gCallback_onPartialImageMethodID;
 static jmethodID gCanvas_constructorMethodID;
 static jmethodID gCanvas_releaseMethodID;
 
-static jobject native_create(JNIEnv* env, std::unique_ptr<SkStream> stream) {
+// Clear and return any pending exception for handling other than throwing directly.
+static jthrowable get_and_clear_exception(JNIEnv* env) {
+    jthrowable jexception = env->ExceptionOccurred();
+    if (jexception) {
+        env->ExceptionClear();
+    }
+    return jexception;
+}
+
+// Throw a new ImageDecoder.DecodeException. Returns null for convenience.
+static jobject throw_exception(JNIEnv* env, ImageDecoder::Error error, const char* msg,
+                               jthrowable cause, jobject source) {
+    jstring jstr = nullptr;
+    if (msg) {
+        jstr = env->NewStringUTF(msg);
+        if (!jstr) {
+            // Out of memory.
+            return nullptr;
+        }
+    }
+    jthrowable exception = (jthrowable) env->NewObject(gDecodeException_class,
+            gDecodeException_constructorMethodID, error, jstr, cause, source);
+    // Only throw if not out of memory.
+    if (exception) {
+        env->Throw(exception);
+    }
+    return nullptr;
+}
+
+static jobject native_create(JNIEnv* env, std::unique_ptr<SkStream> stream, jobject source) {
     if (!stream.get()) {
-        doThrowIOE(env, "Failed to create a stream");
-        return nullptr;
+        return throw_exception(env, ImageDecoder::kSourceMalformedData, "Failed to create a stream",
+                               nullptr, source);
     }
     std::unique_ptr<ImageDecoder> decoder(new ImageDecoder);
     SkCodec::Result result;
     auto codec = SkCodec::MakeFromStream(std::move(stream), &result, decoder->mPeeker.get());
+    if (jthrowable jexception = get_and_clear_exception(env)) {
+        return throw_exception(env, ImageDecoder::kSourceException, "", jexception, source);
+    }
     if (!codec) {
         switch (result) {
             case SkCodec::kIncompleteInput:
-                env->ThrowNew(gIncomplete_class, "Incomplete input");
-                break;
+                return throw_exception(env, ImageDecoder::kSourceIncomplete, "", nullptr, source);
             default:
                 SkString msg;
                 msg.printf("Failed to create image decoder with message '%s'",
                            SkCodec::ResultToString(result));
-                doThrowIOE(env, msg.c_str());
-                break;
+                return throw_exception(env, ImageDecoder::kSourceMalformedData,  msg.c_str(),
+                                       nullptr, source);
 
         }
-        return nullptr;
     }
 
-    // FIXME: Avoid parsing the whole image?
     const bool animated = codec->getFrameCount() > 1;
+    if (jthrowable jexception = get_and_clear_exception(env)) {
+        return throw_exception(env, ImageDecoder::kSourceException, "", jexception, source);
+    }
+
     decoder->mCodec = SkAndroidCodec::MakeFromCodec(std::move(codec),
             SkAndroidCodec::ExifOrientationBehavior::kRespect);
     if (!decoder->mCodec.get()) {
-        doThrowIOE(env, "Could not create AndroidCodec");
-        return nullptr;
+        return throw_exception(env, ImageDecoder::kSourceMalformedData, "", nullptr, source);
     }
+
     const auto& info = decoder->mCodec->getInfo();
     const int width = info.width();
     const int height = info.height();
@@ -89,26 +122,26 @@
 }
 
 static jobject ImageDecoder_nCreateFd(JNIEnv* env, jobject /*clazz*/,
-        jobject fileDescriptor) {
+        jobject fileDescriptor, jobject source) {
     int descriptor = jniGetFDFromFileDescriptor(env, fileDescriptor);
 
     struct stat fdStat;
     if (fstat(descriptor, &fdStat) == -1) {
-        doThrowIOE(env, "broken file descriptor; fstat returned -1");
-        return nullptr;
+        return throw_exception(env, ImageDecoder::kSourceMalformedData,
+                               "broken file descriptor; fstat returned -1", nullptr, source);
     }
 
     int dupDescriptor = dup(descriptor);
     FILE* file = fdopen(dupDescriptor, "r");
     if (file == NULL) {
         close(dupDescriptor);
-        doThrowIOE(env, "Could not open file");
-        return nullptr;
+        return throw_exception(env, ImageDecoder::kSourceMalformedData, "Could not open file",
+                               nullptr, source);
     }
     std::unique_ptr<SkFILEStream> fileStream(new SkFILEStream(file));
 
     if (::lseek(descriptor, 0, SEEK_CUR) == 0) {
-        return native_create(env, std::move(fileStream));
+        return native_create(env, std::move(fileStream), source);
     }
 
     // FIXME: This allows us to pretend the current location is the beginning,
@@ -116,44 +149,46 @@
     // point as the beginning.
     std::unique_ptr<SkStream> stream(SkFrontBufferedStream::Make(std::move(fileStream),
                 SkCodec::MinBufferedBytesNeeded()));
-    return native_create(env, std::move(stream));
+    return native_create(env, std::move(stream), source);
 }
 
 static jobject ImageDecoder_nCreateInputStream(JNIEnv* env, jobject /*clazz*/,
-        jobject is, jbyteArray storage) {
+        jobject is, jbyteArray storage, jobject source) {
     std::unique_ptr<SkStream> stream(CreateJavaInputStreamAdaptor(env, is, storage, false));
 
     if (!stream.get()) {
-        doThrowIOE(env, "Failed to create stream!");
-        return nullptr;
+        return throw_exception(env, ImageDecoder::kSourceMalformedData, "Failed to create a stream",
+                               nullptr, source);
     }
+
     std::unique_ptr<SkStream> bufferedStream(
         SkFrontBufferedStream::Make(std::move(stream),
         SkCodec::MinBufferedBytesNeeded()));
-    return native_create(env, std::move(bufferedStream));
+    return native_create(env, std::move(bufferedStream), source);
 }
 
-static jobject ImageDecoder_nCreateAsset(JNIEnv* env, jobject /*clazz*/, jlong assetPtr) {
+static jobject ImageDecoder_nCreateAsset(JNIEnv* env, jobject /*clazz*/, jlong assetPtr,
+                                         jobject source) {
     Asset* asset = reinterpret_cast<Asset*>(assetPtr);
     std::unique_ptr<SkStream> stream(new AssetStreamAdaptor(asset));
-    return native_create(env, std::move(stream));
+    return native_create(env, std::move(stream), source);
 }
 
 static jobject ImageDecoder_nCreateByteBuffer(JNIEnv* env, jobject /*clazz*/, jobject jbyteBuffer,
-                                              jint initialPosition, jint limit) {
+                                              jint initialPosition, jint limit, jobject source) {
     std::unique_ptr<SkStream> stream = CreateByteBufferStreamAdaptor(env, jbyteBuffer,
                                                                      initialPosition, limit);
     if (!stream) {
-        doThrowIOE(env, "Failed to read ByteBuffer");
-        return nullptr;
+        return throw_exception(env, ImageDecoder::kSourceMalformedData, "Failed to read ByteBuffer",
+                               nullptr, source);
     }
-    return native_create(env, std::move(stream));
+    return native_create(env, std::move(stream), source);
 }
 
 static jobject ImageDecoder_nCreateByteArray(JNIEnv* env, jobject /*clazz*/, jbyteArray byteArray,
-                                             jint offset, jint length) {
+                                             jint offset, jint length, jobject source) {
     std::unique_ptr<SkStream> stream(CreateByteArrayStreamAdaptor(env, byteArray, offset, length));
-    return native_create(env, std::move(stream));
+    return native_create(env, std::move(stream), source);
 }
 
 jint postProcessAndRelease(JNIEnv* env, jobject jimageDecoder, std::unique_ptr<Canvas> canvas) {
@@ -170,10 +205,8 @@
     return env->CallIntMethod(jimageDecoder, gImageDecoder_postProcessMethodID, jcanvas);
 }
 
-// Note: jpostProcess points to an ImageDecoder object if it has a PostProcess object, and nullptr
-// otherwise.
 static jobject ImageDecoder_nDecodeBitmap(JNIEnv* env, jobject /*clazz*/, jlong nativePtr,
-                                          jobject jcallback, jobject jpostProcess,
+                                          jobject jdecoder, jboolean jpostProcess,
                                           jint desiredWidth, jint desiredHeight, jobject jsubset,
                                           jboolean requireMutable, jint allocator,
                                           jboolean requireUnpremul, jboolean preferRamOverQuality,
@@ -264,11 +297,8 @@
     SkAndroidCodec::AndroidOptions options;
     options.fSampleSize = sampleSize;
     auto result = codec->getAndroidPixels(decodeInfo, bm.getPixels(), bm.rowBytes(), &options);
-    jthrowable jexception = env->ExceptionOccurred();
-    if (jexception) {
-        env->ExceptionClear();
-    }
-    int onPartialImageError = jexception ? 1  // ImageDecoder.java's ERROR_SOURCE_EXCEPTION
+    jthrowable jexception = get_and_clear_exception(env);
+    int onPartialImageError = jexception ? ImageDecoder::kSourceException
                                          : 0; // No error.
     switch (result) {
         case SkCodec::kSuccess:
@@ -278,12 +308,12 @@
             break;
         case SkCodec::kIncompleteInput:
             if (!jexception) {
-                onPartialImageError = 2; // ImageDecoder.java's ERROR_SOURCE_EXCEPTION
+                onPartialImageError = ImageDecoder::kSourceIncomplete;
             }
             break;
         case SkCodec::kErrorInInput:
             if (!jexception) {
-                onPartialImageError = 3; // ImageDecoder.java's ERROR_SOURCE_ERROR
+                onPartialImageError = ImageDecoder::kSourceMalformedData;
             }
             break;
         default:
@@ -293,24 +323,12 @@
             return nullptr;
     }
 
-    if (jexception || onPartialImageError) {
-        bool throwException = !jcallback ||
-            !env->CallBooleanMethod(jcallback, gCallback_onPartialImageMethodID,
-                                    onPartialImageError);
+    if (onPartialImageError) {
+        env->CallVoidMethod(jdecoder, gCallback_onPartialImageMethodID, onPartialImageError,
+                jexception);
         if (env->ExceptionCheck()) {
             return nullptr;
         }
-
-        if (throwException) {
-            if (jexception) {
-                env->Throw(jexception);
-            } else if (onPartialImageError == 2) {
-                env->ThrowNew(gIncomplete_class, "Incomplete input");
-            } else {
-                doThrowIOE(env, "image has an error!");
-            }
-            return nullptr;
-        }
     }
 
     float scaleX = 1.0f;
@@ -357,11 +375,6 @@
             SkIRect subset;
             GraphicsJNI::jrect_to_irect(env, jsubset, &subset);
 
-            // FIXME: If there is no scale, should this instead call
-            // SkBitmap::extractSubset? If we could upload a subset
-            // (b/70626068), this would save memory and time. Even for a
-            // software Bitmap, the extra speed might be worth the memory
-            // tradeoff if the subset is large?
             translateX    = -subset.fLeft;
             translateY    = -subset.fTop;
             desiredWidth  =  subset.width();
@@ -404,7 +417,7 @@
     if (jpostProcess) {
         std::unique_ptr<Canvas> canvas(Canvas::create_canvas(bm));
 
-        jint pixelFormat = postProcessAndRelease(env, jpostProcess, std::move(canvas));
+        jint pixelFormat = postProcessAndRelease(env, jdecoder, std::move(canvas));
         if (env->ExceptionCheck()) {
             return nullptr;
         }
@@ -495,12 +508,12 @@
 }
 
 static const JNINativeMethod gImageDecoderMethods[] = {
-    { "nCreate",        "(J)Landroid/graphics/ImageDecoder;",    (void*) ImageDecoder_nCreateAsset },
-    { "nCreate",        "(Ljava/nio/ByteBuffer;II)Landroid/graphics/ImageDecoder;", (void*) ImageDecoder_nCreateByteBuffer },
-    { "nCreate",        "([BII)Landroid/graphics/ImageDecoder;", (void*) ImageDecoder_nCreateByteArray },
-    { "nCreate",        "(Ljava/io/InputStream;[B)Landroid/graphics/ImageDecoder;", (void*) ImageDecoder_nCreateInputStream },
-    { "nCreate",        "(Ljava/io/FileDescriptor;)Landroid/graphics/ImageDecoder;", (void*) ImageDecoder_nCreateFd },
-    { "nDecodeBitmap",  "(JLandroid/graphics/ImageDecoder;Landroid/graphics/ImageDecoder;IILandroid/graphics/Rect;ZIZZZ)Landroid/graphics/Bitmap;",
+    { "nCreate",        "(JLandroid/graphics/ImageDecoder$Source;)Landroid/graphics/ImageDecoder;",    (void*) ImageDecoder_nCreateAsset },
+    { "nCreate",        "(Ljava/nio/ByteBuffer;IILandroid/graphics/ImageDecoder$Source;)Landroid/graphics/ImageDecoder;", (void*) ImageDecoder_nCreateByteBuffer },
+    { "nCreate",        "([BIILandroid/graphics/ImageDecoder$Source;)Landroid/graphics/ImageDecoder;", (void*) ImageDecoder_nCreateByteArray },
+    { "nCreate",        "(Ljava/io/InputStream;[BLandroid/graphics/ImageDecoder$Source;)Landroid/graphics/ImageDecoder;", (void*) ImageDecoder_nCreateInputStream },
+    { "nCreate",        "(Ljava/io/FileDescriptor;Landroid/graphics/ImageDecoder$Source;)Landroid/graphics/ImageDecoder;", (void*) ImageDecoder_nCreateFd },
+    { "nDecodeBitmap",  "(JLandroid/graphics/ImageDecoder;ZIILandroid/graphics/Rect;ZIZZZ)Landroid/graphics/Bitmap;",
                                                                  (void*) ImageDecoder_nDecodeBitmap },
     { "nGetSampledSize","(JI)Landroid/util/Size;",               (void*) ImageDecoder_nGetSampledSize },
     { "nGetPadding",    "(JLandroid/graphics/Rect;)V",           (void*) ImageDecoder_nGetPadding },
@@ -516,10 +529,10 @@
     gSize_class = MakeGlobalRefOrDie(env, FindClassOrDie(env, "android/util/Size"));
     gSize_constructorMethodID = GetMethodIDOrDie(env, gSize_class, "<init>", "(II)V");
 
-    gIncomplete_class = MakeGlobalRefOrDie(env, FindClassOrDie(env, "android/graphics/ImageDecoder$IncompleteException"));
-    gIncomplete_constructorMethodID = GetMethodIDOrDie(env, gIncomplete_class, "<init>", "()V");
+    gDecodeException_class = MakeGlobalRefOrDie(env, FindClassOrDie(env, "android/graphics/ImageDecoder$DecodeException"));
+    gDecodeException_constructorMethodID = GetMethodIDOrDie(env, gDecodeException_class, "<init>", "(ILjava/lang/String;Ljava/lang/Throwable;Landroid/graphics/ImageDecoder$Source;)V");
 
-    gCallback_onPartialImageMethodID = GetMethodIDOrDie(env, gImageDecoder_class, "onPartialImage", "(I)Z");
+    gCallback_onPartialImageMethodID = GetMethodIDOrDie(env, gImageDecoder_class, "onPartialImage", "(ILjava/lang/Throwable;)V");
 
     gCanvas_class = MakeGlobalRefOrDie(env, FindClassOrDie(env, "android/graphics/Canvas"));
     gCanvas_constructorMethodID = GetMethodIDOrDie(env, gCanvas_class, "<init>", "(J)V");
diff --git a/core/jni/android/graphics/ImageDecoder.h b/core/jni/android/graphics/ImageDecoder.h
index 5d7e676..fd9827b 100644
--- a/core/jni/android/graphics/ImageDecoder.h
+++ b/core/jni/android/graphics/ImageDecoder.h
@@ -33,6 +33,13 @@
         kHardware_Allocator     = 3,
     };
 
+    // These need to stay in sync with ImageDecoder.java's Error constants.
+    enum Error {
+        kSourceException     = 1,
+        kSourceIncomplete    = 2,
+        kSourceMalformedData = 3,
+    };
+
     // These need to stay in sync with PixelFormat.java's Format constants.
     enum PixelFormat {
         kUnknown     =  0,
diff --git a/core/proto/android/providers/settings.proto b/core/proto/android/providers/settings.proto
index 4bb9707..953da17 100644
--- a/core/proto/android/providers/settings.proto
+++ b/core/proto/android/providers/settings.proto
@@ -744,9 +744,10 @@
     optional SettingProto backup_manager_constants = 193;
     optional SettingProto backup_local_transport_parameters = 194;
     optional SettingProto bluetooth_on_while_driving = 195 [ (android.privacy).dest = DEST_AUTOMATIC ];
+    optional SettingsProto volume_hush_gesture = 196 [ (android.privacy).dest = DEST_AUTOMATIC ];
     // Please insert fields in the same order as in
     // frameworks/base/core/java/android/provider/Settings.java.
-    // Next tag = 196
+    // Next tag = 197
 }
 
 message SystemSettingsProto {
diff --git a/core/proto/android/service/package.proto b/core/proto/android/service/package.proto
index f8050a1..88bb4a6 100644
--- a/core/proto/android/service/package.proto
+++ b/core/proto/android/service/package.proto
@@ -110,6 +110,7 @@
         optional bool is_launched = 6;
         optional EnabledState enabled_state = 7;
         optional string last_disabled_app_caller = 8;
+        optional string suspending_package = 9;
     }
 
     // Name of package. e.g. "com.android.providers.telephony".
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index 2ebffb7..97b80ff 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -1441,6 +1441,13 @@
         android:label="@string/permlab_bluetooth"
         android:protectionLevel="normal" />
 
+    <!-- @SystemApi Allows an application to suspend other apps, which will prevent the user
+         from using them until they are unsuspended.
+         @hide
+    -->
+    <permission android:name="android.permission.SUSPEND_APPS"
+        android:protectionLevel="signature|privileged" />
+
     <!-- Allows applications to discover and pair bluetooth devices.
          <p>Protection level: normal
     -->
diff --git a/core/res/res/values/attrs.xml b/core/res/res/values/attrs.xml
index 75b3bcf..3135455 100644
--- a/core/res/res/values/attrs.xml
+++ b/core/res/res/values/attrs.xml
@@ -5968,6 +5968,9 @@
              in the encoded data. Setting this to infinite (-1) will result in the
              animation repeating as long as it is displayed (once start() is called). -->
         <attr name="repeatCount"/>
+        <!-- When true, automatically start animating. The default is false, meaning
+             that the animation will not start until start() is called. -->
+        <attr name="autoStart" />
     </declare-styleable>
 
     <!-- Drawable used to draw bitmaps. -->
@@ -7984,8 +7987,6 @@
              android.content.pm.PackageInfo#getLongVersionCode()} for the target package.
         -->
         <attr name="maxLongVersionCode" format="string" />
-        <!-- TODO(b/74445943): STOPSHIP (urlBarResourceId should be removed after P DP2 is branched)-->
-        <attr name="urlBarResourceId" format="string" />
     </declare-styleable>
 
     <!-- =============================== -->
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index bbb0b0a..55c17b9 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -2911,6 +2911,10 @@
          is non-interactive. -->
     <bool name="config_cameraDoubleTapPowerGestureEnabled">true</bool>
 
+    <!-- Allow the gesture power + volume up to change the ringer mode while the device
+         is interactive. -->
+    <bool name="config_volumeHushGestureEnabled">true</bool>
+
     <!-- Name of the component to handle network policy notifications. If present,
          disables NetworkPolicyManagerService's presentation of data-usage notifications. -->
     <string translatable="false" name="config_networkPolicyNotificationComponent"></string>
diff --git a/core/res/res/values/public.xml b/core/res/res/values/public.xml
index 2c0deed..0246c80 100644
--- a/core/res/res/values/public.xml
+++ b/core/res/res/values/public.xml
@@ -2869,8 +2869,6 @@
       <public name="outlineSpotShadowColor" />
       <public name="outlineAmbientShadowColor" />
       <public name="maxLongVersionCode" />
-      <!-- TODO(b/74445943): STOPSHIP (urlBarResourceId should be removed after P DP2 is branched)-->
-      <public name="urlBarResourceId" />
       <!-- @hide @SystemApi -->
       <public name="userRestriction" />
       <public name="textFontWeight" />
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index f0f7270..ba85f70 100644
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -4888,6 +4888,9 @@
     <!-- Notification action for editing a screenshot (drawing on it, cropping it, etc) -->
     <string name="screenshot_edit">Edit</string>
 
+    <string name="volume_dialog_ringer_guidance_vibrate">Calls and notifications will vibrate</string>
+    <string name="volume_dialog_ringer_guidance_silent">Calls and notifications will be muted</string>
+
     <!-- Title for the notification channel notifying user of settings system changes. [CHAR LIMIT=NONE] -->
     <string name="notification_channel_system_changes">System changes</string>
     <!-- Title for the notification channel notifying user of do not disturb system changes (i.e. Do Not Disturb has changed). [CHAR LIMIT=NONE] -->
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index 4cf50f5..9d65a60 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -1024,6 +1024,8 @@
   <java-symbol type="string" name="volume_icon_description_media" />
   <java-symbol type="string" name="volume_icon_description_notification" />
   <java-symbol type="string" name="volume_icon_description_ringer" />
+  <java-symbol type="string" name="volume_dialog_ringer_guidance_vibrate" />
+  <java-symbol type="string" name="volume_dialog_ringer_guidance_silent" />
   <java-symbol type="string" name="wait" />
   <java-symbol type="string" name="webpage_unresponsive" />
   <java-symbol type="string" name="whichApplication" />
@@ -2621,6 +2623,7 @@
   <java-symbol type="bool" name="config_cameraDoubleTapPowerGestureEnabled" />
   <java-symbol type="integer" name="config_cameraLiftTriggerSensorType" />
   <java-symbol type="string" name="config_cameraLiftTriggerSensorStringType" />
+  <java-symbol type="bool" name="config_volumeHushGestureEnabled" />
 
   <java-symbol type="drawable" name="platlogo_m" />
 
diff --git a/core/tests/coretests/src/com/android/internal/os/BatteryStatsTests.java b/core/tests/coretests/src/com/android/internal/os/BatteryStatsTests.java
index f5fe80c..94492ba 100644
--- a/core/tests/coretests/src/com/android/internal/os/BatteryStatsTests.java
+++ b/core/tests/coretests/src/com/android/internal/os/BatteryStatsTests.java
@@ -43,6 +43,7 @@
         KernelUidCpuActiveTimeReaderTest.class,
         KernelUidCpuClusterTimeReaderTest.class,
         KernelWakelockReaderTest.class,
+        LongSamplingCounterTest.class,
         LongSamplingCounterArrayTest.class,
         PowerCalculatorTest.class,
         PowerProfileTest.class
diff --git a/core/tests/coretests/src/com/android/internal/os/LongSamplingCounterTest.java b/core/tests/coretests/src/com/android/internal/os/LongSamplingCounterTest.java
new file mode 100644
index 0000000..853bf8a
--- /dev/null
+++ b/core/tests/coretests/src/com/android/internal/os/LongSamplingCounterTest.java
@@ -0,0 +1,194 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.internal.os;
+
+import static android.os.BatteryStats.STATS_SINCE_CHARGED;
+
+import static com.android.internal.os.BatteryStatsImpl.LongSamplingCounter;
+import static com.android.internal.os.BatteryStatsImpl.TimeBase;
+
+import static org.junit.Assert.assertEquals;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.verifyNoMoreInteractions;
+import static org.mockito.Mockito.verifyZeroInteractions;
+import static org.mockito.Mockito.when;
+
+import android.os.Parcel;
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.Mockito;
+import org.mockito.MockitoAnnotations;
+
+/**
+ * Test class for {@link LongSamplingCounter}.
+ *
+ * To run the tests, use
+ *
+ * bit FrameworksCoreTests:com.android.internal.os.LongSamplingCounterTest
+ */
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class LongSamplingCounterTest {
+
+    private static final long COUNT = 1111;
+    private static final long CURRENT_COUNT = 5555;
+
+    @Mock
+    private TimeBase mTimeBase;
+    private LongSamplingCounter mCounter;
+
+    @Before
+    public void setUp() {
+        MockitoAnnotations.initMocks(this);
+        mCounter = new LongSamplingCounter(mTimeBase);
+        Mockito.reset(mTimeBase);
+    }
+
+    @Test
+    public void testReadWriteParcel() {
+        final Parcel parcel = Parcel.obtain();
+        updateCounts(COUNT, CURRENT_COUNT);
+        mCounter.writeToParcel(parcel);
+        parcel.setDataPosition(0);
+
+        // Now clear counterArray and verify values are read from parcel correctly.
+        updateCounts(0, 0);
+
+        mCounter = new LongSamplingCounter(mTimeBase, parcel);
+        assertEquals(COUNT, mCounter.mCount);
+        assertEquals(CURRENT_COUNT, mCounter.mCurrentCount);
+        parcel.recycle();
+    }
+
+    @Test
+    public void testReadWriteSummaryParcel() {
+        final Parcel parcel = Parcel.obtain();
+        updateCounts(COUNT, CURRENT_COUNT);
+        mCounter.writeSummaryFromParcelLocked(parcel);
+        parcel.setDataPosition(0);
+
+        // Now clear counterArray and verify values are read from parcel correctly.
+        updateCounts(0, 0);
+
+        mCounter.readSummaryFromParcelLocked(parcel);
+        assertEquals(COUNT, mCounter.mCount);
+        parcel.recycle();
+    }
+
+    @Test
+    public void testOnTimeStarted() {
+        updateCounts(COUNT, CURRENT_COUNT);
+        mCounter.onTimeStarted(0, 0, 0);
+        assertEquals(COUNT, mCounter.mCount);
+        assertEquals(COUNT, mCounter.mUnpluggedCount);
+    }
+
+    @Test
+    public void testOnTimeStopped() {
+        updateCounts(COUNT, CURRENT_COUNT);
+        mCounter.onTimeStopped(0, 0, 0);
+        assertEquals(COUNT, mCounter.mCount);
+    }
+
+    @Test
+    public void testAddCountLocked() {
+        updateCounts(0, 0);
+        assertEquals(0, mCounter.getCountLocked(0));
+        when(mTimeBase.isRunning()).thenReturn(true);
+        mCounter.addCountLocked(111);
+        assertEquals(111, mCounter.getCountLocked(STATS_SINCE_CHARGED));
+        assertEquals(111, mCounter.mCurrentCount);
+        mCounter.addCountLocked(222);
+        assertEquals(333, mCounter.getCountLocked(STATS_SINCE_CHARGED));
+        assertEquals(333, mCounter.mCurrentCount);
+
+        when(mTimeBase.isRunning()).thenReturn(false);
+        mCounter.addCountLocked(456);
+        assertEquals(333, mCounter.getCountLocked(STATS_SINCE_CHARGED));
+        assertEquals(789, mCounter.mCurrentCount);
+
+        mCounter.addCountLocked(444, true);
+        assertEquals(777, mCounter.getCountLocked(STATS_SINCE_CHARGED));
+        assertEquals(1233, mCounter.mCurrentCount);
+        mCounter.addCountLocked(567, false);
+        assertEquals(777, mCounter.getCountLocked(STATS_SINCE_CHARGED));
+        assertEquals(1800, mCounter.mCurrentCount);
+    }
+
+    @Test
+    public void testUpdate() {
+        updateCounts(0, 0);
+        assertEquals(0, mCounter.getCountLocked(0));
+        when(mTimeBase.isRunning()).thenReturn(true);
+        mCounter.update(111);
+        assertEquals(111, mCounter.getCountLocked(STATS_SINCE_CHARGED));
+        assertEquals(111, mCounter.mCurrentCount);
+        mCounter.update(333);
+        assertEquals(333, mCounter.getCountLocked(STATS_SINCE_CHARGED));
+        assertEquals(333, mCounter.mCurrentCount);
+
+        when(mTimeBase.isRunning()).thenReturn(false);
+        mCounter.update(789);
+        assertEquals(333, mCounter.getCountLocked(STATS_SINCE_CHARGED));
+        assertEquals(789, mCounter.mCurrentCount);
+        mCounter.update(100);
+        assertEquals(333, mCounter.getCountLocked(STATS_SINCE_CHARGED));
+        assertEquals(100, mCounter.mCurrentCount);
+
+        mCounter.update(544, true);
+        assertEquals(777, mCounter.getCountLocked(STATS_SINCE_CHARGED));
+        assertEquals(544, mCounter.mCurrentCount);
+        mCounter.update(1544, false);
+        assertEquals(777, mCounter.getCountLocked(STATS_SINCE_CHARGED));
+        assertEquals(1544, mCounter.mCurrentCount);
+    }
+
+    @Test
+    public void testReset() {
+        updateCounts(COUNT, CURRENT_COUNT);
+        // Test with detachIfReset=false
+        mCounter.reset(false /* detachIfReset */);
+        assertEquals(0, mCounter.mCount);
+        assertEquals(CURRENT_COUNT, mCounter.mCurrentCount);
+        verifyZeroInteractions(mTimeBase);
+
+        updateCounts(COUNT, CURRENT_COUNT);
+        // Test with detachIfReset=true
+        mCounter.reset(true /* detachIfReset */);
+        assertEquals(0, mCounter.mCount);
+        assertEquals(CURRENT_COUNT, mCounter.mCurrentCount);
+        verify(mTimeBase).remove(mCounter);
+        verifyNoMoreInteractions(mTimeBase);
+    }
+
+    @Test
+    public void testDetach() {
+        mCounter.detach();
+        verify(mTimeBase).remove(mCounter);
+        verifyNoMoreInteractions(mTimeBase);
+    }
+
+    private void updateCounts(long total, long current) {
+        mCounter.mCount = total;
+        mCounter.mCurrentCount = current;
+    }
+}
diff --git a/core/tests/coretests/src/com/android/internal/policy/PhoneWindowTest.java b/core/tests/coretests/src/com/android/internal/policy/PhoneWindowTest.java
index 002df88..518cadd 100644
--- a/core/tests/coretests/src/com/android/internal/policy/PhoneWindowTest.java
+++ b/core/tests/coretests/src/com/android/internal/policy/PhoneWindowTest.java
@@ -16,7 +16,6 @@
 
 package com.android.internal.policy;
 
-import static android.view.WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS;
 import static android.view.WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_DEFAULT;
 import static android.view.WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_NEVER;
 import static android.view.WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_SHORT_EDGES;
@@ -27,7 +26,6 @@
 import android.content.Context;
 import android.platform.test.annotations.Presubmit;
 import android.support.test.InstrumentationRegistry;
-import android.support.test.filters.FlakyTest;
 import android.support.test.filters.SmallTest;
 import android.support.test.runner.AndroidJUnit4;
 import android.view.ActionMode;
@@ -44,7 +42,6 @@
  */
 @SmallTest
 @Presubmit
-@FlakyTest(detail = "Promote to presubmit once monitored to be stable.")
 @RunWith(AndroidJUnit4.class)
 public final class PhoneWindowTest {
 
diff --git a/graphics/java/android/graphics/ImageDecoder.java b/graphics/java/android/graphics/ImageDecoder.java
index 2f09c65..5ca0ad6 100644
--- a/graphics/java/android/graphics/ImageDecoder.java
+++ b/graphics/java/android/graphics/ImageDecoder.java
@@ -24,6 +24,7 @@
 import android.annotation.IntDef;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
+import android.annotation.TestApi;
 import android.content.ContentResolver;
 import android.content.res.AssetFileDescriptor;
 import android.content.res.AssetManager;
@@ -102,7 +103,7 @@
 
         @Override
         public ImageDecoder createImageDecoder() throws IOException {
-            return nCreate(mData, mOffset, mLength);
+            return nCreate(mData, mOffset, mLength, this);
         }
     }
 
@@ -117,9 +118,9 @@
             if (!mBuffer.isDirect() && mBuffer.hasArray()) {
                 int offset = mBuffer.arrayOffset() + mBuffer.position();
                 int length = mBuffer.limit() - mBuffer.position();
-                return nCreate(mBuffer.array(), offset, length);
+                return nCreate(mBuffer.array(), offset, length, this);
             }
-            return nCreate(mBuffer, mBuffer.position(), mBuffer.limit());
+            return nCreate(mBuffer, mBuffer.position(), mBuffer.limit(), this);
         }
     }
 
@@ -156,7 +157,7 @@
                     throw new FileNotFoundException(mUri.toString());
                 }
 
-                return createFromStream(is, true);
+                return createFromStream(is, true, this);
             }
 
             final FileDescriptor fd = assetFd.getFileDescriptor();
@@ -166,9 +167,9 @@
             try {
                 try {
                     Os.lseek(fd, offset, SEEK_SET);
-                    decoder = nCreate(fd);
+                    decoder = nCreate(fd, this);
                 } catch (ErrnoException e) {
-                    decoder = createFromStream(new FileInputStream(fd), true);
+                    decoder = createFromStream(new FileInputStream(fd), true, this);
                 }
             } finally {
                 if (decoder == null) {
@@ -182,18 +183,19 @@
     }
 
     @NonNull
-    private static ImageDecoder createFromFile(@NonNull File file) throws IOException {
+    private static ImageDecoder createFromFile(@NonNull File file,
+            @NonNull Source source) throws IOException {
         FileInputStream stream = new FileInputStream(file);
         FileDescriptor fd = stream.getFD();
         try {
             Os.lseek(fd, 0, SEEK_CUR);
         } catch (ErrnoException e) {
-            return createFromStream(stream, true);
+            return createFromStream(stream, true, source);
         }
 
         ImageDecoder decoder = null;
         try {
-            decoder = nCreate(fd);
+            decoder = nCreate(fd, source);
         } finally {
             if (decoder == null) {
                 IoUtils.closeQuietly(stream);
@@ -207,12 +209,12 @@
 
     @NonNull
     private static ImageDecoder createFromStream(@NonNull InputStream is,
-            boolean closeInputStream) throws IOException {
+            boolean closeInputStream, Source source) throws IOException {
         // Arbitrary size matches BitmapFactory.
         byte[] storage = new byte[16 * 1024];
         ImageDecoder decoder = null;
         try {
-            decoder = nCreate(is, storage);
+            decoder = nCreate(is, storage, source);
         } finally {
             if (decoder == null) {
                 if (closeInputStream) {
@@ -260,7 +262,7 @@
                 }
                 InputStream is = mInputStream;
                 mInputStream = null;
-                return createFromStream(is, false);
+                return createFromStream(is, false, this);
             }
         }
     }
@@ -305,7 +307,7 @@
                 }
                 AssetInputStream ais = mAssetInputStream;
                 mAssetInputStream = null;
-                return createFromAsset(ais);
+                return createFromAsset(ais, this);
             }
         }
     }
@@ -340,18 +342,19 @@
                 mResDensity = value.density;
             }
 
-            return createFromAsset((AssetInputStream) is);
+            return createFromAsset((AssetInputStream) is, this);
         }
     }
 
     /**
      *  ImageDecoder will own the AssetInputStream.
      */
-    private static ImageDecoder createFromAsset(AssetInputStream ais) throws IOException {
+    private static ImageDecoder createFromAsset(AssetInputStream ais,
+            Source source) throws IOException {
         ImageDecoder decoder = null;
         try {
             long asset = ais.getNativeAsset();
-            decoder = nCreate(asset);
+            decoder = nCreate(asset, source);
         } finally {
             if (decoder == null) {
                 IoUtils.closeQuietly(ais);
@@ -375,7 +378,7 @@
         @Override
         public ImageDecoder createImageDecoder() throws IOException {
             InputStream is = mAssets.open(mFileName);
-            return createFromAsset((AssetInputStream) is);
+            return createFromAsset((AssetInputStream) is, this);
         }
     }
 
@@ -388,7 +391,7 @@
 
         @Override
         public ImageDecoder createImageDecoder() throws IOException {
-            return createFromFile(mFile);
+            return createFromFile(mFile, this);
         }
     }
 
@@ -431,9 +434,10 @@
         }
     };
 
-    /**
-     *  Thrown if the provided data is incomplete.
+    /** @removed
+     * @deprecated Subsumed by {@link #DecodeException}.
      */
+    @java.lang.Deprecated
     public static class IncompleteException extends IOException {};
 
     /**
@@ -453,24 +457,102 @@
 
     };
 
-    /**
-     *  An Exception was thrown reading the {@link Source}.
+    /** @removed
+     * @deprecated Replaced by {@link #DecodeException#SOURCE_EXCEPTION}.
      */
+    @java.lang.Deprecated
     public static final int ERROR_SOURCE_EXCEPTION  = 1;
 
-    /**
-     *  The encoded data was incomplete.
+    /** @removed
+     * @deprecated Replaced by {@link #DecodeException#SOURCE_INCOMPLETE}.
      */
+    @java.lang.Deprecated
     public static final int ERROR_SOURCE_INCOMPLETE = 2;
 
-    /**
-     *  The encoded data contained an error.
+    /** @removed
+     * @deprecated Replaced by {@link #DecodeException#SOURCE_MALFORMED_DATA}.
      */
+    @java.lang.Deprecated
     public static final int ERROR_SOURCE_ERROR      = 3;
 
-    @Retention(SOURCE)
-    @IntDef({ ERROR_SOURCE_EXCEPTION, ERROR_SOURCE_INCOMPLETE, ERROR_SOURCE_ERROR })
-    public @interface Error {};
+    /**
+     *  Information about an interrupted decode.
+     */
+    public static final class DecodeException extends IOException {
+        /**
+         *  An Exception was thrown reading the {@link Source}.
+         */
+        public static final int SOURCE_EXCEPTION  = 1;
+
+        /**
+         *  The encoded data was incomplete.
+         */
+        public static final int SOURCE_INCOMPLETE = 2;
+
+        /**
+         *  The encoded data contained an error.
+         */
+        public static final int SOURCE_MALFORMED_DATA      = 3;
+
+        /** @hide **/
+        @Retention(SOURCE)
+        @IntDef(value = { SOURCE_EXCEPTION, SOURCE_INCOMPLETE, SOURCE_MALFORMED_DATA },
+                prefix = {"SOURCE_"})
+        public @interface Error {};
+
+        @Error final int mError;
+        @NonNull final Source mSource;
+
+        DecodeException(@Error int error, @Nullable Throwable cause, @NonNull Source source) {
+            super(errorMessage(error, cause), cause);
+            mError = error;
+            mSource = source;
+        }
+
+        /**
+         * Private method called by JNI.
+         */
+        @SuppressWarnings("unused")
+        DecodeException(@Error int error, @Nullable String msg, @Nullable Throwable cause,
+                @NonNull Source source) {
+            super(msg + errorMessage(error, cause), cause);
+            mError = error;
+            mSource = source;
+        }
+
+        /**
+         *  Retrieve the reason that decoding was interrupted.
+         *
+         *  <p>If the error is {@link #SOURCE_EXCEPTION}, the underlying
+         *  {@link java.lang.Throwable} can be retrieved with
+         *  {@link java.lang.Throwable#getCause}.</p>
+         */
+        @Error
+        public int getError() {
+            return mError;
+        }
+
+        /**
+         *  Retrieve the {@link Source} that was interrupted.
+         */
+        @NonNull
+        public Source getSource() {
+            return mSource;
+        }
+
+        private static String errorMessage(@Error int error, @Nullable Throwable cause) {
+            switch (error) {
+                case SOURCE_EXCEPTION:
+                    return "Exception in input: " + cause;
+                case SOURCE_INCOMPLETE:
+                    return "Input was incomplete.";
+                case SOURCE_MALFORMED_DATA:
+                    return "Input contained an error.";
+                default:
+                    return "";
+            }
+        }
+    }
 
     /**
      *  Optional listener supplied to the ImageDecoder.
@@ -486,13 +568,12 @@
          *  optionally finish the rest of the decode/creation process to create
          *  a partial {@link Drawable}/{@link Bitmap}.
          *
-         *  @param error indicating what interrupted the decode.
-         *  @param source that had the error.
+         *  @param e containing information about the decode interruption.
          *  @return True to create and return a {@link Drawable}/{@link Bitmap}
          *      with partial data. False (which is the default) to abort the
-         *      decode and throw {@link java.io.IOException}.
+         *      decode and throw {@code e}.
          */
-        public boolean onPartialImage(@Error int error, @NonNull Source source);
+        boolean onPartialImage(@NonNull DecodeException e);
     };
 
     // Fields
@@ -667,6 +748,7 @@
      * Internal API used to generate bitmaps for use by Drawables (i.e. BitmapDrawable)
      * @hide
      */
+    @TestApi
     public static Source createSource(Resources res, InputStream is, int density) {
         return new InputStreamSource(res, is, density);
     }
@@ -1087,14 +1169,8 @@
     @NonNull
     private Bitmap decodeBitmapInternal() throws IOException {
         checkState();
-        // nDecodeBitmap calls onPartialImage only if mOnPartialImageListener
-        // exists
-        ImageDecoder partialImagePtr = mOnPartialImageListener == null ? null : this;
-        // nDecodeBitmap calls postProcessAndRelease only if mPostProcessor
-        // exists.
-        ImageDecoder postProcessPtr = mPostProcessor == null ? null : this;
-        return nDecodeBitmap(mNativePtr, partialImagePtr,
-                postProcessPtr, mDesiredWidth, mDesiredHeight, mCropRect,
+        return nDecodeBitmap(mNativePtr, this, mPostProcessor != null,
+                mDesiredWidth, mDesiredHeight, mCropRect,
                 mMutable, mAllocator, mRequireUnpremultiplied,
                 mConserveMemory, mDecodeAsAlphaMask);
     }
@@ -1310,23 +1386,28 @@
      * Private method called by JNI.
      */
     @SuppressWarnings("unused")
-    private boolean onPartialImage(@Error int error) {
-        return mOnPartialImageListener.onPartialImage(error, mSource);
+    private void onPartialImage(@DecodeException.Error int error, @Nullable Throwable cause)
+            throws DecodeException {
+        DecodeException exception = new DecodeException(error, cause, mSource);
+        if (mOnPartialImageListener == null
+                || !mOnPartialImageListener.onPartialImage(exception)) {
+            throw exception;
+        }
     }
 
-    private static native ImageDecoder nCreate(long asset) throws IOException;
-    private static native ImageDecoder nCreate(ByteBuffer buffer,
-                                               int position,
-                                               int limit) throws IOException;
-    private static native ImageDecoder nCreate(byte[] data, int offset,
-                                               int length) throws IOException;
-    private static native ImageDecoder nCreate(InputStream is, byte[] storage);
+    private static native ImageDecoder nCreate(long asset, Source src) throws IOException;
+    private static native ImageDecoder nCreate(ByteBuffer buffer, int position,
+                                               int limit, Source src) throws IOException;
+    private static native ImageDecoder nCreate(byte[] data, int offset, int length,
+                                               Source src) throws IOException;
+    private static native ImageDecoder nCreate(InputStream is, byte[] storage,
+                                               Source src) throws IOException;
     // The fd must be seekable.
-    private static native ImageDecoder nCreate(FileDescriptor fd) throws IOException;
+    private static native ImageDecoder nCreate(FileDescriptor fd, Source src) throws IOException;
     @NonNull
     private static native Bitmap nDecodeBitmap(long nativePtr,
-            @Nullable ImageDecoder partialImageListener,
-            @Nullable ImageDecoder postProcessor,
+            @NonNull ImageDecoder decoder,
+            boolean doPostProcess,
             int width, int height,
             @Nullable Rect cropRect, boolean mutable,
             int allocator, boolean requireUnpremul,
diff --git a/graphics/java/android/graphics/Picture.java b/graphics/java/android/graphics/Picture.java
index 9ac94d8..d01ff6f 100644
--- a/graphics/java/android/graphics/Picture.java
+++ b/graphics/java/android/graphics/Picture.java
@@ -209,6 +209,8 @@
         public PictureCanvas(Picture pict, long nativeCanvas) {
             super(nativeCanvas);
             mPicture = pict;
+            // Disable bitmap density scaling. This matches DisplayListCanvas.
+            mDensity = 0;
         }
 
         @Override
diff --git a/graphics/java/android/graphics/drawable/AnimatedImageDrawable.java b/graphics/java/android/graphics/drawable/AnimatedImageDrawable.java
index a47ecf5..457e4aa 100644
--- a/graphics/java/android/graphics/drawable/AnimatedImageDrawable.java
+++ b/graphics/java/android/graphics/drawable/AnimatedImageDrawable.java
@@ -261,6 +261,12 @@
         if (repeatCount != REPEAT_UNDEFINED) {
             this.setRepeatCount(repeatCount);
         }
+
+        boolean autoStart = a.getBoolean(
+                R.styleable.AnimatedImageDrawable_autoStart, false);
+        if (autoStart && mState.mNativePtr != 0) {
+            this.start();
+        }
     }
 
     /**
diff --git a/libs/hwui/renderthread/CanvasContext.cpp b/libs/hwui/renderthread/CanvasContext.cpp
index 820789d..f4d8051 100644
--- a/libs/hwui/renderthread/CanvasContext.cpp
+++ b/libs/hwui/renderthread/CanvasContext.cpp
@@ -355,7 +355,14 @@
             // Already drew for this vsync pulse, UI draw request missed
             // the deadline for RT animations
             info.out.canDrawThisFrame = false;
-        } else if (vsyncDelta >= mRenderThread.timeLord().frameIntervalNanos() * 3 ||
+        }
+        /* This logic exists to try and recover from a display latch miss, which essentially
+         * results in the bufferqueue being double-buffered instead of triple-buffered.
+         * SurfaceFlinger itself now tries to handle & recover from this situation, so this
+         * logic should no longer be necessary. As it's occasionally triggering when
+         * undesired disable it.
+         * TODO: Remove this entirely if the results are solid.
+        else if (vsyncDelta >= mRenderThread.timeLord().frameIntervalNanos() * 3 ||
                    (latestVsync - mLastDropVsync) < 500_ms) {
             // It's been several frame intervals, assume the buffer queue is fine
             // or the last drop was too recent
@@ -367,6 +374,7 @@
                 mLastDropVsync = mRenderThread.timeLord().latestVsync();
             }
         }
+        */
     } else {
         info.out.canDrawThisFrame = true;
     }
diff --git a/media/java/android/media/AudioManagerInternal.java b/media/java/android/media/AudioManagerInternal.java
index 0a1de33..98c2d7f 100644
--- a/media/java/android/media/AudioManagerInternal.java
+++ b/media/java/android/media/AudioManagerInternal.java
@@ -42,6 +42,8 @@
 
     public abstract void setRingerModeInternal(int ringerMode, String caller);
 
+    public abstract void silenceRingerModeInternal(String caller);
+
     public abstract void updateRingerModeAffectedStreamsInternal();
 
     public abstract void setAccessibilityServiceUids(IntArray uids);
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java
index 797b4f9..3467df5 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java
@@ -1928,6 +1928,9 @@
         dumpSetting(s, p,
                 Settings.Secure.BLUETOOTH_ON_WHILE_DRIVING,
                 SecureSettingsProto.BLUETOOTH_ON_WHILE_DRIVING);
+        dumpSetting(s, p,
+                Settings.Secure.VOLUME_HUSH_GESTURE,
+                SecureSettingsProto.VOLUME_HUSH_GESTURE);
         // Please insert new settings using the same order as in Settings.Secure.
 
         p.end(token);
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
index b37071b..7fd0698 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
@@ -2914,7 +2914,7 @@
         }
 
         private final class UpgradeController {
-            private static final int SETTINGS_VERSION = 161;
+            private static final int SETTINGS_VERSION = 162;
 
             private final int mUserId;
 
@@ -3673,6 +3673,21 @@
                     currentVersion = 161;
                 }
 
+                if (currentVersion == 161) {
+                    // Version 161: Add a gesture for silencing phones
+                    final SettingsState secureSettings = getSecureSettingsLocked(userId);
+                    final Setting currentSetting = secureSettings.getSettingLocked(
+                            Secure.VOLUME_HUSH_GESTURE);
+                    if (currentSetting.isNull()) {
+                        secureSettings.insertSettingLocked(
+                                Secure.VOLUME_HUSH_GESTURE,
+                                Integer.toString(Secure.VOLUME_HUSH_VIBRATE),
+                                null, true, SettingsState.SYSTEM_PACKAGE_NAME);
+                    }
+
+                    currentVersion = 162;
+                }
+
                 // vXXX: Add new settings above this point.
 
                 if (currentVersion != newVersion) {
diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml
index 375c31a..a4b7608 100644
--- a/packages/SystemUI/res/values/strings.xml
+++ b/packages/SystemUI/res/values/strings.xml
@@ -1353,8 +1353,6 @@
 
     <string name="volume_dialog_title">%s volume controls</string>
 
-    <string name="volume_dialog_ringer_guidance_vibrate">Calls and notifications will vibrate</string>
-    <string name="volume_dialog_ringer_guidance_silent">Calls and notifications will be muted</string>
     <string name="volume_dialog_ringer_guidance_ring">Calls and notifications will ring</string>
 
     <string name="output_title">Media output</string>
diff --git a/packages/SystemUI/src/com/android/systemui/qs/PagedTileLayout.java b/packages/SystemUI/src/com/android/systemui/qs/PagedTileLayout.java
index ea3a60b..8923952 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/PagedTileLayout.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/PagedTileLayout.java
@@ -42,16 +42,14 @@
     };
 
 
-    private final ArrayList<TileRecord> mTiles = new ArrayList<TileRecord>();
-    private final ArrayList<TilePage> mPages = new ArrayList<TilePage>();
+    private final ArrayList<TileRecord> mTiles = new ArrayList<>();
+    private final ArrayList<TilePage> mPages = new ArrayList<>();
 
     private PageIndicator mPageIndicator;
 
     private int mNumPages;
     private PageListener mPageListener;
 
-    private int mPosition;
-    private boolean mOffPage;
     private boolean mListening;
     private Scroller mScroller;
 
@@ -85,16 +83,12 @@
     public void setListening(boolean listening) {
         if (mListening == listening) return;
         mListening = listening;
-        if (mListening) {
-            setPageListening(mPosition, true);
-            if (mOffPage) {
-                setPageListening(mPosition + 1, true);
-            }
-        } else {
-            // Make sure no pages are listening.
-            for (int i = 0; i < mPages.size(); i++) {
-                mPages.get(i).setListening(false);
-            }
+        updateListening();
+    }
+
+    private void updateListening() {
+        for (TilePage tilePage : mPages) {
+            tilePage.setListening(tilePage.getParent() == null ? false : mListening);
         }
     }
 
@@ -137,43 +131,6 @@
         super.computeScroll();
     }
 
-    /**
-     * Sets individual pages to listening or not.  If offPage it will set
-     * the next page after position to listening as well since we are in between
-     * pages.
-     */
-    private void setCurrentPage(int position, boolean offPage) {
-        if (mPosition == position && mOffPage == offPage) return;
-        if (mListening) {
-            if (mPosition != position) {
-                // Clear out the last pages from listening.
-                setPageListening(mPosition, false);
-                if (mOffPage) {
-                    setPageListening(mPosition + 1, false);
-                }
-                // Set the new pages to listening
-                setPageListening(position, true);
-                if (offPage) {
-                    setPageListening(position + 1, true);
-                }
-            } else if (mOffPage != offPage) {
-                // Whether we are showing position + 1 has changed.
-                setPageListening(mPosition + 1, offPage);
-            }
-        }
-        // Save the current state.
-        mPosition = position;
-        mOffPage = offPage;
-    }
-
-    private void setPageListening(int position, boolean listening) {
-        if (position >= mPages.size()) return;
-        if (isLayoutRtl()) {
-            position = mPages.size() - 1 - position;
-        }
-        mPages.get(position).setListening(listening);
-    }
-
     @Override
     public boolean hasOverlappingRendering() {
         return false;
@@ -362,7 +319,6 @@
                 public void onPageScrolled(int position, float positionOffset,
                         int positionOffsetPixels) {
                     if (mPageIndicator == null) return;
-                    setCurrentPage(position, positionOffset != 0);
                     mPageIndicator.setLocation(position + positionOffset);
                     if (mPageListener != null) {
                         mPageListener.onPageChanged(positionOffsetPixels == 0 &&
@@ -407,11 +363,14 @@
     }
 
     private final PagerAdapter mAdapter = new PagerAdapter() {
+        @Override
         public void destroyItem(ViewGroup container, int position, Object object) {
             if (DEBUG) Log.d(TAG, "Destantiating " + position);
             container.removeView((View) object);
+            updateListening();
         }
 
+        @Override
         public Object instantiateItem(ViewGroup container, int position) {
             if (DEBUG) Log.d(TAG, "Instantiating " + position);
             if (isLayoutRtl()) {
@@ -419,6 +378,7 @@
             }
             ViewGroup view = mPages.get(position);
             container.addView(view);
+            updateListening();
             return view;
         }
 
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickStepController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickStepController.java
index 19544b1..9abbfb83 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickStepController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickStepController.java
@@ -352,7 +352,7 @@
 
     @Override
     public void onDraw(Canvas canvas) {
-        if (mNavigationBarView.isQuickScrubEnabled()) {
+        if (!mNavigationBarView.isQuickScrubEnabled()) {
             return;
         }
         int color = (int) mTrackColorEvaluator.evaluate(mDarkIntensity, mLightTrackColor,
diff --git a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java
index e94d6bd..1c8a26c 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java
@@ -451,11 +451,11 @@
                 toastText = R.string.volume_dialog_ringer_guidance_ring;
                 break;
             case RINGER_MODE_SILENT:
-                toastText = R.string.volume_dialog_ringer_guidance_silent;
+                toastText = com.android.internal.R.string.volume_dialog_ringer_guidance_silent;
                 break;
             case RINGER_MODE_VIBRATE:
             default:
-                toastText = R.string.volume_dialog_ringer_guidance_vibrate;
+                toastText = com.android.internal.R.string.volume_dialog_ringer_guidance_vibrate;
         }
 
         Toast.makeText(mContext, toastText, Toast.LENGTH_SHORT).show();
diff --git a/services/autofill/java/com/android/server/autofill/AutofillManagerService.java b/services/autofill/java/com/android/server/autofill/AutofillManagerService.java
index 7409ec2..eba5d65 100644
--- a/services/autofill/java/com/android/server/autofill/AutofillManagerService.java
+++ b/services/autofill/java/com/android/server/autofill/AutofillManagerService.java
@@ -108,10 +108,6 @@
     private static final char COMPAT_PACKAGE_URL_IDS_BLOCK_BEGIN = '[';
     private static final char COMPAT_PACKAGE_URL_IDS_BLOCK_END = ']';
 
-    // TODO(b/74445943): temporary work around until P Development Preview 3 is branched
-    private static final List<String> DEFAULT_BUTTONS = Arrays.asList("url_bar",
-            "location_bar_edit_text");
-
     private final Context mContext;
     private final AutoFillUI mUi;
 
@@ -600,7 +596,7 @@
             final List<String> urlBarIds;
             if (urlBlockIndex == -1) {
                 packageName = packageBlock;
-                urlBarIds = DEFAULT_BUTTONS; // TODO(b/74445943): back to null
+                urlBarIds = null;
             } else {
                 if (packageBlock.charAt(packageBlock.length() - 1)
                         != COMPAT_PACKAGE_URL_IDS_BLOCK_END) {
diff --git a/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java b/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java
index 54ea3ba..ef0d7e6 100644
--- a/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java
+++ b/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java
@@ -1189,7 +1189,7 @@
     boolean isFieldClassificationEnabledLocked() {
         return Settings.Secure.getIntForUser(
                 mContext.getContentResolver(),
-                Settings.Secure.AUTOFILL_FEATURE_FIELD_CLASSIFICATION, 0,
+                Settings.Secure.AUTOFILL_FEATURE_FIELD_CLASSIFICATION, 1,
                 mUserId) == 1;
     }
 
diff --git a/services/core/java/com/android/server/am/BatteryExternalStatsWorker.java b/services/core/java/com/android/server/am/BatteryExternalStatsWorker.java
index f5e1a31..2291e44 100644
--- a/services/core/java/com/android/server/am/BatteryExternalStatsWorker.java
+++ b/services/core/java/com/android/server/am/BatteryExternalStatsWorker.java
@@ -283,30 +283,34 @@
                 mUseLatestStates = true;
             }
 
-            synchronized (mWorkerLock) {
-                if (DEBUG) {
-                    Slog.d(TAG, "begin updateExternalStatsSync reason=" + reason);
-                }
-                try {
-                    updateExternalStatsLocked(reason, updateFlags, onBattery,
-                            onBatteryScreenOff, useLatestStates);
-                } finally {
+            try {
+                synchronized (mWorkerLock) {
                     if (DEBUG) {
-                        Slog.d(TAG, "end updateExternalStatsSync");
+                        Slog.d(TAG, "begin updateExternalStatsSync reason=" + reason);
+                    }
+                    try {
+                        updateExternalStatsLocked(reason, updateFlags, onBattery,
+                                onBatteryScreenOff, useLatestStates);
+                    } finally {
+                        if (DEBUG) {
+                            Slog.d(TAG, "end updateExternalStatsSync");
+                        }
                     }
                 }
-            }
 
-            if ((updateFlags & UPDATE_CPU) != 0) {
-                mStats.copyFromAllUidsCpuTimes();
-            }
-
-            // Clean up any UIDs if necessary.
-            synchronized (mStats) {
-                for (int uid : uidsToRemove) {
-                    mStats.removeIsolatedUidLocked(uid);
+                if ((updateFlags & UPDATE_CPU) != 0) {
+                    mStats.copyFromAllUidsCpuTimes();
                 }
-                mStats.clearPendingRemovedUids();
+
+                // Clean up any UIDs if necessary.
+                synchronized (mStats) {
+                    for (int uid : uidsToRemove) {
+                        mStats.removeIsolatedUidLocked(uid);
+                    }
+                    mStats.clearPendingRemovedUids();
+                }
+            } catch (Exception e) {
+                Slog.wtf(TAG, "Error updating external stats: ", e);
             }
         }
     };
@@ -398,7 +402,7 @@
                 if (bluetoothInfo.isValid()) {
                     mStats.updateBluetoothStateLocked(bluetoothInfo);
                 } else {
-                    Slog.e(TAG, "bluetooth info is invalid: " + bluetoothInfo);
+                    Slog.w(TAG, "bluetooth info is invalid: " + bluetoothInfo);
                 }
             }
         }
@@ -410,7 +414,7 @@
             if (wifiInfo.isValid()) {
                 mStats.updateWifiState(extractDeltaLocked(wifiInfo));
             } else {
-                Slog.e(TAG, "wifi info is invalid: " + wifiInfo);
+                Slog.w(TAG, "wifi info is invalid: " + wifiInfo);
             }
         }
 
@@ -418,7 +422,7 @@
             if (modemInfo.isValid()) {
                 mStats.updateMobileRadioState(modemInfo);
             } else {
-                Slog.e(TAG, "modem info is invalid: " + modemInfo);
+                Slog.w(TAG, "modem info is invalid: " + modemInfo);
             }
         }
     }
diff --git a/services/core/java/com/android/server/am/RecentTasks.java b/services/core/java/com/android/server/am/RecentTasks.java
index fc8b624..1335ced 100644
--- a/services/core/java/com/android/server/am/RecentTasks.java
+++ b/services/core/java/com/android/server/am/RecentTasks.java
@@ -508,6 +508,10 @@
                     && tr.userId == userId
                     && tr.realActivitySuspended != suspended) {
                tr.realActivitySuspended = suspended;
+               if (suspended) {
+                   mService.mStackSupervisor.removeTaskByIdLocked(tr.taskId, false,
+                           REMOVE_FROM_RECENTS, "suspended-package");
+               }
                notifyTaskPersisterLocked(tr, false);
             }
         }
diff --git a/services/core/java/com/android/server/audio/AudioService.java b/services/core/java/com/android/server/audio/AudioService.java
index c036549..3a23f18 100644
--- a/services/core/java/com/android/server/audio/AudioService.java
+++ b/services/core/java/com/android/server/audio/AudioService.java
@@ -24,6 +24,9 @@
 import static android.media.AudioManager.STREAM_MUSIC;
 import static android.media.AudioManager.STREAM_SYSTEM;
 import static android.os.Process.FIRST_APPLICATION_UID;
+import static android.provider.Settings.Secure.VOLUME_HUSH_MUTE;
+import static android.provider.Settings.Secure.VOLUME_HUSH_OFF;
+import static android.provider.Settings.Secure.VOLUME_HUSH_VIBRATE;
 
 import android.Manifest;
 import android.annotation.NonNull;
@@ -108,6 +111,7 @@
 import android.os.UserManager;
 import android.os.UserManagerInternal;
 import android.os.UserManagerInternal.UserRestrictionsListener;
+import android.os.VibrationEffect;
 import android.os.Vibrator;
 import android.provider.Settings;
 import android.provider.Settings.System;
@@ -124,6 +128,7 @@
 import android.util.SparseIntArray;
 import android.view.KeyEvent;
 import android.view.accessibility.AccessibilityManager;
+import android.widget.Toast;
 
 import com.android.internal.annotations.GuardedBy;
 import com.android.internal.util.DumpUtils;
@@ -440,6 +445,12 @@
 
     // Is there a vibrator
     private final boolean mHasVibrator;
+    // Used to play vibrations
+    private Vibrator mVibrator;
+    private static final AudioAttributes VIBRATION_ATTRIBUTES = new AudioAttributes.Builder()
+            .setContentType(AudioAttributes.CONTENT_TYPE_SONIFICATION)
+            .setUsage(AudioAttributes.USAGE_ASSISTANCE_SONIFICATION)
+            .build();
 
     // Broadcast receiver for device connections intent broadcasts
     private final BroadcastReceiver mReceiver = new AudioServiceBroadcastReceiver();
@@ -697,8 +708,8 @@
         PowerManager pm = (PowerManager)context.getSystemService(Context.POWER_SERVICE);
         mAudioEventWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "handleAudioEvent");
 
-        Vibrator vibrator = (Vibrator) context.getSystemService(Context.VIBRATOR_SERVICE);
-        mHasVibrator = vibrator == null ? false : vibrator.hasVibrator();
+        mVibrator = (Vibrator) context.getSystemService(Context.VIBRATOR_SERVICE);
+        mHasVibrator = mVibrator == null ? false : mVibrator.hasVibrator();
 
         // Initialize volume
         int maxCallVolume = SystemProperties.getInt("ro.config.vc_call_vol_steps", -1);
@@ -2423,6 +2434,54 @@
         setRingerMode(ringerMode, caller, false /*external*/);
     }
 
+    public void silenceRingerModeInternal(String reason) {
+        VibrationEffect effect = null;
+        int ringerMode = AudioManager.RINGER_MODE_SILENT;
+        int toastText = 0;
+
+        int silenceRingerSetting = Settings.Secure.VOLUME_HUSH_OFF;
+        if (mContext.getResources()
+                .getBoolean(com.android.internal.R.bool.config_volumeHushGestureEnabled)) {
+            silenceRingerSetting = Settings.Secure.getIntForUser(mContentResolver,
+                    Settings.Secure.VOLUME_HUSH_GESTURE, VOLUME_HUSH_OFF,
+                    UserHandle.USER_CURRENT);
+        }
+
+        switch(silenceRingerSetting) {
+            case VOLUME_HUSH_MUTE:
+                effect = VibrationEffect.get(VibrationEffect.EFFECT_DOUBLE_CLICK);
+                ringerMode = AudioManager.RINGER_MODE_SILENT;
+                toastText = com.android.internal.R.string.volume_dialog_ringer_guidance_silent;
+                break;
+            case VOLUME_HUSH_VIBRATE:
+                effect = VibrationEffect.get(VibrationEffect.EFFECT_HEAVY_CLICK);
+                ringerMode = AudioManager.RINGER_MODE_VIBRATE;
+                toastText = com.android.internal.R.string.volume_dialog_ringer_guidance_vibrate;
+                break;
+        }
+        maybeVibrate(effect);
+        setRingerModeInternal(ringerMode, reason);
+        Toast.makeText(mContext, toastText, Toast.LENGTH_SHORT).show();
+    }
+
+    private boolean maybeVibrate(VibrationEffect effect) {
+        if (!mHasVibrator) {
+            return false;
+        }
+        final boolean hapticsDisabled = Settings.System.getIntForUser(mContext.getContentResolver(),
+                Settings.System.HAPTIC_FEEDBACK_ENABLED, 0, UserHandle.USER_CURRENT) == 0;
+        if (hapticsDisabled) {
+            return false;
+        }
+
+        if (effect == null) {
+            return false;
+        }
+        mVibrator.vibrate(
+                Binder.getCallingUid(), mContext.getOpPackageName(), effect, VIBRATION_ATTRIBUTES);
+        return true;
+    }
+
     private void setRingerMode(int ringerMode, String caller, boolean external) {
         if (mUseFixedVolume || mIsSingleVolume) {
             return;
@@ -7246,6 +7305,11 @@
         }
 
         @Override
+        public void silenceRingerModeInternal(String caller) {
+            AudioService.this.silenceRingerModeInternal(caller);
+        }
+
+        @Override
         public void updateRingerModeAffectedStreamsInternal() {
             synchronized (mSettingsLock) {
                 if (updateRingerAndZenModeAffectedStreams()) {
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index 052f239..576d228 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -23,7 +23,6 @@
 import static android.Manifest.permission.READ_EXTERNAL_STORAGE;
 import static android.Manifest.permission.REQUEST_DELETE_PACKAGES;
 import static android.Manifest.permission.WRITE_EXTERNAL_STORAGE;
-import static android.Manifest.permission.WRITE_MEDIA_STORAGE;
 import static android.content.pm.PackageManager.CERT_INPUT_RAW_X509;
 import static android.content.pm.PackageManager.CERT_INPUT_SHA256;
 import static android.content.pm.PackageManager.COMPONENT_ENABLED_STATE_DEFAULT;
@@ -98,7 +97,6 @@
 import static com.android.server.pm.InstructionSets.getDexCodeInstructionSets;
 import static com.android.server.pm.InstructionSets.getPreferredInstructionSet;
 import static com.android.server.pm.InstructionSets.getPrimaryInstructionSet;
-import static com.android.server.pm.PackageManagerServiceCompilerMapping.getCompilerFilterForReason;
 import static com.android.server.pm.PackageManagerServiceCompilerMapping.getDefaultCompilerFilter;
 import static com.android.server.pm.PackageManagerServiceUtils.compareSignatures;
 import static com.android.server.pm.PackageManagerServiceUtils.compressedFileExists;
@@ -214,6 +212,7 @@
 import android.os.Parcel;
 import android.os.ParcelFileDescriptor;
 import android.os.PatternMatcher;
+import android.os.PersistableBundle;
 import android.os.Process;
 import android.os.RemoteCallbackList;
 import android.os.RemoteException;
@@ -238,7 +237,6 @@
 import android.security.KeyStore;
 import android.security.SystemKeyStore;
 import android.service.pm.PackageServiceDumpProto;
-import android.service.textclassifier.TextClassifierService;
 import android.system.ErrnoException;
 import android.system.Os;
 import android.text.TextUtils;
@@ -407,7 +405,7 @@
     static final boolean DEBUG_DOMAIN_VERIFICATION = false;
     private static final boolean DEBUG_BACKUP = false;
     public static final boolean DEBUG_INSTALL = false;
-    public static final boolean DEBUG_REMOVE = false;
+    public static final boolean DEBUG_REMOVE = true;
     private static final boolean DEBUG_BROADCASTS = false;
     private static final boolean DEBUG_SHOW_INFO = false;
     private static final boolean DEBUG_PACKAGE_INFO = false;
@@ -10355,7 +10353,7 @@
 
         if (Build.IS_DEBUGGABLE &&
                 pkg.isPrivileged() &&
-                !SystemProperties.getBoolean("pm.dexopt.priv-apps", true)) {
+                !SystemProperties.getBoolean(PROPERTY_NAME_PM_DEXOPT_PRIV_APPS_OOB, true)) {
             PackageManagerServiceUtils.logPackageHasUncompressedCode(pkg);
         }
 
@@ -13964,29 +13962,45 @@
 
     @Override
     public String[] setPackagesSuspendedAsUser(String[] packageNames, boolean suspended,
+            PersistableBundle appExtras, PersistableBundle launcherExtras, String callingPackage,
             int userId) {
-        mContext.enforceCallingOrSelfPermission(android.Manifest.permission.MANAGE_USERS, null);
+        try {
+            mContext.enforceCallingOrSelfPermission(android.Manifest.permission.SUSPEND_APPS, null);
+        } catch (SecurityException e) {
+            mContext.enforceCallingOrSelfPermission(Manifest.permission.MANAGE_USERS,
+                    "Callers need to have either " + Manifest.permission.SUSPEND_APPS + " or "
+                            + Manifest.permission.MANAGE_USERS);
+        }
         final int callingUid = Binder.getCallingUid();
         mPermissionManager.enforceCrossUserPermission(callingUid, userId,
                 true /* requireFullPermission */, true /* checkShell */,
                 "setPackagesSuspended for user " + userId);
+        if (callingUid != Process.ROOT_UID &&
+                !UserHandle.isSameApp(getPackageUid(callingPackage, 0, userId), callingUid)) {
+            throw new IllegalArgumentException("callingPackage " + callingPackage + " does not"
+                    + " belong to calling app id " + UserHandle.getAppId(callingUid));
+        }
 
         if (ArrayUtils.isEmpty(packageNames)) {
             return packageNames;
         }
 
         // List of package names for whom the suspended state has changed.
-        List<String> changedPackages = new ArrayList<>(packageNames.length);
+        final List<String> changedPackages = new ArrayList<>(packageNames.length);
         // List of package names for whom the suspended state is not set as requested in this
         // method.
-        List<String> unactionedPackages = new ArrayList<>(packageNames.length);
-        long callingId = Binder.clearCallingIdentity();
+        final List<String> unactionedPackages = new ArrayList<>(packageNames.length);
+        final long callingId = Binder.clearCallingIdentity();
         try {
-            for (int i = 0; i < packageNames.length; i++) {
-                String packageName = packageNames[i];
-                boolean changed = false;
-                final int appId;
-                synchronized (mPackages) {
+            synchronized (mPackages) {
+                for (int i = 0; i < packageNames.length; i++) {
+                    final String packageName = packageNames[i];
+                    if (packageName == callingPackage) {
+                        Slog.w(TAG, "Calling package: " + callingPackage + "trying to "
+                                + (suspended ? "" : "un") + "suspend itself. Ignoring");
+                        unactionedPackages.add(packageName);
+                        continue;
+                    }
                     final PackageSetting pkgSetting = mSettings.mPackages.get(packageName);
                     if (pkgSetting == null
                             || filterAppAccessLPr(pkgSetting, callingUid, userId)) {
@@ -13995,42 +14009,75 @@
                         unactionedPackages.add(packageName);
                         continue;
                     }
-                    appId = pkgSetting.appId;
                     if (pkgSetting.getSuspended(userId) != suspended) {
                         if (!canSuspendPackageForUserLocked(packageName, userId)) {
                             unactionedPackages.add(packageName);
                             continue;
                         }
-                        pkgSetting.setSuspended(suspended, userId);
-                        mSettings.writePackageRestrictionsLPr(userId);
-                        changed = true;
+                        pkgSetting.setSuspended(suspended, callingPackage, appExtras,
+                                launcherExtras, userId);
                         changedPackages.add(packageName);
                     }
                 }
-
-                if (changed && suspended) {
-                    killApplication(packageName, UserHandle.getUid(userId, appId),
-                            "suspending package");
-                }
             }
         } finally {
             Binder.restoreCallingIdentity(callingId);
         }
-
+        // TODO (b/75036698): Also send each package a broadcast when suspended state changed
         if (!changedPackages.isEmpty()) {
             sendPackagesSuspendedForUser(changedPackages.toArray(
                     new String[changedPackages.size()]), userId, suspended);
+            synchronized (mPackages) {
+                scheduleWritePackageRestrictionsLocked(userId);
+            }
         }
 
         return unactionedPackages.toArray(new String[unactionedPackages.size()]);
     }
 
     @Override
+    public PersistableBundle getPackageSuspendedAppExtras(String packageName, int userId) {
+        final int callingUid = Binder.getCallingUid();
+        if (getPackageUid(packageName, 0, userId) != callingUid) {
+            mContext.enforceCallingOrSelfPermission(Manifest.permission.SUSPEND_APPS, null);
+        }
+        synchronized (mPackages) {
+            final PackageSetting ps = mSettings.mPackages.get(packageName);
+            if (ps == null || filterAppAccessLPr(ps, callingUid, userId)) {
+                throw new IllegalArgumentException("Unknown target package: " + packageName);
+            }
+            final PackageUserState packageUserState = ps.readUserState(userId);
+            return packageUserState.suspended ? packageUserState.suspendedAppExtras : null;
+        }
+    }
+
+    @Override
+    public void setSuspendedPackageAppExtras(String packageName, PersistableBundle appExtras,
+            int userId) {
+        final int callingUid = Binder.getCallingUid();
+        mContext.enforceCallingOrSelfPermission(Manifest.permission.SUSPEND_APPS, null);
+        synchronized (mPackages) {
+            final PackageSetting ps = mSettings.mPackages.get(packageName);
+            if (ps == null || filterAppAccessLPr(ps, callingUid, userId)) {
+                throw new IllegalArgumentException("Unknown target package: " + packageName);
+            }
+            final PackageUserState packageUserState = ps.readUserState(userId);
+            if (packageUserState.suspended) {
+                // TODO (b/75036698): Also send this package a broadcast with the new app extras
+                packageUserState.suspendedAppExtras = appExtras;
+            }
+        }
+    }
+
+    @Override
     public boolean isPackageSuspendedForUser(String packageName, int userId) {
         final int callingUid = Binder.getCallingUid();
         mPermissionManager.enforceCrossUserPermission(callingUid, userId,
                 true /* requireFullPermission */, false /* checkShell */,
                 "isPackageSuspendedForUser for user " + userId);
+        if (getPackageUid(packageName, 0, userId) != callingUid) {
+            mContext.enforceCallingOrSelfPermission(Manifest.permission.SUSPEND_APPS, null);
+        }
         synchronized (mPackages) {
             final PackageSetting ps = mSettings.mPackages.get(packageName);
             if (ps == null || filterAppAccessLPr(ps, callingUid, userId)) {
@@ -14040,6 +14087,21 @@
         }
     }
 
+    void onSuspendingPackageRemoved(String packageName, int userId) {
+        final int[] userIds = (userId == UserHandle.USER_ALL) ? sUserManager.getUserIds()
+                : new int[] {userId};
+        synchronized (mPackages) {
+            for (PackageSetting ps : mSettings.mPackages.values()) {
+                for (int user : userIds) {
+                    final PackageUserState pus = ps.readUserState(user);
+                    if (pus.suspended && packageName.equals(pus.suspendingPackage)) {
+                        ps.setSuspended(false, null, null, null, user);
+                    }
+                }
+            }
+        }
+    }
+
     @GuardedBy("mPackages")
     private boolean canSuspendPackageForUserLocked(String packageName, int userId) {
         if (isPackageDeviceAdmin(packageName, userId)) {
@@ -14096,6 +14158,11 @@
             return false;
         }
 
+        if (PLATFORM_PACKAGE_NAME.equals(packageName)) {
+            Slog.w(TAG, "Cannot suspend package: " + packageName);
+            return false;
+        }
+
         return true;
     }
 
@@ -18612,6 +18679,7 @@
                 }
                 final int removedUserId = (user != null) ? user.getIdentifier()
                         : UserHandle.USER_ALL;
+
                 if (!clearPackageStateForUserLIF(ps, removedUserId, outInfo)) {
                     return false;
                 }
@@ -18620,6 +18688,11 @@
                 return true;
             }
         }
+        if (ps.getPermissionsState().hasPermission(
+                Manifest.permission.SUSPEND_APPS, user.getIdentifier())) {
+            onSuspendingPackageRemoved(packageName, user.getIdentifier());
+        }
+
 
         if (((!isSystemApp(ps) || (flags&PackageManager.DELETE_SYSTEM_APP) != 0) && user != null
                 && user.getIdentifier() != UserHandle.USER_ALL)) {
@@ -18758,6 +18831,9 @@
                     true /*notLaunched*/,
                     false /*hidden*/,
                     false /*suspended*/,
+                    null, /*suspendingPackage*/
+                    null, /*suspendedAppExtras*/
+                    null, /*suspendedLauncherExtras*/
                     false /*instantApp*/,
                     false /*virtualPreload*/,
                     null /*lastDisableAppCaller*/,
diff --git a/services/core/java/com/android/server/pm/PackageManagerShellCommand.java b/services/core/java/com/android/server/pm/PackageManagerShellCommand.java
index d2ef67b..28e32a5 100644
--- a/services/core/java/com/android/server/pm/PackageManagerShellCommand.java
+++ b/services/core/java/com/android/server/pm/PackageManagerShellCommand.java
@@ -57,12 +57,14 @@
 import android.content.res.AssetManager;
 import android.content.res.Resources;
 import android.net.Uri;
+import android.os.BaseBundle;
 import android.os.Binder;
 import android.os.Build;
 import android.os.Bundle;
 import android.os.IBinder;
 import android.os.IUserManager;
 import android.os.ParcelFileDescriptor;
+import android.os.PersistableBundle;
 import android.os.Process;
 import android.os.RemoteException;
 import android.os.ServiceManager;
@@ -1503,27 +1505,55 @@
     private int runSuspend(boolean suspendedState) {
         final PrintWriter pw = getOutPrintWriter();
         int userId = UserHandle.USER_SYSTEM;
+        final PersistableBundle appExtras = new PersistableBundle();
+        final PersistableBundle launcherExtras = new PersistableBundle();
         String opt;
         while ((opt = getNextOption()) != null) {
             switch (opt) {
                 case "--user":
                     userId = UserHandle.parseUserArg(getNextArgRequired());
                     break;
+                case "--ael":
+                case "--aes":
+                case "--aed":
+                case "--lel":
+                case "--les":
+                case "--led":
+                    final String key = getNextArgRequired();
+                    final String val = getNextArgRequired();
+                    if (!suspendedState) {
+                        break;
+                    }
+                    final PersistableBundle bundleToInsert =
+                            opt.startsWith("--a") ? appExtras : launcherExtras;
+                    switch (opt.charAt(4)) {
+                        case 'l':
+                            bundleToInsert.putLong(key, Long.valueOf(val));
+                            break;
+                        case 'd':
+                            bundleToInsert.putDouble(key, Double.valueOf(val));
+                            break;
+                        case 's':
+                            bundleToInsert.putString(key, val);
+                            break;
+                    }
+                    break;
                 default:
                     pw.println("Error: Unknown option: " + opt);
                     return 1;
             }
         }
 
-        String packageName = getNextArg();
+        final String packageName = getNextArg();
         if (packageName == null) {
             pw.println("Error: package name not specified");
             return 1;
         }
-
+        final String callingPackage =
+                (Binder.getCallingUid() == Process.ROOT_UID) ? "root" : "com.android.shell";
         try {
             mInterface.setPackagesSuspendedAsUser(new String[]{packageName}, suspendedState,
-                    userId);
+                    appExtras, launcherExtras, callingPackage, userId);
             pw.println("Package " + packageName + " new suspended state: "
                     + mInterface.isPackageSuspendedForUser(packageName, userId));
             return 0;
diff --git a/services/core/java/com/android/server/pm/PackageSettingBase.java b/services/core/java/com/android/server/pm/PackageSettingBase.java
index a0ed126..008a81c 100644
--- a/services/core/java/com/android/server/pm/PackageSettingBase.java
+++ b/services/core/java/com/android/server/pm/PackageSettingBase.java
@@ -20,12 +20,16 @@
 import static android.content.pm.PackageManager.COMPONENT_ENABLED_STATE_DISABLED;
 import static android.content.pm.PackageManager.COMPONENT_ENABLED_STATE_ENABLED;
 
+import static com.android.server.pm.PackageManagerService.PLATFORM_PACKAGE_NAME;
+
 import android.content.pm.ApplicationInfo;
 import android.content.pm.IntentFilterVerificationInfo;
 import android.content.pm.PackageManager;
 import android.content.pm.PackageParser;
 import android.content.pm.PackageUserState;
 import android.content.pm.Signature;
+import android.os.BaseBundle;
+import android.os.PersistableBundle;
 import android.service.pm.PackageProto;
 import android.util.ArraySet;
 import android.util.SparseArray;
@@ -394,8 +398,13 @@
         return readUserState(userId).suspended;
     }
 
-    void setSuspended(boolean suspended, int userId) {
-        modifyUserState(userId).suspended = suspended;
+    void setSuspended(boolean suspended, String suspendingPackage, PersistableBundle appExtras,
+            PersistableBundle launcherExtras, int userId) {
+        final PackageUserState existingUserState = modifyUserState(userId);
+        existingUserState.suspended = suspended;
+        existingUserState.suspendingPackage = suspended ? suspendingPackage : null;
+        existingUserState.suspendedAppExtras = suspended ? appExtras : null;
+        existingUserState.suspendedLauncherExtras = suspended ? launcherExtras : null;
     }
 
     public boolean getInstantApp(int userId) {
@@ -415,7 +424,9 @@
     }
 
     void setUserState(int userId, long ceDataInode, int enabled, boolean installed, boolean stopped,
-            boolean notLaunched, boolean hidden, boolean suspended, boolean instantApp,
+            boolean notLaunched, boolean hidden, boolean suspended, String suspendingPackage,
+            PersistableBundle suspendedAppExtras, PersistableBundle suspendedLauncherExtras,
+            boolean instantApp,
             boolean virtualPreload, String lastDisableAppCaller,
             ArraySet<String> enabledComponents, ArraySet<String> disabledComponents,
             int domainVerifState, int linkGeneration, int installReason,
@@ -428,6 +439,9 @@
         state.notLaunched = notLaunched;
         state.hidden = hidden;
         state.suspended = suspended;
+        state.suspendingPackage = suspendingPackage;
+        state.suspendedAppExtras = suspendedAppExtras;
+        state.suspendedLauncherExtras = suspendedLauncherExtras;
         state.lastDisableAppCaller = lastDisableAppCaller;
         state.enabledComponents = enabledComponents;
         state.disabledComponents = disabledComponents;
@@ -594,6 +608,9 @@
             proto.write(PackageProto.UserInfoProto.INSTALL_TYPE, installType);
             proto.write(PackageProto.UserInfoProto.IS_HIDDEN, state.hidden);
             proto.write(PackageProto.UserInfoProto.IS_SUSPENDED, state.suspended);
+            if (state.suspended) {
+                proto.write(PackageProto.UserInfoProto.SUSPENDING_PACKAGE, state.suspendingPackage);
+            }
             proto.write(PackageProto.UserInfoProto.IS_STOPPED, state.stopped);
             proto.write(PackageProto.UserInfoProto.IS_LAUNCHED, !state.notLaunched);
             proto.write(PackageProto.UserInfoProto.ENABLED_STATE, state.enabled);
diff --git a/services/core/java/com/android/server/pm/Settings.java b/services/core/java/com/android/server/pm/Settings.java
index a38cbda..d0e8544 100644
--- a/services/core/java/com/android/server/pm/Settings.java
+++ b/services/core/java/com/android/server/pm/Settings.java
@@ -31,6 +31,7 @@
 import static android.os.Process.SYSTEM_UID;
 
 import static com.android.server.pm.PackageManagerService.DEBUG_DOMAIN_VERIFICATION;
+import static com.android.server.pm.PackageManagerService.PLATFORM_PACKAGE_NAME;
 
 import android.annotation.NonNull;
 import android.annotation.Nullable;
@@ -58,6 +59,7 @@
 import android.os.Handler;
 import android.os.Message;
 import android.os.PatternMatcher;
+import android.os.PersistableBundle;
 import android.os.Process;
 import android.os.SystemClock;
 import android.os.UserHandle;
@@ -199,6 +201,8 @@
     private static final String TAG_DEFAULT_BROWSER = "default-browser";
     private static final String TAG_DEFAULT_DIALER = "default-dialer";
     private static final String TAG_VERSION = "version";
+    private static final String TAG_SUSPENDED_APP_EXTRAS = "suspended-app-extras";
+    private static final String TAG_SUSPENDED_LAUNCHER_EXTRAS = "suspended-launcher-extras";
 
     public static final String ATTR_NAME = "name";
     public static final String ATTR_PACKAGE = "package";
@@ -217,6 +221,7 @@
     // New name for the above attribute.
     private static final String ATTR_HIDDEN = "hidden";
     private static final String ATTR_SUSPENDED = "suspended";
+    private static final String ATTR_SUSPENDING_PACKAGE = "suspending-package";
     // Legacy, uninstall blocks are stored separately.
     @Deprecated
     private static final String ATTR_BLOCK_UNINSTALL = "blockUninstall";
@@ -728,6 +733,9 @@
                                 true /*notLaunched*/,
                                 false /*hidden*/,
                                 false /*suspended*/,
+                                null, /*suspendingPackage*/
+                                null, /*suspendedAppExtras*/
+                                null, /*suspendedLauncherExtras*/
                                 instantApp,
                                 virtualPreload,
                                 null /*lastDisableAppCaller*/,
@@ -1619,6 +1627,9 @@
                                 false /*notLaunched*/,
                                 false /*hidden*/,
                                 false /*suspended*/,
+                                null, /*suspendingPackage*/
+                                null, /*suspendedAppExtras*/
+                                null, /*suspendedLauncherExtras*/
                                 false /*instantApp*/,
                                 false /*virtualPreload*/,
                                 null /*lastDisableAppCaller*/,
@@ -1691,6 +1702,12 @@
 
                     final boolean suspended = XmlUtils.readBooleanAttribute(parser, ATTR_SUSPENDED,
                             false);
+                    String suspendingPackage = parser.getAttributeValue(null,
+                            ATTR_SUSPENDING_PACKAGE);
+                    if (suspended && suspendingPackage == null) {
+                        suspendingPackage = PLATFORM_PACKAGE_NAME;
+                    }
+
                     final boolean blockUninstall = XmlUtils.readBooleanAttribute(parser,
                             ATTR_BLOCK_UNINSTALL, false);
                     final boolean instantApp = XmlUtils.readBooleanAttribute(parser,
@@ -1716,6 +1733,8 @@
 
                     ArraySet<String> enabledComponents = null;
                     ArraySet<String> disabledComponents = null;
+                    PersistableBundle suspendedAppExtras = null;
+                    PersistableBundle suspendedLauncherExtras = null;
 
                     int packageDepth = parser.getDepth();
                     while ((type=parser.next()) != XmlPullParser.END_DOCUMENT
@@ -1725,11 +1744,22 @@
                                 || type == XmlPullParser.TEXT) {
                             continue;
                         }
-                        tagName = parser.getName();
-                        if (tagName.equals(TAG_ENABLED_COMPONENTS)) {
-                            enabledComponents = readComponentsLPr(parser);
-                        } else if (tagName.equals(TAG_DISABLED_COMPONENTS)) {
-                            disabledComponents = readComponentsLPr(parser);
+                        switch (parser.getName()) {
+                            case TAG_ENABLED_COMPONENTS:
+                                enabledComponents = readComponentsLPr(parser);
+                                break;
+                            case TAG_DISABLED_COMPONENTS:
+                                disabledComponents = readComponentsLPr(parser);
+                                break;
+                            case TAG_SUSPENDED_APP_EXTRAS:
+                                suspendedAppExtras = PersistableBundle.restoreFromXml(parser);
+                                break;
+                            case TAG_SUSPENDED_LAUNCHER_EXTRAS:
+                                suspendedLauncherExtras = PersistableBundle.restoreFromXml(parser);
+                                break;
+                            default:
+                                Slog.wtf(TAG, "Unknown tag " + parser.getName() + " under tag "
+                                        + TAG_PACKAGE);
                         }
                     }
 
@@ -1737,7 +1767,8 @@
                         setBlockUninstallLPw(userId, name, true);
                     }
                     ps.setUserState(userId, ceDataInode, enabled, installed, stopped, notLaunched,
-                            hidden, suspended, instantApp, virtualPreload, enabledCaller,
+                            hidden, suspended, suspendingPackage, suspendedAppExtras,
+                            suspendedLauncherExtras, instantApp, virtualPreload, enabledCaller,
                             enabledComponents, disabledComponents, verifState, linkGeneration,
                             installReason, harmfulAppWarning);
                 } else if (tagName.equals("preferred-activities")) {
@@ -2046,6 +2077,27 @@
                 }
                 if (ustate.suspended) {
                     serializer.attribute(null, ATTR_SUSPENDED, "true");
+                    serializer.attribute(null, ATTR_SUSPENDING_PACKAGE, ustate.suspendingPackage);
+                    if (ustate.suspendedAppExtras != null) {
+                        serializer.startTag(null, TAG_SUSPENDED_APP_EXTRAS);
+                        try {
+                            ustate.suspendedAppExtras.saveToXml(serializer);
+                        } catch (XmlPullParserException xmle) {
+                            Slog.wtf(TAG, "Exception while trying to write suspendedAppExtras for "
+                                    + pkg + ". Will be lost on reboot", xmle);
+                        }
+                        serializer.endTag(null, TAG_SUSPENDED_APP_EXTRAS);
+                    }
+                    if (ustate.suspendedLauncherExtras != null) {
+                        serializer.startTag(null, TAG_SUSPENDED_LAUNCHER_EXTRAS);
+                        try {
+                            ustate.suspendedLauncherExtras.saveToXml(serializer);
+                        } catch (XmlPullParserException xmle) {
+                            Slog.wtf(TAG, "Exception while trying to write suspendedLauncherExtras"
+                                    + " for " + pkg + ". Will be lost on reboot", xmle);
+                        }
+                        serializer.endTag(null, TAG_SUSPENDED_LAUNCHER_EXTRAS);
+                    }
                 }
                 if (ustate.instantApp) {
                     serializer.attribute(null, ATTR_INSTANT_APP, "true");
@@ -4697,6 +4749,10 @@
             pw.print(ps.getHidden(user.id));
             pw.print(" suspended=");
             pw.print(ps.getSuspended(user.id));
+            if (ps.getSuspended(user.id)) {
+                pw.print(" suspendingPackage=");
+                pw.print(ps.readUserState(user.id).suspendingPackage);
+            }
             pw.print(" stopped=");
             pw.print(ps.getStopped(user.id));
             pw.print(" notLaunched=");
diff --git a/services/core/java/com/android/server/policy/PhoneWindowManager.java b/services/core/java/com/android/server/policy/PhoneWindowManager.java
index 6b70f5c..4c9b585 100644
--- a/services/core/java/com/android/server/policy/PhoneWindowManager.java
+++ b/services/core/java/com/android/server/policy/PhoneWindowManager.java
@@ -39,6 +39,7 @@
 import static android.content.res.Configuration.UI_MODE_TYPE_MASK;
 import static android.os.Build.VERSION_CODES.M;
 import static android.os.Build.VERSION_CODES.O;
+import static android.provider.Settings.Secure.VOLUME_HUSH_OFF;
 import static android.view.Display.DEFAULT_DISPLAY;
 import static android.view.Display.STATE_OFF;
 import static android.view.WindowManager.DOCKED_LEFT;
@@ -187,6 +188,7 @@
 import android.hardware.power.V1_0.PowerHint;
 import android.media.AudioAttributes;
 import android.media.AudioManager;
+import android.media.AudioManagerInternal;
 import android.media.AudioSystem;
 import android.media.IAudioService;
 import android.media.session.MediaSessionLegacyHelper;
@@ -455,6 +457,7 @@
     PowerManagerInternal mPowerManagerInternal;
     IStatusBarService mStatusBarService;
     StatusBarManagerInternal mStatusBarManagerInternal;
+    AudioManagerInternal mAudioManagerInternal;
     boolean mPreloadedRecentApps;
     final Object mServiceAquireLock = new Object();
     Vibrator mVibrator; // Vibrator for giving feedback of orientation changes
@@ -772,6 +775,9 @@
     private boolean mScreenshotChordPowerKeyTriggered;
     private long mScreenshotChordPowerKeyTime;
 
+    // Ringer toggle should reuse timing and triggering from screenshot power and a11y vol up
+    private int mRingerToggleChord = VOLUME_HUSH_OFF;
+
     private static final long BUGREPORT_TV_GESTURE_TIMEOUT_MILLIS = 1000;
 
     private boolean mBugreportTvKey1Pressed;
@@ -836,6 +842,7 @@
     private static final int MSG_LAUNCH_ASSIST_LONG_PRESS = 27;
     private static final int MSG_POWER_VERY_LONG_PRESS = 28;
     private static final int MSG_NOTIFY_USER_ACTIVITY = 29;
+    private static final int MSG_RINGER_TOGGLE_CHORD = 30;
 
     private static final int MSG_REQUEST_TRANSIENT_BARS_ARG_STATUS = 0;
     private static final int MSG_REQUEST_TRANSIENT_BARS_ARG_NAVIGATION = 1;
@@ -943,6 +950,8 @@
                     intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
                     mContext.sendBroadcastAsUser(intent, UserHandle.ALL,
                             android.Manifest.permission.USER_ACTIVITY);
+                case MSG_RINGER_TOGGLE_CHORD:
+                    handleRingerChordGesture();
                     break;
             }
         }
@@ -996,6 +1005,9 @@
             resolver.registerContentObserver(Settings.Secure.getUriFor(
                     Settings.Secure.SHOW_ROTATION_SUGGESTIONS), false, this,
                     UserHandle.USER_ALL);
+            resolver.registerContentObserver(Settings.Secure.getUriFor(
+                    Settings.Secure.VOLUME_HUSH_GESTURE), false, this,
+                    UserHandle.USER_ALL);
             resolver.registerContentObserver(Settings.Global.getUriFor(
                     Settings.Global.POLICY_CONTROL), false, this,
                     UserHandle.USER_ALL);
@@ -1117,6 +1129,14 @@
     @VisibleForTesting
     SystemGesturesPointerEventListener mSystemGestures;
 
+    private void handleRingerChordGesture() {
+        if (mRingerToggleChord == VOLUME_HUSH_OFF) {
+            return;
+        }
+        getAudioManagerInternal();
+        mAudioManagerInternal.silenceRingerModeInternal("volume_hush");
+    }
+
     IStatusBarService getStatusBarService() {
         synchronized (mServiceAquireLock) {
             if (mStatusBarService == null) {
@@ -1137,6 +1157,15 @@
         }
     }
 
+    AudioManagerInternal getAudioManagerInternal() {
+        synchronized (mServiceAquireLock) {
+            if (mAudioManagerInternal == null) {
+                mAudioManagerInternal = LocalServices.getService(AudioManagerInternal.class);
+            }
+            return mAudioManagerInternal;
+        }
+    }
+
     /*
      * We always let the sensor be switched on by default except when
      * the user has explicitly disabled sensor based rotation or when the
@@ -1306,6 +1335,7 @@
             mScreenshotChordPowerKeyTriggered = true;
             mScreenshotChordPowerKeyTime = event.getDownTime();
             interceptScreenshotChord();
+            interceptRingerToggleChord();
         }
 
         // Stop ringing or end call if configured to do so when power is pressed.
@@ -1701,6 +1731,22 @@
         }
     }
 
+    private void interceptRingerToggleChord() {
+        if (mRingerToggleChord != Settings.Secure.VOLUME_HUSH_OFF
+                && mScreenshotChordPowerKeyTriggered && mA11yShortcutChordVolumeUpKeyTriggered) {
+            final long now = SystemClock.uptimeMillis();
+            if (now <= mA11yShortcutChordVolumeUpKeyTime + SCREENSHOT_CHORD_DEBOUNCE_DELAY_MILLIS
+                    && now <= mScreenshotChordPowerKeyTime
+                    + SCREENSHOT_CHORD_DEBOUNCE_DELAY_MILLIS) {
+                mA11yShortcutChordVolumeUpKeyConsumed = true;
+                cancelPendingPowerKeyAction();
+
+                mHandler.sendMessageDelayed(mHandler.obtainMessage(MSG_RINGER_TOGGLE_CHORD),
+                        getRingerToggleChordDelay());
+            }
+        }
+    }
+
     private long getAccessibilityShortcutTimeout() {
         ViewConfiguration config = ViewConfiguration.get(mContext);
         return Settings.Secure.getIntForUser(mContext.getContentResolver(),
@@ -1718,6 +1764,11 @@
         return ViewConfiguration.get(mContext).getDeviceGlobalActionKeyTimeout();
     }
 
+    private long getRingerToggleChordDelay() {
+        // Always timeout like a tap
+        return ViewConfiguration.getTapTimeout();
+    }
+
     private void cancelPendingScreenshotChordAction() {
         mHandler.removeCallbacks(mScreenshotRunnable);
     }
@@ -1726,6 +1777,10 @@
         mHandler.removeMessages(MSG_ACCESSIBILITY_SHORTCUT);
     }
 
+    private void cancelPendingRingerToggleChordAction() {
+        mHandler.removeMessages(MSG_RINGER_TOGGLE_CHORD);
+    }
+
     private final Runnable mEndCallLongPress = new Runnable() {
         @Override
         public void run() {
@@ -2382,7 +2437,13 @@
             mSystemNavigationKeysEnabled = Settings.Secure.getIntForUser(resolver,
                     Settings.Secure.SYSTEM_NAVIGATION_KEYS_ENABLED,
                     0, UserHandle.USER_CURRENT) == 1;
-
+            mRingerToggleChord = Settings.Secure.getIntForUser(resolver,
+                    Settings.Secure.VOLUME_HUSH_GESTURE, VOLUME_HUSH_OFF,
+                    UserHandle.USER_CURRENT);
+            if (!mContext.getResources()
+                    .getBoolean(com.android.internal.R.bool.config_volumeHushGestureEnabled)) {
+                mRingerToggleChord = Settings.Secure.VOLUME_HUSH_OFF;
+            }
             // Configure rotation suggestions.
             int showRotationSuggestions = Settings.Secure.getIntForUser(resolver,
                     Settings.Secure.SHOW_ROTATION_SUGGESTIONS,
@@ -3531,6 +3592,25 @@
             }
         }
 
+        // If a ringer toggle chord could be on the way but we're not sure, then tell the dispatcher
+        // to wait a little while and try again later before dispatching.
+        if (mRingerToggleChord != VOLUME_HUSH_OFF && (flags & KeyEvent.FLAG_FALLBACK) == 0) {
+            if (mA11yShortcutChordVolumeUpKeyTriggered && !mScreenshotChordPowerKeyTriggered) {
+                final long now = SystemClock.uptimeMillis();
+                final long timeoutTime = mA11yShortcutChordVolumeUpKeyTime
+                        + SCREENSHOT_CHORD_DEBOUNCE_DELAY_MILLIS;
+                if (now < timeoutTime) {
+                    return timeoutTime - now;
+                }
+            }
+            if (keyCode == KeyEvent.KEYCODE_VOLUME_UP && mA11yShortcutChordVolumeUpKeyConsumed) {
+                if (!down) {
+                    mA11yShortcutChordVolumeUpKeyConsumed = false;
+                }
+                return -1;
+            }
+        }
+
         // Cancel any pending meta actions if we see any other keys being pressed between the down
         // of the meta key and its corresponding up.
         if (mPendingMetaAction && !KeyEvent.isMetaKey(keyCode)) {
@@ -5997,6 +6077,9 @@
             case KeyEvent.KEYCODE_VOLUME_MUTE: {
                 if (keyCode == KeyEvent.KEYCODE_VOLUME_DOWN) {
                     if (down) {
+                        // Any activity on the vol down button stops the ringer toggle shortcut
+                        cancelPendingRingerToggleChordAction();
+
                         if (interactive && !mScreenshotChordVolumeDownKeyTriggered
                                 && (event.getFlags() & KeyEvent.FLAG_FALLBACK) == 0) {
                             mScreenshotChordVolumeDownKeyTriggered = true;
@@ -6020,12 +6103,16 @@
                             mA11yShortcutChordVolumeUpKeyConsumed = false;
                             cancelPendingPowerKeyAction();
                             cancelPendingScreenshotChordAction();
+                            cancelPendingRingerToggleChordAction();
+
                             interceptAccessibilityShortcutChord();
+                            interceptRingerToggleChord();
                         }
                     } else {
                         mA11yShortcutChordVolumeUpKeyTriggered = false;
                         cancelPendingScreenshotChordAction();
                         cancelPendingAccessibilityShortcutAction();
+                        cancelPendingRingerToggleChordAction();
                     }
                 }
                 if (down) {
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
index 884f348..2e07703 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
@@ -9252,7 +9252,7 @@
             long id = mInjector.binderClearCallingIdentity();
             try {
                 return mIPackageManager.setPackagesSuspendedAsUser(
-                        packageNames, suspended, callingUserId);
+                        packageNames, suspended, null, null, "android", callingUserId);
             } catch (RemoteException re) {
                 // Shouldn't happen.
                 Slog.e(LOG_TAG, "Failed talking to the package manager", re);
diff --git a/services/tests/servicestests/Android.mk b/services/tests/servicestests/Android.mk
index 0ca0a1a..cdb339a 100644
--- a/services/tests/servicestests/Android.mk
+++ b/services/tests/servicestests/Android.mk
@@ -36,6 +36,7 @@
 LOCAL_SRC_FILES += aidl/com/android/servicestests/aidl/INetworkStateObserver.aidl \
     aidl/com/android/servicestests/aidl/ICmdReceiverService.aidl
 LOCAL_SRC_FILES += $(call all-java-files-under, test-apps/JobTestApp/src)
+LOCAL_SRC_FILES += $(call all-java-files-under, test-apps/SuspendTestApp/src)
 
 LOCAL_JAVA_LIBRARIES := \
     android.hidl.manager-V1.0-java \
diff --git a/services/tests/servicestests/AndroidManifest.xml b/services/tests/servicestests/AndroidManifest.xml
index 372b8cc..ce98d65 100644
--- a/services/tests/servicestests/AndroidManifest.xml
+++ b/services/tests/servicestests/AndroidManifest.xml
@@ -62,6 +62,7 @@
     <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
     <uses-permission android:name="android.permission.WATCH_APPOPS" />
     <uses-permission android:name="android.permission.FOREGROUND_SERVICE"/>
+    <uses-permission android:name="android.permission.SUSPEND_APPS"/>
 
     <!-- Uses API introduced in O (26) -->
     <uses-sdk android:minSdkVersion="1"
diff --git a/services/tests/servicestests/AndroidTest.xml b/services/tests/servicestests/AndroidTest.xml
index 23e5072..082827c 100644
--- a/services/tests/servicestests/AndroidTest.xml
+++ b/services/tests/servicestests/AndroidTest.xml
@@ -15,9 +15,11 @@
 -->
 <configuration description="Runs Frameworks Services Tests.">
     <target_preparer class="com.android.tradefed.targetprep.TestAppInstallSetup">
+        <option name="cleanup-apks" value="true" />
         <option name="test-file-name" value="FrameworksServicesTests.apk" />
         <option name="test-file-name" value="JobTestApp.apk" />
         <option name="test-file-name" value="ConnTestApp.apk" />
+        <option name="test-file-name" value="SuspendTestApp.apk" />
     </target_preparer>
 
     <option name="test-suite-tag" value="apct" />
diff --git a/services/tests/servicestests/src/com/android/server/autofill/AutofillManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/autofill/AutofillManagerServiceTest.java
index c348e70..d5a28f6 100644
--- a/services/tests/servicestests/src/com/android/server/autofill/AutofillManagerServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/autofill/AutofillManagerServiceTest.java
@@ -27,8 +27,6 @@
 
 @RunWith(JUnit4.class)
 public class AutofillManagerServiceTest {
-    // TODO(b/74445943): temporary work around until P Development Preview 3 is branched
-    private static final boolean ADDS_DEFAULT_BUTTON = true;
 
     @Test
     public void testGetWhitelistedCompatModePackages_null() {
@@ -42,16 +40,8 @@
 
     @Test
     public void testGetWhitelistedCompatModePackages_onePackageNoUrls() {
-        if (ADDS_DEFAULT_BUTTON) {
-            final Map<String, String[]> result =
-                    getWhitelistedCompatModePackages("one_is_the_loniest_package");
-            assertThat(result).hasSize(1);
-            assertThat(result.get("one_is_the_loniest_package")).asList()
-                    .containsExactly("url_bar", "location_bar_edit_text");
-        } else {
-            assertThat(getWhitelistedCompatModePackages("one_is_the_loniest_package"))
-                    .containsExactly("one_is_the_loniest_package", null);
-        }
+        assertThat(getWhitelistedCompatModePackages("one_is_the_loniest_package"))
+                .containsExactly("one_is_the_loniest_package", null);
     }
 
     @Test
@@ -80,12 +70,7 @@
     public void testGetWhitelistedCompatModePackages_multiplePackagesOneInvalid() {
         final Map<String, String[]> result = getWhitelistedCompatModePackages("one:two[");
         assertThat(result).hasSize(1);
-        if (ADDS_DEFAULT_BUTTON) {
-            assertThat(result.get("one")).asList()
-                    .containsExactly("url_bar", "location_bar_edit_text");
-        } else {
-            assertThat(result.get("one")).isNull();
-        }
+        assertThat(result.get("one")).isNull();
     }
 
     @Test
@@ -94,12 +79,7 @@
                 getWhitelistedCompatModePackages("p1[p1u1]:p2:p3[p3u1,p3u2]");
         assertThat(result).hasSize(3);
         assertThat(result.get("p1")).asList().containsExactly("p1u1");
-        if (ADDS_DEFAULT_BUTTON) {
-            assertThat(result.get("p2")).asList()
-                    .containsExactly("url_bar", "location_bar_edit_text");
-        } else {
-            assertThat(result.get("p2")).isNull();
-        }
+        assertThat(result.get("p2")).isNull();
         assertThat(result.get("p3")).asList().containsExactly("p3u1", "p3u2");
     }
 
diff --git a/services/tests/servicestests/src/com/android/server/backup/testutils/PackageManagerStub.java b/services/tests/servicestests/src/com/android/server/backup/testutils/PackageManagerStub.java
index 10a21fd..2d5afad 100644
--- a/services/tests/servicestests/src/com/android/server/backup/testutils/PackageManagerStub.java
+++ b/services/tests/servicestests/src/com/android/server/backup/testutils/PackageManagerStub.java
@@ -32,6 +32,7 @@
 import android.graphics.Rect;
 import android.graphics.drawable.Drawable;
 import android.os.Handler;
+import android.os.PersistableBundle;
 import android.os.UserHandle;
 import android.os.storage.VolumeInfo;
 
@@ -874,8 +875,8 @@
     }
 
     @Override
-    public String[] setPackagesSuspendedAsUser(String[] packageNames, boolean suspended,
-            int userId) {
+    public String[] setPackagesSuspended(String[] packageNames, boolean suspended,
+            PersistableBundle appExtras, PersistableBundle launcherExtras, String dialogMessage) {
         return new String[0];
     }
 
diff --git a/services/tests/servicestests/src/com/android/server/pm/PackageManagerSettingsTests.java b/services/tests/servicestests/src/com/android/server/pm/PackageManagerSettingsTests.java
index 53d97e7..ebb4248 100644
--- a/services/tests/servicestests/src/com/android/server/pm/PackageManagerSettingsTests.java
+++ b/services/tests/servicestests/src/com/android/server/pm/PackageManagerSettingsTests.java
@@ -21,13 +21,12 @@
 import static android.content.pm.PackageManager.COMPONENT_ENABLED_STATE_DISABLED_USER;
 import static android.content.pm.PackageManager.COMPONENT_ENABLED_STATE_ENABLED;
 
+import static org.hamcrest.CoreMatchers.equalTo;
 import static org.hamcrest.CoreMatchers.is;
 import static org.hamcrest.CoreMatchers.not;
 import static org.hamcrest.CoreMatchers.notNullValue;
 import static org.hamcrest.CoreMatchers.nullValue;
-import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertNotSame;
-import static org.junit.Assert.assertNull;
 import static org.junit.Assert.assertSame;
 import static org.junit.Assert.assertThat;
 import static org.junit.Assert.assertTrue;
@@ -39,12 +38,13 @@
 import android.content.pm.PackageParser;
 import android.content.pm.PackageUserState;
 import android.content.pm.UserInfo;
+import android.os.BaseBundle;
+import android.os.PersistableBundle;
 import android.os.UserHandle;
 import android.os.UserManagerInternal;
-import android.security.keystore.ArrayUtils;
 import android.support.test.InstrumentationRegistry;
+import android.support.test.filters.SmallTest;
 import android.support.test.runner.AndroidJUnit4;
-import android.test.suitebuilder.annotation.SmallTest;
 import android.util.ArrayMap;
 import android.util.ArraySet;
 import android.util.Log;
@@ -54,8 +54,8 @@
 import com.android.server.LocalServices;
 import com.android.server.pm.permission.PermissionManagerInternal;
 import com.android.server.pm.permission.PermissionManagerService;
-import com.android.server.pm.permission.DefaultPermissionGrantPolicy.DefaultPermissionGrantedCallback;
 
+import org.junit.After;
 import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
@@ -71,9 +71,9 @@
 @RunWith(AndroidJUnit4.class)
 @SmallTest
 public class PackageManagerSettingsTests {
-    private static final String PACKAGE_NAME_2 = "com.google.app2";
+    private static final String PACKAGE_NAME_2 = "com.android.app2";
     private static final String PACKAGE_NAME_3 = "com.android.app3";
-    private static final String PACKAGE_NAME_1 = "com.google.app1";
+    private static final String PACKAGE_NAME_1 = "com.android.app1";
     public static final String TAG = "PackageManagerSettingsTests";
     protected final String PREFIX = "android.content.pm";
 
@@ -156,6 +156,92 @@
         assertThat(ps.getEnabled(1), is(COMPONENT_ENABLED_STATE_DEFAULT));
     }
 
+    private PersistableBundle getPersistableBundle(String packageName, long longVal,
+            double doubleVal, boolean boolVal, String textVal) {
+        final PersistableBundle bundle = new PersistableBundle();
+        bundle.putString(packageName + ".TEXT_VALUE", textVal);
+        bundle.putLong(packageName + ".LONG_VALUE", longVal);
+        bundle.putBoolean(packageName + ".BOOL_VALUE", boolVal);
+        bundle.putDouble(packageName + ".DOUBLE_VALUE", doubleVal);
+        return bundle;
+    }
+
+    @Test
+    public void testReadPackageRestrictions_oldSuspendInfo() {
+        writePackageRestrictions_oldSuspendInfoXml(0);
+        final Object lock = new Object();
+        final Context context = InstrumentationRegistry.getTargetContext();
+        final Settings settingsUnderTest = new Settings(context.getFilesDir(), null, lock);
+        settingsUnderTest.mPackages.put(PACKAGE_NAME_1, createPackageSetting(PACKAGE_NAME_1));
+        settingsUnderTest.mPackages.put(PACKAGE_NAME_2, createPackageSetting(PACKAGE_NAME_2));
+        settingsUnderTest.readPackageRestrictionsLPr(0);
+
+        final PackageSetting ps1 = settingsUnderTest.mPackages.get(PACKAGE_NAME_1);
+        final PackageUserState packageUserState1 = ps1.readUserState(0);
+        assertThat(packageUserState1.suspended, is(true));
+        assertThat("android".equals(packageUserState1.suspendingPackage), is(true));
+
+        final PackageSetting ps2 = settingsUnderTest.mPackages.get(PACKAGE_NAME_2);
+        final PackageUserState packageUserState2 = ps2.readUserState(0);
+        assertThat(packageUserState2.suspended, is(false));
+        assertThat(packageUserState2.suspendingPackage, is(nullValue()));
+    }
+
+    @Test
+    public void testReadWritePackageRestrictions_newSuspendInfo() {
+        final Context context = InstrumentationRegistry.getTargetContext();
+        final Settings settingsUnderTest = new Settings(context.getFilesDir(), null, new Object());
+        final PackageSetting ps1 = createPackageSetting(PACKAGE_NAME_1);
+        final PackageSetting ps2 = createPackageSetting(PACKAGE_NAME_2);
+        final PackageSetting ps3 = createPackageSetting(PACKAGE_NAME_3);
+
+        final PersistableBundle appExtras1 = getPersistableBundle(
+                PACKAGE_NAME_1, 1L, 0.01, true, "appString1");
+        final PersistableBundle launcherExtras1 = getPersistableBundle(
+                PACKAGE_NAME_1, 10L, 0.1, false, "launcherString1");
+        ps1.setSuspended(true, "suspendingPackage1", appExtras1, launcherExtras1, 0);
+        settingsUnderTest.mPackages.put(PACKAGE_NAME_1, ps1);
+
+        ps2.setSuspended(true, "suspendingPackage2", null, null, 0);
+        settingsUnderTest.mPackages.put(PACKAGE_NAME_2, ps2);
+
+        ps3.setSuspended(false, "irrelevant", null, null, 0);
+        settingsUnderTest.mPackages.put(PACKAGE_NAME_3, ps3);
+
+        settingsUnderTest.writePackageRestrictionsLPr(0);
+
+        settingsUnderTest.mPackages.clear();
+        settingsUnderTest.mPackages.put(PACKAGE_NAME_1, createPackageSetting(PACKAGE_NAME_1));
+        settingsUnderTest.mPackages.put(PACKAGE_NAME_2, createPackageSetting(PACKAGE_NAME_2));
+        settingsUnderTest.mPackages.put(PACKAGE_NAME_3, createPackageSetting(PACKAGE_NAME_3));
+        // now read and verify
+        settingsUnderTest.readPackageRestrictionsLPr(0);
+        final PackageUserState readPus1 = settingsUnderTest.mPackages.get(PACKAGE_NAME_1).
+                readUserState(0);
+        assertThat(readPus1.suspended, is(true));
+        assertThat(readPus1.suspendingPackage, equalTo("suspendingPackage1"));
+        assertThat(BaseBundle.kindofEquals(readPus1.suspendedAppExtras, appExtras1), is(true));
+        assertThat(BaseBundle.kindofEquals(readPus1.suspendedLauncherExtras, launcherExtras1),
+                is(true));
+
+        final PackageUserState readPus2 = settingsUnderTest.mPackages.get(PACKAGE_NAME_2).
+                readUserState(0);
+        assertThat(readPus2.suspended, is(true));
+        assertThat(readPus2.suspendingPackage, equalTo("suspendingPackage2"));
+        assertThat(readPus2.suspendedAppExtras, is(nullValue()));
+        assertThat(readPus2.suspendedLauncherExtras, is(nullValue()));
+
+        final PackageUserState readPus3 = settingsUnderTest.mPackages.get(PACKAGE_NAME_3).
+                readUserState(0);
+        assertThat(readPus3.suspended, is(false));
+    }
+
+    @Test
+    public void testPackageRestrictionsSuspendedDefault() {
+        final PackageSetting defaultSetting =  createPackageSetting(PACKAGE_NAME_1);
+        assertThat(defaultSetting.getSuspended(0), is(false));
+    }
+
     @Test
     public void testEnableDisable() {
         // Write the package files and make sure they're parsed properly the first time
@@ -686,6 +772,26 @@
                 null /*usesStaticLibrariesVersions*/);
     }
 
+    private PackageSetting createPackageSetting(String packageName) {
+        return new PackageSetting(
+                packageName,
+                packageName,
+                INITIAL_CODE_PATH /*codePath*/,
+                INITIAL_CODE_PATH /*resourcePath*/,
+                null /*legacyNativeLibraryPathString*/,
+                "x86_64" /*primaryCpuAbiString*/,
+                "x86" /*secondaryCpuAbiString*/,
+                null /*cpuAbiOverrideString*/,
+                INITIAL_VERSION_CODE,
+                0,
+                0 /*privateFlags*/,
+                null /*parentPackageName*/,
+                null /*childPackageNames*/,
+                0,
+                null /*usesStaticLibraries*/,
+                null /*usesStaticLibrariesVersions*/);
+    }
+
     private @NonNull List<UserInfo> createFakeUsers() {
         ArrayList<UserInfo> users = new ArrayList<>();
         users.add(new UserInfo(UserHandle.USER_SYSTEM, "test user", UserInfo.FLAG_INITIALIZED));
@@ -718,13 +824,13 @@
                 + "<item name=\"android.permission.ACCESS_WIMAX_STATE\" package=\"android\" />"
                 + "<item name=\"android.permission.REBOOT\" package=\"android\" protection=\"18\" />"
                 + "</permissions>"
-                + "<package name=\"com.google.app1\" codePath=\"/system/app/app1.apk\" nativeLibraryPath=\"/data/data/com.google.app1/lib\" flags=\"1\" ft=\"1360e2caa70\" it=\"135f2f80d08\" ut=\"1360e2caa70\" version=\"1109\" sharedUserId=\"11000\">"
+                + "<package name=\"com.android.app1\" codePath=\"/system/app/app1.apk\" nativeLibraryPath=\"/data/data/com.android.app1/lib\" flags=\"1\" ft=\"1360e2caa70\" it=\"135f2f80d08\" ut=\"1360e2caa70\" version=\"1109\" sharedUserId=\"11000\">"
                 + "<sigs count=\"1\">"
                 + "<cert index=\"0\" key=\"" + KeySetStrings.ctsKeySetCertA + "\" />"
                 + "</sigs>"
                 + "<proper-signing-keyset identifier=\"1\" />"
                 + "</package>"
-                + "<package name=\"com.google.app2\" codePath=\"/system/app/app2.apk\" nativeLibraryPath=\"/data/data/com.google.app2/lib\" flags=\"1\" ft=\"1360e578718\" it=\"135f2f80d08\" ut=\"1360e578718\" version=\"15\" enabled=\"3\" userId=\"11001\">"
+                + "<package name=\"com.android.app2\" codePath=\"/system/app/app2.apk\" nativeLibraryPath=\"/data/data/com.android.app2/lib\" flags=\"1\" ft=\"1360e578718\" it=\"135f2f80d08\" ut=\"1360e578718\" version=\"15\" enabled=\"3\" userId=\"11001\">"
                 + "<sigs count=\"1\">"
                 + "<cert index=\"0\" />"
                 + "</sigs>"
@@ -774,11 +880,26 @@
                 + "</packages>").getBytes());
     }
 
+    private void writePackageRestrictions_oldSuspendInfoXml(final int userId) {
+        writeFile(new File(InstrumentationRegistry.getContext().getFilesDir(), "system/users/"
+                        + userId + "/package-restrictions.xml"),
+                ( "<?xml version='1.0' encoding='utf-8' standalone='yes' ?>\n"
+                        + "<package-restrictions>\n"
+                        + "    <pkg name=\"" + PACKAGE_NAME_1 + "\" suspended=\"true\" />"
+                        + "    <pkg name=\"" + PACKAGE_NAME_2 + "\" suspended=\"false\" />"
+                        + "    <preferred-activities />\n"
+                        + "    <persistent-preferred-activities />\n"
+                        + "    <crossProfile-intent-filters />\n"
+                        + "    <default-apps />\n"
+                        + "</package-restrictions>\n")
+                        .getBytes());
+    }
+
     private void writeStoppedPackagesXml() {
         writeFile(new File(InstrumentationRegistry.getContext().getFilesDir(), "system/packages-stopped.xml"),
                 ( "<?xml version='1.0' encoding='utf-8' standalone='yes' ?>"
                 + "<stopped-packages>"
-                + "<pkg name=\"com.google.app1\" nl=\"1\" />"
+                + "<pkg name=\"com.android.app1\" nl=\"1\" />"
                 + "<pkg name=\"com.android.app3\" nl=\"1\" />"
                 + "</stopped-packages>")
                 .getBytes());
@@ -786,8 +907,8 @@
 
     private void writePackagesList() {
         writeFile(new File(InstrumentationRegistry.getContext().getFilesDir(), "system/packages.list"),
-                ( "com.google.app1 11000 0 /data/data/com.google.app1 seinfo1"
-                + "com.google.app2 11001 0 /data/data/com.google.app2 seinfo2"
+                ( "com.android.app1 11000 0 /data/data/com.android.app1 seinfo1"
+                + "com.android.app2 11001 0 /data/data/com.android.app2 seinfo2"
                 + "com.android.app3 11030 0 /data/data/com.android.app3 seinfo3")
                 .getBytes());
     }
@@ -828,6 +949,11 @@
         });
     }
 
+    @After
+    public void tearDown() throws Exception {
+        deleteFolder(InstrumentationRegistry.getTargetContext().getFilesDir());
+    }
+
     private void verifyKeySetMetaData(Settings settings)
             throws ReflectiveOperationException, IllegalAccessException {
         ArrayMap<String, PackageSetting> packages = settings.mPackages;
@@ -871,9 +997,9 @@
         assertThat(KeySetUtils.getLastIssuedKeySetId(ksms), is(4L));
 
         /* verify packages have been given the appropriate information */
-        PackageSetting ps = packages.get("com.google.app1");
+        PackageSetting ps = packages.get("com.android.app1");
         assertThat(ps.keySetData.getProperSigningKeySet(), is(1L));
-        ps = packages.get("com.google.app2");
+        ps = packages.get("com.android.app2");
         assertThat(ps.keySetData.getProperSigningKeySet(), is(1L));
         assertThat(ps.keySetData.getAliases().get("AB"), is(4L));
         ps = packages.get("com.android.app3");
diff --git a/services/tests/servicestests/src/com/android/server/pm/PackageUserStateTest.java b/services/tests/servicestests/src/com/android/server/pm/PackageUserStateTest.java
index 50be8db..4e1418c 100644
--- a/services/tests/servicestests/src/com/android/server/pm/PackageUserStateTest.java
+++ b/services/tests/servicestests/src/com/android/server/pm/PackageUserStateTest.java
@@ -23,8 +23,9 @@
 import static org.junit.Assert.assertThat;
 
 import android.content.pm.PackageUserState;
+import android.os.PersistableBundle;
+import android.support.test.filters.SmallTest;
 import android.support.test.runner.AndroidJUnit4;
-import android.test.suitebuilder.annotation.SmallTest;
 import android.util.ArraySet;
 
 import org.junit.Test;
@@ -170,4 +171,44 @@
         testUserState03.enabledComponents.add("com.android.unit_test_04");
         assertThat(testUserState03.equals(oldUserState), is(false));
     }
+
+    @Test
+    public void testPackageUserState05() {
+        PersistableBundle appExtras1 = new PersistableBundle();
+        PersistableBundle appExtras2 = new PersistableBundle();
+        appExtras1.putInt("appExtraId", 1);
+        appExtras2.putInt("appExtraId", 2);
+        PersistableBundle launcherExtras1 = new PersistableBundle();
+        PersistableBundle launcherExtras2 = new PersistableBundle();
+        launcherExtras1.putString("name", "launcherExtras1");
+        launcherExtras2.putString("name", "launcherExtras2");
+        final String suspendingPackage1 = "package1";
+        final String suspendingPackage2 = "package2";
+
+        final PackageUserState testUserState1 = new PackageUserState();
+        testUserState1.suspended = true;
+        testUserState1.suspendedAppExtras = appExtras1;
+        testUserState1.suspendedLauncherExtras = launcherExtras1;
+        testUserState1.suspendingPackage = suspendingPackage1;
+
+        final PackageUserState testUserState2 = new PackageUserState(testUserState1);
+        assertThat(testUserState1.equals(testUserState2), is(true));
+        testUserState2.suspendingPackage = suspendingPackage2;
+        assertThat(testUserState1.equals(testUserState2), is(false));
+
+        testUserState2.suspendingPackage = testUserState1.suspendingPackage;
+        testUserState2.suspendedAppExtras = appExtras2;
+        assertThat(testUserState1.equals(testUserState2), is(false));
+
+        testUserState2.suspendedAppExtras = testUserState1.suspendedAppExtras;
+        testUserState2.suspendedLauncherExtras = launcherExtras2;
+        assertThat(testUserState1.equals(testUserState2), is(false));
+
+        // Everything is different but irrelevant if suspended is false
+        testUserState2.suspended = testUserState1.suspended = false;
+        testUserState2.suspendedAppExtras = appExtras2;
+        testUserState2.suspendingPackage = suspendingPackage2;
+        assertThat(testUserState1.equals(testUserState2), is(true));
+    }
+
 }
diff --git a/services/tests/servicestests/src/com/android/server/pm/SuspendPackagesTest.java b/services/tests/servicestests/src/com/android/server/pm/SuspendPackagesTest.java
new file mode 100644
index 0000000..d702318
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/pm/SuspendPackagesTest.java
@@ -0,0 +1,127 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.pm;
+
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+
+import android.content.BroadcastReceiver;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.content.pm.PackageManager;
+import android.os.BaseBundle;
+import android.os.Bundle;
+import android.os.Handler;
+import android.os.Looper;
+import android.os.PersistableBundle;
+import android.support.test.InstrumentationRegistry;
+import android.support.test.filters.MediumTest;
+import android.support.test.runner.AndroidJUnit4;
+
+import com.android.servicestests.apps.suspendtestapp.SuspendTestReceiver;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.AtomicReference;
+
+@RunWith(AndroidJUnit4.class)
+@MediumTest
+public class SuspendPackagesTest {
+    private static final String TEST_APP_PACKAGE_NAME = SuspendTestReceiver.PACKAGE_NAME;
+    private static final String[] PACKAGES_TO_SUSPEND = new String[]{TEST_APP_PACKAGE_NAME};
+
+    private Context mContext;
+    private PackageManager mPackageManager;
+    private Handler mReceiverHandler;
+    private ComponentName mTestReceiverComponent;
+
+    @Before
+    public void setUp() {
+        mContext = InstrumentationRegistry.getTargetContext();
+        mPackageManager = mContext.getPackageManager();
+        mPackageManager.setPackagesSuspended(PACKAGES_TO_SUSPEND, false, null, null, null);
+        mReceiverHandler = new Handler(Looper.getMainLooper());
+        mTestReceiverComponent = new ComponentName(TEST_APP_PACKAGE_NAME,
+                SuspendTestReceiver.class.getCanonicalName());
+    }
+
+    private Bundle requestAppAction(String action) throws InterruptedException {
+        final AtomicReference<Bundle> result = new AtomicReference<>();
+        final CountDownLatch receiverLatch = new CountDownLatch(1);
+
+        final Intent broadcastIntent = new Intent(action)
+                .setComponent(mTestReceiverComponent)
+                .setFlags(Intent.FLAG_RECEIVER_FOREGROUND);
+        mContext.sendOrderedBroadcast(broadcastIntent, null, new BroadcastReceiver() {
+            @Override
+            public void onReceive(Context context, Intent intent) {
+                result.set(getResultExtras(true));
+                receiverLatch.countDown();
+            }
+        }, mReceiverHandler, 0, null, null);
+
+        assertTrue("Test receiver timed out ", receiverLatch.await(5, TimeUnit.SECONDS));
+        return result.get();
+    }
+
+    private PersistableBundle getExtras(String keyPrefix, long lval, String sval, double dval) {
+        final PersistableBundle extras = new PersistableBundle(3);
+        extras.putLong(keyPrefix + ".LONG_VALUE", lval);
+        extras.putDouble(keyPrefix + ".DOUBLE_VALUE", dval);
+        extras.putString(keyPrefix + ".STRING_VALUE", sval);
+        return extras;
+    }
+
+    private void suspendTestPackage(PersistableBundle appExtras, PersistableBundle launcherExtras) {
+        final String[] unchangedPackages = mPackageManager.setPackagesSuspended(
+                PACKAGES_TO_SUSPEND, true, appExtras, launcherExtras, null);
+        assertTrue("setPackagesSuspended returned non-empty list", unchangedPackages.length == 0);
+    }
+
+    @Test
+    public void testIsPackageSuspended() {
+        suspendTestPackage(null, null);
+        assertTrue("isPackageSuspended is false",
+                mPackageManager.isPackageSuspended(TEST_APP_PACKAGE_NAME));
+    }
+
+    @Test
+    public void testSuspendedStateFromApp() throws Exception {
+        Bundle resultFromApp = requestAppAction(SuspendTestReceiver.ACTION_GET_SUSPENDED_STATE);
+        assertFalse(resultFromApp.getBoolean(SuspendTestReceiver.EXTRA_SUSPENDED, true));
+        assertNull(resultFromApp.getParcelable(SuspendTestReceiver.EXTRA_SUSPENDED_APP_EXTRAS));
+
+        final PersistableBundle appExtras = getExtras("appExtras", 20, "20", 0.2);
+        suspendTestPackage(appExtras, null);
+
+        resultFromApp = requestAppAction(SuspendTestReceiver.ACTION_GET_SUSPENDED_STATE);
+        assertTrue("resultFromApp:suspended is false",
+                resultFromApp.getBoolean(SuspendTestReceiver.EXTRA_SUSPENDED));
+        final PersistableBundle receivedAppExtras =
+                resultFromApp.getParcelable(SuspendTestReceiver.EXTRA_SUSPENDED_APP_EXTRAS);
+        receivedAppExtras.get(""); // hack to unparcel the bundles
+        appExtras.get("");
+        assertTrue("Received app extras " + receivedAppExtras + " different to the ones supplied",
+                BaseBundle.kindofEquals(appExtras, receivedAppExtras));
+    }
+}
diff --git a/services/tests/servicestests/test-apps/SuspendTestApp/Android.mk b/services/tests/servicestests/test-apps/SuspendTestApp/Android.mk
new file mode 100644
index 0000000..40a34b9
--- /dev/null
+++ b/services/tests/servicestests/test-apps/SuspendTestApp/Android.mk
@@ -0,0 +1,30 @@
+# Copyright (C) 2018 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+LOCAL_PATH:= $(call my-dir)
+
+include $(CLEAR_VARS)
+
+LOCAL_MODULE_TAGS := tests
+LOCAL_SDK_VERSION := current
+
+LOCAL_COMPATIBILITY_SUITE := device-tests
+
+LOCAL_SRC_FILES := $(call all-subdir-java-files)
+
+LOCAL_PACKAGE_NAME := SuspendTestApp
+LOCAL_DEX_PREOPT := false
+LOCAL_PROGUARD_ENABLED := disabled
+
+include $(BUILD_PACKAGE)
\ No newline at end of file
diff --git a/services/tests/servicestests/test-apps/SuspendTestApp/AndroidManifest.xml b/services/tests/servicestests/test-apps/SuspendTestApp/AndroidManifest.xml
new file mode 100644
index 0000000..70a1fd0
--- /dev/null
+++ b/services/tests/servicestests/test-apps/SuspendTestApp/AndroidManifest.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2018 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+        package="com.android.servicestests.apps.suspendtestapp">
+
+    <application>
+        <activity android:name=".SuspendTestActivity"
+                  android:exported="true" />
+        <receiver android:name=".SuspendTestReceiver"
+                  android:exported="true" />
+    </application>
+
+</manifest>
\ No newline at end of file
diff --git a/services/tests/servicestests/test-apps/SuspendTestApp/src/com/android/servicestests/apps/suspendtestapp/SuspendTestActivity.java b/services/tests/servicestests/test-apps/SuspendTestApp/src/com/android/servicestests/apps/suspendtestapp/SuspendTestActivity.java
new file mode 100644
index 0000000..fa5fc58
--- /dev/null
+++ b/services/tests/servicestests/test-apps/SuspendTestApp/src/com/android/servicestests/apps/suspendtestapp/SuspendTestActivity.java
@@ -0,0 +1,24 @@
+/*
+ * Copyright (C) 2018 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.servicestests.apps.suspendtestapp;
+
+import android.app.Activity;
+
+public class SuspendTestActivity extends Activity {
+    private static final String TAG = SuspendTestActivity.class.getSimpleName();
+
+}
\ No newline at end of file
diff --git a/services/tests/servicestests/test-apps/SuspendTestApp/src/com/android/servicestests/apps/suspendtestapp/SuspendTestReceiver.java b/services/tests/servicestests/test-apps/SuspendTestApp/src/com/android/servicestests/apps/suspendtestapp/SuspendTestReceiver.java
new file mode 100644
index 0000000..6f353a0
--- /dev/null
+++ b/services/tests/servicestests/test-apps/SuspendTestApp/src/com/android/servicestests/apps/suspendtestapp/SuspendTestReceiver.java
@@ -0,0 +1,56 @@
+/*
+ * Copyright (C) 2018 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.servicestests.apps.suspendtestapp;
+
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.pm.PackageManager;
+import android.os.Bundle;
+import android.os.PersistableBundle;
+import android.util.Log;
+
+public class SuspendTestReceiver extends BroadcastReceiver {
+    private static final String TAG = SuspendTestReceiver.class.getSimpleName();
+
+    public static final String PACKAGE_NAME = "com.android.servicestests.apps.suspendtestapp";
+    public static final String ACTION_GET_SUSPENDED_STATE =
+            PACKAGE_NAME + ".action.GET_SUSPENDED_STATE";
+    public static final String EXTRA_SUSPENDED = PACKAGE_NAME + ".extra.SUSPENDED";
+    public static final String EXTRA_SUSPENDED_APP_EXTRAS =
+            PACKAGE_NAME + ".extra.SUSPENDED_APP_EXTRAS";
+
+    private PackageManager mPm;
+
+    @Override
+    public void onReceive(Context context, Intent intent) {
+        mPm = context.getPackageManager();
+        Log.d(TAG, "Received request action " + intent.getAction());
+        switch (intent.getAction()) {
+            case ACTION_GET_SUSPENDED_STATE:
+                final Bundle result = new Bundle();
+                final boolean suspended = mPm.isPackageSuspended();
+                final PersistableBundle appExtras = mPm.getSuspendedPackageAppExtras();
+                result.putBoolean(EXTRA_SUSPENDED, suspended);
+                result.putParcelable(EXTRA_SUSPENDED_APP_EXTRAS, appExtras);
+                setResult(0, null, result);
+                break;
+            default:
+                Log.e(TAG, "Unknown action: " + intent.getAction());
+        }
+    }
+}
diff --git a/telephony/java/android/telephony/CarrierConfigManager.java b/telephony/java/android/telephony/CarrierConfigManager.java
index eebe2a1..c79eec0 100644
--- a/telephony/java/android/telephony/CarrierConfigManager.java
+++ b/telephony/java/android/telephony/CarrierConfigManager.java
@@ -2227,7 +2227,9 @@
     /**
      * Gets the configuration values for a particular subscription, which is associated with a
      * specific SIM card. If an invalid subId is used, the returned config will contain default
-     * values.
+     * values. After using this method to get the configuration bundle,
+     * {@link #isConfigForIdentifiedCarrier(PersistableBundle)} should be called to confirm whether
+     * any carrier specific configuration has been applied.
      *
      * <p>Requires Permission:
      * {@link android.Manifest.permission#READ_PHONE_STATE READ_PHONE_STATE}
@@ -2254,7 +2256,9 @@
     }
 
     /**
-     * Gets the configuration values for the default subscription.
+     * Gets the configuration values for the default subscription. After using this method to get
+     * the configuration bundle, {@link #isConfigForIdentifiedCarrier(PersistableBundle)} should be
+     * called to confirm whether any carrier specific configuration has been applied.
      *
      * <p>Requires Permission:
      * {@link android.Manifest.permission#READ_PHONE_STATE READ_PHONE_STATE}
@@ -2283,6 +2287,9 @@
      * <p>
      * After using {@link #getConfig()} or {@link #getConfigForSubId(int)} an app should always
      * use this method to confirm whether any carrier specific configuration has been applied.
+     * Especially when an app misses the broadcast {@link #ACTION_CARRIER_CONFIG_CHANGED} but it
+     * still needs to get the current configuration, it must use this method to verify whether the
+     * configuration is default or carrier overridden.
      * </p>
      *
      * @param bundle the configuration bundle to be checked.
diff --git a/test-mock/src/android/test/mock/MockPackageManager.java b/test-mock/src/android/test/mock/MockPackageManager.java
index 8ebb77d..c2aca6b 100644
--- a/test-mock/src/android/test/mock/MockPackageManager.java
+++ b/test-mock/src/android/test/mock/MockPackageManager.java
@@ -54,6 +54,7 @@
 import android.graphics.drawable.Drawable;
 import android.net.Uri;
 import android.os.Handler;
+import android.os.PersistableBundle;
 import android.os.UserHandle;
 import android.os.storage.VolumeInfo;
 
@@ -951,7 +952,8 @@
 
     /** @hide */
     @Override
-    public String[] setPackagesSuspendedAsUser(String[] packageNames, boolean hidden, int userId) {
+    public String[] setPackagesSuspended(String[] packageNames, boolean hidden,
+            PersistableBundle appExtras, PersistableBundle launcherExtras, String dialogMessage) {
         throw new UnsupportedOperationException();
     }