Merge "PackageManagerNative: Implement getModuleMetadataPackageName" into qt-dev
diff --git a/CleanSpec.mk b/CleanSpec.mk
index 7c21875..f311fc8 100644
--- a/CleanSpec.mk
+++ b/CleanSpec.mk
@@ -252,6 +252,7 @@
 $(call add-clean-step, rm -rf $(PRODUCT_OUT)/system/media/audio)
 $(call add-clean-step, rm -rf $(PRODUCT_OUT)/system/priv-app/DynamicAndroidInstallationService)
 $(call add-clean-step, rm -rf $(PRODUCT_OUT)/system/priv-app/DefaultContainerService)
+$(call add-clean-step, rm -rf $(PRODUCT_OUT)/system/app/CaptivePortalLogin)
 # ******************************************************************
 # NEWER CLEAN STEPS MUST BE AT THE END OF THE LIST ABOVE THIS BANNER
 # ******************************************************************
diff --git a/api/test-current.txt b/api/test-current.txt
index 0de0d75..b1ffbad 100644
--- a/api/test-current.txt
+++ b/api/test-current.txt
@@ -3171,6 +3171,7 @@
 
   @UiThread public class View implements android.view.accessibility.AccessibilityEventSource android.graphics.drawable.Drawable.Callback android.view.KeyEvent.Callback {
     method public android.view.View getTooltipView();
+    method public boolean isAutofilled();
     method public static boolean isDefaultFocusHighlightEnabled();
     method public boolean isDefaultFocusHighlightNeeded(android.graphics.drawable.Drawable, android.graphics.drawable.Drawable);
     method protected void resetResolvedDrawables();
diff --git a/cmds/incident/Android.bp b/cmds/incident/Android.bp
index f56f101..9e9dac1 100644
--- a/cmds/incident/Android.bp
+++ b/cmds/incident/Android.bp
@@ -30,7 +30,7 @@
     ],
 
     static_libs: [
-        "libplatformprotos",
+        "libprotoutil",
     ],
 
     cflags: [
diff --git a/cmds/incident/main.cpp b/cmds/incident/main.cpp
index eca781f..dfb4f99 100644
--- a/cmds/incident/main.cpp
+++ b/cmds/incident/main.cpp
@@ -21,6 +21,7 @@
 #include <android/os/BnIncidentReportStatusListener.h>
 #include <android/os/IIncidentManager.h>
 #include <android/os/IncidentReportArgs.h>
+#include <android/util/ProtoOutputStream.h>
 #include <binder/IPCThreadState.h>
 #include <binder/IServiceManager.h>
 #include <utils/Looper.h>
@@ -36,6 +37,9 @@
 using namespace android::base;
 using namespace android::binder;
 using namespace android::os;
+using android::util::FIELD_COUNT_SINGLE;
+using android::util::FIELD_TYPE_STRING;
+using android::util::ProtoOutputStream;
 
 // ================================================================================
 class StatusListener : public BnIncidentReportStatusListener {
@@ -129,11 +133,11 @@
 static IncidentSection const*
 find_section(const char* name)
 {
-    size_t low = 0;
-    size_t high = INCIDENT_SECTION_COUNT - 1;
+    ssize_t low = 0;
+    ssize_t high = INCIDENT_SECTION_COUNT - 1;
 
     while (low <= high) {
-        size_t mid = (low + high) >> 1;
+        ssize_t mid = (low + high) / 2;
         IncidentSection const* section = INCIDENT_SECTIONS + mid;
 
         int cmp = strcmp(section->name, name);
@@ -208,6 +212,7 @@
     fprintf(out, "and one of these destinations:\n");
     fprintf(out, "  -b           (default) print the report to stdout (in proto format)\n");
     fprintf(out, "  -d           send the report into dropbox\n");
+    fprintf(out, "  -r REASON    human readable description of why the report is taken.\n");
     fprintf(out, "  -s PKG/CLS   send broadcast to the broadcast receiver.\n");
     fprintf(out, "\n");
     fprintf(out, "  SECTION     the field numbers of the incident report fields to include\n");
@@ -221,11 +226,12 @@
     IncidentReportArgs args;
     enum { DEST_UNSET, DEST_DROPBOX, DEST_STDOUT, DEST_BROADCAST } destination = DEST_UNSET;
     int privacyPolicy = PRIVACY_POLICY_AUTOMATIC;
+    string reason;
     string receiverArg;
 
     // Parse the args
     int opt;
-    while ((opt = getopt(argc, argv, "bhdlp:s:")) != -1) {
+    while ((opt = getopt(argc, argv, "bhdlp:r:s:")) != -1) {
         switch (opt) {
             case 'h':
                 usage(stdout);
@@ -250,6 +256,13 @@
             case 'p':
                 privacyPolicy = get_privacy_policy(optarg);
                 break;
+            case 'r':
+                if (reason.size() > 0) {
+                    usage(stderr);
+                    return 1;
+                }
+                reason = optarg;
+                break;
             case 's':
                 if (destination != DEST_UNSET) {
                     usage(stderr);
@@ -291,6 +304,7 @@
                 } else {
                     IncidentSection const* ic = find_section(arg);
                     if (ic == NULL) {
+                        ALOGD("Invalid section: %s\n", arg);
                         fprintf(stderr, "Invalid section: %s\n", arg);
                         return 1;
                     }
@@ -301,6 +315,14 @@
     }
     args.setPrivacyPolicy(privacyPolicy);
 
+    if (reason.size() > 0) {
+        ProtoOutputStream proto;
+        proto.write(/* reason field id */ 2 | FIELD_TYPE_STRING | FIELD_COUNT_SINGLE, reason);
+        vector<uint8_t> header;
+        proto.serializeToVector(&header);
+        args.addHeader(header);
+    }
+
     // Start the thread pool.
     sp<ProcessState> ps(ProcessState::self());
     ps->startThreadPool();
diff --git a/cmds/telecom/src/com/android/commands/telecom/Telecom.java b/cmds/telecom/src/com/android/commands/telecom/Telecom.java
index 0524450..e0f7d86 100644
--- a/cmds/telecom/src/com/android/commands/telecom/Telecom.java
+++ b/cmds/telecom/src/com/android/commands/telecom/Telecom.java
@@ -20,16 +20,21 @@
 import android.content.Context;
 import android.net.Uri;
 import android.os.IUserManager;
+import android.os.Process;
 import android.os.RemoteException;
 import android.os.ServiceManager;
+import android.os.SystemProperties;
 import android.os.UserHandle;
 import android.telecom.Log;
 import android.telecom.PhoneAccount;
 import android.telecom.PhoneAccountHandle;
+import android.telephony.TelephonyManager;
 import android.text.TextUtils;
 
 import com.android.internal.os.BaseCommand;
 import com.android.internal.telecom.ITelecomService;
+import com.android.internal.telephony.ITelephony;
+import com.android.internal.telephony.TelephonyProperties;
 
 import java.io.PrintStream;
 
@@ -62,10 +67,14 @@
     private static final String COMMAND_GET_DEFAULT_DIALER = "get-default-dialer";
     private static final String COMMAND_GET_SYSTEM_DIALER = "get-system-dialer";
     private static final String COMMAND_WAIT_ON_HANDLERS = "wait-on-handlers";
+    private static final String COMMAND_SET_SIM_COUNT = "set-sim-count";
+    private static final String COMMAND_GET_SIM_CONFIG = "get-sim-config";
+    private static final String COMMAND_GET_MAX_PHONES = "get-max-phones";
 
     private ComponentName mComponent;
     private String mAccountId;
     private ITelecomService mTelecomService;
+    private ITelephony mTelephonyService;
     private IUserManager mUserManager;
 
     @Override
@@ -88,21 +97,32 @@
                 + "usage: telecom get-default-dialer\n"
                 + "usage: telecom get-system-dialer\n"
                 + "usage: telecom wait-on-handlers\n"
+                + "usage: telecom set-sim-count <COUNT>\n"
+                + "usage: telecom get-sim-config\n"
+                + "usage: telecom get-max-phones\n"
                 + "\n"
-                + "telecom set-phone-account-enabled: Enables the given phone account, if it has \n"
-                + " already been registered with Telecom.\n"
+                + "telecom set-phone-account-enabled: Enables the given phone account, if it has"
+                        + " already been registered with Telecom.\n"
                 + "\n"
-                + "telecom set-phone-account-disabled: Disables the given phone account, if it \n"
-                + " has already been registered with telecom.\n"
+                + "telecom set-phone-account-disabled: Disables the given phone account, if it"
+                        + " has already been registered with telecom.\n"
                 + "\n"
-                + "telecom set-default-dialer: Sets the override default dialer to the given "
-                + "component; this will override whatever the dialer role is set to. \n"
+                + "telecom set-default-dialer: Sets the override default dialer to the given"
+                        + " component; this will override whatever the dialer role is set to.\n"
                 + "\n"
-                + "telecom get-default-dialer: Displays the current default dialer. \n"
+                + "telecom get-default-dialer: Displays the current default dialer.\n"
                 + "\n"
-                + "telecom get-system-dialer: Displays the current system dialer. \n"
+                + "telecom get-system-dialer: Displays the current system dialer.\n"
                 + "\n"
-                + "telecom wait-on-handlers: Wait until all handlers finish their work. \n"
+                + "telecom wait-on-handlers: Wait until all handlers finish their work.\n"
+                + "\n"
+                + "telecom set-sim-count: Set num SIMs (2 for DSDS, 1 for single SIM."
+                        + " This may restart the device.\n"
+                + "\n"
+                + "telecom get-sim-config: Get the mSIM config string. \"DSDS\" for DSDS mode,"
+                        + " or \"\" for single SIM\n"
+                + "\n"
+                + "telecom get-max-phones: Get the max supported phones from the modem.\n"
         );
     }
 
@@ -115,6 +135,15 @@
             showError("Error: Could not access the Telecom Manager. Is the system running?");
             return;
         }
+
+        mTelephonyService = ITelephony.Stub.asInterface(
+                ServiceManager.getService(Context.TELEPHONY_SERVICE));
+        if (mTelephonyService == null) {
+            Log.w(this, "onRun: Can't access telephony service.");
+            showError("Error: Could not access the Telephony Service. Is the system running?");
+            return;
+        }
+
         mUserManager = IUserManager.Stub
                 .asInterface(ServiceManager.getService(Context.USER_SERVICE));
         if (mUserManager == null) {
@@ -170,6 +199,15 @@
             case COMMAND_WAIT_ON_HANDLERS:
                 runWaitOnHandler();
                 break;
+            case COMMAND_SET_SIM_COUNT:
+                runSetSimCount();
+                break;
+            case COMMAND_GET_SIM_CONFIG:
+                runGetSimConfig();
+                break;
+            case COMMAND_GET_MAX_PHONES:
+                runGetMaxPhones();
+                break;
             default:
                 Log.w(this, "onRun: unknown command: %s", command);
                 throw new IllegalArgumentException ("unknown command '" + command + "'");
@@ -271,6 +309,35 @@
 
     }
 
+    private void runSetSimCount() throws RemoteException {
+        if (!callerIsRoot()) {
+            System.out.println("set-sim-count requires adb root");
+            return;
+        }
+        int numSims = Integer.parseInt(nextArgRequired());
+        System.out.println("Setting sim count to " + numSims + ". Device may reboot");
+        mTelephonyService.switchMultiSimConfig(numSims);
+    }
+
+    /**
+     * Prints the mSIM config to the console.
+     * "DSDS" for a phone in DSDS mode
+     * "" (empty string) for a phone in SS mode
+     */
+    private void runGetSimConfig() throws RemoteException {
+        System.out.println(SystemProperties.get(TelephonyProperties.PROPERTY_MULTI_SIM_CONFIG));
+    }
+
+    private void runGetMaxPhones() throws RemoteException {
+        // This assumes the max number of SIMs is 2, which it currently is
+        if (TelephonyManager.MULTISIM_ALLOWED
+                == mTelephonyService.isMultiSimSupported("com.android.commands.telecom")) {
+            System.out.println("2");
+        } else {
+            System.out.println("1");
+        }
+    }
+
     private PhoneAccountHandle getPhoneAccountHandleFromArgs() throws RemoteException {
         if (TextUtils.isEmpty(mArgs.peekNextArg())) {
             return null;
@@ -289,6 +356,10 @@
         return new PhoneAccountHandle(component, accountId, userHandle);
     }
 
+    private boolean callerIsRoot() {
+        return Process.ROOT_UID == Process.myUid();
+    }
+
     private ComponentName parseComponentName(String component) {
         ComponentName cn = ComponentName.unflattenFromString(component);
         if (cn == null) {
diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java
index 4e1bcc1..2db1bcc 100644
--- a/core/java/android/app/ActivityThread.java
+++ b/core/java/android/app/ActivityThread.java
@@ -3554,11 +3554,13 @@
             @NonNull RemoteCallback callback) {
         final ActivityClientRecord r = mActivities.get(activityToken);
         if (r == null) {
+            Log.w(TAG, "requestDirectActions(): no activity for " + activityToken);
             callback.sendResult(null);
             return;
         }
         final int lifecycleState = r.getLifecycleState();
         if (lifecycleState < ON_START || lifecycleState >= ON_STOP) {
+            Log.w(TAG, "requestDirectActions(" + r + "): wrong lifecycle: " + lifecycleState);
             callback.sendResult(null);
             return;
         }
diff --git a/core/java/android/app/IUriGrantsManager.aidl b/core/java/android/app/IUriGrantsManager.aidl
index 928c627..9e7f2fe 100644
--- a/core/java/android/app/IUriGrantsManager.aidl
+++ b/core/java/android/app/IUriGrantsManager.aidl
@@ -31,11 +31,12 @@
             in Uri uri, int mode, int sourceUserId, int targetUserId);
     /**
      * Gets the URI permissions granted to an arbitrary package (or all packages if null)
-     * NOTE: this is different from getPersistedUriPermissions(), which returns the URIs the package
+     * NOTE: this is different from getUriPermissions(), which returns the URIs the package
      * granted to another packages (instead of those granted to it).
      */
     ParceledListSlice getGrantedUriPermissions(in String packageName, int userId);
     /** Clears the URI permissions granted to an arbitrary package. */
     void clearGrantedUriPermissions(in String packageName, int userId);
-    ParceledListSlice getPersistedUriPermissions(in String packageName, boolean incoming);
+    ParceledListSlice getUriPermissions(in String packageName, boolean incoming,
+            boolean persistedOnly);
 }
diff --git a/core/java/android/bluetooth/le/ScanFilter.java b/core/java/android/bluetooth/le/ScanFilter.java
index 07ba2c6..038994f 100644
--- a/core/java/android/bluetooth/le/ScanFilter.java
+++ b/core/java/android/bluetooth/le/ScanFilter.java
@@ -590,6 +590,9 @@
         public @NonNull Builder setServiceSolicitationUuid(
                 @Nullable ParcelUuid serviceSolicitationUuid) {
             mServiceSolicitationUuid = serviceSolicitationUuid;
+            if (serviceSolicitationUuid == null) {
+                mServiceSolicitationUuidMask = null;
+            }
             return this;
         }
 
@@ -600,13 +603,16 @@
          * indicate a match is needed for the bit in {@code serviceSolicitationUuid}, and 0 to
          * ignore that bit.
          *
+         * @param serviceSolicitationUuid can only be null if solicitationUuidMask is null.
+         * @param solicitationUuidMask can be null or a mask with no restriction.
+         *
          * @throws IllegalArgumentException If {@code serviceSolicitationUuid} is {@code null} but
          *             {@code serviceSolicitationUuidMask} is not {@code null}.
          */
         public @NonNull Builder setServiceSolicitationUuid(
                 @Nullable ParcelUuid serviceSolicitationUuid,
                 @Nullable ParcelUuid solicitationUuidMask) {
-            if (mServiceSolicitationUuidMask != null && mServiceSolicitationUuid == null) {
+            if (solicitationUuidMask != null && serviceSolicitationUuid == null) {
                 throw new IllegalArgumentException(
                         "SolicitationUuid is null while SolicitationUuidMask is not null!");
             }
diff --git a/core/java/android/content/ContentResolver.java b/core/java/android/content/ContentResolver.java
index 2c5860a..0a1bc85 100644
--- a/core/java/android/content/ContentResolver.java
+++ b/core/java/android/content/ContentResolver.java
@@ -2482,8 +2482,8 @@
      */
     public @NonNull List<UriPermission> getPersistedUriPermissions() {
         try {
-            return UriGrantsManager.getService()
-                    .getPersistedUriPermissions(mPackageName, true).getList();
+            return UriGrantsManager.getService().getUriPermissions(
+                    mPackageName, true /* incoming */, true /* persistedOnly */).getList();
         } catch (RemoteException e) {
             throw e.rethrowFromSystemServer();
         }
@@ -2498,8 +2498,18 @@
      */
     public @NonNull List<UriPermission> getOutgoingPersistedUriPermissions() {
         try {
-            return UriGrantsManager.getService()
-                    .getPersistedUriPermissions(mPackageName, false).getList();
+            return UriGrantsManager.getService().getUriPermissions(
+                    mPackageName, false /* incoming */, true /* persistedOnly */).getList();
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+    }
+
+    /** @hide */
+    public @NonNull List<UriPermission> getOutgoingUriPermissions() {
+        try {
+            return UriGrantsManager.getService().getUriPermissions(
+                    mPackageName, false /* incoming */, false /* persistedOnly */).getList();
         } catch (RemoteException e) {
             throw e.rethrowFromSystemServer();
         }
diff --git a/core/java/android/net/ConnectivityManager.java b/core/java/android/net/ConnectivityManager.java
index a69ca99..3bc40a7 100644
--- a/core/java/android/net/ConnectivityManager.java
+++ b/core/java/android/net/ConnectivityManager.java
@@ -3612,8 +3612,9 @@
      * @param networkCallback The {@link NetworkCallback} to be utilized for this request. Note
      *                        the callback must not be shared - it uniquely specifies this request.
      *                        The callback is invoked on the default internal Handler.
-     * @throws IllegalArgumentException if {@code request} specifies any mutable
-     *         {@code NetworkCapabilities}.
+     * @throws IllegalArgumentException if {@code request} contains invalid network capabilities.
+     * @throws SecurityException if missing the appropriate permissions.
+     * @throws RuntimeException if request limit per UID is exceeded.
      */
     public void requestNetwork(@NonNull NetworkRequest request,
             @NonNull NetworkCallback networkCallback) {
@@ -3648,8 +3649,9 @@
      * @param networkCallback The {@link NetworkCallback} to be utilized for this request. Note
      *                        the callback must not be shared - it uniquely specifies this request.
      * @param handler {@link Handler} to specify the thread upon which the callback will be invoked.
-     * @throws IllegalArgumentException if {@code request} specifies any mutable
-     *         {@code NetworkCapabilities}.
+     * @throws IllegalArgumentException if {@code request} contains invalid network capabilities.
+     * @throws SecurityException if missing the appropriate permissions.
+     * @throws RuntimeException if request limit per UID is exceeded.
      */
     public void requestNetwork(@NonNull NetworkRequest request,
             @NonNull NetworkCallback networkCallback, @NonNull Handler handler) {
@@ -3685,6 +3687,9 @@
      * @param timeoutMs The time in milliseconds to attempt looking for a suitable network
      *                  before {@link NetworkCallback#onUnavailable()} is called. The timeout must
      *                  be a positive value (i.e. >0).
+     * @throws IllegalArgumentException if {@code request} contains invalid network capabilities.
+     * @throws SecurityException if missing the appropriate permissions.
+     * @throws RuntimeException if request limit per UID is exceeded.
      */
     public void requestNetwork(@NonNull NetworkRequest request,
             @NonNull NetworkCallback networkCallback, int timeoutMs) {
@@ -3719,6 +3724,9 @@
      * @param handler {@link Handler} to specify the thread upon which the callback will be invoked.
      * @param timeoutMs The time in milliseconds to attempt looking for a suitable network
      *                  before {@link NetworkCallback#onUnavailable} is called.
+     * @throws IllegalArgumentException if {@code request} contains invalid network capabilities.
+     * @throws SecurityException if missing the appropriate permissions.
+     * @throws RuntimeException if request limit per UID is exceeded.
      */
     public void requestNetwork(@NonNull NetworkRequest request,
             @NonNull NetworkCallback networkCallback, @NonNull Handler handler, int timeoutMs) {
@@ -3789,9 +3797,9 @@
      * @param operation Action to perform when the network is available (corresponds
      *                  to the {@link NetworkCallback#onAvailable} call.  Typically
      *                  comes from {@link PendingIntent#getBroadcast}. Cannot be null.
-     * @throws IllegalArgumentException if {@code request} contains either
-     *         {@link NetworkCapabilities#NET_CAPABILITY_VALIDATED} or
-     *         {@link NetworkCapabilities#NET_CAPABILITY_CAPTIVE_PORTAL}.
+     * @throws IllegalArgumentException if {@code request} contains invalid network capabilities.
+     * @throws SecurityException if missing the appropriate permissions.
+     * @throws RuntimeException if request limit per UID is exceeded.
      */
     public void requestNetwork(@NonNull NetworkRequest request,
             @NonNull PendingIntent operation) {
diff --git a/core/java/android/net/StaticIpConfiguration.java b/core/java/android/net/StaticIpConfiguration.java
index 87f8739..fe42111 100644
--- a/core/java/android/net/StaticIpConfiguration.java
+++ b/core/java/android/net/StaticIpConfiguration.java
@@ -58,15 +58,15 @@
     @Nullable
     public LinkAddress ipAddress;
     /** @hide */
-    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P)
+    @UnsupportedAppUsage
     @Nullable
     public InetAddress gateway;
     /** @hide */
-    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P)
+    @UnsupportedAppUsage
     @NonNull
     public final ArrayList<InetAddress> dnsServers;
     /** @hide */
-    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P)
+    @UnsupportedAppUsage
     @Nullable
     public String domains;
 
diff --git a/core/java/android/provider/DocumentsContract.java b/core/java/android/provider/DocumentsContract.java
index 22ce39d..fd81178 100644
--- a/core/java/android/provider/DocumentsContract.java
+++ b/core/java/android/provider/DocumentsContract.java
@@ -36,7 +36,6 @@
 import android.graphics.ImageDecoder;
 import android.graphics.Point;
 import android.media.ExifInterface;
-import android.media.MediaFile;
 import android.net.Uri;
 import android.os.Build;
 import android.os.Bundle;
@@ -1681,46 +1680,35 @@
     public static AssetFileDescriptor openImageThumbnail(File file) throws FileNotFoundException {
         final ParcelFileDescriptor pfd = ParcelFileDescriptor.open(
                 file, ParcelFileDescriptor.MODE_READ_ONLY);
-        Bundle extras = null;
-
         try {
             final ExifInterface exif = new ExifInterface(file.getAbsolutePath());
 
-            switch (exif.getAttributeInt(ExifInterface.TAG_ORIENTATION, -1)) {
-                case ExifInterface.ORIENTATION_ROTATE_90:
-                    extras = new Bundle(1);
-                    extras.putInt(EXTRA_ORIENTATION, 90);
-                    break;
-                case ExifInterface.ORIENTATION_ROTATE_180:
-                    extras = new Bundle(1);
-                    extras.putInt(EXTRA_ORIENTATION, 180);
-                    break;
-                case ExifInterface.ORIENTATION_ROTATE_270:
-                    extras = new Bundle(1);
-                    extras.putInt(EXTRA_ORIENTATION, 270);
-                    break;
-            }
-
             final long[] thumb = exif.getThumbnailRange();
             if (thumb != null) {
+                // If we use thumb to decode, we need to handle the rotation by ourselves.
+                Bundle extras = null;
+                switch (exif.getAttributeInt(ExifInterface.TAG_ORIENTATION, -1)) {
+                    case ExifInterface.ORIENTATION_ROTATE_90:
+                        extras = new Bundle(1);
+                        extras.putInt(EXTRA_ORIENTATION, 90);
+                        break;
+                    case ExifInterface.ORIENTATION_ROTATE_180:
+                        extras = new Bundle(1);
+                        extras.putInt(EXTRA_ORIENTATION, 180);
+                        break;
+                    case ExifInterface.ORIENTATION_ROTATE_270:
+                        extras = new Bundle(1);
+                        extras.putInt(EXTRA_ORIENTATION, 270);
+                        break;
+                }
+
                 return new AssetFileDescriptor(pfd, thumb[0], thumb[1], extras);
             }
         } catch (IOException e) {
         }
 
-        // Use ImageDecoder to do full image decode of heif format file
-        // will have right orientation. So, we don't need to add orientation
-        // information into extras.
-        final String mimeType = MediaFile.getMimeTypeForFile(file.getName());
-        if (mimeType.equals("image/heif")
-                || mimeType.equals("image/heif-sequence")
-                || mimeType.equals("image/heic")
-                || mimeType.equals("image/heic-sequence")) {
-            return new AssetFileDescriptor(pfd, 0 /* startOffset */,
-                    AssetFileDescriptor.UNKNOWN_LENGTH, null /* extras */);
-        }
-
-        return new AssetFileDescriptor(pfd, 0, AssetFileDescriptor.UNKNOWN_LENGTH, extras);
+        // Do full file decoding, we don't need to handle the orientation
+        return new AssetFileDescriptor(pfd, 0, AssetFileDescriptor.UNKNOWN_LENGTH, null);
     }
 
     private static void rethrowIfNecessary(Exception e) throws FileNotFoundException {
diff --git a/core/java/android/provider/Downloads.java b/core/java/android/provider/Downloads.java
index d507447..9a384c6 100644
--- a/core/java/android/provider/Downloads.java
+++ b/core/java/android/provider/Downloads.java
@@ -849,6 +849,8 @@
     public static final String CALL_MEDIASTORE_DOWNLOADS_DELETED = "mediastore_downloads_deleted";
     /** @hide */
     public static final String CALL_CREATE_EXTERNAL_PUBLIC_DIR = "create_external_public_dir";
+    /** @hide */
+    public static final String CALL_REVOKE_MEDIASTORE_URI_PERMS = "revoke_mediastore_uri_perms";
 
     /** @hide */
     public static final String EXTRA_IDS = "ids";
diff --git a/core/java/android/service/autofill/augmented/AugmentedAutofillService.java b/core/java/android/service/autofill/augmented/AugmentedAutofillService.java
index 87e369f..66c3e19 100644
--- a/core/java/android/service/autofill/augmented/AugmentedAutofillService.java
+++ b/core/java/android/service/autofill/augmented/AugmentedAutofillService.java
@@ -228,7 +228,7 @@
         } else {
             // TODO(b/123099468): figure out if it's ok to reuse the proxy; add logging
             if (sDebug) Log.d(TAG, "Reusing proxy for session " + sessionId);
-            proxy.update(focusedId, focusedValue, callback);
+            proxy.update(focusedId, focusedValue, callback, cancellationSignal);
         }
 
         try {
@@ -252,6 +252,15 @@
                     Log.w(TAG, "No proxy for session " + sessionId);
                     return;
                 }
+                if (proxy.mCallback != null) {
+                    try {
+                        if (!proxy.mCallback.isCompleted()) {
+                            proxy.mCallback.cancel();
+                        }
+                    } catch (Exception e) {
+                        Log.e(TAG, "failed to check current pending request status", e);
+                    }
+                }
                 proxy.destroy();
             }
             mAutofillProxies.clear();
@@ -442,7 +451,7 @@
         }
 
         private void update(@NonNull AutofillId focusedId, @NonNull AutofillValue focusedValue,
-                @NonNull IFillCallback callback) {
+                @NonNull IFillCallback callback, @NonNull CancellationSignal cancellationSignal) {
             synchronized (mLock) {
                 mFocusedId = focusedId;
                 mFocusedValue = focusedValue;
@@ -457,6 +466,7 @@
                     Log.d(TAG, "mCallback is updated.");
                 }
                 mCallback = callback;
+                mCancellationSignal = cancellationSignal;
             }
         }
 
diff --git a/core/java/android/service/notification/Adjustment.java b/core/java/android/service/notification/Adjustment.java
index aa11445..e81ce7f 100644
--- a/core/java/android/service/notification/Adjustment.java
+++ b/core/java/android/service/notification/Adjustment.java
@@ -16,7 +16,6 @@
 package android.service.notification;
 
 import android.annotation.NonNull;
-import android.annotation.Nullable;
 import android.annotation.StringDef;
 import android.annotation.SystemApi;
 import android.annotation.TestApi;
@@ -49,7 +48,6 @@
     private final CharSequence mExplanation;
     private final Bundle mSignals;
     private final int mUser;
-    @Nullable private String mIssuer;
 
     /** @hide */
     @StringDef (prefix = { "KEY_" }, value = {
@@ -185,7 +183,6 @@
         }
         mSignals = in.readBundle();
         mUser = in.readInt();
-        mIssuer = in.readString();
     }
 
     public static final @android.annotation.NonNull Creator<Adjustment> CREATOR = new Creator<Adjustment>() {
@@ -254,7 +251,6 @@
         }
         dest.writeBundle(mSignals);
         dest.writeInt(mUser);
-        dest.writeString(mIssuer);
     }
 
     @Override
@@ -263,14 +259,4 @@
                 + "mSignals=" + mSignals
                 + '}';
     }
-
-    /** @hide */
-    public void setIssuer(@Nullable String issuer) {
-        mIssuer = issuer;
-    }
-
-    /** @hide */
-    public @Nullable String getIssuer() {
-        return mIssuer;
-    }
 }
diff --git a/core/java/android/service/notification/NotificationAssistantService.java b/core/java/android/service/notification/NotificationAssistantService.java
index 3699156..cafeb87 100644
--- a/core/java/android/service/notification/NotificationAssistantService.java
+++ b/core/java/android/service/notification/NotificationAssistantService.java
@@ -236,7 +236,6 @@
     public final void adjustNotification(@NonNull Adjustment adjustment) {
         if (!isBound()) return;
         try {
-            setAdjustmentIssuer(adjustment);
             getNotificationInterface().applyEnqueuedAdjustmentFromAssistant(mWrapper, adjustment);
         } catch (android.os.RemoteException ex) {
             Log.v(TAG, "Unable to contact notification manager", ex);
@@ -254,9 +253,6 @@
     public final void adjustNotifications(@NonNull List<Adjustment> adjustments) {
         if (!isBound()) return;
         try {
-            for (Adjustment adjustment : adjustments) {
-                setAdjustmentIssuer(adjustment);
-            }
             getNotificationInterface().applyAdjustmentsFromAssistant(mWrapper, adjustments);
         } catch (android.os.RemoteException ex) {
             Log.v(TAG, "Unable to contact notification manager", ex);
@@ -370,10 +366,6 @@
         }
     }
 
-    private void setAdjustmentIssuer(Adjustment adjustment) {
-        adjustment.setIssuer(getOpPackageName() + "/" + getClass().getName());
-    }
-
     private final class MyHandler extends Handler {
         public static final int MSG_ON_NOTIFICATION_ENQUEUED = 1;
         public static final int MSG_ON_NOTIFICATION_SNOOZED = 2;
@@ -397,7 +389,6 @@
                     NotificationChannel channel = (NotificationChannel) args.arg2;
                     args.recycle();
                     Adjustment adjustment = onNotificationEnqueued(sbn, channel);
-                    setAdjustmentIssuer(adjustment);
                     if (adjustment != null) {
                         if (!isBound()) {
                             Log.w(TAG, "MSG_ON_NOTIFICATION_ENQUEUED: service not bound, skip.");
diff --git a/core/java/android/text/Emoji.java b/core/java/android/text/Emoji.java
index 876c64e..04fa110 100644
--- a/core/java/android/text/Emoji.java
+++ b/core/java/android/text/Emoji.java
@@ -73,22 +73,20 @@
      * Returns true if the character is a new emoji still not supported in our version of ICU.
      */
     public static boolean isNewEmoji(int c) {
-        // Emoji characters new in Unicode emoji 11
-        // From https://www.unicode.org/Public/emoji/11.0/emoji-data.txt
-        // TODO: Remove once emoji-data.text 11 is in ICU or update to 11.
-        if (c < 0x1F6F9 || c > 0x1F9FF) {
+        // Emoji characters new in Unicode emoji 12
+        // From https://www.unicode.org/Public/emoji/12.0/emoji-data.txt
+        // TODO: Remove once emoji-data.text 12 is in ICU or update to 12.
+        if (c < 0x1F6D5 || c > 0x1FA95) {
             // Optimization for characters outside the new emoji range.
             return false;
         }
-        return c == 0x265F || c == 0x267E || c == 0x1F6F9 || c == 0x1F97A
-                || (0x1F94D <= c && c <= 0x1F94F)
-                || (0x1F96C <= c && c <= 0x1F970)
-                || (0x1F973 <= c && c <= 0x1F976)
-                || (0x1F97C <= c && c <= 0x1F97F)
-                || (0x1F998 <= c && c <= 0x1F9A2)
-                || (0x1F9B0 <= c && c <= 0x1F9B9)
-                || (0x1F9C1 <= c && c <= 0x1F9C2)
-                || (0x1F9E7 <= c && c <= 0x1F9FF);
+        return c == 0x1F6D5 || c == 0x1F6FA || c == 0x1F93F || c == 0x1F971 || c == 0x1F97B
+                || (0x1F7E0 <= c && c <= 0x1F7EB) || (0x1F90D <= c && c <= 0x1F90F)
+                || (0x1F9A5 <= c && c <= 0x1F9AA) || (0x1F9AE <= c && c <= 0x1F9AF)
+                || (0x1F9BA <= c && c <= 0x1F9BF) || (0x1F9C3 <= c && c <= 0x1F9CA)
+                || (0x1F9CD <= c && c <= 0x1F9CF) || (0x1FA70 <= c && c <= 0x1FA73)
+                || (0x1FA78 <= c && c <= 0x1FA7A) || (0x1FA80 <= c && c <= 0x1FA82)
+                || (0x1FA90 <= c && c <= 0x1FA95);
     }
 
     /**
diff --git a/core/java/android/view/RenderNodeAnimator.java b/core/java/android/view/RenderNodeAnimator.java
index c2f9601..93f52a0 100644
--- a/core/java/android/view/RenderNodeAnimator.java
+++ b/core/java/android/view/RenderNodeAnimator.java
@@ -213,7 +213,7 @@
         // it with the final value here.
         if (mRenderProperty == RenderNodeAnimator.ALPHA) {
             mViewTarget.ensureTransformationInfo();
-            mViewTarget.mTransformationInfo.mAlpha = mFinalValue;
+            mViewTarget.setAlphaInternal(mFinalValue);
         }
 
         moveToRunningState();
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index 06d70cd..bf6191e 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -4123,7 +4123,7 @@
          * completely transparent and 1 means completely opaque.
          */
         @ViewDebug.ExportedProperty
-        float mAlpha = 1f;
+        private float mAlpha = 1f;
 
         /**
          * The opacity of the view as manipulated by the Fade transition. This is a
@@ -8852,6 +8852,7 @@
     /**
      * @hide
      */
+    @TestApi
     public boolean isAutofilled() {
         return (mPrivateFlags3 & PFLAG3_IS_AUTOFILLED) != 0;
     }
@@ -16187,7 +16188,7 @@
         return false;
     }
 
-    private void setAlphaInternal(float alpha) {
+    void setAlphaInternal(float alpha) {
         float oldAlpha = mTransformationInfo.mAlpha;
         mTransformationInfo.mAlpha = alpha;
         // Report visibility changes, which can affect children, to accessibility
@@ -21508,23 +21509,27 @@
         }
 
         saveCount = canvas.getSaveCount();
+        int topSaveCount = -1;
+        int bottomSaveCount = -1;
+        int leftSaveCount = -1;
+        int rightSaveCount = -1;
 
         int solidColor = getSolidColor();
         if (solidColor == 0) {
             if (drawTop) {
-                canvas.saveUnclippedLayer(left, top, right, top + length);
+                topSaveCount = canvas.saveUnclippedLayer(left, top, right, top + length);
             }
 
             if (drawBottom) {
-                canvas.saveUnclippedLayer(left, bottom - length, right, bottom);
+                bottomSaveCount = canvas.saveUnclippedLayer(left, bottom - length, right, bottom);
             }
 
             if (drawLeft) {
-                canvas.saveUnclippedLayer(left, top, left + length, bottom);
+                leftSaveCount = canvas.saveUnclippedLayer(left, top, left + length, bottom);
             }
 
             if (drawRight) {
-                canvas.saveUnclippedLayer(right - length, top, right, bottom);
+                rightSaveCount = canvas.saveUnclippedLayer(right - length, top, right, bottom);
             }
         } else {
             scrollabilityCache.setFadeColor(solidColor);
@@ -21541,21 +21546,19 @@
         final Matrix matrix = scrollabilityCache.matrix;
         final Shader fade = scrollabilityCache.shader;
 
-        if (drawTop) {
-            matrix.setScale(1, fadeHeight * topFadeStrength);
-            matrix.postTranslate(left, top);
+        // must be restored in the reverse order that they were saved
+        if (drawRight) {
+            matrix.setScale(1, fadeHeight * rightFadeStrength);
+            matrix.postRotate(90);
+            matrix.postTranslate(right, top);
             fade.setLocalMatrix(matrix);
             p.setShader(fade);
-            canvas.drawRect(left, top, right, top + length, p);
-        }
+            if (solidColor == 0) {
+                canvas.restoreUnclippedLayer(rightSaveCount, p);
 
-        if (drawBottom) {
-            matrix.setScale(1, fadeHeight * bottomFadeStrength);
-            matrix.postRotate(180);
-            matrix.postTranslate(left, bottom);
-            fade.setLocalMatrix(matrix);
-            p.setShader(fade);
-            canvas.drawRect(left, bottom - length, right, bottom, p);
+            } else {
+                canvas.drawRect(right - length, top, right, bottom, p);
+            }
         }
 
         if (drawLeft) {
@@ -21564,16 +21567,36 @@
             matrix.postTranslate(left, top);
             fade.setLocalMatrix(matrix);
             p.setShader(fade);
-            canvas.drawRect(left, top, left + length, bottom, p);
+            if (solidColor == 0) {
+                canvas.restoreUnclippedLayer(leftSaveCount, p);
+            } else {
+                canvas.drawRect(left, top, left + length, bottom, p);
+            }
         }
 
-        if (drawRight) {
-            matrix.setScale(1, fadeHeight * rightFadeStrength);
-            matrix.postRotate(90);
-            matrix.postTranslate(right, top);
+        if (drawBottom) {
+            matrix.setScale(1, fadeHeight * bottomFadeStrength);
+            matrix.postRotate(180);
+            matrix.postTranslate(left, bottom);
             fade.setLocalMatrix(matrix);
             p.setShader(fade);
-            canvas.drawRect(right - length, top, right, bottom, p);
+            if (solidColor == 0) {
+                canvas.restoreUnclippedLayer(bottomSaveCount, p);
+            } else {
+                canvas.drawRect(left, bottom - length, right, bottom, p);
+            }
+        }
+
+        if (drawTop) {
+            matrix.setScale(1, fadeHeight * topFadeStrength);
+            matrix.postTranslate(left, top);
+            fade.setLocalMatrix(matrix);
+            p.setShader(fade);
+            if (solidColor == 0) {
+                canvas.restoreUnclippedLayer(topSaveCount, p);
+            } else {
+                canvas.drawRect(left, top, right, top + length, p);
+            }
         }
 
         canvas.restoreToCount(saveCount);
diff --git a/core/java/android/view/ViewPropertyAnimator.java b/core/java/android/view/ViewPropertyAnimator.java
index afee1e5..957673d 100644
--- a/core/java/android/view/ViewPropertyAnimator.java
+++ b/core/java/android/view/ViewPropertyAnimator.java
@@ -972,7 +972,6 @@
      * @param value The value to set the property to
      */
     private void setValue(int propertyConstant, float value) {
-        final View.TransformationInfo info = mView.mTransformationInfo;
         final RenderNode renderNode = mView.mRenderNode;
         switch (propertyConstant) {
             case TRANSLATION_X:
@@ -1009,7 +1008,7 @@
                 renderNode.setTranslationZ(value - renderNode.getElevation());
                 break;
             case ALPHA:
-                info.mAlpha = value;
+                mView.setAlphaInternal(value);
                 renderNode.setAlpha(value);
                 break;
         }
@@ -1047,7 +1046,7 @@
             case Z:
                 return node.getElevation() + node.getTranslationZ();
             case ALPHA:
-                return mView.mTransformationInfo.mAlpha;
+                return mView.getAlpha();
         }
         return 0;
     }
diff --git a/core/java/android/view/autofill/AutofillManager.java b/core/java/android/view/autofill/AutofillManager.java
index c36b894..1f7ae0e 100644
--- a/core/java/android/view/autofill/AutofillManager.java
+++ b/core/java/android/view/autofill/AutofillManager.java
@@ -1204,10 +1204,6 @@
         AutofillValue value = null;
 
         synchronized (mLock) {
-            if (mForAugmentedAutofillOnly) {
-                if (sVerbose) Log.v(TAG,  "notifyValueChanged(): ignoring on augmented only mode");
-                return;
-            }
             // If the session is gone some fields might still be highlighted, hence we have to
             // remove the isAutofilled property even if no sessions are active.
             if (mLastAutofilledData == null) {
@@ -1229,6 +1225,13 @@
                 }
             }
 
+            if (mForAugmentedAutofillOnly) {
+                if (sVerbose) {
+                    Log.v(TAG,  "notifyValueChanged(): not notifying system server on "
+                            + "augmented-only mode");
+                }
+                return;
+            }
             if (!mEnabled || !isActiveLocked()) {
                 if (sVerbose) {
                     Log.v(TAG, "notifyValueChanged(" + view.getAutofillId()
diff --git a/core/java/com/android/internal/app/ChooserActivity.java b/core/java/com/android/internal/app/ChooserActivity.java
index 5924fb15..a88c51a 100644
--- a/core/java/com/android/internal/app/ChooserActivity.java
+++ b/core/java/com/android/internal/app/ChooserActivity.java
@@ -32,7 +32,6 @@
 import android.app.prediction.AppPredictor;
 import android.app.prediction.AppTarget;
 import android.app.prediction.AppTargetEvent;
-import android.app.prediction.AppTargetId;
 import android.content.ClipData;
 import android.content.ClipboardManager;
 import android.content.ComponentName;
@@ -125,7 +124,9 @@
 import java.util.Arrays;
 import java.util.Collections;
 import java.util.Comparator;
+import java.util.HashMap;
 import java.util.List;
+import java.util.Map;
 
 /**
  * The Chooser Activity handles intent resolution specifically for sharing intents -
@@ -162,6 +163,7 @@
     public static final String APP_PREDICTION_INTENT_FILTER_KEY = "intent_filter";
     private AppPredictor mAppPredictor;
     private AppPredictor.Callback mAppPredictorCallback;
+    private Map<ChooserTarget, AppTarget> mDirectShareAppTargetCache;
 
     /**
      * If set to true, use ShortcutManager to retrieve the matching direct share targets, instead of
@@ -235,7 +237,6 @@
 
     private boolean mListViewDataChanged = false;
 
-
     @Retention(SOURCE)
     @IntDef({CONTENT_PREVIEW_FILE, CONTENT_PREVIEW_IMAGE, CONTENT_PREVIEW_TEXT})
     private @interface ContentPreviewType {
@@ -454,6 +455,7 @@
 
         AppPredictor appPredictor = getAppPredictorForDirectShareIfEnabled();
         if (appPredictor != null) {
+            mDirectShareAppTargetCache = new HashMap<>();
             mAppPredictorCallback = resultList -> {
                 if (isFinishing() || isDestroyed()) {
                     return;
@@ -480,8 +482,7 @@
                             new ComponentName(
                                 appTarget.getPackageName(), appTarget.getClassName())));
                 }
-                sendShareShortcutInfoList(shareShortcutInfos, driList);
-                sendShortcutManagerShareTargetResultCompleted();
+                sendShareShortcutInfoList(shareShortcutInfos, driList, resultList);
             };
             appPredictor
                 .registerPredictionUpdates(this.getMainExecutor(), mAppPredictorCallback);
@@ -1318,13 +1319,14 @@
         AsyncTask.execute(() -> {
             ShortcutManager sm = (ShortcutManager) getSystemService(Context.SHORTCUT_SERVICE);
             List<ShortcutManager.ShareShortcutInfo> resultList = sm.getShareTargets(filter);
-            sendShareShortcutInfoList(resultList, driList);
+            sendShareShortcutInfoList(resultList, driList, null);
         });
     }
 
     private void sendShareShortcutInfoList(
                 List<ShortcutManager.ShareShortcutInfo> resultList,
-                List<DisplayResolveInfo> driList) {
+                List<DisplayResolveInfo> driList,
+                @Nullable List<AppTarget> appTargets) {
         // Match ShareShortcutInfos with DisplayResolveInfos to be able to use the old code path
         // for direct share targets. After ShareSheet is refactored we should use the
         // ShareShortcutInfos directly.
@@ -1334,7 +1336,13 @@
             for (int j = 0; j < resultList.size(); j++) {
                 if (driList.get(i).getResolvedComponentName().equals(
                             resultList.get(j).getTargetComponent())) {
-                    chooserTargets.add(convertToChooserTarget(resultList.get(j)));
+                    ShortcutManager.ShareShortcutInfo shareShortcutInfo = resultList.get(j);
+                    ChooserTarget chooserTarget = convertToChooserTarget(shareShortcutInfo);
+                    chooserTargets.add(chooserTarget);
+                    if (mDirectShareAppTargetCache != null && appTargets != null) {
+                        // Note that appTargets.size() == resultList.size() is always true.
+                        mDirectShareAppTargetCache.put(chooserTarget, appTargets.get(j));
+                    }
                 }
             }
             if (chooserTargets.isEmpty()) {
@@ -1442,33 +1450,25 @@
     }
 
     private void sendClickToAppPredictor(TargetInfo targetInfo) {
-        AppPredictor appPredictor = getAppPredictorForDirectShareIfEnabled();
-        if (appPredictor == null) {
+        AppPredictor directShareAppPredictor = getAppPredictorForDirectShareIfEnabled();
+        if (directShareAppPredictor == null) {
             return;
         }
         if (!(targetInfo instanceof ChooserTargetInfo)) {
             return;
         }
         ChooserTarget chooserTarget = ((ChooserTargetInfo) targetInfo).getChooserTarget();
-        ComponentName componentName = chooserTarget.getComponentName();
-        Bundle extras = chooserTarget.getIntentExtras();
-        if (extras == null) {
-            return;
+        AppTarget appTarget = null;
+        if (mDirectShareAppTargetCache != null) {
+            appTarget = mDirectShareAppTargetCache.get(chooserTarget);
         }
-        String shortcutId = extras.getString(Intent.EXTRA_SHORTCUT_ID);
-        if (shortcutId == null) {
-            return;
+        // This is a direct share click that was provided by the APS
+        if (appTarget != null) {
+            directShareAppPredictor.notifyAppTargetEvent(
+                    new AppTargetEvent.Builder(appTarget, AppTargetEvent.ACTION_LAUNCH)
+                        .setLaunchLocation(LAUNCH_LOCATON_DIRECT_SHARE)
+                        .build());
         }
-        appPredictor.notifyAppTargetEvent(
-                new AppTargetEvent.Builder(
-                    // TODO(b/124404997) Send full shortcut info, not just Id with AppTargetId.
-                    new AppTarget.Builder(new AppTargetId(shortcutId),
-                            componentName.getPackageName(), getUser())
-                        .setClassName(componentName.getClassName())
-                        .build(),
-                    AppTargetEvent.ACTION_LAUNCH)
-                    .setLaunchLocation(LAUNCH_LOCATON_DIRECT_SHARE)
-                    .build());
     }
 
     @Nullable
@@ -2035,7 +2035,8 @@
             return;
         }
 
-        if (mChooserRowAdapter.calculateChooserTargetWidth(right - left)
+        int availableWidth = right - left - v.getPaddingLeft() - v.getPaddingRight();
+        if (mChooserRowAdapter.calculateChooserTargetWidth(availableWidth)
                 || mAdapterView.getAdapter() == null) {
             mAdapterView.setAdapter(mChooserRowAdapter);
 
@@ -2044,7 +2045,9 @@
                     return;
                 }
 
-                int offset = 0;
+                final int bottomInset = mSystemWindowInsets != null
+                                            ? mSystemWindowInsets.bottom : 0;
+                int offset = bottomInset;
                 int rowsToShow = mChooserRowAdapter.getContentPreviewRowCount()
                         + mChooserRowAdapter.getProfileRowCount()
                         + mChooserRowAdapter.getServiceTargetRowCount()
@@ -2059,7 +2062,7 @@
                 // still zero? then use a default height and leave, which
                 // can happen when there are no targets to show
                 if (rowsToShow == 0) {
-                    offset = getResources().getDimensionPixelSize(
+                    offset += getResources().getDimensionPixelSize(
                             R.dimen.chooser_max_collapsed_height);
                     mResolverDrawerLayout.setCollapsibleHeightReserved(offset);
                     return;
@@ -2084,8 +2087,9 @@
                     // make sure to leave room for direct share 4->8 expansion
                     int requiredExpansionHeight =
                             (int) (directShareHeight / DIRECT_SHARE_EXPANSION_RATE);
+                    int topInset = mSystemWindowInsets != null ? mSystemWindowInsets.top : 0;
                     int minHeight = bottom - top - mResolverDrawerLayout.getAlwaysShowHeight()
-                                        - requiredExpansionHeight;
+                                        - requiredExpansionHeight - topInset - bottomInset;
 
                     offset = Math.min(offset, minHeight);
                 }
@@ -2655,7 +2659,7 @@
         @Override
         public boolean isEnabled(int position) {
             int viewType = getItemViewType(position);
-            if (viewType == VIEW_TYPE_CONTENT_PREVIEW) {
+            if (viewType == VIEW_TYPE_CONTENT_PREVIEW || viewType == VIEW_TYPE_AZ_LABEL) {
                 return false;
             }
             return true;
diff --git a/core/java/com/android/internal/app/ResolverActivity.java b/core/java/com/android/internal/app/ResolverActivity.java
index 3ea746d..a5daa0a 100644
--- a/core/java/com/android/internal/app/ResolverActivity.java
+++ b/core/java/com/android/internal/app/ResolverActivity.java
@@ -46,6 +46,7 @@
 import android.graphics.Bitmap;
 import android.graphics.ColorMatrix;
 import android.graphics.ColorMatrixColorFilter;
+import android.graphics.Insets;
 import android.graphics.drawable.BitmapDrawable;
 import android.graphics.drawable.Drawable;
 import android.net.Uri;
@@ -67,12 +68,15 @@
 import android.view.LayoutInflater;
 import android.view.View;
 import android.view.ViewGroup;
+import android.view.ViewGroup.LayoutParams;
+import android.view.WindowInsets;
 import android.widget.AbsListView;
 import android.widget.AdapterView;
 import android.widget.BaseAdapter;
 import android.widget.Button;
 import android.widget.ImageView;
 import android.widget.ListView;
+import android.widget.Space;
 import android.widget.TextView;
 import android.widget.Toast;
 
@@ -136,6 +140,9 @@
 
     private ColorMatrixColorFilter mSuspendedMatrixColorFilter;
 
+    protected Insets mSystemWindowInsets = null;
+    private Space mFooterSpacer = null;
+
     /** See {@link #setRetainInOnStop}. */
     private boolean mRetainInOnStop;
 
@@ -329,6 +336,11 @@
             if (isVoiceInteraction()) {
                 rdl.setCollapsed(false);
             }
+
+            rdl.setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION
+                    | View.SYSTEM_UI_FLAG_LAYOUT_STABLE);
+            rdl.setOnApplyWindowInsetsListener(this::onApplyWindowInsets);
+
             mResolverDrawerLayout = rdl;
         }
 
@@ -364,10 +376,38 @@
         finish();
     }
 
+    protected WindowInsets onApplyWindowInsets(View v, WindowInsets insets) {
+        mSystemWindowInsets = insets.getSystemWindowInsets();
+
+        mResolverDrawerLayout.setPadding(mSystemWindowInsets.left, mSystemWindowInsets.top,
+                mSystemWindowInsets.right, 0);
+
+        View emptyView = findViewById(R.id.empty);
+        emptyView.setPadding(0, 0, 0, mSystemWindowInsets.bottom
+                + getResources().getDimensionPixelSize(
+                        R.dimen.chooser_edge_margin_normal) * 2);
+
+        if (mFooterSpacer == null) {
+            mFooterSpacer = new Space(getApplicationContext());
+        } else {
+            ((ListView) mAdapterView).removeFooterView(mFooterSpacer);
+        }
+        mFooterSpacer.setLayoutParams(new AbsListView.LayoutParams(LayoutParams.MATCH_PARENT,
+                mSystemWindowInsets.bottom));
+        ((ListView) mAdapterView).addFooterView(mFooterSpacer);
+
+        return insets.consumeSystemWindowInsets();
+    }
+
     @Override
     public void onConfigurationChanged(Configuration newConfig) {
         super.onConfigurationChanged(newConfig);
         mAdapter.handlePackagesChanged();
+
+        if (mSystemWindowInsets != null) {
+            mResolverDrawerLayout.setPadding(mSystemWindowInsets.left, mSystemWindowInsets.top,
+                    mSystemWindowInsets.right, 0);
+        }
     }
 
     private void initSuspendedColorMatrix() {
@@ -1277,6 +1317,10 @@
         final ViewGroup buttonLayout = findViewById(R.id.button_bar);
         if (buttonLayout != null) {
             buttonLayout.setVisibility(View.VISIBLE);
+            int inset = mSystemWindowInsets != null ? mSystemWindowInsets.bottom : 0;
+            buttonLayout.setPadding(buttonLayout.getPaddingLeft(), buttonLayout.getPaddingTop(),
+                    buttonLayout.getPaddingRight(), buttonLayout.getPaddingBottom() + inset);
+
             mOnceButton = (Button) buttonLayout.findViewById(R.id.button_once);
             mSettingsButton = (Button) buttonLayout.findViewById(R.id.button_app_settings);
             mAlwaysButton = (Button) buttonLayout.findViewById(R.id.button_always);
diff --git a/core/java/com/android/internal/widget/ResolverDrawerLayout.java b/core/java/com/android/internal/widget/ResolverDrawerLayout.java
index 3adb36f..c73de8f 100644
--- a/core/java/com/android/internal/widget/ResolverDrawerLayout.java
+++ b/core/java/com/android/internal/widget/ResolverDrawerLayout.java
@@ -854,12 +854,11 @@
 
         final int widthSpec = MeasureSpec.makeMeasureSpec(widthSize, MeasureSpec.EXACTLY);
         final int heightSpec = MeasureSpec.makeMeasureSpec(heightSize, MeasureSpec.EXACTLY);
-        final int widthPadding = getPaddingLeft() + getPaddingRight();
 
         // Currently we allot more height than is really needed so that the entirety of the
         // sheet may be pulled up.
         // TODO: Restrict the height here to be the right value.
-        int heightUsed = getPaddingTop() + getPaddingBottom();
+        int heightUsed = 0;
 
         // Measure always-show children first.
         final int childCount = getChildCount();
@@ -869,11 +868,11 @@
             if (lp.alwaysShow && child.getVisibility() != GONE) {
                 if (lp.maxHeight != -1) {
                     final int remainingHeight = heightSize - heightUsed;
-                    measureChildWithMargins(child, widthSpec, widthPadding,
+                    measureChildWithMargins(child, widthSpec, 0,
                             MeasureSpec.makeMeasureSpec(lp.maxHeight, MeasureSpec.AT_MOST),
                             lp.maxHeight > remainingHeight ? lp.maxHeight - remainingHeight : 0);
                 } else {
-                    measureChildWithMargins(child, widthSpec, widthPadding, heightSpec, heightUsed);
+                    measureChildWithMargins(child, widthSpec, 0, heightSpec, heightUsed);
                 }
                 heightUsed += child.getMeasuredHeight();
             }
@@ -889,11 +888,11 @@
             if (!lp.alwaysShow && child.getVisibility() != GONE) {
                 if (lp.maxHeight != -1) {
                     final int remainingHeight = heightSize - heightUsed;
-                    measureChildWithMargins(child, widthSpec, widthPadding,
+                    measureChildWithMargins(child, widthSpec, 0,
                             MeasureSpec.makeMeasureSpec(lp.maxHeight, MeasureSpec.AT_MOST),
                             lp.maxHeight > remainingHeight ? lp.maxHeight - remainingHeight : 0);
                 } else {
-                    measureChildWithMargins(child, widthSpec, widthPadding, heightSpec, heightUsed);
+                    measureChildWithMargins(child, widthSpec, 0, heightSpec, heightUsed);
                 }
                 heightUsed += child.getMeasuredHeight();
             }
diff --git a/core/jni/android_graphics_Canvas.cpp b/core/jni/android_graphics_Canvas.cpp
index 7a8c5c8..ebc6cd7 100644
--- a/core/jni/android_graphics_Canvas.cpp
+++ b/core/jni/android_graphics_Canvas.cpp
@@ -106,6 +106,11 @@
     return reinterpret_cast<jint>(get_canvas(canvasHandle)->saveUnclippedLayer(l, t, r, b));
 }
 
+static void restoreUnclippedLayer(jlong canvasHandle, jint saveCount, jlong paintHandle) {
+    Paint* paint = reinterpret_cast<Paint*>(paintHandle);
+    get_canvas(canvasHandle)->restoreUnclippedLayer(saveCount, *paint);
+}
+
 static bool restore(jlong canvasHandle) {
     Canvas* canvas = get_canvas(canvasHandle);
     if (canvas->getSaveCount() <= 1) {
@@ -668,6 +673,7 @@
     {"nSaveLayer","(JFFFFJI)I", (void*) CanvasJNI::saveLayer},
     {"nSaveLayerAlpha","(JFFFFII)I", (void*) CanvasJNI::saveLayerAlpha},
     {"nSaveUnclippedLayer","(JIIII)I", (void*) CanvasJNI::saveUnclippedLayer},
+    {"nRestoreUnclippedLayer","(JIJ)V", (void*) CanvasJNI::restoreUnclippedLayer},
     {"nGetSaveCount","(J)I", (void*) CanvasJNI::getSaveCount},
     {"nRestore","(J)Z", (void*) CanvasJNI::restore},
     {"nRestoreToCount","(JI)V", (void*) CanvasJNI::restoreToCount},
diff --git a/core/proto/android/app/settings_enums.proto b/core/proto/android/app/settings_enums.proto
index 36eb4c4..4874c41 100644
--- a/core/proto/android/app/settings_enums.proto
+++ b/core/proto/android/app/settings_enums.proto
@@ -2374,6 +2374,12 @@
     // Settings > Apps and notifications > Notifications > Gentle notifications
     GENTLE_NOTIFICATIONS_SCREEN = 1715;
 
+    // OPEN: Settings > Display > Dark Theme
+    // CATEGORY: SETTINGS
+    // OS: Q
+    // Note: Only shows up on first time toggle
+    DIALOG_DARK_UI_INFO = 1740;
+
     // OPEN: Settings > System > Gestures > Global Actions Panel
     // CATEGORY: SETTINGS
     // OS: Q
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index 142e2a4..1c1225b 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -904,9 +904,9 @@
         android:backgroundPermission="android.permission.ACCESS_BACKGROUND_LOCATION"
         android:protectionLevel="dangerous|instant" />
 
-    <!-- Allows an app to access location in the background.  If you
-         are requesting this, you should also request {@link #ACCESS_FINE_LOCATION}.
-         Requesting this by itself is not sufficient to give you
+    <!-- Allows an app to access location in the background. If you're requesting this permission,
+         you must also request either {@link #ACCESS_COARSE_LOCATION} or
+         {@link #ACCESS_FINE_LOCATION}. Requesting this permission by itself doesn't give you
          location access.
          <p>Protection level: dangerous
     -->
diff --git a/core/res/res/values-night/themes_device_defaults.xml b/core/res/res/values-night/themes_device_defaults.xml
index 051f7a0..8ba2c60 100644
--- a/core/res/res/values-night/themes_device_defaults.xml
+++ b/core/res/res/values-night/themes_device_defaults.xml
@@ -58,6 +58,7 @@
         <item name="colorPrimary">@color/primary_dark_device_default_settings</item>
         <item name="colorPrimaryDark">@color/primary_dark_device_default_settings</item>
         <item name="colorBackground">@color/primary_dark_device_default_settings</item>
+        <item name="colorEdgeEffect">@color/edge_effect_device_default_dark</item>
 
         <item name="colorListDivider">@color/list_divider_color_dark</item>
         <item name="opacityListDivider">@color/list_divider_opacity_device_default_dark</item>
@@ -87,5 +88,4 @@
     <style name="Theme.DeviceDefault.Resolver" parent="Theme.DeviceDefault.ResolverCommon">
         <item name="windowLightNavigationBar">false</item>
     </style>
-
 </resources>
diff --git a/core/res/res/values/colors_device_defaults.xml b/core/res/res/values/colors_device_defaults.xml
index c60b399..7a8f411 100644
--- a/core/res/res/values/colors_device_defaults.xml
+++ b/core/res/res/values/colors_device_defaults.xml
@@ -50,8 +50,12 @@
     <color name="list_divider_color_dark">#85ffffff</color>
     <color name="list_divider_opacity_device_default_light">@android:color/white</color>
     <color name="list_divider_opacity_device_default_dark">@android:color/white</color>
-    <color name="loading_gradient_background_color_dark">#2D3033</color>
-    <color name="loading_gradient_background_color_light">#DADCE0</color>
-    <color name="loading_gradient_highlight_color_dark">#3C4043</color>
+
+    <color name="loading_gradient_background_color_dark">#44484C</color>
+    <color name="loading_gradient_background_color_light">#F8F9FA</color>
+    <color name="loading_gradient_highlight_color_dark">#4D5155</color>
     <color name="loading_gradient_highlight_color_light">#F1F3F4</color>
+
+    <color name="edge_effect_device_default_light">@android:color/black</color>
+    <color name="edge_effect_device_default_dark">@android:color/white</color>
 </resources>
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index 0daebd7..2de5397 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -3457,7 +3457,7 @@
 
     <!-- Flag indicating whether the assist disclosure can be disabled using
          ASSIST_DISCLOSURE_ENABLED. -->
-    <bool name="config_allowDisablingAssistDisclosure">false</bool>
+    <bool name="config_allowDisablingAssistDisclosure">true</bool>
 
     <!-- True if the device supports system navigation keys. -->
     <bool name="config_supportSystemNavigationKeys">false</bool>
diff --git a/core/res/res/values/themes_device_defaults.xml b/core/res/res/values/themes_device_defaults.xml
index 2b9321c..6289262 100644
--- a/core/res/res/values/themes_device_defaults.xml
+++ b/core/res/res/values/themes_device_defaults.xml
@@ -1471,7 +1471,7 @@
         <item name="colorSecondary">@color/secondary_device_default_settings_light</item>
         <item name="colorAccent">@color/accent_device_default_light</item>
         <item name="colorError">@color/error_color_device_default_light</item>
-        <item name="colorEdgeEffect">@android:color/black</item>
+        <item name="colorEdgeEffect">@color/edge_effect_device_default_light</item>
 
         <!-- Add white nav bar with divider that matches material -->
         <item name="navigationBarDividerColor">@color/navigation_bar_divider_device_default_settings</item>
@@ -1678,8 +1678,11 @@
         <item name="colorControlActivated">?attr/colorControlHighlight</item>
         <item name="listPreferredItemPaddingStart">?attr/dialogPreferredPadding</item>
         <item name="listPreferredItemPaddingEnd">?attr/dialogPreferredPadding</item>
-        <item name="navigationBarColor">?attr/colorBackgroundFloating</item>
-        <item name="navigationBarDividerColor">@color/chooser_row_divider</item>
+        <item name="navigationBarColor">@android:color/transparent</item>
+    </style>
+
+    <style name="Theme.DeviceDefault.Resolver" parent="Theme.DeviceDefault.ResolverCommon">
+        <item name="windowLightNavigationBar">true</item>
     </style>
 
     <style name="Animation.DeviceDefault.Activity.Resolver" parent="Animation.DeviceDefault.Activity">
@@ -1690,10 +1693,6 @@
         <item name="taskOpenExitAnimation">@anim/resolver_close_anim</item>
     </style>
 
-    <style name="Theme.DeviceDefault.Resolver" parent="Theme.DeviceDefault.ResolverCommon">
-        <item name="windowLightNavigationBar">true</item>
-    </style>
-
     <!-- @hide DeviceDefault themes for the autofill FillUi -->
     <style name="Theme.DeviceDefault.Autofill" />
     <style name="Theme.DeviceDefault.Light.Autofill" />
diff --git a/core/tests/coretests/src/android/text/EmojiTest.java b/core/tests/coretests/src/android/text/EmojiTest.java
index 1948994..7a42731 100644
--- a/core/tests/coretests/src/android/text/EmojiTest.java
+++ b/core/tests/coretests/src/android/text/EmojiTest.java
@@ -40,7 +40,7 @@
 public class EmojiTest {
 
     @Test
-    public void testIsNewEmoji_Emoji5() {
+    public void testIsNewEmoji_Emoji() {
         // each row in the data is the range of emoji
         final int[][][] data = new int[][][]{
                 {       // EMOJI 5
@@ -66,6 +66,24 @@
                         {0x1F9B0, 0x1F9B9},
                         {0x1F9C1, 0x1F9C2},
                         {0x1F9E7, 0x1F9FF},
+                },
+                {       // EMOJI 12
+                        {0x1F6D5, 0x1F6D5},
+                        {0x1F6FA, 0x1F6FA},
+                        {0x1F93F, 0x1F93F},
+                        {0x1F971, 0x1F971},
+                        {0x1F97B, 0x1F97B},
+                        {0x1F7E0, 0x1F7EB},
+                        {0x1F90D, 0x1F90F},
+                        {0x1F9A5, 0x1F9AA},
+                        {0x1F9AE, 0x1F9AF},
+                        {0x1F9BA, 0x1F9BF},
+                        {0x1F9C3, 0x1F9CA},
+                        {0x1F9CD, 0x1F9CF},
+                        {0x1FA70, 0x1FA73},
+                        {0x1FA78, 0x1FA7A},
+                        {0x1FA80, 0x1FA82},
+                        {0x1FA90, 0x1FA95}
                 }
         };
 
diff --git a/data/etc/hiddenapi-package-whitelist.xml b/data/etc/hiddenapi-package-whitelist.xml
index 5cfae11..e24f26c1 100644
--- a/data/etc/hiddenapi-package-whitelist.xml
+++ b/data/etc/hiddenapi-package-whitelist.xml
@@ -55,5 +55,6 @@
   <hidden-api-whitelisted-app package="com.android.storagemanager" />
   <hidden-api-whitelisted-app package="com.android.systemui.plugins" />
   <hidden-api-whitelisted-app package="com.android.terminal" />
+  <hidden-api-whitelisted-app package="com.android.wallpaper" />
   <hidden-api-whitelisted-app package="jp.co.omronsoft.openwnn" />
 </config>
diff --git a/graphics/java/android/graphics/Canvas.java b/graphics/java/android/graphics/Canvas.java
index d4d5ae7..5648b85 100644
--- a/graphics/java/android/graphics/Canvas.java
+++ b/graphics/java/android/graphics/Canvas.java
@@ -559,6 +559,16 @@
     }
 
     /**
+     * @hide
+     * @param saveCount The save level to restore to.
+     * @param paint     This is copied and is applied to the area within the unclipped layer's
+     *                  bounds (i.e. equivalent to a drawPaint()) before restore() is called.
+     */
+    public void restoreUnclippedLayer(int saveCount, Paint paint) {
+        nRestoreUnclippedLayer(mNativeCanvasWrapper, saveCount, paint.getNativeInstance());
+    }
+
+    /**
      * Helper version of saveLayer() that takes 4 values rather than a RectF.
      *
      * As of API Level API level {@value Build.VERSION_CODES#P} the only valid
@@ -1398,6 +1408,9 @@
     @CriticalNative
     private static native int nSaveUnclippedLayer(long nativeCanvas, int l, int t, int r, int b);
     @CriticalNative
+    private static native void nRestoreUnclippedLayer(long nativeCanvas, int saveCount,
+            long nativePaint);
+    @CriticalNative
     private static native boolean nRestore(long canvasHandle);
     @CriticalNative
     private static native void nRestoreToCount(long canvasHandle, int saveCount);
diff --git a/libs/hwui/DisplayListOps.in b/libs/hwui/DisplayListOps.in
index 14e3a32..2deb565 100644
--- a/libs/hwui/DisplayListOps.in
+++ b/libs/hwui/DisplayListOps.in
@@ -26,7 +26,8 @@
 X(ClipRect) 
 X(ClipRRect) 
 X(ClipRegion)
-X(DrawPaint) 
+X(DrawPaint)
+X(DrawBehind)
 X(DrawPath) 
 X(DrawRect) 
 X(DrawRegion) 
diff --git a/libs/hwui/RecordingCanvas.cpp b/libs/hwui/RecordingCanvas.cpp
index 8594766..e58fbbe 100644
--- a/libs/hwui/RecordingCanvas.cpp
+++ b/libs/hwui/RecordingCanvas.cpp
@@ -20,6 +20,7 @@
 
 #include "SkAndroidFrameworkUtils.h"
 #include "SkCanvas.h"
+#include "SkCanvasPriv.h"
 #include "SkData.h"
 #include "SkDrawShadowInfo.h"
 #include "SkImage.h"
@@ -187,6 +188,12 @@
     SkPaint paint;
     void draw(SkCanvas* c, const SkMatrix&) const { c->drawPaint(paint); }
 };
+struct DrawBehind final : Op {
+    static const auto kType = Type::DrawBehind;
+    DrawBehind(const SkPaint& paint) : paint(paint) {}
+    SkPaint paint;
+    void draw(SkCanvas* c, const SkMatrix&) const { SkCanvasPriv::DrawBehind(c, paint); }
+};
 struct DrawPath final : Op {
     static const auto kType = Type::DrawPath;
     DrawPath(const SkPath& path, const SkPaint& paint) : path(path), paint(paint) {}
@@ -565,6 +572,9 @@
 void DisplayListData::drawPaint(const SkPaint& paint) {
     this->push<DrawPaint>(0, paint);
 }
+void DisplayListData::drawBehind(const SkPaint& paint) {
+    this->push<DrawBehind>(0, paint);
+}
 void DisplayListData::drawPath(const SkPath& path, const SkPaint& paint) {
     this->push<DrawPath>(0, path, paint);
 }
@@ -834,6 +844,9 @@
 void RecordingCanvas::onDrawPaint(const SkPaint& paint) {
     fDL->drawPaint(paint);
 }
+void RecordingCanvas::onDrawBehind(const SkPaint& paint) {
+    fDL->drawBehind(paint);
+}
 void RecordingCanvas::onDrawPath(const SkPath& path, const SkPaint& paint) {
     fDL->drawPath(path, paint);
 }
diff --git a/libs/hwui/RecordingCanvas.h b/libs/hwui/RecordingCanvas.h
index 3a76ca1..7269bca 100644
--- a/libs/hwui/RecordingCanvas.h
+++ b/libs/hwui/RecordingCanvas.h
@@ -89,6 +89,7 @@
     void clipRegion(const SkRegion&, SkClipOp);
 
     void drawPaint(const SkPaint&);
+    void drawBehind(const SkPaint&);
     void drawPath(const SkPath&, const SkPaint&);
     void drawRect(const SkRect&, const SkPaint&);
     void drawRegion(const SkRegion&, const SkPaint&);
@@ -157,6 +158,7 @@
     void onClipRegion(const SkRegion&, SkClipOp) override;
 
     void onDrawPaint(const SkPaint&) override;
+    void onDrawBehind(const SkPaint&) override;
     void onDrawPath(const SkPath&, const SkPaint&) override;
     void onDrawRect(const SkRect&, const SkPaint&) override;
     void onDrawRegion(const SkRegion&, const SkPaint&) override;
diff --git a/libs/hwui/SkiaCanvas.cpp b/libs/hwui/SkiaCanvas.cpp
index f328a53..bebda85 100644
--- a/libs/hwui/SkiaCanvas.cpp
+++ b/libs/hwui/SkiaCanvas.cpp
@@ -26,6 +26,7 @@
 
 #include <SkAndroidFrameworkUtils.h>
 #include <SkAnimatedImage.h>
+#include <SkCanvasPriv.h>
 #include <SkCanvasStateUtils.h>
 #include <SkColorFilter.h>
 #include <SkDeque.h>
@@ -191,6 +192,18 @@
     return SkAndroidFrameworkUtils::SaveBehind(mCanvas, &bounds);
 }
 
+void SkiaCanvas::restoreUnclippedLayer(int restoreCount, const SkPaint& paint) {
+
+    while (mCanvas->getSaveCount() > restoreCount + 1) {
+        this->restore();
+    }
+
+    if (mCanvas->getSaveCount() == restoreCount + 1) {
+        SkCanvasPriv::DrawBehind(mCanvas, *filterPaint(paint));
+        this->restore();
+    }
+}
+
 class SkiaCanvas::Clip {
 public:
     Clip(const SkRect& rect, SkClipOp op, const SkMatrix& m)
diff --git a/libs/hwui/SkiaCanvas.h b/libs/hwui/SkiaCanvas.h
index 3fe2bce..bbe91eb 100644
--- a/libs/hwui/SkiaCanvas.h
+++ b/libs/hwui/SkiaCanvas.h
@@ -69,6 +69,7 @@
     virtual int save(SaveFlags::Flags flags) override;
     virtual void restore() override;
     virtual void restoreToCount(int saveCount) override;
+    virtual void restoreUnclippedLayer(int saveCount, const SkPaint& paint) override;
 
     virtual int saveLayer(float left, float top, float right, float bottom, const SkPaint* paint,
                           SaveFlags::Flags flags) override;
diff --git a/libs/hwui/hwui/Canvas.h b/libs/hwui/hwui/Canvas.h
index 11e8579..ac8db21 100644
--- a/libs/hwui/hwui/Canvas.h
+++ b/libs/hwui/hwui/Canvas.h
@@ -191,6 +191,7 @@
     virtual int save(SaveFlags::Flags flags) = 0;
     virtual void restore() = 0;
     virtual void restoreToCount(int saveCount) = 0;
+    virtual void restoreUnclippedLayer(int saveCount, const SkPaint& paint) = 0;
 
     virtual int saveLayer(float left, float top, float right, float bottom, const SkPaint* paint,
                           SaveFlags::Flags flags) = 0;
diff --git a/libs/hwui/pipeline/skia/SkiaPipeline.cpp b/libs/hwui/pipeline/skia/SkiaPipeline.cpp
index ccc1701..1f9ab5a 100644
--- a/libs/hwui/pipeline/skia/SkiaPipeline.cpp
+++ b/libs/hwui/pipeline/skia/SkiaPipeline.cpp
@@ -176,7 +176,7 @@
             // position
             Matrix4 windowTransform;
             damageAccumulator.computeCurrentTransform(&windowTransform);
-            node->getSkiaLayer()->inverseTransformInWindow = windowTransform;
+            node->getSkiaLayer()->inverseTransformInWindow.loadInverse(windowTransform);
         } else {
             String8 cachesOutput;
             mRenderThread.cacheManager().dumpMemoryUsage(cachesOutput,
diff --git a/libs/protoutil/include/android/util/ProtoOutputStream.h b/libs/protoutil/include/android/util/ProtoOutputStream.h
index 60d0318..a6af475 100644
--- a/libs/protoutil/include/android/util/ProtoOutputStream.h
+++ b/libs/protoutil/include/android/util/ProtoOutputStream.h
@@ -19,6 +19,7 @@
 
 #include <cstdint>
 #include <string>
+#include <vector>
 
 #include <android/util/EncodedBuffer.h>
 
@@ -124,6 +125,7 @@
     sp<ProtoReader> data(); // Get the reader apis of the data.
     bool flush(int fd); // Flush data directly to a file descriptor.
     bool serializeToString(std::string* out); // Serializes the proto to a string.
+    bool serializeToVector(std::vector<uint8_t>* out); // Serializes the proto to a vector<uint8_t>.
 
     /**
      * Clears the ProtoOutputStream so the buffer can be reused instead of deallocation/allocation again.
diff --git a/libs/protoutil/src/ProtoOutputStream.cpp b/libs/protoutil/src/ProtoOutputStream.cpp
index 98a68c6..6cfa357 100644
--- a/libs/protoutil/src/ProtoOutputStream.cpp
+++ b/libs/protoutil/src/ProtoOutputStream.cpp
@@ -454,7 +454,6 @@
     if (out == nullptr) return false;
     if (!compact()) return false;
 
-
     sp<ProtoReader> reader = mBuffer->read();
     out->reserve(reader->size());
     while (reader->hasNext()) {
@@ -465,6 +464,23 @@
     return true;
 }
 
+bool
+ProtoOutputStream::serializeToVector(std::vector<uint8_t>* out)
+{
+    if (out == nullptr) return false;
+    if (!compact()) return false;
+
+    sp<ProtoReader> reader = mBuffer->read();
+    out->reserve(reader->size());
+    while (reader->hasNext()) {
+        const uint8_t* buf = reader->readBuffer();
+        size_t size = reader->currentToRead();
+        out->insert(out->end(), buf, buf + size);
+        reader->move(size);
+    }
+    return true;
+}
+
 sp<ProtoReader>
 ProtoOutputStream::data()
 {
diff --git a/libs/protoutil/tests/ProtoOutputStream_test.cpp b/libs/protoutil/tests/ProtoOutputStream_test.cpp
index 6282fd5..9b768b7 100644
--- a/libs/protoutil/tests/ProtoOutputStream_test.cpp
+++ b/libs/protoutil/tests/ProtoOutputStream_test.cpp
@@ -132,6 +132,53 @@
     EXPECT_EQ(primitives.val_enum(), PrimitiveProto_Count_TWO);
 }
 
+TEST(ProtoOutputStreamTest, SerializeToVectorPrimitives) {
+    std::string s = "hello";
+    const char b[5] = { 'a', 'p', 'p', 'l', 'e' };
+
+    ProtoOutputStream proto;
+    EXPECT_TRUE(proto.write(FIELD_TYPE_INT32 | PrimitiveProto::kValInt32FieldNumber, 123));
+    EXPECT_TRUE(proto.write(FIELD_TYPE_INT64 | PrimitiveProto::kValInt64FieldNumber, -1LL));
+    EXPECT_TRUE(proto.write(FIELD_TYPE_FLOAT | PrimitiveProto::kValFloatFieldNumber, -23.5f));
+    EXPECT_TRUE(proto.write(FIELD_TYPE_DOUBLE | PrimitiveProto::kValDoubleFieldNumber, 324.5));
+    EXPECT_TRUE(proto.write(FIELD_TYPE_UINT32 | PrimitiveProto::kValUint32FieldNumber, 3424));
+    EXPECT_TRUE(proto.write(FIELD_TYPE_UINT64 | PrimitiveProto::kValUint64FieldNumber, 57LL));
+    EXPECT_TRUE(proto.write(FIELD_TYPE_FIXED32 | PrimitiveProto::kValFixed32FieldNumber, -20));
+    EXPECT_TRUE(proto.write(FIELD_TYPE_FIXED64 | PrimitiveProto::kValFixed64FieldNumber, -37LL));
+    EXPECT_TRUE(proto.write(FIELD_TYPE_BOOL | PrimitiveProto::kValBoolFieldNumber, true));
+    EXPECT_TRUE(proto.write(FIELD_TYPE_STRING | PrimitiveProto::kValStringFieldNumber, s));
+    EXPECT_TRUE(proto.write(FIELD_TYPE_BYTES | PrimitiveProto::kValBytesFieldNumber, b, 5));
+    EXPECT_TRUE(proto.write(FIELD_TYPE_SFIXED32 | PrimitiveProto::kValSfixed32FieldNumber, 63));
+    EXPECT_TRUE(proto.write(FIELD_TYPE_SFIXED64 | PrimitiveProto::kValSfixed64FieldNumber, -54));
+    EXPECT_TRUE(proto.write(FIELD_TYPE_SINT32 | PrimitiveProto::kValSint32FieldNumber, -533));
+    EXPECT_TRUE(proto.write(FIELD_TYPE_SINT64 | PrimitiveProto::kValSint64FieldNumber, -61224762453LL));
+    EXPECT_TRUE(proto.write(FIELD_TYPE_ENUM | PrimitiveProto::kValEnumFieldNumber, 2));
+
+    PrimitiveProto primitives;
+    std::vector<uint8_t> vec;
+    ASSERT_TRUE(proto.serializeToVector(&vec));
+
+    std::string serialized(vec.data(), vec.data() + vec.size());
+    ASSERT_TRUE(primitives.ParseFromString(serialized));
+
+    EXPECT_EQ(primitives.val_int32(), 123);
+    EXPECT_EQ(primitives.val_int64(), -1);
+    EXPECT_EQ(primitives.val_float(), -23.5f);
+    EXPECT_EQ(primitives.val_double(), 324.5f);
+    EXPECT_EQ(primitives.val_uint32(), 3424);
+    EXPECT_EQ(primitives.val_uint64(), 57);
+    EXPECT_EQ(primitives.val_fixed32(), -20);
+    EXPECT_EQ(primitives.val_fixed64(), -37);
+    EXPECT_EQ(primitives.val_bool(), true);
+    EXPECT_THAT(primitives.val_string(), StrEq(s.c_str()));
+    EXPECT_THAT(primitives.val_bytes(), StrEq("apple"));
+    EXPECT_EQ(primitives.val_sfixed32(), 63);
+    EXPECT_EQ(primitives.val_sfixed64(), -54);
+    EXPECT_EQ(primitives.val_sint32(), -533);
+    EXPECT_EQ(primitives.val_sint64(), -61224762453LL);
+    EXPECT_EQ(primitives.val_enum(), PrimitiveProto_Count_TWO);
+}
+
 TEST(ProtoOutputStreamTest, Complex) {
     std::string name1 = "cat";
     std::string name2 = "dog";
diff --git a/location/java/com/android/internal/location/GpsNetInitiatedHandler.java b/location/java/com/android/internal/location/GpsNetInitiatedHandler.java
index 04e7bab..e890514 100644
--- a/location/java/com/android/internal/location/GpsNetInitiatedHandler.java
+++ b/location/java/com/android/internal/location/GpsNetInitiatedHandler.java
@@ -360,7 +360,7 @@
     /**
      * Posts a notification in the status bar using the contents in {@code notif} object.
      */
-    public synchronized void setNiNotification(GpsNiNotification notif) {
+    private synchronized void setNiNotification(GpsNiNotification notif) {
         NotificationManager notificationManager = (NotificationManager) mContext
                 .getSystemService(Context.NOTIFICATION_SERVICE);
         if (notificationManager == null) {
@@ -541,35 +541,26 @@
      */
     static private String decodeString(String original, boolean isHex, int coding)
     {
-        if (coding == GPS_ENC_NONE) {
+        if (coding == GPS_ENC_NONE || coding == GPS_ENC_UNKNOWN) {
             return original;
         }
 
-        String decoded = original;
         byte[] input = stringToByteArray(original, isHex);
 
         switch (coding) {
-        case GPS_ENC_SUPL_GSM_DEFAULT:
-            decoded = decodeGSMPackedString(input);
-            break;
+            case GPS_ENC_SUPL_GSM_DEFAULT:
+                return decodeGSMPackedString(input);
 
-        case GPS_ENC_SUPL_UTF8:
-            decoded = decodeUTF8String(input);
-            break;
+            case GPS_ENC_SUPL_UTF8:
+                return decodeUTF8String(input);
 
-        case GPS_ENC_SUPL_UCS2:
-            decoded = decodeUCS2String(input);
-            break;
+            case GPS_ENC_SUPL_UCS2:
+                return decodeUCS2String(input);
 
-        case GPS_ENC_UNKNOWN:
-            decoded = original;
-            break;
-
-        default:
-            Log.e(TAG, "Unknown encoding " + coding + " for NI text " + original);
-            break;
+            default:
+                Log.e(TAG, "Unknown encoding " + coding + " for NI text " + original);
+                return original;
         }
-        return decoded;
     }
 
     // change this to configure notification display
diff --git a/media/java/android/media/ThumbnailUtils.java b/media/java/android/media/ThumbnailUtils.java
index b3c2bb7..534d63b 100644
--- a/media/java/android/media/ThumbnailUtils.java
+++ b/media/java/android/media/ThumbnailUtils.java
@@ -265,13 +265,10 @@
             }
         }
 
-        boolean isHeifFile = false;
-
         if (mimeType.equals("image/heif")
                 || mimeType.equals("image/heif-sequence")
                 || mimeType.equals("image/heic")
                 || mimeType.equals("image/heic-sequence")) {
-            isHeifFile = true;
             try (MediaMetadataRetriever retriever = new MediaMetadataRetriever()) {
                 retriever.setDataSource(file.getAbsolutePath());
                 bitmap = retriever.getThumbnailImageAtIndex(-1,
@@ -298,11 +295,8 @@
 
         if (bitmap == null) {
             bitmap = ImageDecoder.decodeBitmap(ImageDecoder.createSource(file), resizer);
-            // Use ImageDecoder to do full image decode of heif format file
-            // will have right orientation. Don't rotate the bitmap again.
-            if (isHeifFile) {
-                return bitmap;
-            }
+            // Use ImageDecoder to do full file decoding, we don't need to handle the orientation
+            return bitmap;
         }
 
         // Transform the bitmap if the orientation of the image is not 0.
diff --git a/packages/BackupRestoreConfirmation/res/values-eu/strings.xml b/packages/BackupRestoreConfirmation/res/values-eu/strings.xml
index ca89aa6..3905a0b 100644
--- a/packages/BackupRestoreConfirmation/res/values-eu/strings.xml
+++ b/packages/BackupRestoreConfirmation/res/values-eu/strings.xml
@@ -18,10 +18,10 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="backup_confirm_title" msgid="827563724209303345">"Babeskopia osoa"</string>
     <string name="restore_confirm_title" msgid="5469365809567486602">"Leheneratze osoa"</string>
-    <string name="backup_confirm_text" msgid="1878021282758896593">"Datu guztien babeskopia egitea eta konektatutako ordenagailu batean gordetzea eskatu da. Horretarako baimena eman nahi duzu?\n\nEz baduzu babeskopia egitea zeuk eskatu, ez eman eragiketarekin jarraitzeko baimena."</string>
+    <string name="backup_confirm_text" msgid="1878021282758896593">"Datu guztien babeskopia egitea eta konektatutako ordenagailu batean gordetzea eskatu da. Horretarako baimena eman nahi duzu?\n\nEz baduzu babeskopia egitea zuk eskatu, ez eman eragiketarekin jarraitzeko baimena."</string>
     <string name="allow_backup_button_label" msgid="4217228747769644068">"Egin datuen babeskopia"</string>
     <string name="deny_backup_button_label" msgid="6009119115581097708">"Ez egin babeskopia"</string>
-    <string name="restore_confirm_text" msgid="7499866728030461776">"Konektatutako ordenagailu bateko datu guztiak leheneratzeko eskatu da. Horretarako baimena eman nahi duzu?\n\nEz baduzu leheneratzea zeuk eskatu, ez eman eragiketarekin jarraitzeko baimena. Eragiketa gauzatzen bada, gailuan dituzun datu guztiak ordeztuko dira!"</string>
+    <string name="restore_confirm_text" msgid="7499866728030461776">"Konektatutako ordenagailu bateko datu guztiak leheneratzeko eskatu da. Horretarako baimena eman nahi duzu?\n\nEz baduzu leheneratzea zuk eskatu, ez eman eragiketarekin jarraitzeko baimena. Eragiketa gauzatzen bada, gailuan dituzun datu guztiak ordeztuko dira!"</string>
     <string name="allow_restore_button_label" msgid="3081286752277127827">"Leheneratu datuak"</string>
     <string name="deny_restore_button_label" msgid="1724367334453104378">"Ez leheneratu"</string>
     <string name="current_password_text" msgid="8268189555578298067">"Idatzi babeskopien uneko pasahitza behean:"</string>
diff --git a/packages/BackupRestoreConfirmation/res/values-hi/strings.xml b/packages/BackupRestoreConfirmation/res/values-hi/strings.xml
index ae9e7c3..2e53cb6 100644
--- a/packages/BackupRestoreConfirmation/res/values-hi/strings.xml
+++ b/packages/BackupRestoreConfirmation/res/values-hi/strings.xml
@@ -16,8 +16,8 @@
 
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="backup_confirm_title" msgid="827563724209303345">"पूर्ण सुरक्षा"</string>
-    <string name="restore_confirm_title" msgid="5469365809567486602">"पूर्ण पुनर्स्‍थापना"</string>
+    <string name="backup_confirm_title" msgid="827563724209303345">"पूरा बैकअप"</string>
+    <string name="restore_confirm_title" msgid="5469365809567486602">"पूरी तरह से पुनर्स्‍थापना"</string>
     <string name="backup_confirm_text" msgid="1878021282758896593">"कनेक्‍ट कि‍ए गए डेस्‍कटॉप कंप्‍यूटर से पूरे डेटा के बैकअप का अनुरोध कि‍या गया है. क्‍या आप इसकी अनुमति‍ देना चाहते हैं?\n\nअगर आपने बैकअप का अनुरोध नहीं कि‍या है, तो इस प्रक्रि‍या को जारी रखने की अनुमति‍ न दें."</string>
     <string name="allow_backup_button_label" msgid="4217228747769644068">"मेरे डेटा का बैकअप लें"</string>
     <string name="deny_backup_button_label" msgid="6009119115581097708">"बैकअप न लें"</string>
@@ -32,7 +32,7 @@
     <string name="backup_enc_password_required" msgid="7889652203371654149">"चूंकि आपका डिवाइस एन्क्रिप्ट किया हुआ है, इसलिए आपको अपने बैकअप को एन्क्रिप्ट करना आवश्यक है. कृपया नीचे पासवर्ड डालें:"</string>
     <string name="restore_enc_password_text" msgid="6140898525580710823">"अगर रिस्टोर किया गया डेटा सुरक्षित कि‍या गया है, तो कृपया नीचे पासवर्ड डालें:"</string>
     <string name="toast_backup_started" msgid="550354281452756121">"सुरक्षित करना शुरु हो रहा है..."</string>
-    <string name="toast_backup_ended" msgid="3818080769548726424">"सुरक्षित करना पूर्ण"</string>
+    <string name="toast_backup_ended" msgid="3818080769548726424">"बैकअप करना पूरा हुआ"</string>
     <string name="toast_restore_started" msgid="7881679218971277385">"पुनर्स्‍थापना प्रारंभ हो रही है..."</string>
     <string name="toast_restore_ended" msgid="1764041639199696132">"पुनर्स्‍थापना खत्म"</string>
     <string name="toast_timeout" msgid="5276598587087626877">"काम नहीं हो सका. टाइम आउट हो गया"</string>
diff --git a/packages/CaptivePortalLogin/res/values-bs/strings.xml b/packages/CaptivePortalLogin/res/values-bs/strings.xml
index 60c153a..83b5067 100644
--- a/packages/CaptivePortalLogin/res/values-bs/strings.xml
+++ b/packages/CaptivePortalLogin/res/values-bs/strings.xml
@@ -18,7 +18,7 @@
     <string name="ssl_error_unknown" msgid="4405203446079465859">"Nepoznata greška potvrde."</string>
     <string name="ssl_security_warning_title" msgid="8768539813847504404">"Sigurnosno upozorenje"</string>
     <string name="ssl_error_view_certificate" msgid="5722652540168339333">"Prikaži potvrdu"</string>
-    <string name="ok" msgid="2817931639040794018">"UREDU"</string>
+    <string name="ok" msgid="2817931639040794018">"Uredu"</string>
     <string name="page_info_address" msgid="1261481517455692363">"Adresa:"</string>
     <string name="page_info" msgid="4416941086705172545">"Informacije o stranici"</string>
 </resources>
diff --git a/packages/CarSystemUI/res/layout/car_ongoing_privacy_chip.xml b/packages/CarSystemUI/res/layout/car_ongoing_privacy_chip.xml
new file mode 100644
index 0000000..918abd9
--- /dev/null
+++ b/packages/CarSystemUI/res/layout/car_ongoing_privacy_chip.xml
@@ -0,0 +1,37 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+     Copyright (C) 2019 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.
+-->
+
+<com.android.systemui.statusbar.car.privacy.OngoingPrivacyChip
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:id="@+id/car_privacy_chip"
+    android:layout_width="wrap_content"
+    android:layout_height="match_parent"
+    android:layout_margin="@dimen/ongoing_appops_chip_margin"
+    android:layout_toStartOf="@+id/clock_container"
+    android:focusable="true"
+    android:gravity="center_vertical|end"
+    android:orientation="horizontal"
+    android:paddingEnd="@dimen/ongoing_appops_chip_side_padding"
+    android:paddingStart="@dimen/ongoing_appops_chip_side_padding"
+    android:visibility="visible">
+
+    <LinearLayout
+        android:id="@+id/icons_container"
+        android:layout_width="wrap_content"
+        android:layout_height="match_parent"
+        android:gravity="center_vertical|start"/>
+</com.android.systemui.statusbar.car.privacy.OngoingPrivacyChip>
\ No newline at end of file
diff --git a/packages/CarSystemUI/res/layout/car_top_navigation_bar.xml b/packages/CarSystemUI/res/layout/car_top_navigation_bar.xml
index 925ccb4..cae89c1 100644
--- a/packages/CarSystemUI/res/layout/car_top_navigation_bar.xml
+++ b/packages/CarSystemUI/res/layout/car_top_navigation_bar.xml
@@ -65,6 +65,8 @@
             />
         </FrameLayout>
 
+        <include layout="@layout/car_ongoing_privacy_chip"/>
+
         <FrameLayout
             android:id="@+id/clock_container"
             android:layout_width="wrap_content"
diff --git a/packages/CarSystemUI/res/values/dimens.xml b/packages/CarSystemUI/res/values/dimens.xml
index 0358357b..7027ce3 100644
--- a/packages/CarSystemUI/res/values/dimens.xml
+++ b/packages/CarSystemUI/res/values/dimens.xml
@@ -59,6 +59,16 @@
     <dimen name="car_keyline_1">24dp</dimen>
     <dimen name="car_keyline_2">96dp</dimen>
     <dimen name="car_keyline_3">128dp</dimen>
+    <dimen name="privacy_chip_icon_height">36dp</dimen>
+    <dimen name="privacy_chip_icon_padding_left">0dp</dimen>
+    <dimen name="privacy_chip_icon_padding_right">0dp</dimen>
+    <dimen name="privacy_chip_icon_padding_top">0dp</dimen>
+    <dimen name="privacy_chip_icon_padding_bottom">0dp</dimen>
+
+    <dimen name="privacy_chip_text_padding_left">0dp</dimen>
+    <dimen name="privacy_chip_text_padding_right">0dp</dimen>
+    <dimen name="privacy_chip_text_padding_top">0dp</dimen>
+    <dimen name="privacy_chip_text_padding_bottom">0dp</dimen>
 
     <dimen name="privacy_chip_icon_max_height">100dp</dimen>
 
@@ -76,6 +86,16 @@
     <dimen name="ongoing_appops_chip_bg_padding">4dp</dimen>
     <!-- Radius of Ongoing App Ops chip corners -->
     <dimen name="ongoing_appops_chip_bg_corner_radius">12dp</dimen>
+    <!-- Start padding for the app icon displayed in the dialog -->
+    <dimen name="privacy_dialog_app_icon_padding_start">40dp</dimen>
+    <!-- End padding for the app opps icon displayed in the dialog -->
+    <dimen name="privacy_dialog_app_ops_icon_padding_end">40dp</dimen>
+    <!-- Top padding for the list of application displayed in the dialog -->
+    <dimen name="privacy_dialog_app_list_padding_top">20dp</dimen>
+    <!-- Top padding for the dialog container-->
+    <dimen name="privacy_dialog_container_padding_top">10dp</dimen>
+    <!-- Top padding for the dialog title-->
+    <dimen name="privacy_dialog_title_padding_start">10dp</dimen>
 
     <!-- Car volume dimens. -->
     <dimen name="car_volume_item_height">@*android:dimen/car_single_line_list_item_height</dimen>
diff --git a/packages/CarSystemUI/src/com/android/systemui/statusbar/car/privacy/OngoingPrivacyChip.java b/packages/CarSystemUI/src/com/android/systemui/statusbar/car/privacy/OngoingPrivacyChip.java
new file mode 100644
index 0000000..ead1de2
--- /dev/null
+++ b/packages/CarSystemUI/src/com/android/systemui/statusbar/car/privacy/OngoingPrivacyChip.java
@@ -0,0 +1,228 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.statusbar.car.privacy;
+
+import android.app.ActivityManager;
+import android.app.AppOpsManager;
+import android.content.Context;
+import android.content.Intent;
+import android.os.Handler;
+import android.os.Looper;
+import android.os.UserHandle;
+import android.os.UserManager;
+import android.util.AttributeSet;
+import android.view.View;
+import android.widget.ImageView;
+import android.widget.LinearLayout;
+
+import com.android.systemui.Dependency;
+import com.android.systemui.R;
+import com.android.systemui.appops.AppOpItem;
+import com.android.systemui.appops.AppOpsController;
+import com.android.systemui.plugins.ActivityStarter;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Objects;
+import java.util.stream.Collectors;
+
+/**
+ * Layout defining the privacy chip that will be displayed in CarStatusRar with the information for
+ * which applications are using AppOpps permission fpr camera, mic and location.
+ */
+public class OngoingPrivacyChip extends LinearLayout implements View.OnClickListener {
+
+    private Context mContext;
+
+    private LinearLayout mIconsContainer;
+    private List<PrivacyItem> mPrivacyItems;
+    private static AppOpsController sAppOpsController;
+    private UserManager mUserManager;
+    private int mCurrentUser;
+    private List<Integer> mCurrentUserIds;
+    private boolean mListening = false;
+    PrivacyDialogBuilder mPrivacyDialogBuilder;
+    private LinearLayout mPrivacyChip;
+    private ActivityStarter mActivityStarter;
+
+    protected static final int[] OPS = new int[]{
+            AppOpsManager.OP_CAMERA,
+            AppOpsManager.OP_RECORD_AUDIO,
+            AppOpsManager.OP_COARSE_LOCATION,
+            AppOpsManager.OP_FINE_LOCATION
+    };
+
+    public OngoingPrivacyChip(Context context) {
+        super(context, null);
+        init(context);
+    }
+
+    public OngoingPrivacyChip(Context context, AttributeSet attr) {
+        super(context, attr);
+        init(context);
+    }
+
+    public OngoingPrivacyChip(Context context, AttributeSet attr, int defStyle) {
+        super(context, attr, defStyle);
+        init(context);
+    }
+
+    public OngoingPrivacyChip(Context context, AttributeSet attr, int defStyle, int a) {
+        super(context, attr, defStyle, a);
+        init(context);
+    }
+
+    private void init(Context context) {
+        mContext = context;
+        mPrivacyItems = new ArrayList<>();
+        sAppOpsController = Dependency.get(AppOpsController.class);
+        mUserManager = mContext.getSystemService(UserManager.class);
+        mActivityStarter = Dependency.get(ActivityStarter.class);
+        mCurrentUser = ActivityManager.getCurrentUser();
+        mCurrentUserIds = mUserManager.getProfiles(mCurrentUser).stream().map(
+                userInfo -> userInfo.id).collect(Collectors.toList());
+
+        mPrivacyDialogBuilder = new PrivacyDialogBuilder(context, mPrivacyItems);
+    }
+
+    private AppOpsController.Callback mCallback = new AppOpsController.Callback() {
+
+        @Override
+        public void onActiveStateChanged(int code, int uid, String packageName, boolean active) {
+            int userId = UserHandle.getUserId(uid);
+            if (mCurrentUserIds.contains(userId)) {
+                updatePrivacyList();
+            }
+        }
+    };
+
+    @Override
+    public void onFinishInflate() {
+        mIconsContainer = findViewById(R.id.icons_container);
+        mPrivacyChip = (LinearLayout) findViewById(R.id.car_privacy_chip);
+        if (mPrivacyChip != null) {
+            mPrivacyChip.setOnClickListener(this);
+            setListening(true);
+        }
+    }
+
+    @Override
+    public void onDetachedFromWindow() {
+        if (mPrivacyChip != null) {
+            setListening(false);
+        }
+        super.onDetachedFromWindow();
+    }
+
+    @Override
+    public void onClick(View v) {
+        updatePrivacyList();
+        Handler mUiHandler = new Handler(Looper.getMainLooper());
+        mUiHandler.post(() -> {
+            mActivityStarter.postStartActivityDismissingKeyguard(
+                    new Intent(Intent.ACTION_REVIEW_ONGOING_PERMISSION_USAGE), 0);
+        });
+    }
+
+    private void setListening(boolean listen) {
+        if (mListening == listen) {
+            return;
+        }
+        mListening = listen;
+        if (mListening) {
+            sAppOpsController.addCallback(OPS, mCallback);
+            updatePrivacyList();
+        } else {
+            sAppOpsController.removeCallback(OPS, mCallback);
+        }
+    }
+
+    private void updatePrivacyList() {
+        mPrivacyItems = mCurrentUserIds.stream()
+                .flatMap(item -> sAppOpsController.getActiveAppOpsForUser(item).stream())
+                .filter(Objects::nonNull)
+                .map(item -> toPrivacyItem(item))
+                .filter(Objects::nonNull)
+                .collect(Collectors.toList());
+        mPrivacyDialogBuilder = new PrivacyDialogBuilder(mContext, mPrivacyItems);
+
+        Handler refresh = new Handler(Looper.getMainLooper());
+        refresh.post(new Runnable() {
+            @Override
+            public void run() {
+                updateView();
+            }
+        });
+    }
+
+    private PrivacyItem toPrivacyItem(AppOpItem appOpItem) {
+        PrivacyType type;
+        switch (appOpItem.getCode()) {
+            case AppOpsManager.OP_CAMERA:
+                type = PrivacyType.TYPE_CAMERA;
+                break;
+            case AppOpsManager.OP_COARSE_LOCATION:
+                type = PrivacyType.TYPE_LOCATION;
+                break;
+            case AppOpsManager.OP_FINE_LOCATION:
+                type = PrivacyType.TYPE_LOCATION;
+                break;
+            case AppOpsManager.OP_RECORD_AUDIO:
+                type = PrivacyType.TYPE_MICROPHONE;
+                break;
+            default:
+                return null;
+        }
+        PrivacyApplication app = new PrivacyApplication(appOpItem.getPackageName(), mContext);
+        return new PrivacyItem(type, app, appOpItem.getTimeStarted());
+    }
+
+    // Should only be called if the mPrivacyDialogBuilder icons or app changed
+    private void updateView() {
+        if (mPrivacyItems.isEmpty()) {
+            mPrivacyChip.setVisibility(GONE);
+            return;
+        }
+        mPrivacyChip.setVisibility(VISIBLE);
+        setIcons(mPrivacyDialogBuilder);
+
+        requestLayout();
+    }
+
+    private void setIcons(PrivacyDialogBuilder dialogBuilder) {
+        mIconsContainer.removeAllViews();
+        dialogBuilder.generateIcons().forEach(item -> {
+            int size = mContext.getResources().getDimensionPixelSize(
+                    R.dimen.privacy_chip_icon_height);
+            ImageView image = new ImageView(mContext);
+            image.setImageDrawable(item);
+            LinearLayout.LayoutParams layoutParams = new LinearLayout.LayoutParams(size, size);
+
+            int leftPadding = mContext.getResources().getDimensionPixelSize(
+                    R.dimen.privacy_chip_icon_padding_left);
+            int topPadding = mContext.getResources().getDimensionPixelSize(
+                    R.dimen.privacy_chip_icon_padding_top);
+            int rightPadding = mContext.getResources().getDimensionPixelSize(
+                    R.dimen.privacy_chip_icon_padding_right);
+            int bottomPadding = mContext.getResources().getDimensionPixelSize(
+                    R.dimen.privacy_chip_icon_padding_bottom);
+            image.setLayoutParams(layoutParams);
+            image.setPadding(leftPadding, topPadding, rightPadding, bottomPadding);
+            mIconsContainer.addView(image);
+        });
+    }
+}
diff --git a/packages/CarSystemUI/src/com/android/systemui/statusbar/car/privacy/PrivacyApplication.java b/packages/CarSystemUI/src/com/android/systemui/statusbar/car/privacy/PrivacyApplication.java
new file mode 100644
index 0000000..5ec7a77
--- /dev/null
+++ b/packages/CarSystemUI/src/com/android/systemui/statusbar/car/privacy/PrivacyApplication.java
@@ -0,0 +1,62 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.statusbar.car.privacy;
+
+import android.car.userlib.CarUserManagerHelper;
+import android.content.Context;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.PackageManager;
+import android.graphics.drawable.Drawable;
+import android.util.Log;
+
+/**
+ * Class to hold the data for the applications that are using the AppOps permissions.
+ */
+public class PrivacyApplication {
+    private static final String TAG = "PrivacyApplication";
+
+    private Drawable mIcon;
+    private String mApplicationName;
+
+    public PrivacyApplication(String packageName, Context context) {
+        try {
+            CarUserManagerHelper carUserManagerHelper = new CarUserManagerHelper(context);
+            ApplicationInfo app = context.getPackageManager()
+                    .getApplicationInfoAsUser(packageName, 0,
+                            carUserManagerHelper.getCurrentForegroundUserId());
+            mIcon = context.getPackageManager().getApplicationIcon(app);
+            mApplicationName = context.getPackageManager().getApplicationLabel(app).toString();
+        } catch (PackageManager.NameNotFoundException e) {
+            mApplicationName = packageName;
+            Log.e(TAG, "Failed to to find package name", e);
+        }
+    }
+
+    /**
+     * Gets the application name.
+     */
+    public Drawable getIcon() {
+        return mIcon;
+    }
+
+    /**
+     * Gets the application name.
+     */
+    public String getApplicationName() {
+        return mApplicationName;
+    }
+}
diff --git a/packages/CarSystemUI/src/com/android/systemui/statusbar/car/privacy/PrivacyDialogBuilder.java b/packages/CarSystemUI/src/com/android/systemui/statusbar/car/privacy/PrivacyDialogBuilder.java
new file mode 100644
index 0000000..3b83e7c
--- /dev/null
+++ b/packages/CarSystemUI/src/com/android/systemui/statusbar/car/privacy/PrivacyDialogBuilder.java
@@ -0,0 +1,59 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.statusbar.car.privacy;
+
+import android.content.Context;
+import android.graphics.drawable.Drawable;
+
+import java.util.List;
+import java.util.Map;
+import java.util.Objects;
+import java.util.stream.Collectors;
+
+/**
+ * Helper class to build the {@link OngoingPrivacyDialog}
+ */
+public class PrivacyDialogBuilder {
+
+    private Map<PrivacyType, List<PrivacyItem>> mItemsByType;
+    private PrivacyApplication mApplication;
+    private Context mContext;
+
+    public PrivacyDialogBuilder(Context context, List<PrivacyItem> itemsList) {
+        mContext = context;
+        mItemsByType = itemsList.stream().filter(Objects::nonNull).collect(
+                Collectors.groupingBy(PrivacyItem::getPrivacyType));
+        List<PrivacyApplication> apps = itemsList.stream().filter(Objects::nonNull).map(
+                PrivacyItem::getPrivacyApplication).distinct().collect(Collectors.toList());
+        mApplication = apps.size() == 1 ? apps.get(0) : null;
+    }
+
+    /**
+     * Gets the icon id for all the {@link PrivacyItem} in the same order as of itemList.
+     */
+    public List<Drawable> generateIcons() {
+        return mItemsByType.keySet().stream().map(item -> item.getIconId(mContext)).collect(
+                Collectors.toList());
+    }
+
+    /**
+     * Gets the application object.
+     */
+    public PrivacyApplication getApplication() {
+        return mApplication;
+    }
+}
diff --git a/packages/CarSystemUI/src/com/android/systemui/statusbar/car/privacy/PrivacyItem.java b/packages/CarSystemUI/src/com/android/systemui/statusbar/car/privacy/PrivacyItem.java
new file mode 100644
index 0000000..fca1373
--- /dev/null
+++ b/packages/CarSystemUI/src/com/android/systemui/statusbar/car/privacy/PrivacyItem.java
@@ -0,0 +1,46 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.statusbar.car.privacy;
+
+/**
+ * Class for holding the data of each privacy item displayed in {@link OngoingPrivacyDialog}
+ */
+public class PrivacyItem {
+
+    private PrivacyType mPrivacyType;
+    private PrivacyApplication mPrivacyApplication;
+
+    public PrivacyItem(PrivacyType privacyType, PrivacyApplication privacyApplication,
+            long timeStarted) {
+        this.mPrivacyType = privacyType;
+        this.mPrivacyApplication = privacyApplication;
+    }
+
+    /**
+     * Gets the application object.
+     */
+    public PrivacyApplication getPrivacyApplication() {
+        return mPrivacyApplication;
+    }
+
+    /**
+     * Gets the privacy type for the application.
+     */
+    public PrivacyType getPrivacyType() {
+        return mPrivacyType;
+    }
+}
diff --git a/packages/CarSystemUI/src/com/android/systemui/statusbar/car/privacy/PrivacyType.java b/packages/CarSystemUI/src/com/android/systemui/statusbar/car/privacy/PrivacyType.java
new file mode 100644
index 0000000..8955c87
--- /dev/null
+++ b/packages/CarSystemUI/src/com/android/systemui/statusbar/car/privacy/PrivacyType.java
@@ -0,0 +1,53 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.statusbar.car.privacy;
+
+import android.content.Context;
+import android.graphics.drawable.Drawable;
+
+import com.android.systemui.R;
+
+/**
+ * Enum for storing data for camera, mic and location.
+ */
+public enum PrivacyType {
+    TYPE_CAMERA(R.string.privacy_type_camera, com.android.internal.R.drawable.ic_camera),
+    TYPE_LOCATION(R.string.privacy_type_location, R.drawable.stat_sys_location),
+    TYPE_MICROPHONE(R.string.privacy_type_microphone, R.drawable.ic_mic_white);
+
+    private int mNameId;
+    private int mIconId;
+
+    PrivacyType(int nameId, int iconId) {
+        mNameId = nameId;
+        mIconId = iconId;
+    }
+
+    /**
+     * Get the icon Id.
+     */
+    public Drawable getIconId(Context context) {
+        return context.getResources().getDrawable(mIconId, null);
+    }
+
+    /**
+     * Get the name Id.
+     */
+    public String getNameId(Context context) {
+        return context.getResources().getString(mNameId);
+    }
+}
diff --git a/packages/ExtServices/src/android/ext/services/notification/Assistant.java b/packages/ExtServices/src/android/ext/services/notification/Assistant.java
index 69aa0f9..d01878a 100644
--- a/packages/ExtServices/src/android/ext/services/notification/Assistant.java
+++ b/packages/ExtServices/src/android/ext/services/notification/Assistant.java
@@ -30,11 +30,9 @@
 import android.app.NotificationChannel;
 import android.content.Context;
 import android.content.pm.IPackageManager;
-import android.ext.services.notification.AgingHelper.Callback;
 import android.os.AsyncTask;
 import android.os.Bundle;
 import android.os.Environment;
-import android.os.SystemProperties;
 import android.os.UserHandle;
 import android.os.storage.StorageManager;
 import android.service.notification.Adjustment;
@@ -76,8 +74,6 @@
 public class Assistant extends NotificationAssistantService {
     private static final String TAG = "ExtAssistant";
     private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
-    public static final boolean AGE_NOTIFICATIONS = SystemProperties.getBoolean(
-            "debug.age_notifs", false);
 
     private static final String TAG_ASSISTANT = "assistant";
     private static final String TAG_IMPRESSION = "impression-set";
@@ -94,7 +90,6 @@
 
     private SmartActionsHelper mSmartActionsHelper;
     private NotificationCategorizer mNotificationCategorizer;
-    private AgingHelper mAgingHelper;
 
     // key : impressions tracker
     // TODO: prune deleted channels and apps
@@ -125,9 +120,6 @@
                 getApplicationContext().getContentResolver(), getUserId(), this::updateThresholds);
         mSmartActionsHelper = new SmartActionsHelper(getContext(), mSettings);
         mNotificationCategorizer = new NotificationCategorizer();
-        mAgingHelper = new AgingHelper(getContext(),
-                mNotificationCategorizer,
-                new AgingCallback());
         mSmsHelper = new SmsHelper(this);
         mSmsHelper.initialize();
     }
@@ -313,7 +305,6 @@
                             sbn.getPackageName(), sbn.getKey(), sbn.getUserId()));
                 }
                 mLiveNotifications.put(sbn.getKey(), entry);
-                mAgingHelper.onNotificationPosted(entry);
             }
         } catch (Throwable e) {
             Log.e(TAG, "Error occurred processing post", e);
@@ -328,8 +319,6 @@
                 return;
             }
 
-            mAgingHelper.onNotificationRemoved(sbn.getKey());
-
             boolean updatedImpressions = false;
             String channelId = mLiveNotifications.remove(sbn.getKey()).getChannel().getId();
             String key = getKey(sbn.getPackageName(), sbn.getUserId(), channelId);
@@ -374,22 +363,6 @@
 
     @Override
     public void onNotificationsSeen(List<String> keys) {
-        try {
-            if (keys == null) {
-                return;
-            }
-
-            for (String key : keys) {
-                NotificationEntry entry = mLiveNotifications.get(key);
-
-                if (entry != null) {
-                    entry.setSeen();
-                    mAgingHelper.onNotificationSeen(entry);
-                }
-            }
-        } catch (Throwable e) {
-            Slog.e(TAG, "Error occurred processing seen", e);
-        }
     }
 
     @Override
@@ -456,9 +429,6 @@
 
     @Override
     public void onListenerDisconnected() {
-        if (mAgingHelper != null) {
-            mAgingHelper.onDestroy();
-        }
     }
 
     private boolean isForCurrentUser(StatusBarNotification sbn) {
@@ -541,21 +511,4 @@
             }
         }
     }
-
-    protected final class AgingCallback implements Callback {
-        @Override
-        public void sendAdjustment(String key, int newImportance) {
-            if (AGE_NOTIFICATIONS) {
-                NotificationEntry entry = mLiveNotifications.get(key);
-                if (entry != null) {
-                    Bundle bundle = new Bundle();
-                    bundle.putInt(KEY_IMPORTANCE, newImportance);
-                    Adjustment adjustment = new Adjustment(entry.getSbn().getPackageName(), key,
-                            bundle, "aging", entry.getSbn().getUserId());
-                    adjustNotification(adjustment);
-                }
-            }
-        }
-    }
-
 }
diff --git a/packages/NetworkStack/Android.bp b/packages/NetworkStack/Android.bp
index e15526a..aefa882 100644
--- a/packages/NetworkStack/Android.bp
+++ b/packages/NetworkStack/Android.bp
@@ -109,7 +109,9 @@
     // InProcessNetworkStack is a replacement for NetworkStack
     overrides: ["NetworkStack"],
     // The permission configuration *must* be included to ensure security of the device
-    required: ["PlatformNetworkPermissionConfig"],
+    // The InProcessNetworkStack goes together with the PlatformCaptivePortalLogin, which replaces
+    // the default CaptivePortalLogin.
+    required: ["PlatformNetworkPermissionConfig", "PlatformCaptivePortalLogin"],
 }
 
 // Updatable network stack packaged as an application
diff --git a/packages/PackageInstaller/res/values-bs/strings.xml b/packages/PackageInstaller/res/values-bs/strings.xml
index 329e940..ebf0685 100644
--- a/packages/PackageInstaller/res/values-bs/strings.xml
+++ b/packages/PackageInstaller/res/values-bs/strings.xml
@@ -40,7 +40,7 @@
     <string name="unknown_apps_admin_dlg_text" msgid="4456572224020176095">"Vaš administrator ne dozvoljava instaliranje aplikacija iz nepoznatih izvora"</string>
     <string name="unknown_apps_user_restriction_dlg_text" msgid="151020786933988344">"Ovaj korisnik ne može instalirati nepoznate aplikacije"</string>
     <string name="install_apps_user_restriction_dlg_text" msgid="2154119597001074022">"Ovom korisniku nije dozvoljeno instaliranje aplikacija"</string>
-    <string name="ok" msgid="7871959885003339302">"UREDU"</string>
+    <string name="ok" msgid="7871959885003339302">"Uredu"</string>
     <string name="manage_applications" msgid="5400164782453975580">"Uprav. aplik."</string>
     <string name="out_of_space_dlg_title" msgid="4156690013884649502">"Nedostatak prostora"</string>
     <string name="out_of_space_dlg_text" msgid="8727714096031856231">"Ne možete instalirati aplikaciju <xliff:g id="APP_NAME">%1$s</xliff:g>. Oslobodite prostor u pohrani i pokušajte ponovo."</string>
diff --git a/packages/PackageInstaller/res/values-eu/strings.xml b/packages/PackageInstaller/res/values-eu/strings.xml
index 9c23097..dbcb2bb 100644
--- a/packages/PackageInstaller/res/values-eu/strings.xml
+++ b/packages/PackageInstaller/res/values-eu/strings.xml
@@ -83,9 +83,9 @@
     <string name="untrusted_external_source_warning" product="tablet" msgid="6539403649459942547">"Segurtasuna bermatzeko, ezin dira instalatu iturburu honetako aplikazio ezezagunak tableta honetan."</string>
     <string name="untrusted_external_source_warning" product="tv" msgid="1206648674551321364">"Segurtasuna bermatzeko, ezin dira instalatu iturburu honetako aplikazio ezezagunak telebista honetan."</string>
     <string name="untrusted_external_source_warning" product="default" msgid="7279739265754475165">"Segurtasuna bermatzeko, ezin dira instalatu iturburu honetako aplikazio ezezagunak telefono honetan."</string>
-    <string name="anonymous_source_warning" product="default" msgid="2784902545920822500">"Telefonoak eta datu pertsonalek aplikazio ezezagunen erasoak jaso ditzakete. Aplikazio hau instalatzen baduzu, onartu egingo duzu zeu zarela hura erabiltzeagatik telefonoak jasan ditzakeen kalteen edo datu-galeren erantzulea."</string>
-    <string name="anonymous_source_warning" product="tablet" msgid="3939101621438855516">"Tabletak eta datu pertsonalek aplikazio ezezagunen erasoak jaso ditzakete. Aplikazio hau instalatzen baduzu, onartu egingo duzu zeu zarela hura erabiltzeagatik tabletak jasan ditzakeen kalteen edo datu-galeren erantzulea."</string>
-    <string name="anonymous_source_warning" product="tv" msgid="5599483539528168566">"Telebistak eta datu pertsonalek aplikazio ezezagunen erasoak jaso ditzakete. Aplikazio hau instalatzen baduzu, onartu egingo duzu zeu zarela hura erabiltzeagatik telebistak jasan ditzakeen kalteen edo datu-galeren erantzulea."</string>
+    <string name="anonymous_source_warning" product="default" msgid="2784902545920822500">"Telefonoak eta datu pertsonalek aplikazio ezezagunen erasoak jaso ditzakete. Aplikazio hau instalatzen baduzu, onartu egingo duzu zu zarela hura erabiltzeagatik telefonoak jasan ditzakeen kalteen edo datu-galeren erantzulea."</string>
+    <string name="anonymous_source_warning" product="tablet" msgid="3939101621438855516">"Tabletak eta datu pertsonalek aplikazio ezezagunen erasoak jaso ditzakete. Aplikazio hau instalatzen baduzu, onartu egingo duzu zu zarela hura erabiltzeagatik tabletak jasan ditzakeen kalteen edo datu-galeren erantzulea."</string>
+    <string name="anonymous_source_warning" product="tv" msgid="5599483539528168566">"Telebistak eta datu pertsonalek aplikazio ezezagunen erasoak jaso ditzakete. Aplikazio hau instalatzen baduzu, onartu egingo duzu zu zarela hura erabiltzeagatik telebistak jasan ditzakeen kalteen edo datu-galeren erantzulea."</string>
     <string name="anonymous_source_continue" msgid="4375745439457209366">"Egin aurrera"</string>
     <string name="external_sources_settings" msgid="4046964413071713807">"Ezarpenak"</string>
     <string name="wear_app_channel" msgid="1960809674709107850">"Wear aplikazioak instalatzea/desinstalatzea"</string>
diff --git a/packages/PrintSpooler/res/values-fr/strings.xml b/packages/PrintSpooler/res/values-fr/strings.xml
index 3c2aec3..f6e901d 100644
--- a/packages/PrintSpooler/res/values-fr/strings.xml
+++ b/packages/PrintSpooler/res/values-fr/strings.xml
@@ -65,7 +65,7 @@
     <string name="notification_channel_failure" msgid="9042250774797916414">"Tâches d\'impression non abouties"</string>
     <string name="could_not_create_file" msgid="3425025039427448443">"Impossible de créer le fichier"</string>
     <string name="print_services_disabled_toast" msgid="9089060734685174685">"Certains services d\'impression sont désactivés."</string>
-    <string name="print_searching_for_printers" msgid="6550424555079932867">"Recherche d\'imprimantes en cours"</string>
+    <string name="print_searching_for_printers" msgid="6550424555079932867">"Recherche d\'imprimantes..."</string>
     <string name="print_no_print_services" msgid="8561247706423327966">"Aucun service d\'impression activé"</string>
     <string name="print_no_printers" msgid="4869403323900054866">"Aucune imprimante trouvée"</string>
     <string name="cannot_add_printer" msgid="7840348733668023106">"Impossible d\'ajouter des imprimantes"</string>
diff --git a/packages/PrintSpooler/res/values-hi/strings.xml b/packages/PrintSpooler/res/values-hi/strings.xml
index 6f98070..2637c3c 100644
--- a/packages/PrintSpooler/res/values-hi/strings.xml
+++ b/packages/PrintSpooler/res/values-hi/strings.xml
@@ -34,7 +34,7 @@
     <string name="print_preview" msgid="8010217796057763343">"प्रिंट की झलक"</string>
     <string name="install_for_print_preview" msgid="6366303997385509332">"झलक देखने के लिए PDF व्यूअर इंस्टॉल करें"</string>
     <string name="printing_app_crashed" msgid="854477616686566398">"प्रिंटिंग ऐप बंद हो गया"</string>
-    <string name="generating_print_job" msgid="3119608742651698916">"प्रिंट कार्य जनरेट हो रहा है"</string>
+    <string name="generating_print_job" msgid="3119608742651698916">"प्रिंट जॉ जनरेट हो रहा है"</string>
     <string name="save_as_pdf" msgid="5718454119847596853">"पीडीएफ़ के तौर पर सेव करें"</string>
     <string name="all_printers" msgid="5018829726861876202">"सभी प्रिंटर..."</string>
     <string name="print_dialog" msgid="32628687461331979">"प्रिंट डॉयलॉग"</string>
@@ -61,8 +61,8 @@
     </plurals>
     <string name="printer_extended_description_template" msgid="1366699227703381874">"<xliff:g id="PRINT_SERVICE_LABEL">%1$s</xliff:g> - <xliff:g id="PRINTER_DESCRIPTION">%2$s</xliff:g>"</string>
     <string name="printer_info_desc" msgid="7181988788991581654">"इस प्रिंटर के बारे में ज़्यादा जानकारी"</string>
-    <string name="notification_channel_progress" msgid="872788690775721436">"चल रहे प्रिंट कार्य"</string>
-    <string name="notification_channel_failure" msgid="9042250774797916414">"असफल रहे प्रिंट कार्य"</string>
+    <string name="notification_channel_progress" msgid="872788690775721436">"चल रहे प्रिंट जॉ"</string>
+    <string name="notification_channel_failure" msgid="9042250774797916414">"असफल रहे प्रिंट जॉ"</string>
     <string name="could_not_create_file" msgid="3425025039427448443">"फ़ाइल नहीं बनाई जा सकी"</string>
     <string name="print_services_disabled_toast" msgid="9089060734685174685">"कुछ प्रिंट सेवाएं अक्षम हैं"</string>
     <string name="print_searching_for_printers" msgid="6550424555079932867">"प्रिंटर सर्च कर रहा है"</string>
diff --git a/packages/PrintSpooler/res/values-my/strings.xml b/packages/PrintSpooler/res/values-my/strings.xml
index 34297b6..fdcdd7c 100644
--- a/packages/PrintSpooler/res/values-my/strings.xml
+++ b/packages/PrintSpooler/res/values-my/strings.xml
@@ -86,7 +86,7 @@
     <string name="cancel" msgid="4373674107267141885">"မလုပ်တော့"</string>
     <string name="restart" msgid="2472034227037808749">"ပြန်စရန်"</string>
     <string name="no_connection_to_printer" msgid="2159246915977282728">"စာထုတ်စက်နဲ့ ဆက်သွယ်ထားမှု မရှိပါ"</string>
-    <string name="reason_unknown" msgid="5507940196503246139">"မသိပါ"</string>
+    <string name="reason_unknown" msgid="5507940196503246139">"မသိ"</string>
     <string name="print_service_security_warning_title" msgid="2160752291246775320">"<xliff:g id="SERVICE">%1$s</xliff:g>ကိုသုံးမလား။"</string>
     <string name="print_service_security_warning_summary" msgid="1427434625361692006">"သင်၏ စာရွက်စာတမ်းများသည် ပရင်တာထံသို့ သွားစဉ် ဆာဗာ တစ်ခု သို့မဟုတ် ပိုများပြီး ဖြတ်ကျော်နိုင်ရသည်။"</string>
   <string-array name="color_mode_labels">
@@ -99,7 +99,7 @@
     <item msgid="79513688117503758">"အနားသတ် အတို"</item>
   </string-array>
   <string-array name="orientation_labels">
-    <item msgid="4061931020926489228">"ထောင်လိုက်"</item>
+    <item msgid="4061931020926489228">"ဒေါင်လိုက်"</item>
     <item msgid="3199660090246166812">"အလျားလိုက်"</item>
   </string-array>
     <string name="print_write_error_message" msgid="5787642615179572543">"ဖိုင်သို့ မရေးနိုင်ခဲ့"</string>
diff --git a/packages/PrintSpooler/res/values-pl/strings.xml b/packages/PrintSpooler/res/values-pl/strings.xml
index a960fe2..0b310f0 100644
--- a/packages/PrintSpooler/res/values-pl/strings.xml
+++ b/packages/PrintSpooler/res/values-pl/strings.xml
@@ -67,7 +67,7 @@
     <string name="notification_channel_failure" msgid="9042250774797916414">"Nieudane zadania drukowania"</string>
     <string name="could_not_create_file" msgid="3425025039427448443">"Nie udało się utworzyć pliku"</string>
     <string name="print_services_disabled_toast" msgid="9089060734685174685">"Niektóre usługi drukowania są wyłączone"</string>
-    <string name="print_searching_for_printers" msgid="6550424555079932867">"Szukanie drukarek"</string>
+    <string name="print_searching_for_printers" msgid="6550424555079932867">"Szukam drukarek"</string>
     <string name="print_no_print_services" msgid="8561247706423327966">"Brak włączonych usług drukowania"</string>
     <string name="print_no_printers" msgid="4869403323900054866">"Nie znaleziono drukarek"</string>
     <string name="cannot_add_printer" msgid="7840348733668023106">"Nie można dodawać drukarek"</string>
diff --git a/packages/PrintSpooler/res/values-ta/strings.xml b/packages/PrintSpooler/res/values-ta/strings.xml
index 7773718..4bb167a 100644
--- a/packages/PrintSpooler/res/values-ta/strings.xml
+++ b/packages/PrintSpooler/res/values-ta/strings.xml
@@ -87,7 +87,7 @@
     <string name="restart" msgid="2472034227037808749">"மீண்டும் தொடங்கு"</string>
     <string name="no_connection_to_printer" msgid="2159246915977282728">"அச்சுப்பொறியுடன் இணைக்கப்படவில்லை"</string>
     <string name="reason_unknown" msgid="5507940196503246139">"அறியப்படாதது"</string>
-    <string name="print_service_security_warning_title" msgid="2160752291246775320">"<xliff:g id="SERVICE">%1$s</xliff:g>ஐப் பயன்படுத்தவா?"</string>
+    <string name="print_service_security_warning_title" msgid="2160752291246775320">"<xliff:g id="SERVICE">%1$s</xliff:g> ஐப் பயன்படுத்தவா?"</string>
     <string name="print_service_security_warning_summary" msgid="1427434625361692006">"உங்கள் ஆவணம் பிரிண்டருக்குச் செல்லும் வழியில் ஒன்று அல்லது அதற்கு மேற்பட்ட சேவையகங்களைக் கடந்து செல்லக்கூடும்."</string>
   <string-array name="color_mode_labels">
     <item msgid="7602948745415174937">"கருப்பு &amp; வெள்ளை"</item>
diff --git a/packages/SystemUI/res-keyguard/layout/keyguard_status_area.xml b/packages/SystemUI/res-keyguard/layout/keyguard_status_area.xml
index a84ddaf..4db2280 100644
--- a/packages/SystemUI/res-keyguard/layout/keyguard_status_area.xml
+++ b/packages/SystemUI/res-keyguard/layout/keyguard_status_area.xml
@@ -34,7 +34,6 @@
               android:layout_height="wrap_content"
               android:paddingStart="44dp"
               android:paddingEnd="44dp"
-              android:letterSpacing="0.02"
               android:visibility="gone"
               android:textColor="?attr/wallpaperTextColor"
               android:theme="@style/TextAppearance.Keyguard"
diff --git a/packages/SystemUI/res-keyguard/values/styles.xml b/packages/SystemUI/res-keyguard/values/styles.xml
index 137c30a..1c8e141 100644
--- a/packages/SystemUI/res-keyguard/values/styles.xml
+++ b/packages/SystemUI/res-keyguard/values/styles.xml
@@ -115,7 +115,6 @@
         <item name="android:layout_height">wrap_content</item>
         <item name="android:lines">1</item>
         <item name="android:textSize">@dimen/widget_label_font_size</item>
-        <item name="android:letterSpacing">0.02</item>
     </style>
 
     <style name="TextAppearance.Keyguard.BottomArea">
diff --git a/packages/SystemUI/res/drawable/corner_gesture_hint.xml b/packages/SystemUI/res/drawable/corner_gesture_hint.xml
new file mode 100644
index 0000000..3f4abb0
--- /dev/null
+++ b/packages/SystemUI/res/drawable/corner_gesture_hint.xml
@@ -0,0 +1,25 @@
+<!--
+    Copyright (C) 2019 The Android Open Source Project
+
+    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.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:height="12dp"
+    android:width="12dp"
+    android:viewportWidth="12"
+    android:viewportHeight="12">
+
+    <path android:fillColor="#00000000"
+          android:pathData="M 1.18 10.65 C 1.18 5.58 5.41 1.18 10.65 1.18"
+          android:strokeColor="#000"
+          android:strokeLineCap="round"
+          android:strokeWidth="1.3" />
+</vector>
diff --git a/packages/SystemUI/res/layout/quick_settings_header_info.xml b/packages/SystemUI/res/layout/quick_settings_header_info.xml
index 3582d39..1e16e5d1 100644
--- a/packages/SystemUI/res/layout/quick_settings_header_info.xml
+++ b/packages/SystemUI/res/layout/quick_settings_header_info.xml
@@ -27,14 +27,12 @@
             android:id="@+id/status_container"
             android:layout_width="match_parent"
             android:layout_weight="1"
-            android:layout_height="match_parent"
-            android:gravity="start" >
+            android:layout_height="match_parent">
 
             <LinearLayout
                 android:id = "@+id/alarm_container"
                 android:layout_width="wrap_content"
                 android:layout_height="match_parent"
-                android:layout_gravity="center_vertical"
                 android:gravity="center_vertical"
                 android:focusable="true"
                 android:clickable="true">
@@ -69,7 +67,6 @@
                 android:id = "@+id/ringer_container"
                 android:layout_width="wrap_content"
                 android:layout_height="match_parent"
-                android:layout_gravity="center_vertical"
                 android:gravity="center_vertical"
                 android:focusable="true"
                 android:clickable="true">
diff --git a/packages/SystemUI/res/layout/rounded_corners.xml b/packages/SystemUI/res/layout/rounded_corners.xml
index 26cf792..02651a2 100644
--- a/packages/SystemUI/res/layout/rounded_corners.xml
+++ b/packages/SystemUI/res/layout/rounded_corners.xml
@@ -32,4 +32,22 @@
         android:tint="#ff000000"
         android:layout_gravity="right|bottom"
         android:src="@drawable/rounded" />
+    <ImageView
+        android:id="@+id/assist_hint_left"
+        android:layout_width="32dp"
+        android:layout_height="32dp"
+        android:padding="6dp"
+        android:layout_gravity="left|top"
+        android:src="@drawable/corner_gesture_hint"
+        android:tint="#ffffffff"
+        android:visibility="gone" />
+    <ImageView
+        android:id="@+id/assist_hint_right"
+        android:layout_width="32dp"
+        android:layout_height="32dp"
+        android:padding="6dp"
+        android:layout_gravity="right|bottom"
+        android:src="@drawable/corner_gesture_hint"
+        android:tint="#ffffffff"
+        android:visibility="gone" />
 </com.android.systemui.RegionInterceptingFrameLayout>
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/system/QuickStepContract.java b/packages/SystemUI/shared/src/com/android/systemui/shared/system/QuickStepContract.java
index b89b9ef..cc3a67c 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/system/QuickStepContract.java
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/system/QuickStepContract.java
@@ -28,6 +28,7 @@
 
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
+import java.util.StringJoiner;
 
 /**
  * Various shared constants between Launcher and SysUI as part of quickstep
@@ -35,7 +36,6 @@
 public class QuickStepContract {
 
     public static final String KEY_EXTRA_SYSUI_PROXY = "extra_sysui_proxy";
-    public static final String KEY_EXTRA_INPUT_CHANNEL = "extra_input_channel";
     public static final String KEY_EXTRA_INPUT_MONITOR = "extra_input_monitor";
     public static final String KEY_EXTRA_WINDOW_CORNER_RADIUS = "extra_window_corner_radius";
     public static final String KEY_EXTRA_SUPPORTS_WINDOW_CORNERS = "extra_supports_window_corners";
@@ -47,12 +47,26 @@
     public static final String NAV_BAR_MODE_GESTURAL_OVERLAY =
             WindowManagerPolicyConstants.NAV_BAR_MODE_GESTURAL_OVERLAY;
 
+    // Overview is disabled, either because the device is in lock task mode, or because the device
+    // policy has disabled the feature
     public static final int SYSUI_STATE_SCREEN_PINNING = 1 << 0;
+    // The navigation bar is hidden due to immersive mode
     public static final int SYSUI_STATE_NAV_BAR_HIDDEN = 1 << 1;
+    // The notification panel is expanded and interactive (either locked or unlocked), and the
+    // quick settings is not expanded
     public static final int SYSUI_STATE_NOTIFICATION_PANEL_EXPANDED = 1 << 2;
+    // The keyguard bouncer is showing
     public static final int SYSUI_STATE_BOUNCER_SHOWING = 1 << 3;
+    // The navigation bar a11y button should be shown
     public static final int SYSUI_STATE_A11Y_BUTTON_CLICKABLE = 1 << 4;
+    // The navigation bar a11y button shortcut is available
     public static final int SYSUI_STATE_A11Y_BUTTON_LONG_CLICKABLE = 1 << 5;
+    // The keyguard is showing
+    public static final int SYSUI_STATE_STATUS_BAR_KEYGUARD_SHOWING = 1 << 6;
+    // The recents feature is disabled (either by SUW/SysUI/device policy)
+    public static final int SYSUI_STATE_OVERVIEW_DISABLED = 1 << 7;
+    // The home feature is disabled (either by SUW/SysUI/device policy)
+    public static final int SYSUI_STATE_HOME_DISABLED = 1 << 8;
 
     @Retention(RetentionPolicy.SOURCE)
     @IntDef({SYSUI_STATE_SCREEN_PINNING,
@@ -60,10 +74,27 @@
             SYSUI_STATE_NOTIFICATION_PANEL_EXPANDED,
             SYSUI_STATE_BOUNCER_SHOWING,
             SYSUI_STATE_A11Y_BUTTON_CLICKABLE,
-            SYSUI_STATE_A11Y_BUTTON_LONG_CLICKABLE
+            SYSUI_STATE_A11Y_BUTTON_LONG_CLICKABLE,
+            SYSUI_STATE_STATUS_BAR_KEYGUARD_SHOWING,
+            SYSUI_STATE_OVERVIEW_DISABLED,
+            SYSUI_STATE_HOME_DISABLED
     })
     public @interface SystemUiStateFlags {}
 
+    public static String getSystemUiStateString(int flags) {
+        StringJoiner str = new StringJoiner("|");
+        str.add((flags & SYSUI_STATE_SCREEN_PINNING) != 0 ? "screen_pinned" : "");
+        str.add((flags & SYSUI_STATE_OVERVIEW_DISABLED) != 0 ? "overview_disabled" : "");
+        str.add((flags & SYSUI_STATE_HOME_DISABLED) != 0 ? "home_disabled" : "");
+        str.add((flags & SYSUI_STATE_NAV_BAR_HIDDEN) != 0 ? "navbar_hidden" : "");
+        str.add((flags & SYSUI_STATE_NOTIFICATION_PANEL_EXPANDED) != 0 ? "notif_visible" : "");
+        str.add((flags & SYSUI_STATE_STATUS_BAR_KEYGUARD_SHOWING) != 0 ? "keygrd_visible" : "");
+        str.add((flags & SYSUI_STATE_BOUNCER_SHOWING) != 0 ? "bouncer_visible" : "");
+        str.add((flags & SYSUI_STATE_A11Y_BUTTON_CLICKABLE) != 0 ? "a11y_click" : "");
+        str.add((flags & SYSUI_STATE_A11Y_BUTTON_LONG_CLICKABLE) != 0 ? "a11y_long_click" : "");
+        return str.toString();
+    }
+
     /**
      * Touch slopes and thresholds for quick step operations. Drag slop is the point where the
      * home button press/long press over are ignored and will start to drag when exceeded and the
@@ -87,6 +118,37 @@
     }
 
     /**
+     * Returns whether the specified sysui state is such that the assistant gesture should be
+     * disabled.
+     */
+    public static boolean isAssistantGestureDisabled(int sysuiStateFlags) {
+        // Disable when in screen pinning, immersive, the bouncer is showing, or the notifications
+        // are interactive
+        int disableFlags = SYSUI_STATE_SCREEN_PINNING
+                | SYSUI_STATE_NAV_BAR_HIDDEN
+                | SYSUI_STATE_BOUNCER_SHOWING
+                | SYSUI_STATE_NOTIFICATION_PANEL_EXPANDED;
+        return (sysuiStateFlags & disableFlags) != 0;
+    }
+
+    /**
+     * Returns whether the specified sysui state is such that the back gesture should be
+     * disabled.
+     */
+    public static boolean isBackGestureDisabled(int sysuiStateFlags) {
+        // Always allow when the bouncer is showing (even on top of the keyguard)
+        if ((sysuiStateFlags & SYSUI_STATE_BOUNCER_SHOWING) != 0) {
+            return false;
+        }
+        // Disable when in screen pinning, immersive, or the notifications are interactive
+        int disableFlags = SYSUI_STATE_SCREEN_PINNING
+                | SYSUI_STATE_NAV_BAR_HIDDEN
+                | SYSUI_STATE_NOTIFICATION_PANEL_EXPANDED
+                | SYSUI_STATE_STATUS_BAR_KEYGUARD_SHOWING;
+        return (sysuiStateFlags & disableFlags) != 0;
+    }
+
+    /**
      * @return whether this nav bar mode is edge to edge
      */
     public static boolean isGesturalMode(int mode) {
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardPatternView.java b/packages/SystemUI/src/com/android/keyguard/KeyguardPatternView.java
index 0e91e41..d8086da 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardPatternView.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardPatternView.java
@@ -64,6 +64,9 @@
     // How much we scale up the duration of the disappear animation when the current user is locked
     public static final float DISAPPEAR_MULTIPLIER_LOCKED = 1.5f;
 
+    // Extra padding, in pixels, that should eat touch events.
+    private static final int PATTERNS_TOUCH_AREA_EXTENSION = 40;
+
     private final KeyguardUpdateMonitor mKeyguardUpdateMonitor;
     private final AppearAnimationUtils mAppearAnimationUtils;
     private final DisappearAnimationUtils mDisappearAnimationUtils;
@@ -204,9 +207,10 @@
     protected void onLayout(boolean changed, int l, int t, int r, int b) {
         super.onLayout(changed, l, t, r, b);
         mLockPatternView.getLocationOnScreen(mTmpPosition);
-        mLockPatternScreenBounds.set(mTmpPosition[0], mTmpPosition[1],
-                mTmpPosition[0] + mLockPatternView.getWidth(),
-                mTmpPosition[1] + mLockPatternView.getHeight());
+        mLockPatternScreenBounds.set(mTmpPosition[0] - PATTERNS_TOUCH_AREA_EXTENSION,
+                mTmpPosition[1] - PATTERNS_TOUCH_AREA_EXTENSION,
+                mTmpPosition[0] + mLockPatternView.getWidth() + PATTERNS_TOUCH_AREA_EXTENSION,
+                mTmpPosition[1] + mLockPatternView.getHeight() + PATTERNS_TOUCH_AREA_EXTENSION);
     }
 
     @Override
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainer.java b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainer.java
index 0914fb8..6cd971d 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainer.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainer.java
@@ -71,6 +71,8 @@
     private static final float TOUCH_Y_MULTIPLIER = 0.25f;
     // How much you need to drag the bouncer to trigger an auth retry (in dps.)
     private static final float MIN_DRAG_SIZE = 10;
+    // How much to scale the default slop by, to avoid accidental drags.
+    private static final float SLOP_SCALE = 2f;
 
     private KeyguardSecurityModel mSecurityModel;
     private LockPatternUtils mLockPatternUtils;
@@ -179,7 +181,7 @@
                     return false;
                 }
                 int index = event.findPointerIndex(mActivePointerId);
-                int touchSlop = mViewConfiguration.getScaledTouchSlop();
+                float touchSlop = mViewConfiguration.getScaledTouchSlop() * SLOP_SCALE;
                 if (mCurrentSecurityView != null && index != -1
                         && mStartTouchY - event.getY(index) > touchSlop) {
                     mIsDragging = true;
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
index 417cc68..6a4dbc8d 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
@@ -1187,7 +1187,7 @@
                 throw new IllegalArgumentException("only handles intent ACTION_SIM_STATE_CHANGED");
             }
             String stateExtra = intent.getStringExtra(IccCardConstants.INTENT_KEY_ICC_STATE);
-            int slotId = intent.getIntExtra(PhoneConstants.SLOT_KEY, 0);
+            int slotId = intent.getIntExtra(PhoneConstants.PHONE_KEY, 0);
             int subId = intent.getIntExtra(PhoneConstants.SUBSCRIPTION_KEY,
                     SubscriptionManager.INVALID_SUBSCRIPTION_ID);
             if (IccCardConstants.INTENT_VALUE_ICC_ABSENT.equals(stateExtra)) {
diff --git a/packages/SystemUI/src/com/android/systemui/ScreenDecorations.java b/packages/SystemUI/src/com/android/systemui/ScreenDecorations.java
index c0f03a6..69d3af8 100644
--- a/packages/SystemUI/src/com/android/systemui/ScreenDecorations.java
+++ b/packages/SystemUI/src/com/android/systemui/ScreenDecorations.java
@@ -105,6 +105,7 @@
     private float mDensity;
     private WindowManager mWindowManager;
     private int mRotation;
+    private boolean mAssistHintVisible;
     private DisplayCutoutView mCutoutTop;
     private DisplayCutoutView mCutoutBottom;
     private SecureSetting mColorInversionSetting;
@@ -133,6 +134,55 @@
         mHandler = startHandlerThread();
         mHandler.post(this::startOnScreenDecorationsThread);
         setupStatusBarPaddingIfNeeded();
+        putComponent(ScreenDecorations.class, this);
+    }
+
+    private void fade(View view, boolean fadeIn) {
+        if (fadeIn) {
+            view.animate().cancel();
+            view.setAlpha(0f);
+            view.setVisibility(View.VISIBLE);
+            view.animate().alpha(1f);
+        } else {
+            view.animate().cancel();
+            view.animate().alpha(0f).withEndAction(() -> view.setVisibility(View.INVISIBLE));
+        }
+
+    }
+
+    /**
+     * Controls the visibility of the assist gesture handles.
+     *
+     * @param visible whether the handles should be shown
+     */
+    public void setAssistHintVisible(boolean visible) {
+        if (mAssistHintVisible != visible) {
+            mAssistHintVisible = visible;
+
+            View assistHintTopLeft = mOverlay.findViewById(R.id.assist_hint_left);
+            View assistHintTopRight = mOverlay.findViewById(R.id.assist_hint_right);
+            View assistHintBottomLeft = mBottomOverlay.findViewById(R.id.assist_hint_left);
+            View assistHintBottomRight = mBottomOverlay.findViewById(R.id.assist_hint_right);
+
+            switch (mRotation) {
+                case RotationUtils.ROTATION_NONE:
+                    fade(assistHintBottomLeft, mAssistHintVisible);
+                    fade(assistHintBottomRight, mAssistHintVisible);
+                    break;
+                case RotationUtils.ROTATION_LANDSCAPE:
+                    fade(assistHintTopRight, mAssistHintVisible);
+                    fade(assistHintBottomRight, mAssistHintVisible);
+                    break;
+                case RotationUtils.ROTATION_SEASCAPE:
+                    fade(assistHintTopLeft, mAssistHintVisible);
+                    fade(assistHintBottomLeft, mAssistHintVisible);
+                    break;
+                case RotationUtils.ROTATION_UPSIDE_DOWN:
+                    fade(assistHintTopLeft, mAssistHintVisible);
+                    fade(assistHintTopRight, mAssistHintVisible);
+                    break;
+            }
+        }
     }
 
     @VisibleForTesting
@@ -375,12 +425,52 @@
             updateView(bottomRight, Gravity.TOP | Gravity.LEFT, 0);
         }
 
+        updateAssistantHandleViews();
         mCutoutTop.setRotation(mRotation);
         mCutoutBottom.setRotation(mRotation);
 
         updateWindowVisibilities();
     }
 
+    private void updateAssistantHandleViews() {
+        View assistHintTopLeft = mOverlay.findViewById(R.id.assist_hint_left);
+        View assistHintTopRight = mOverlay.findViewById(R.id.assist_hint_right);
+        View assistHintBottomLeft = mBottomOverlay.findViewById(R.id.assist_hint_left);
+        View assistHintBottomRight = mBottomOverlay.findViewById(R.id.assist_hint_right);
+
+        final int assistHintVisibility = mAssistHintVisible ? View.VISIBLE : View.INVISIBLE;
+
+        if (mRotation == RotationUtils.ROTATION_NONE) {
+            assistHintTopLeft.setVisibility(View.GONE);
+            assistHintTopRight.setVisibility(View.GONE);
+            assistHintBottomLeft.setVisibility(assistHintVisibility);
+            assistHintBottomRight.setVisibility(assistHintVisibility);
+            updateView(assistHintBottomLeft, Gravity.BOTTOM | Gravity.LEFT, 270);
+            updateView(assistHintBottomRight, Gravity.BOTTOM | Gravity.RIGHT, 180);
+        } else if (mRotation == RotationUtils.ROTATION_LANDSCAPE) {
+            assistHintTopLeft.setVisibility(View.GONE);
+            assistHintTopRight.setVisibility(assistHintVisibility);
+            assistHintBottomLeft.setVisibility(View.GONE);
+            assistHintBottomRight.setVisibility(assistHintVisibility);
+            updateView(assistHintTopRight, Gravity.BOTTOM | Gravity.LEFT, 270);
+            updateView(assistHintBottomRight, Gravity.BOTTOM | Gravity.RIGHT, 180);
+        } else if (mRotation == RotationUtils.ROTATION_UPSIDE_DOWN) {
+            assistHintTopLeft.setVisibility(assistHintVisibility);
+            assistHintTopRight.setVisibility(assistHintVisibility);
+            assistHintBottomLeft.setVisibility(View.GONE);
+            assistHintBottomRight.setVisibility(View.GONE);
+            updateView(assistHintTopLeft, Gravity.BOTTOM | Gravity.LEFT, 270);
+            updateView(assistHintTopRight, Gravity.BOTTOM | Gravity.RIGHT, 180);
+        } else if (mRotation == RotationUtils.ROTATION_SEASCAPE) {
+            assistHintTopLeft.setVisibility(assistHintVisibility);
+            assistHintTopRight.setVisibility(View.GONE);
+            assistHintBottomLeft.setVisibility(assistHintVisibility);
+            assistHintBottomRight.setVisibility(View.GONE);
+            updateView(assistHintTopLeft, Gravity.BOTTOM | Gravity.RIGHT, 180);
+            updateView(assistHintBottomLeft, Gravity.BOTTOM | Gravity.LEFT, 270);
+        }
+    }
+
     private void updateView(View v, int gravity, int rotation) {
         ((FrameLayout.LayoutParams)v.getLayoutParams()).gravity = gravity;
         v.setRotation(rotation);
diff --git a/packages/SystemUI/src/com/android/systemui/assist/AssistManager.java b/packages/SystemUI/src/com/android/systemui/assist/AssistManager.java
index 51bd9f8..f0c38fb 100644
--- a/packages/SystemUI/src/com/android/systemui/assist/AssistManager.java
+++ b/packages/SystemUI/src/com/android/systemui/assist/AssistManager.java
@@ -169,7 +169,7 @@
     }
 
     protected boolean shouldShowOrb() {
-        return true;
+        return false;
     }
 
     public void startAssist(Bundle args) {
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleController.java b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleController.java
index dcc0419..7e016bb 100644
--- a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleController.java
+++ b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleController.java
@@ -16,6 +16,7 @@
 
 package com.android.systemui.bubbles;
 
+import static android.content.pm.ActivityInfo.DOCUMENT_LAUNCH_ALWAYS;
 import static android.service.notification.NotificationListenerService.REASON_APP_CANCEL;
 import static android.service.notification.NotificationListenerService.REASON_APP_CANCEL_ALL;
 import static android.service.notification.NotificationListenerService.REASON_CANCEL;
@@ -41,7 +42,9 @@
 import android.app.IActivityTaskManager;
 import android.app.Notification;
 import android.app.NotificationManager;
+import android.app.PendingIntent;
 import android.content.Context;
+import android.content.pm.ActivityInfo;
 import android.content.pm.ParceledListSlice;
 import android.content.res.Configuration;
 import android.graphics.Rect;
@@ -112,7 +115,7 @@
     public static final int MAX_BUBBLES = 5; // TODO: actually enforce this
 
     // Enables some subset of notifs to automatically become bubbles
-    private static final boolean DEBUG_ENABLE_AUTO_BUBBLE = false;
+    public static final boolean DEBUG_ENABLE_AUTO_BUBBLE = false;
 
     /** Flag to enable or disable the entire feature */
     private static final String ENABLE_BUBBLES = "experiment_enable_bubbles";
@@ -450,7 +453,8 @@
             if (!areBubblesEnabled(mContext)) {
                 return;
             }
-            if (mNotificationInterruptionStateProvider.shouldBubbleUp(entry)) {
+            if (mNotificationInterruptionStateProvider.shouldBubbleUp(entry)
+                    && canLaunchInActivityView(mContext, entry)) {
                 updateShowInShadeForSuppressNotification(entry);
             }
         }
@@ -460,7 +464,8 @@
             if (!areBubblesEnabled(mContext)) {
                 return;
             }
-            if (mNotificationInterruptionStateProvider.shouldBubbleUp(entry)) {
+            if (mNotificationInterruptionStateProvider.shouldBubbleUp(entry)
+                    && canLaunchInActivityView(mContext, entry)) {
                 updateBubble(entry);
             }
         }
@@ -470,7 +475,8 @@
             if (!areBubblesEnabled(mContext)) {
                 return;
             }
-            boolean shouldBubble = mNotificationInterruptionStateProvider.shouldBubbleUp(entry);
+            boolean shouldBubble = mNotificationInterruptionStateProvider.shouldBubbleUp(entry)
+                    && canLaunchInActivityView(mContext, entry);
             if (!shouldBubble && mBubbleData.hasBubbleWithKey(entry.key)) {
                 // It was previously a bubble but no longer a bubble -- lets remove it
                 removeBubble(entry.key, DISMISS_NO_LONGER_BUBBLE);
@@ -657,12 +663,6 @@
                 || autoBubbleAll;
     }
 
-    private boolean shouldAutoExpand(NotificationEntry entry) {
-        Notification.BubbleMetadata metadata = entry.getBubbleMetadata();
-        return metadata != null && metadata.getAutoExpandBubble()
-                && isForegroundApp(mContext, entry.notification.getPackageName());
-    }
-
     private void updateShowInShadeForSuppressNotification(NotificationEntry entry) {
         boolean suppressNotification = entry.getBubbleMetadata() != null
                 && entry.getBubbleMetadata().isNotificationSuppressed()
@@ -771,6 +771,48 @@
                 (int) (defaultBounciness * 100)) / 100f;
     }
 
+    /**
+     * Whether an intent is properly configured to display in an {@link android.app.ActivityView}.
+     *
+     * Keep checks in sync with NotificationManagerService#canLaunchInActivityView. Typically
+     * that should filter out any invalid bubbles, but should protect SysUI side just in case.
+     *
+     * @param context the context to use.
+     * @param entry the entry to bubble.
+     */
+    static boolean canLaunchInActivityView(Context context, NotificationEntry entry) {
+        PendingIntent intent = entry.getBubbleMetadata() != null
+                ? entry.getBubbleMetadata().getIntent()
+                : null;
+        if (intent == null) {
+            Log.w(TAG, "Unable to create bubble -- no intent");
+            return false;
+        }
+        ActivityInfo info =
+                intent.getIntent().resolveActivityInfo(context.getPackageManager(), 0);
+        if (info == null) {
+            Log.w(TAG, "Unable to send as bubble -- couldn't find activity info for intent: "
+                    + intent);
+            return false;
+        }
+        if (!ActivityInfo.isResizeableMode(info.resizeMode)) {
+            Log.w(TAG, "Unable to send as bubble -- activity is not resizable for intent: "
+                    + intent);
+            return false;
+        }
+        if (info.documentLaunchMode != DOCUMENT_LAUNCH_ALWAYS) {
+            Log.w(TAG, "Unable to send as bubble -- activity is not documentLaunchMode=always "
+                    + "for intent: " + intent);
+            return false;
+        }
+        if ((info.flags & ActivityInfo.FLAG_ALLOW_EMBEDDED) == 0) {
+            Log.w(TAG, "Unable to send as bubble -- activity is not embeddable for intent: "
+                    + intent);
+            return false;
+        }
+        return true;
+    }
+
     /** PinnedStackListener that dispatches IME visibility updates to the stack. */
     private class BubblesImeListener extends IPinnedStackListener.Stub {
 
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleExpandedView.java b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleExpandedView.java
index e7948b5..6add4a4 100644
--- a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleExpandedView.java
+++ b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleExpandedView.java
@@ -16,12 +16,10 @@
 
 package com.android.systemui.bubbles;
 
-import static android.content.pm.ActivityInfo.DOCUMENT_LAUNCH_ALWAYS;
-import static android.util.StatsLogInternal.BUBBLE_DEVELOPER_ERROR_REPORTED__ERROR__ACTIVITY_INFO_MISSING;
-import static android.util.StatsLogInternal.BUBBLE_DEVELOPER_ERROR_REPORTED__ERROR__ACTIVITY_INFO_NOT_RESIZABLE;
-import static android.util.StatsLogInternal.BUBBLE_DEVELOPER_ERROR_REPORTED__ERROR__DOCUMENT_LAUNCH_NOT_ALWAYS;
 import static android.view.Display.INVALID_DISPLAY;
 
+import static com.android.systemui.bubbles.BubbleController.DEBUG_ENABLE_AUTO_BUBBLE;
+
 import android.annotation.Nullable;
 import android.app.ActivityOptions;
 import android.app.ActivityView;
@@ -30,7 +28,6 @@
 import android.app.PendingIntent;
 import android.content.Context;
 import android.content.Intent;
-import android.content.pm.ActivityInfo;
 import android.content.pm.ApplicationInfo;
 import android.content.pm.PackageManager;
 import android.content.res.Resources;
@@ -337,11 +334,10 @@
                 mNotifRow = null;
             }
             mActivityView.setVisibility(VISIBLE);
-        } else {
+        } else if (DEBUG_ENABLE_AUTO_BUBBLE) {
             // Hide activity view if we had it previously
             mActivityView.setVisibility(GONE);
             mNotifRow = mEntry.getRow();
-
         }
         updateView();
     }
@@ -532,59 +528,14 @@
     @Nullable
     private PendingIntent getBubbleIntent(NotificationEntry entry) {
         Notification notif = entry.notification.getNotification();
-        String packageName = entry.notification.getPackageName();
         Notification.BubbleMetadata data = notif.getBubbleMetadata();
-        if (data != null && canLaunchInActivityView(data.getIntent(), true /* enableLogging */,
-                packageName)) {
+        if (BubbleController.canLaunchInActivityView(mContext, entry) && data != null) {
             return data.getIntent();
-        } else if (BubbleController.shouldUseContentIntent(mContext)
-                && canLaunchInActivityView(notif.contentIntent, false /* enableLogging */,
-                packageName)) {
-            return notif.contentIntent;
         }
         return null;
     }
 
     /**
-     * Whether an intent is properly configured to display in an {@link android.app.ActivityView}.
-     *
-     * @param intent the pending intent of the bubble.
-     * @param enableLogging whether bubble developer error should be logged.
-     * @param packageName the notification package name for this bubble.
-     * @return
-     */
-    private boolean canLaunchInActivityView(PendingIntent intent, boolean enableLogging,
-            String packageName) {
-        if (intent == null) {
-            return false;
-        }
-        ActivityInfo info =
-                intent.getIntent().resolveActivityInfo(mContext.getPackageManager(), 0);
-        if (info == null) {
-            if (enableLogging) {
-                StatsLog.write(StatsLog.BUBBLE_DEVELOPER_ERROR_REPORTED, packageName,
-                        BUBBLE_DEVELOPER_ERROR_REPORTED__ERROR__ACTIVITY_INFO_MISSING);
-            }
-            return false;
-        }
-        if (!ActivityInfo.isResizeableMode(info.resizeMode)) {
-            if (enableLogging) {
-                StatsLog.write(StatsLog.BUBBLE_DEVELOPER_ERROR_REPORTED, packageName,
-                        BUBBLE_DEVELOPER_ERROR_REPORTED__ERROR__ACTIVITY_INFO_NOT_RESIZABLE);
-            }
-            return false;
-        }
-        if (info.documentLaunchMode != DOCUMENT_LAUNCH_ALWAYS) {
-            if (enableLogging) {
-                StatsLog.write(StatsLog.BUBBLE_DEVELOPER_ERROR_REPORTED, packageName,
-                        BUBBLE_DEVELOPER_ERROR_REPORTED__ERROR__DOCUMENT_LAUNCH_NOT_ALWAYS);
-            }
-            return false;
-        }
-        return (info.flags & ActivityInfo.FLAG_ALLOW_EMBEDDED) != 0;
-    }
-
-    /**
      * Listener that is notified when a bubble is blocked.
      */
     public interface OnBubbleBlockedListener {
diff --git a/packages/SystemUI/src/com/android/systemui/chooser/ChooserHelper.java b/packages/SystemUI/src/com/android/systemui/chooser/ChooserHelper.java
index a7df6f1..6c1da47 100644
--- a/packages/SystemUI/src/com/android/systemui/chooser/ChooserHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/chooser/ChooserHelper.java
@@ -21,6 +21,7 @@
 import android.content.Intent;
 import android.os.Bundle;
 import android.os.IBinder;
+import android.os.StrictMode;
 
 /**
  * When a target is chosen from the SystemUI Chooser activity, unpack its arguments and
@@ -40,7 +41,15 @@
         final boolean ignoreTargetSecurity =
                 thisIntent.getBooleanExtra(ActivityTaskManager.EXTRA_IGNORE_TARGET_SECURITY, false);
         final int userId = thisIntent.getIntExtra(Intent.EXTRA_USER_ID, -1);
-        activity.startActivityAsCaller(
-                chosenIntent, options, permissionToken, ignoreTargetSecurity, userId);
+
+        // We're dispatching intents that might be coming from legacy apps, so
+        // (as in com.android.internal.app.ResolverActivity) exempt ourselves from death.
+        StrictMode.disableDeathOnFileUriExposure();
+        try {
+            activity.startActivityAsCaller(
+                    chosenIntent, options, permissionToken, ignoreTargetSecurity, userId);
+        } finally {
+            StrictMode.enableDeathOnFileUriExposure();
+        }
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSHeaderInfoLayout.kt b/packages/SystemUI/src/com/android/systemui/qs/QSHeaderInfoLayout.kt
index 86f54a9..c654621 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSHeaderInfoLayout.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSHeaderInfoLayout.kt
@@ -41,6 +41,7 @@
     private lateinit var alarmContainer: View
     private lateinit var ringerContainer: View
     private lateinit var statusSeparator: View
+    private val location = Location(0, 0)
 
     override fun onFinishInflate() {
         super.onFinishInflate()
@@ -53,33 +54,23 @@
         // At most one view is there
         if (statusSeparator.visibility == View.GONE) super.onLayout(changed, l, t, r, b)
         else {
-            val alarmWidth = alarmContainer.measuredWidth
-            val separatorWidth = statusSeparator.measuredWidth
-            val ringerWidth = ringerContainer.measuredWidth
-            val availableSpace = (r - l) - separatorWidth
-            var left = l
-            if (alarmWidth < availableSpace / 2) {
-                alarmContainer.layout(left, t, left + alarmWidth, b)
-                left += alarmWidth
-                statusSeparator.layout(left, t, left + separatorWidth, b)
-                left += separatorWidth
-                ringerContainer.layout(left, t, left + Math.min(ringerWidth, r - left), b)
-            } else if (ringerWidth < availableSpace / 2) {
-                val alarmAllocation = Math.min(availableSpace - ringerWidth, alarmWidth)
-                alarmContainer.layout(left, t, left + alarmAllocation, b)
-                left += alarmWidth
-                statusSeparator.layout(left, t, left + separatorWidth, b)
-                left += separatorWidth
-                ringerContainer.layout(left, t, left + ringerWidth, b)
-            } else {
-                alarmContainer.layout(left, t, left + availableSpace / 2, b)
-                left += availableSpace / 2
-                statusSeparator.layout(left, t, left + separatorWidth, b)
-                ringerContainer.layout(r - availableSpace / 2, t, r, b)
-            }
+            val layoutRTL = isLayoutRtl
+            val width = r - l
+            val height = b - t
+            var offset = 0
+
+            offset += alarmContainer.layoutView(width, height, offset, layoutRTL)
+            offset += statusSeparator.layoutView(width, height, offset, layoutRTL)
+            ringerContainer.layoutView(width, height, offset, layoutRTL)
         }
     }
 
+    private fun View.layoutView(pWidth: Int, pHeight: Int, offset: Int, RTL: Boolean): Int {
+        location.setLocationFromOffset(pWidth, offset, this.measuredWidth, RTL)
+        layout(location.left, 0, location.right, pHeight)
+        return this.measuredWidth
+    }
+
     override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) {
         super.onMeasure(
                 MeasureSpec.makeMeasureSpec(
@@ -120,4 +111,21 @@
         }
         setMeasuredDimension(width, measuredHeight)
     }
+
+    private data class Location(var left: Int, var right: Int) {
+        /**
+         * Sets the [left] and [right] with the correct values for laying out the child, respecting
+         * RTL. Only set the variable through here to prevent concurrency issues.
+         * This is done to prevent allocation of [Pair] in [onLayout].
+         */
+        fun setLocationFromOffset(parentWidth: Int, offset: Int, width: Int, RTL: Boolean) {
+            if (RTL) {
+                left = parentWidth - offset - width
+                right = parentWidth - offset
+            } else {
+                left = offset
+                right = offset + width
+            }
+        }
+    }
 }
\ No newline at end of file
diff --git a/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java b/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java
index 738f893..1848219 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java
@@ -27,9 +27,6 @@
 import static com.android.systemui.shared.system.QuickStepContract.KEY_EXTRA_SUPPORTS_WINDOW_CORNERS;
 import static com.android.systemui.shared.system.QuickStepContract.KEY_EXTRA_SYSUI_PROXY;
 import static com.android.systemui.shared.system.QuickStepContract.KEY_EXTRA_WINDOW_CORNER_RADIUS;
-import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_BOUNCER_SHOWING;
-import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_NAV_BAR_HIDDEN;
-import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_NOTIFICATION_PANEL_EXPANDED;
 
 import android.annotation.FloatRange;
 import android.app.ActivityTaskManager;
@@ -69,6 +66,7 @@
 import com.android.systemui.stackdivider.Divider;
 import com.android.systemui.statusbar.NavigationBarController;
 import com.android.systemui.statusbar.phone.NavigationBarFragment;
+import com.android.systemui.statusbar.phone.NavigationBarView;
 import com.android.systemui.statusbar.phone.NavigationModeController;
 import com.android.systemui.statusbar.phone.StatusBar;
 import com.android.systemui.statusbar.policy.CallbackController;
@@ -505,6 +503,7 @@
         }
         if (mSysUiStateFlags != newState) {
             mSysUiStateFlags = newState;
+            notifySystemUiStateChanged(mSysUiStateFlags);
             notifySystemUiStateFlags(mSysUiStateFlags);
         }
     }
@@ -516,18 +515,19 @@
     private void updateSystemUiStateFlags() {
         final NavigationBarController navBar = Dependency.get(NavigationBarController.class);
         final NavigationBarFragment navBarFragment = navBar.getDefaultNavigationBarFragment();
+        final NavigationBarView navBarView = navBar.getNavigationBarView(mContext.getDisplayId());
         final StatusBar statusBar = SysUiServiceProvider.getComponent(mContext, StatusBar.class);
-        final boolean panelExpanded = statusBar != null && statusBar.getPanel() != null
-                && statusBar.getPanel().isFullyExpanded();
-        final boolean bouncerShowing = statusBar != null && statusBar.isBouncerShowing();
+
         mSysUiStateFlags = 0;
-        mSysUiStateFlags |= (navBarFragment != null && !navBarFragment.isNavBarWindowVisible())
-                ? SYSUI_STATE_NAV_BAR_HIDDEN : 0;
-        mSysUiStateFlags |= panelExpanded
-                ? SYSUI_STATE_NOTIFICATION_PANEL_EXPANDED : 0;
-        mSysUiStateFlags |= bouncerShowing
-                ? SYSUI_STATE_BOUNCER_SHOWING : 0;
-        mSysUiStateFlags |= navBarFragment != null ? navBarFragment.getA11yButtonState(null) : 0;
+        if (navBarFragment != null) {
+            navBarFragment.updateSystemUiStateFlags(-1);
+        }
+        if (navBarView != null) {
+            navBarView.updateSystemUiStateFlags();
+        }
+        if (statusBar != null) {
+            statusBar.updateSystemUiStateFlags();
+        }
         notifySystemUiStateFlags(mSysUiStateFlags);
     }
 
@@ -633,6 +633,7 @@
         mConnectionCallbacks.add(listener);
         listener.onConnectionChanged(mOverviewProxy != null);
         listener.onBackButtonAlphaChanged(mBackButtonAlpha, false);
+        listener.onSystemUiStateChanged(mSysUiStateFlags);
     }
 
     @Override
@@ -703,6 +704,12 @@
         }
     }
 
+    private void notifySystemUiStateChanged(int sysuiStateFlags) {
+        for (int i = mConnectionCallbacks.size() - 1; i >= 0; --i) {
+            mConnectionCallbacks.get(i).onSystemUiStateChanged(sysuiStateFlags);
+        }
+    }
+
     private void notifyStartAssistant(Bundle bundle) {
         for (int i = mConnectionCallbacks.size() - 1; i >= 0; --i) {
             mConnectionCallbacks.get(i).startAssistant(bundle);
@@ -742,6 +749,11 @@
         pw.print("  quickStepIntent="); pw.println(mQuickStepIntent);
         pw.print("  quickStepIntentResolved="); pw.println(isEnabled());
         pw.print("  mSysUiStateFlags="); pw.println(mSysUiStateFlags);
+        pw.println("    " + QuickStepContract.getSystemUiStateString(mSysUiStateFlags));
+        pw.print("    backGestureDisabled=");
+        pw.println(QuickStepContract.isBackGestureDisabled(mSysUiStateFlags));
+        pw.print("    assistantGestureDisabled=");
+        pw.println(QuickStepContract.isAssistantGestureDisabled(mSysUiStateFlags));
     }
 
     public interface OverviewProxyListener {
@@ -750,6 +762,7 @@
         default void onOverviewShown(boolean fromHome) {}
         default void onQuickScrubStarted() {}
         default void onBackButtonAlphaChanged(float alpha, boolean animate) {}
+        default void onSystemUiStateChanged(int sysuiStateFlags) {}
         default void onAssistantProgress(@FloatRange(from = 0.0, to = 1.0) float progress) {}
         default void onAssistantGestureCompletion(float velocity) {}
         default void startAssistant(Bundle bundle) {}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarMobileView.java b/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarMobileView.java
index 812c9a7..689d161 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarMobileView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarMobileView.java
@@ -212,7 +212,7 @@
             return;
         }
         mMobileDrawable.setTintList(
-                ColorStateList.valueOf(mDualToneHandler.getFillColor(darkIntensity)));
+                ColorStateList.valueOf(mDualToneHandler.getSingleColor(darkIntensity)));
         ColorStateList color = ColorStateList.valueOf(getTint(area, this, tint));
         mIn.setImageTintList(color);
         mOut.setImageTintList(color);
@@ -238,7 +238,7 @@
         // We want the ability to change the theme from the one set by SignalDrawable in certain
         // surfaces. In this way, we can pass a theme to the view.
         mMobileDrawable.setTintList(
-                ColorStateList.valueOf(mDualToneHandler.getFillColor(intensity)));
+                ColorStateList.valueOf(mDualToneHandler.getSingleColor(intensity)));
         mIn.setImageTintList(list);
         mOut.setImageTintList(list);
         mMobileType.setImageTintList(list);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java
index 2651d4b..8c73e98 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java
@@ -409,7 +409,7 @@
     private final ViewOutlineProvider mOutlineProvider = new ViewOutlineProvider() {
         @Override
         public void getOutline(View view, Outline outline) {
-            if (mAmbientState.isDarkAtAll() || !mShowDarkShelf) {
+            if (mAmbientState.isDarkAtAll()) {
                 float xProgress = mDarkXInterpolator.getInterpolation(
                         (1 - mLinearDarkAmount) * mBackgroundXFactor);
                 outline.setRoundRect(mBackgroundAnimationRect,
@@ -507,7 +507,6 @@
     /**
      * If the {@link NotificationShelf} should be visible when dark.
      */
-    private boolean mShowDarkShelf;
     private boolean mAnimateBottomOnLayout;
 
     @Inject
@@ -1368,8 +1367,7 @@
             mIsClipped = clipped;
         }
 
-        if (!mAmbientPulseManager.hasNotifications()
-                && mAmbientState.isFullyDark() && mShowDarkShelf) {
+        if (!mAmbientPulseManager.hasNotifications() && mAmbientState.isFullyDark()) {
             setClipBounds(null);
         } else if (mAmbientState.isDarkAtAll()) {
             clipToOutline = true;
@@ -4723,9 +4721,6 @@
         if (mAmbientState.isDark() == dark) {
             return;
         }
-        if (!dark) {
-            mShowDarkShelf = false;
-        }
         mAmbientState.setDark(dark);
         if (animate && mAnimationsEnabled) {
             mDarkNeedsAnimation = true;
@@ -4787,7 +4782,7 @@
         boolean nowDarkAtAll = mAmbientState.isDarkAtAll();
         if (nowFullyDark != wasFullyDark) {
             updateContentHeight();
-            if (nowFullyDark && mShowDarkShelf) {
+            if (nowFullyDark) {
                 updateDarkShelfVisibility();
             }
         }
@@ -4803,14 +4798,6 @@
         requestChildrenUpdate();
     }
 
-    /**
-     * If the shelf should be visible when the device is in ambient mode (dozing.)
-     */
-    @ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
-    public void showDarkShelf() {
-        mShowDarkShelf = true;
-    }
-
     private void updateDarkShelfVisibility() {
         DozeParameters dozeParameters = DozeParameters.getInstance(mContext);
         if (dozeParameters.shouldControlScreenOff()) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/EdgeBackGestureHandler.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/EdgeBackGestureHandler.java
index 4638c40..aba64bdf 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/EdgeBackGestureHandler.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/EdgeBackGestureHandler.java
@@ -17,10 +17,6 @@
 
 import static android.view.Display.INVALID_DISPLAY;
 
-import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_BOUNCER_SHOWING;
-import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_NAV_BAR_HIDDEN;
-import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_NOTIFICATION_PANEL_EXPANDED;
-
 import android.content.Context;
 import android.content.pm.ParceledListSlice;
 import android.content.res.Resources;
@@ -318,9 +314,7 @@
             // either the bouncer is showing or the notification panel is hidden
             int stateFlags = mOverviewProxyService.getSystemUiStateFlags();
             mIsOnLeftEdge = ev.getX() <= mEdgeWidth;
-            mAllowGesture = (stateFlags & SYSUI_STATE_NAV_BAR_HIDDEN) == 0
-                    && ((stateFlags & SYSUI_STATE_BOUNCER_SHOWING) == SYSUI_STATE_BOUNCER_SHOWING
-                            || (stateFlags & SYSUI_STATE_NOTIFICATION_PANEL_EXPANDED) == 0)
+            mAllowGesture = !QuickStepContract.isBackGestureDisabled(stateFlags)
                     && isWithinTouchRegion((int) ev.getX(), (int) ev.getY());
             if (mAllowGesture) {
                 mEdgePanelLp.gravity = mIsOnLeftEdge
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarFragment.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarFragment.java
index e7dab8e..c9ba76c 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarFragment.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarFragment.java
@@ -329,8 +329,7 @@
         notifyNavigationBarScreenOn();
 
         mOverviewProxyService.addCallback(mOverviewProxyListener);
-        mOverviewProxyService.setSystemUiStateFlag(SYSUI_STATE_NAV_BAR_HIDDEN,
-                !isNavBarWindowVisible(), mDisplayId);
+        updateSystemUiStateFlags(-1);
 
         // Currently there is no accelerometer sensor on non-default display.
         if (mIsOnDefaultDisplay) {
@@ -458,8 +457,7 @@
             mNavigationBarWindowState = state;
             if (DEBUG_WINDOW_STATE) Log.d(TAG, "Navigation bar " + windowStateToString(state));
 
-            mOverviewProxyService.setSystemUiStateFlag(SYSUI_STATE_NAV_BAR_HIDDEN,
-                    !isNavBarWindowVisible(), mDisplayId);
+            updateSystemUiStateFlags(-1);
             mNavigationBarView.getRotateSuggestionButton()
                     .onNavigationBarWindowVisibilityChange(isNavBarWindowVisible());
         }
@@ -576,7 +574,9 @@
                 | StatusBarManager.DISABLE_SEARCH);
         if (masked != mDisabledFlags1) {
             mDisabledFlags1 = masked;
-            if (mNavigationBarView != null) mNavigationBarView.setDisabledFlags(state1);
+            if (mNavigationBarView != null) {
+                mNavigationBarView.setDisabledFlags(state1);
+            }
             updateScreenPinningGestures();
         }
 
@@ -860,18 +860,30 @@
 
     private void updateAccessibilityServicesState(AccessibilityManager accessibilityManager) {
         boolean[] feedbackEnabled = new boolean[1];
-        int flags = getA11yButtonState(feedbackEnabled);
+        int a11yFlags = getA11yButtonState(feedbackEnabled);
 
         mNavigationBarView.getRotateSuggestionButton()
                 .setAccessibilityFeedbackEnabled(feedbackEnabled[0]);
 
-        boolean clickable = (flags & SYSUI_STATE_A11Y_BUTTON_CLICKABLE) != 0;
-        boolean longClickable = (flags & SYSUI_STATE_A11Y_BUTTON_LONG_CLICKABLE) != 0;
+        boolean clickable = (a11yFlags & SYSUI_STATE_A11Y_BUTTON_CLICKABLE) != 0;
+        boolean longClickable = (a11yFlags & SYSUI_STATE_A11Y_BUTTON_LONG_CLICKABLE) != 0;
         mNavigationBarView.setAccessibilityButtonState(clickable, longClickable);
-        mOverviewProxyService.setSystemUiStateFlag(
-                SYSUI_STATE_A11Y_BUTTON_CLICKABLE, clickable, mDisplayId);
-        mOverviewProxyService.setSystemUiStateFlag(
-                SYSUI_STATE_A11Y_BUTTON_LONG_CLICKABLE, longClickable, mDisplayId);
+
+        updateSystemUiStateFlags(a11yFlags);
+    }
+
+    public void updateSystemUiStateFlags(int a11yFlags) {
+        if (a11yFlags < 0) {
+            a11yFlags = getA11yButtonState(null);
+        }
+        boolean clickable = (a11yFlags & SYSUI_STATE_A11Y_BUTTON_CLICKABLE) != 0;
+        boolean longClickable = (a11yFlags & SYSUI_STATE_A11Y_BUTTON_LONG_CLICKABLE) != 0;
+        mOverviewProxyService.setSystemUiStateFlag(SYSUI_STATE_A11Y_BUTTON_CLICKABLE,
+                clickable, mDisplayId);
+        mOverviewProxyService.setSystemUiStateFlag(SYSUI_STATE_A11Y_BUTTON_LONG_CLICKABLE,
+                longClickable, mDisplayId);
+        mOverviewProxyService.setSystemUiStateFlag(SYSUI_STATE_NAV_BAR_HIDDEN,
+                !isNavBarWindowVisible(), mDisplayId);
     }
 
     /**
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java
index 062fb6d..5f61975 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java
@@ -18,7 +18,10 @@
 
 import static android.view.WindowManagerPolicyConstants.NAV_BAR_MODE_3BUTTON;
 
+import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_HOME_DISABLED;
 import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_NOTIFICATION_PANEL_EXPANDED;
+import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_OVERVIEW_DISABLED;
+import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_SCREEN_PINNING;
 import static com.android.systemui.statusbar.phone.BarTransitions.MODE_OPAQUE;
 
 import android.animation.LayoutTransition;
@@ -319,6 +322,7 @@
 
     public void setComponents(NotificationPanelView panel, AssistManager assistManager) {
         mPanelView = panel;
+        updateSystemUiStateFlags();
     }
 
     @Override
@@ -573,6 +577,7 @@
         updateNavButtonIcons();
         updateSlippery();
         setUpSwipeUpOnboarding(isQuickStepSwipeUpEnabled());
+        updateSystemUiStateFlags();
     }
 
     public void updateNavButtonIcons() {
@@ -700,8 +705,21 @@
 
     public void onPanelExpandedChange() {
         updateSlippery();
-        mOverviewProxyService.setSystemUiStateFlag(SYSUI_STATE_NOTIFICATION_PANEL_EXPANDED,
-                mPanelView.isFullyExpanded(), getContext().getDisplayId());
+        updateSystemUiStateFlags();
+    }
+
+    public void updateSystemUiStateFlags() {
+        int displayId = mContext.getDisplayId();
+        mOverviewProxyService.setSystemUiStateFlag(SYSUI_STATE_SCREEN_PINNING,
+                ActivityManagerWrapper.getInstance().isScreenPinningActive(), displayId);
+        mOverviewProxyService.setSystemUiStateFlag(SYSUI_STATE_OVERVIEW_DISABLED,
+                (mDisabledFlags & View.STATUS_BAR_DISABLE_RECENT) != 0, displayId);
+        mOverviewProxyService.setSystemUiStateFlag(SYSUI_STATE_HOME_DISABLED,
+                (mDisabledFlags & View.STATUS_BAR_DISABLE_HOME) != 0, displayId);
+        if (mPanelView != null) {
+            mOverviewProxyService.setSystemUiStateFlag(SYSUI_STATE_NOTIFICATION_PANEL_EXPANDED,
+                    mPanelView.isFullyExpanded() && !mPanelView.isInSettings(), displayId);
+        }
     }
 
     public void updateStates() {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
index da9f244..3fe7f36 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
@@ -2853,9 +2853,6 @@
         if (dozing == mDozing) return;
         mDozing = dozing;
         mNotificationStackScroller.setDark(mDozing, animate, wakeUpTouchLocation);
-        if (mDozing) {
-            mNotificationStackScroller.showDarkShelf();
-        }
         mKeyguardBottomArea.setDozing(mDozing, animate);
 
         if (mBarState == StatusBarState.KEYGUARD
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java
index c6bbf7b..a9a3b2d 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java
@@ -1169,14 +1169,13 @@
     }
 
     protected void notifyBarPanelExpansionChanged() {
-        float fraction = mInstantExpanding ? 1 : mExpandedFraction;
         if (mBar != null) {
-            mBar.panelExpansionChanged(fraction, fraction > 0f
+            mBar.panelExpansionChanged(mExpandedFraction, mExpandedFraction > 0f
                     || mPeekAnimator != null || mInstantExpanding
                     || isPanelVisibleBecauseOfHeadsUp() || mTracking || mHeightAnimator != null);
         }
         if (mExpansionListener != null) {
-            mExpansionListener.onPanelExpansionChanged(fraction, mTracking);
+            mExpansionListener.onPanelExpansionChanged(mExpandedFraction, mTracking);
         }
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
index c43860f..72726b3 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
@@ -31,6 +31,7 @@
 import static com.android.systemui.keyguard.WakefulnessLifecycle.WAKEFULNESS_AWAKE;
 import static com.android.systemui.keyguard.WakefulnessLifecycle.WAKEFULNESS_WAKING;
 import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_BOUNCER_SHOWING;
+import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_STATUS_BAR_KEYGUARD_SHOWING;
 import static com.android.systemui.shared.system.WindowManagerWrapper.NAV_BAR_POS_INVALID;
 import static com.android.systemui.shared.system.WindowManagerWrapper.NAV_BAR_POS_LEFT;
 import static com.android.systemui.statusbar.NotificationLockscreenUserManager.PERMISSION_SELF;
@@ -785,6 +786,7 @@
         Dependency.get(InitController.class).addPostInitTask(
                 () -> setUpDisableFlags(disabledFlags1, disabledFlags2));
 
+        updateSystemUiStateFlags();
     }
 
     // ================================================================================
@@ -3416,6 +3418,7 @@
         updateDozingState();
         checkBarModes();
         updateScrimController();
+        updateSystemUiStateFlags();
         mPresenter.updateMediaMetaData(false, mState != StatusBarState.KEYGUARD);
         mKeyguardMonitor.notifyKeyguardState(mStatusBarKeyguardViewManager.isShowing(),
                 mUnlockMethodCache.isMethodSecure(),
@@ -3582,10 +3585,16 @@
         if (!mBouncerShowing) {
             updatePanelExpansionForKeyguard();
         }
+        updateSystemUiStateFlags();
+    }
 
-        // Notify overview proxy service of the new states
-        Dependency.get(OverviewProxyService.class).setSystemUiStateFlag(SYSUI_STATE_BOUNCER_SHOWING,
-                isBouncerShowing(), mContext.getDisplayId());
+    public void updateSystemUiStateFlags() {
+        OverviewProxyService overviewProxyService = Dependency.get(OverviewProxyService.class);
+        overviewProxyService.setSystemUiStateFlag(SYSUI_STATE_STATUS_BAR_KEYGUARD_SHOWING,
+                mStatusBarStateController.getState() == StatusBarState.KEYGUARD,
+                mDisplayId);
+        overviewProxyService.setSystemUiStateFlag(SYSUI_STATE_BOUNCER_SHOWING,
+                isBouncerShowing(), mDisplayId);
     }
 
     /**
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusIconContainer.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusIconContainer.java
index 22006db..d061649 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusIconContainer.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusIconContainer.java
@@ -378,8 +378,18 @@
         public int visibleState = STATE_ICON;
         public boolean justAdded = true;
 
+        // How far we are from the end of the view actually is the most relevant for animation
+        float distanceToViewEnd = -1;
+
         @Override
         public void applyToView(View view) {
+            float parentWidth = 0;
+            if (view.getParent() instanceof View) {
+                parentWidth = ((View) view.getParent()).getWidth();
+            }
+
+            float currentDistanceToEnd = parentWidth - xTranslation;
+
             if (!(view instanceof StatusIconDisplayable)) {
                 return;
             }
@@ -403,7 +413,7 @@
                     // all other transitions (to/from dot, etc)
                     animationProperties = ANIMATE_ALL_PROPERTIES;
                 }
-            } else if (visibleState != STATE_HIDDEN && xTranslation != view.getTranslationX()) {
+            } else if (visibleState != STATE_HIDDEN && distanceToViewEnd != currentDistanceToEnd) {
                 // Visibility isn't changing, just animate position
                 animationProperties = X_ANIMATION_PROPERTIES;
             }
@@ -416,6 +426,8 @@
             }
 
             justAdded = false;
+            distanceToViewEnd = currentDistanceToEnd;
+
         }
     }
 
diff --git a/packages/SystemUI/tests/src/com/android/systemui/bubbles/animation/ExpandedAnimationControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/bubbles/animation/ExpandedAnimationControllerTest.java
index a1c5707..74b15fb 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/bubbles/animation/ExpandedAnimationControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/bubbles/animation/ExpandedAnimationControllerTest.java
@@ -145,6 +145,7 @@
     }
 
     @Test
+    @Ignore("Flaky")
     public void testMagnetToDismiss_dismiss() throws InterruptedException {
         expand();
 
diff --git a/packages/SystemUI/tests/src/com/android/systemui/bubbles/animation/StackAnimationControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/bubbles/animation/StackAnimationControllerTest.java
index 9b894c3..9218a8b 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/bubbles/animation/StackAnimationControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/bubbles/animation/StackAnimationControllerTest.java
@@ -234,6 +234,7 @@
     }
 
     @Test
+    @Ignore("Flaky")
     public void testMagnetToDismiss_dismiss() throws InterruptedException {
         final Runnable after = Mockito.mock(Runnable.class);
 
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationPanelViewTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationPanelViewTest.java
index 08471d8..2f9d892 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationPanelViewTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationPanelViewTest.java
@@ -119,25 +119,10 @@
         mNotificationPanelView.setDozing(true /* dozing */, true /* animate */, null /* touch */);
         InOrder inOrder = inOrder(mNotificationStackScrollLayout, mStatusBarStateController);
         inOrder.verify(mNotificationStackScrollLayout).setDark(eq(true), eq(true), eq(null));
-        inOrder.verify(mNotificationStackScrollLayout).showDarkShelf();
         inOrder.verify(mStatusBarStateController).setDozeAmount(eq(1f), eq(true));
     }
 
     @Test
-    public void testSetDozing_showsDarkShelfWithDefaultClock() {
-        when(mKeyguardStatusView.hasCustomClock()).thenReturn(false);
-        mNotificationPanelView.setDozing(true /* dozing */, true /* animate */, null /* touch */);
-        verify(mNotificationStackScrollLayout).showDarkShelf();
-    }
-
-    @Test
-    public void testSetDozing_showsDarkShelfWhenCustomClock() {
-        when(mKeyguardStatusView.hasCustomClock()).thenReturn(true);
-        mNotificationPanelView.setDozing(true /* dozing */, true /* animate */, null /* touch */);
-        verify(mNotificationStackScrollLayout).showDarkShelf();
-    }
-
-    @Test
     public void testSetExpandedHeight() {
         mNotificationPanelView.setExpandedHeight(200);
         assertThat((int) mNotificationPanelView.getExpandedHeight()).isEqualTo(200);
diff --git a/packages/overlays/DisplayCutoutEmulationCornerOverlay/res/values-km/strings.xml b/packages/overlays/DisplayCutoutEmulationCornerOverlay/res/values-km/strings.xml
index fb0d88e..287817f 100644
--- a/packages/overlays/DisplayCutoutEmulationCornerOverlay/res/values-km/strings.xml
+++ b/packages/overlays/DisplayCutoutEmulationCornerOverlay/res/values-km/strings.xml
@@ -17,5 +17,5 @@
 
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="display_cutout_emulation_overlay" msgid="1677693377327336341">"សក់សេះនៅជ្រុង"</string>
+    <string name="display_cutout_emulation_overlay" msgid="1677693377327336341">"ក្បាលឆកនៅជ្រុង"</string>
 </resources>
diff --git a/packages/overlays/DisplayCutoutEmulationDoubleOverlay/res/values-km/strings.xml b/packages/overlays/DisplayCutoutEmulationDoubleOverlay/res/values-km/strings.xml
index 1553594..312817f 100644
--- a/packages/overlays/DisplayCutoutEmulationDoubleOverlay/res/values-km/strings.xml
+++ b/packages/overlays/DisplayCutoutEmulationDoubleOverlay/res/values-km/strings.xml
@@ -17,5 +17,5 @@
 
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="display_cutout_emulation_overlay" msgid="5323179900047630217">"សក់សេះ​ភ្លោះ"</string>
+    <string name="display_cutout_emulation_overlay" msgid="5323179900047630217">"ក្បាលឆក​ភ្លោះ"</string>
 </resources>
diff --git a/packages/overlays/DisplayCutoutEmulationNarrowOverlay/res/values-km/strings.xml b/packages/overlays/DisplayCutoutEmulationNarrowOverlay/res/values-km/strings.xml
index 97e867f..1fe37a7 100644
--- a/packages/overlays/DisplayCutoutEmulationNarrowOverlay/res/values-km/strings.xml
+++ b/packages/overlays/DisplayCutoutEmulationNarrowOverlay/res/values-km/strings.xml
@@ -19,5 +19,5 @@
 
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="display_cutout_emulation_overlay" msgid="3947428012427075896">"សក់សេះ​តូច"</string>
+    <string name="display_cutout_emulation_overlay" msgid="3947428012427075896">"ក្បាលឆក​តូច"</string>
 </resources>
diff --git a/packages/overlays/DisplayCutoutEmulationTallOverlay/res/values-km/strings.xml b/packages/overlays/DisplayCutoutEmulationTallOverlay/res/values-km/strings.xml
index 5a01a62..38fc08c 100644
--- a/packages/overlays/DisplayCutoutEmulationTallOverlay/res/values-km/strings.xml
+++ b/packages/overlays/DisplayCutoutEmulationTallOverlay/res/values-km/strings.xml
@@ -17,5 +17,5 @@
 
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="display_cutout_emulation_overlay" msgid="6424539415439220018">"សក់សេះវែង"</string>
+    <string name="display_cutout_emulation_overlay" msgid="6424539415439220018">"ក្បាលឆកវែង"</string>
 </resources>
diff --git a/packages/overlays/DisplayCutoutEmulationWideOverlay/res/values-km/strings.xml b/packages/overlays/DisplayCutoutEmulationWideOverlay/res/values-km/strings.xml
index 7325a73..3a720fd5 100644
--- a/packages/overlays/DisplayCutoutEmulationWideOverlay/res/values-km/strings.xml
+++ b/packages/overlays/DisplayCutoutEmulationWideOverlay/res/values-km/strings.xml
@@ -17,5 +17,5 @@
 
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="display_cutout_emulation_overlay" msgid="4043478945358357737">"សក់សេះ​ធំ"</string>
+    <string name="display_cutout_emulation_overlay" msgid="4043478945358357737">"ក្បាលឆក​ធំ"</string>
 </resources>
diff --git a/proto/src/metrics_constants/metrics_constants.proto b/proto/src/metrics_constants/metrics_constants.proto
index 4131e79..2616466 100644
--- a/proto/src/metrics_constants/metrics_constants.proto
+++ b/proto/src/metrics_constants/metrics_constants.proto
@@ -7365,10 +7365,11 @@
     // OS: Q
     FIELD_EMERGENCY_DIALER_DISCONNECT_CAUSE = 1739;
 
-    // Custom tag for NotificationItem. Hash of the NAS that made adjustments.
-    FIELD_NOTIFICATION_ASSISTANT_SERVICE_HASH = 1740;
-
-    // ---- Skipping ahead to avoid conflicts between master and release branches.
+    // OPEN: Settings > Display > Dark Theme
+    // CATEGORY: SETTINGS
+    // OS: Q
+    // Note: Only shows up on first time toggle
+    DIALOG_DARK_UI_INFO = 1740;
 
     // ---- End Q Constants, all Q constants go above this line ----
     // Add new aosp constants above this line.
diff --git a/services/art-profile b/services/art-profile
index cf0f13c..a9d5982 100644
--- a/services/art-profile
+++ b/services/art-profile
@@ -13532,7 +13532,7 @@
 HSPLcom/android/server/uri/UriGrantsManagerService;->checkUriPermission(Lcom/android/server/uri/GrantUri;II)Z
 HSPLcom/android/server/uri/UriGrantsManagerService;->enforceNotIsolatedCaller(Ljava/lang/String;)V
 HSPLcom/android/server/uri/UriGrantsManagerService;->findOrCreateUriPermission(Ljava/lang/String;Ljava/lang/String;ILcom/android/server/uri/GrantUri;)Lcom/android/server/uri/UriPermission;
-PLcom/android/server/uri/UriGrantsManagerService;->getPersistedUriPermissions(Ljava/lang/String;Z)Landroid/content/pm/ParceledListSlice;
+PLcom/android/server/uri/UriGrantsManagerService;->getPersistedUriPermissions(Ljava/lang/String;ZZ)Landroid/content/pm/ParceledListSlice;
 HSPLcom/android/server/uri/UriGrantsManagerService;->getProviderInfo(Ljava/lang/String;II)Landroid/content/pm/ProviderInfo;
 HSPLcom/android/server/uri/UriGrantsManagerService;->grantUriPermission(ILjava/lang/String;Lcom/android/server/uri/GrantUri;ILcom/android/server/uri/UriPermissionOwner;I)V
 HSPLcom/android/server/uri/UriGrantsManagerService;->grantUriPermissionFromIntent(ILjava/lang/String;Landroid/content/Intent;Lcom/android/server/uri/UriPermissionOwner;I)V
diff --git a/services/autofill/java/com/android/server/autofill/RemoteAugmentedAutofillService.java b/services/autofill/java/com/android/server/autofill/RemoteAugmentedAutofillService.java
index d2b71e5..d42943c 100644
--- a/services/autofill/java/com/android/server/autofill/RemoteAugmentedAutofillService.java
+++ b/services/autofill/java/com/android/server/autofill/RemoteAugmentedAutofillService.java
@@ -225,17 +225,7 @@
 
                 @Override
                 public void cancel() {
-                    synchronized (mLock) {
-                        final boolean cancelled = isCancelledLocked();
-                        final ICancellationSignal cancellation = mCancellation;
-                        if (!cancelled) {
-                            try {
-                                cancellation.cancel();
-                            } catch (RemoteException e) {
-                                Slog.e(mTag, "Error requesting a cancellation", e);
-                            }
-                        }
-                    }
+                    PendingAutofillRequest.this.cancel();
                 }
             };
         }
@@ -304,7 +294,7 @@
                 try {
                     cancellation.cancel();
                 } catch (RemoteException e) {
-                    Slog.e(mTag, "Error cancelling a fill request", e);
+                    Slog.e(mTag, "Error cancelling an augmented fill request", e);
                 }
             }
             return true;
diff --git a/services/core/java/com/android/server/appop/AppOpsService.java b/services/core/java/com/android/server/appop/AppOpsService.java
index 3bed9c3..0a76845 100644
--- a/services/core/java/com/android/server/appop/AppOpsService.java
+++ b/services/core/java/com/android/server/appop/AppOpsService.java
@@ -3814,8 +3814,9 @@
             if (mActiveWatchers.size() > 0 && dumpMode < 0) {
                 needSep = true;
                 boolean printedHeader = false;
-                for (int i = 0; i < mActiveWatchers.size(); i++) {
-                    final SparseArray<ActiveCallback> activeWatchers = mActiveWatchers.valueAt(i);
+                for (int watcherNum = 0; watcherNum < mActiveWatchers.size(); watcherNum++) {
+                    final SparseArray<ActiveCallback> activeWatchers =
+                            mActiveWatchers.valueAt(watcherNum);
                     if (activeWatchers.size() <= 0) {
                         continue;
                     }
@@ -3833,16 +3834,16 @@
                     }
                     pw.print("    ");
                     pw.print(Integer.toHexString(System.identityHashCode(
-                            mActiveWatchers.keyAt(i))));
+                            mActiveWatchers.keyAt(watcherNum))));
                     pw.println(" ->");
                     pw.print("        [");
                     final int opCount = activeWatchers.size();
-                    for (i = 0; i < opCount; i++) {
-                        if (i > 0) {
+                    for (int opNum = 0; opNum < opCount; opNum++) {
+                        if (opNum > 0) {
                             pw.print(' ');
                         }
-                        pw.print(AppOpsManager.opToName(activeWatchers.keyAt(i)));
-                        if (i < opCount - 1) {
+                        pw.print(AppOpsManager.opToName(activeWatchers.keyAt(opNum)));
+                        if (opNum < opCount - 1) {
                             pw.print(',');
                         }
                     }
diff --git a/services/core/java/com/android/server/attention/AttentionManagerService.java b/services/core/java/com/android/server/attention/AttentionManagerService.java
index e148468..3b19d08 100644
--- a/services/core/java/com/android/server/attention/AttentionManagerService.java
+++ b/services/core/java/com/android/server/attention/AttentionManagerService.java
@@ -116,6 +116,14 @@
     }
 
     @Override
+    public void onBootPhase(int phase) {
+        if (phase == SystemService.PHASE_SYSTEM_SERVICES_READY) {
+            mContext.registerReceiver(new ScreenStateReceiver(),
+                    new IntentFilter(Intent.ACTION_SCREEN_OFF));
+        }
+    }
+
+    @Override
     public void onStart() {
         publishBinderService(Context.ATTENTION_SERVICE, new BinderService());
         publishLocalService(AttentionManagerInternal.class, new LocalService());
@@ -135,10 +143,6 @@
     private boolean isServiceAvailable() {
         if (mComponentName == null) {
             mComponentName = resolveAttentionService(mContext);
-            if (mComponentName != null) {
-                mContext.registerReceiver(new ScreenStateReceiver(),
-                        new IntentFilter(Intent.ACTION_SCREEN_OFF));
-            }
         }
         return mComponentName != null;
     }
diff --git a/services/core/java/com/android/server/audio/AudioService.java b/services/core/java/com/android/server/audio/AudioService.java
index 86832f4..15e8851 100644
--- a/services/core/java/com/android/server/audio/AudioService.java
+++ b/services/core/java/com/android/server/audio/AudioService.java
@@ -1452,7 +1452,13 @@
                         Settings.Secure.ASSISTANT, UserHandle.USER_CURRENT);
             }
             if (!TextUtils.isEmpty(assistantName)) {
-                packageName = ComponentName.unflattenFromString(assistantName).getPackageName();
+                ComponentName componentName = ComponentName.unflattenFromString(assistantName);
+                if (componentName == null) {
+                    Slog.w(TAG, "Invalid service name for "
+                            + Settings.Secure.VOICE_INTERACTION_SERVICE + ": " + assistantName);
+                    return;
+                }
+                packageName = componentName.getPackageName();
             }
         }
         if (!TextUtils.isEmpty(packageName)) {
diff --git a/services/core/java/com/android/server/camera/CameraServiceProxy.java b/services/core/java/com/android/server/camera/CameraServiceProxy.java
index 7733d67..8de2595 100644
--- a/services/core/java/com/android/server/camera/CameraServiceProxy.java
+++ b/services/core/java/com/android/server/camera/CameraServiceProxy.java
@@ -42,6 +42,7 @@
 import com.android.server.LocalServices;
 import com.android.server.ServiceThread;
 import com.android.server.SystemService;
+import com.android.server.wm.WindowManagerInternal;
 
 import java.util.ArrayList;
 import java.util.Collection;
@@ -90,8 +91,10 @@
 
     private ICameraService mCameraServiceRaw;
 
+    // Map of currently active camera IDs
     private final ArrayMap<String, CameraUsageEvent> mActiveCameraUsage = new ArrayMap<>();
     private final List<CameraUsageEvent> mCameraUsageHistory = new ArrayList<>();
+
     private final MetricsLogger mLogger = new MetricsLogger();
     private static final String NFC_NOTIFICATION_PROP = "ro.camera.notify_nfc";
     private static final String NFC_SERVICE_BINDER_NAME = "nfc";
@@ -415,6 +418,24 @@
                     }
                     break;
                 case ICameraServiceProxy.CAMERA_STATE_ACTIVE:
+                    // Check current active camera IDs to see if this package is already talking to
+                    // some camera
+                    boolean alreadyActivePackage = false;
+                    for (int i = 0; i < mActiveCameraUsage.size(); i++) {
+                        if (mActiveCameraUsage.valueAt(i).mClientName.equals(clientName)) {
+                            alreadyActivePackage = true;
+                            break;
+                        }
+                    }
+                    // If not already active, notify window manager about this new package using a
+                    // camera
+                    if (!alreadyActivePackage) {
+                        WindowManagerInternal wmi =
+                                LocalServices.getService(WindowManagerInternal.class);
+                        wmi.addNonHighRefreshRatePackage(clientName);
+                    }
+
+                    // Update activity events
                     CameraUsageEvent newEvent = new CameraUsageEvent(facing, clientName, apiLevel);
                     CameraUsageEvent oldEvent = mActiveCameraUsage.put(cameraId, newEvent);
                     if (oldEvent != null) {
@@ -426,13 +447,31 @@
                 case ICameraServiceProxy.CAMERA_STATE_IDLE:
                 case ICameraServiceProxy.CAMERA_STATE_CLOSED:
                     CameraUsageEvent doneEvent = mActiveCameraUsage.remove(cameraId);
-                    if (doneEvent != null) {
-                        doneEvent.markCompleted();
-                        mCameraUsageHistory.add(doneEvent);
-                        if (mCameraUsageHistory.size() > MAX_USAGE_HISTORY) {
-                            dumpUsageEvents();
+                    if (doneEvent == null) break;
+
+                    doneEvent.markCompleted();
+                    mCameraUsageHistory.add(doneEvent);
+                    if (mCameraUsageHistory.size() > MAX_USAGE_HISTORY) {
+                        dumpUsageEvents();
+                    }
+
+                    // Check current active camera IDs to see if this package is still talking to
+                    // some camera
+                    boolean stillActivePackage = false;
+                    for (int i = 0; i < mActiveCameraUsage.size(); i++) {
+                        if (mActiveCameraUsage.valueAt(i).mClientName.equals(clientName)) {
+                            stillActivePackage = true;
+                            break;
                         }
                     }
+                    // If not longer active, notify window manager about this package being done
+                    // with camera
+                    if (!stillActivePackage) {
+                        WindowManagerInternal wmi =
+                                LocalServices.getService(WindowManagerInternal.class);
+                        wmi.removeNonHighRefreshRatePackage(clientName);
+                    }
+
                     break;
             }
             boolean isEmpty = mActiveCameraUsage.isEmpty();
diff --git a/services/core/java/com/android/server/content/SyncManager.java b/services/core/java/com/android/server/content/SyncManager.java
index d8b7c2e..fa8c48b 100644
--- a/services/core/java/com/android/server/content/SyncManager.java
+++ b/services/core/java/com/android/server/content/SyncManager.java
@@ -1170,7 +1170,7 @@
     }
 
     private void removeSyncsForAuthority(EndPoint info, String why) {
-        mLogger.log("removeSyncsForAuthority: ", info);
+        mLogger.log("removeSyncsForAuthority: ", info, why);
         verifyJobScheduler();
         List<SyncOperation> ops = getAllPendingSyncs();
         for (SyncOperation op: ops) {
diff --git a/services/core/java/com/android/server/content/SyncStorageEngine.java b/services/core/java/com/android/server/content/SyncStorageEngine.java
index c7a3f4b..e09c661 100644
--- a/services/core/java/com/android/server/content/SyncStorageEngine.java
+++ b/services/core/java/com/android/server/content/SyncStorageEngine.java
@@ -1027,7 +1027,7 @@
      * Called when the set of account has changed, given the new array of
      * active accounts.
      */
-    public void removeStaleAccounts(@Nullable Account[] accounts, int userId) {
+    public void removeStaleAccounts(@Nullable Account[] currentAccounts, int userId) {
         synchronized (mAuthorities) {
             if (Log.isLoggable(TAG, Log.VERBOSE)) {
                 Slog.v(TAG, "Updating for new accounts...");
@@ -1036,9 +1036,11 @@
             Iterator<AccountInfo> accIt = mAccounts.values().iterator();
             while (accIt.hasNext()) {
                 AccountInfo acc = accIt.next();
-                if ((accounts == null) || (
-                        (acc.accountAndUser.userId == userId)
-                        && !ArrayUtils.contains(accounts, acc.accountAndUser.account))) {
+                if (acc.accountAndUser.userId != userId) {
+                    continue; // Irrelevant user.
+                }
+                if ((currentAccounts == null)
+                        || !ArrayUtils.contains(currentAccounts, acc.accountAndUser.account)) {
                     // This account no longer exists...
                     if (Log.isLoggable(TAG, Log.VERBOSE)) {
                         Slog.v(TAG, "Account removed: " + acc.accountAndUser);
diff --git a/services/core/java/com/android/server/location/GnssConfiguration.java b/services/core/java/com/android/server/location/GnssConfiguration.java
index aa51aec..86a84e3 100644
--- a/services/core/java/com/android/server/location/GnssConfiguration.java
+++ b/services/core/java/com/android/server/location/GnssConfiguration.java
@@ -70,7 +70,6 @@
     private static final String CONFIG_GPS_LOCK = "GPS_LOCK";
     private static final String CONFIG_ES_EXTENSION_SEC = "ES_EXTENSION_SEC";
     public static final String CONFIG_NFW_PROXY_APPS = "NFW_PROXY_APPS";
-    public static final String CONFIG_ES_NOTIFY_INT = "ES_NOTIFY_INT";
 
     // Limit on NI emergency mode time extension after emergency sessions ends
     private static final int MAX_EMERGENCY_MODE_EXTENSION_SECONDS = 300;  // 5 minute maximum
@@ -200,14 +199,6 @@
     }
 
     /**
-     * Returns the value of config parameter ES_NOTIFY_INT or {@code defaulEsNotify} if no
-     * value is provided or if there is an error parsing the configured value.
-     */
-    int getEsNotify(int defaulEsNotify) {
-        return getIntConfig(CONFIG_ES_NOTIFY_INT, defaulEsNotify);
-    }
-
-    /**
      * Updates the GNSS HAL satellite blacklist.
      */
     void setSatelliteBlacklist(int[] constellations, int[] svids) {
diff --git a/services/core/java/com/android/server/location/GnssVisibilityControl.java b/services/core/java/com/android/server/location/GnssVisibilityControl.java
index c49d900..b7e0a0f 100644
--- a/services/core/java/com/android/server/location/GnssVisibilityControl.java
+++ b/services/core/java/com/android/server/location/GnssVisibilityControl.java
@@ -18,6 +18,9 @@
 
 import android.annotation.SuppressLint;
 import android.app.AppOpsManager;
+import android.app.Notification;
+import android.app.NotificationManager;
+import android.app.PendingIntent;
 import android.content.BroadcastReceiver;
 import android.content.Context;
 import android.content.Intent;
@@ -35,6 +38,7 @@
 
 import com.android.internal.R;
 import com.android.internal.location.GpsNetInitiatedHandler;
+import com.android.internal.notification.SystemNotificationChannels;
 
 import java.util.Arrays;
 import java.util.List;
@@ -58,11 +62,6 @@
     // Max wait time for synchronous method onGpsEnabledChanged() to run.
     private static final long ON_GPS_ENABLED_CHANGED_TIMEOUT_MILLIS = 3 * 1000;
 
-    // Valid values for config parameter es_notify_int for posting notification in the status
-    // bar for non-framework location requests in user-initiated emergency use cases.
-    private static final int ES_NOTIFY_NONE = 0;
-    private static final int ES_NOTIFY_ALL = 1;
-
     // Wakelocks
     private static final String WAKELOCK_KEY = TAG;
     private static final long WAKELOCK_TIMEOUT_MILLIS = 60 * 1000;
@@ -74,9 +73,9 @@
     private final Handler mHandler;
     private final Context mContext;
     private final GpsNetInitiatedHandler mNiHandler;
+    private final Notification mEmergencyLocationUserNotification;
 
     private boolean mIsGpsEnabled;
-    private boolean mEsNotify;
 
     // Number of non-framework location access proxy apps is expected to be small (< 5).
     private static final int ARRAY_MAP_INITIAL_CAPACITY_PROXY_APP_TO_LOCATION_PERMISSIONS = 7;
@@ -94,6 +93,7 @@
         mNiHandler = niHandler;
         mAppOps = mContext.getSystemService(AppOpsManager.class);
         mPackageManager = mContext.getPackageManager();
+        mEmergencyLocationUserNotification = createEmergencyLocationUserNotification(mContext);
 
         // Complete initialization as the first event to run in mHandler thread. After that,
         // all object state read/update events run in the mHandler thread.
@@ -135,22 +135,7 @@
     void onConfigurationUpdated(GnssConfiguration configuration) {
         // The configuration object must be accessed only in the caller thread and not in mHandler.
         List<String> nfwLocationAccessProxyApps = configuration.getProxyApps();
-        int esNotify = configuration.getEsNotify(ES_NOTIFY_NONE);
-        runOnHandler(() -> {
-            setEsNotify(esNotify);
-            handleUpdateProxyApps(nfwLocationAccessProxyApps);
-        });
-    }
-
-    private void setEsNotify(int esNotify) {
-        if (esNotify != ES_NOTIFY_NONE && esNotify != ES_NOTIFY_ALL) {
-            Log.e(TAG, "Config parameter " + GnssConfiguration.CONFIG_ES_NOTIFY_INT
-                    + " is set to invalid value: " + esNotify
-                    + ". Using default value: " + ES_NOTIFY_NONE);
-            esNotify = ES_NOTIFY_NONE;
-        }
-
-        mEsNotify = (esNotify == ES_NOTIFY_ALL);
+        runOnHandler(() -> handleUpdateProxyApps(nfwLocationAccessProxyApps));
     }
 
     private void handleInitialize() {
@@ -278,9 +263,6 @@
         private static final byte NFW_RESPONSE_TYPE_ACCEPTED_NO_LOCATION_PROVIDED = 1;
         private static final byte NFW_RESPONSE_TYPE_ACCEPTED_LOCATION_PROVIDED = 2;
 
-        // This must match with NfwProtocolStack enum in IGnssVisibilityControlCallback.hal.
-        private static final byte NFW_PROTOCOL_STACK_SUPL = 1;
-
         private final String mProxyAppPackageName;
         private final byte mProtocolStack;
         private final String mOtherProtocolStackName;
@@ -341,10 +323,6 @@
         private boolean isEmergencyRequestNotification() {
             return mInEmergencyMode && !isRequestAttributedToProxyApp();
         }
-
-        private boolean isRequestTypeSupl() {
-            return mProtocolStack == NFW_PROTOCOL_STACK_SUPL;
-        }
     }
 
     private void handlePermissionsChanged(int uid) {
@@ -517,27 +495,44 @@
 
         logEvent(nfwNotification, isPermissionMismatched);
 
-        if (mEsNotify && nfwNotification.isLocationProvided()) {
-            // Emulate deprecated IGnssNi.hal user notification of emergency NI requests.
-            GpsNetInitiatedHandler.GpsNiNotification notification =
-                    new GpsNetInitiatedHandler.GpsNiNotification();
-            notification.notificationId = 0;
-            notification.niType = nfwNotification.isRequestTypeSupl()
-                    ? GpsNetInitiatedHandler.GPS_NI_TYPE_EMERGENCY_SUPL
-                    : GpsNetInitiatedHandler.GPS_NI_TYPE_UMTS_CTRL_PLANE;
-            notification.needNotify = true;
-            notification.needVerify = false;
-            notification.privacyOverride = false;
-            notification.timeout = 0;
-            notification.defaultResponse = GpsNetInitiatedHandler.GPS_NI_RESPONSE_NORESP;
-            notification.requestorId = nfwNotification.mRequestorId;
-            notification.requestorIdEncoding = GpsNetInitiatedHandler.GPS_ENC_NONE;
-            notification.text = mContext.getString(R.string.global_action_emergency);
-            notification.textEncoding = GpsNetInitiatedHandler.GPS_ENC_NONE;
-            mNiHandler.setNiNotification(notification);
+        if (nfwNotification.isLocationProvided()) {
+            postEmergencyLocationUserNotification(nfwNotification);
         }
     }
 
+    private void postEmergencyLocationUserNotification(NfwNotification nfwNotification) {
+        // Emulate deprecated IGnssNi.hal user notification of emergency NI requests.
+        NotificationManager notificationManager = (NotificationManager) mContext
+                .getSystemService(Context.NOTIFICATION_SERVICE);
+        if (notificationManager == null) {
+            Log.w(TAG, "Could not notify user of emergency location request. Notification: "
+                    + nfwNotification);
+            return;
+        }
+
+        notificationManager.notifyAsUser(/* tag= */ null, /* notificationId= */ 0,
+                mEmergencyLocationUserNotification, UserHandle.ALL);
+    }
+
+    private static Notification createEmergencyLocationUserNotification(Context context) {
+        String firstLineText = context.getString(R.string.gpsNotifTitle);
+        String secondLineText =  context.getString(R.string.global_action_emergency);
+        String accessibilityServicesText = firstLineText + " (" + secondLineText + ")";
+        return new Notification.Builder(context, SystemNotificationChannels.NETWORK_ALERTS)
+                .setSmallIcon(com.android.internal.R.drawable.stat_sys_gps_on)
+                .setWhen(0)
+                .setOngoing(true)
+                .setAutoCancel(true)
+                .setColor(context.getColor(
+                        com.android.internal.R.color.system_notification_accent_color))
+                .setDefaults(0)
+                .setTicker(accessibilityServicesText)
+                .setContentTitle(firstLineText)
+                .setContentText(secondLineText)
+                .setContentIntent(PendingIntent.getBroadcast(context, 0, new Intent(), 0))
+                .build();
+    }
+
     private void logEvent(NfwNotification notification, boolean isPermissionMismatched) {
         StatsLog.write(StatsLog.GNSS_NFW_NOTIFICATION_REPORTED,
                 notification.mProxyAppPackageName,
diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java
index 82bf003..8c58247 100644
--- a/services/core/java/com/android/server/notification/NotificationManagerService.java
+++ b/services/core/java/com/android/server/notification/NotificationManagerService.java
@@ -46,6 +46,7 @@
 import static android.content.Context.BIND_ALLOW_WHITELIST_MANAGEMENT;
 import static android.content.Context.BIND_AUTO_CREATE;
 import static android.content.Context.BIND_FOREGROUND_SERVICE;
+import static android.content.pm.ActivityInfo.DOCUMENT_LAUNCH_ALWAYS;
 import static android.content.pm.PackageManager.FEATURE_LEANBACK;
 import static android.content.pm.PackageManager.FEATURE_TELEVISION;
 import static android.content.pm.PackageManager.MATCH_ALL;
@@ -82,6 +83,9 @@
 import static android.service.notification.NotificationListenerService.REASON_USER_STOPPED;
 import static android.service.notification.NotificationListenerService.TRIM_FULL;
 import static android.service.notification.NotificationListenerService.TRIM_LIGHT;
+import static android.util.StatsLogInternal.BUBBLE_DEVELOPER_ERROR_REPORTED__ERROR__ACTIVITY_INFO_MISSING;
+import static android.util.StatsLogInternal.BUBBLE_DEVELOPER_ERROR_REPORTED__ERROR__ACTIVITY_INFO_NOT_RESIZABLE;
+import static android.util.StatsLogInternal.BUBBLE_DEVELOPER_ERROR_REPORTED__ERROR__DOCUMENT_LAUNCH_NOT_ALWAYS;
 import static android.view.WindowManager.LayoutParams.TYPE_TOAST;
 
 import static com.android.server.am.PendingIntentRecord.FLAG_ACTIVITY_SENDER;
@@ -131,6 +135,7 @@
 import android.content.Context;
 import android.content.Intent;
 import android.content.IntentFilter;
+import android.content.pm.ActivityInfo;
 import android.content.pm.ApplicationInfo;
 import android.content.pm.IPackageManager;
 import android.content.pm.PackageManager;
@@ -197,6 +202,7 @@
 import android.util.Pair;
 import android.util.Slog;
 import android.util.SparseArray;
+import android.util.StatsLog;
 import android.util.Xml;
 import android.util.proto.ProtoOutputStream;
 import android.view.accessibility.AccessibilityEvent;
@@ -4821,10 +4827,14 @@
     private boolean isNotificationAppropriateToBubble(NotificationRecord r, String pkg, int userId,
             NotificationRecord oldRecord) {
         Notification notification = r.getNotification();
+        Notification.BubbleMetadata metadata = notification.getBubbleMetadata();
+        boolean intentCanBubble = metadata != null
+                && canLaunchInActivityView(getContext(), metadata.getIntent(), pkg);
 
         // Does the app want to bubble & is able to bubble
-        boolean canBubble = notification.getBubbleMetadata() != null
+        boolean canBubble = intentCanBubble
                 && mPreferencesHelper.areBubblesAllowed(pkg, userId)
+                && mPreferencesHelper.bubblesEnabled(r.sbn.getUser())
                 && r.getChannel().canBubble()
                 && !mActivityManager.isLowRamDevice();
 
@@ -4868,6 +4878,63 @@
         return false;
     }
 
+    /**
+     * Whether an intent is properly configured to display in an {@link android.app.ActivityView}.
+     *
+     * @param context       the context to use.
+     * @param pendingIntent the pending intent of the bubble.
+     * @param packageName   the notification package name for this bubble.
+     */
+    // Keep checks in sync with BubbleController#canLaunchInActivityView.
+    @VisibleForTesting
+    protected boolean canLaunchInActivityView(Context context, PendingIntent pendingIntent,
+            String packageName) {
+        if (pendingIntent == null) {
+            Log.w(TAG, "Unable to create bubble -- no intent");
+            return false;
+        }
+
+        // Need escalated privileges to get the intent.
+        final long token = Binder.clearCallingIdentity();
+        Intent intent;
+        try {
+            intent = pendingIntent.getIntent();
+        } finally {
+            Binder.restoreCallingIdentity(token);
+        }
+
+        ActivityInfo info = intent != null
+                ? intent.resolveActivityInfo(context.getPackageManager(), 0)
+                : null;
+        if (info == null) {
+            StatsLog.write(StatsLog.BUBBLE_DEVELOPER_ERROR_REPORTED, packageName,
+                    BUBBLE_DEVELOPER_ERROR_REPORTED__ERROR__ACTIVITY_INFO_MISSING);
+            Log.w(TAG, "Unable to send as bubble -- couldn't find activity info for intent: "
+                    + intent);
+            return false;
+        }
+        if (!ActivityInfo.isResizeableMode(info.resizeMode)) {
+            StatsLog.write(StatsLog.BUBBLE_DEVELOPER_ERROR_REPORTED, packageName,
+                    BUBBLE_DEVELOPER_ERROR_REPORTED__ERROR__ACTIVITY_INFO_NOT_RESIZABLE);
+            Log.w(TAG, "Unable to send as bubble -- activity is not resizable for intent: "
+                    + intent);
+            return false;
+        }
+        if (info.documentLaunchMode != DOCUMENT_LAUNCH_ALWAYS) {
+            StatsLog.write(StatsLog.BUBBLE_DEVELOPER_ERROR_REPORTED, packageName,
+                    BUBBLE_DEVELOPER_ERROR_REPORTED__ERROR__DOCUMENT_LAUNCH_NOT_ALWAYS);
+            Log.w(TAG, "Unable to send as bubble -- activity is not documentLaunchMode=always "
+                    + "for intent: " + intent);
+            return false;
+        }
+        if ((info.flags & ActivityInfo.FLAG_ALLOW_EMBEDDED) == 0) {
+            Log.w(TAG, "Unable to send as bubble -- activity is not embeddable for intent: "
+                    + intent);
+            return false;
+        }
+        return true;
+    }
+
     private void doChannelWarningToast(CharSequence toastText) {
         Binder.withCleanCallingIdentity(() -> {
             final int defaultWarningEnabled = Build.IS_DEBUGGABLE ? 1 : 0;
diff --git a/services/core/java/com/android/server/notification/NotificationRecord.java b/services/core/java/com/android/server/notification/NotificationRecord.java
index 4e9b4f7..4ed24ec 100644
--- a/services/core/java/com/android/server/notification/NotificationRecord.java
+++ b/services/core/java/com/android/server/notification/NotificationRecord.java
@@ -1268,22 +1268,6 @@
         }
     }
 
-    // Returns the name of the NAS that made adjustments. By policy, there must only ever be one.
-    // If this is violated, the NAS that first sent an adjustment is returned.
-    private @Nullable String getAdjustmentIssuer() {
-        synchronized (mAdjustments) {
-            for (Adjustment adjustment : mAdjustments) {
-                if (adjustment.getSignals().isEmpty()) {
-                    continue;
-                }
-                if (adjustment.getIssuer() != null) {
-                    return adjustment.getIssuer();
-                }
-            }
-        }
-        return null;
-    }
-
     public LogMaker getLogMaker(long now) {
         LogMaker lm = sbn.getLogMaker()
                 .addTaggedData(MetricsEvent.FIELD_NOTIFICATION_CHANNEL_IMPORTANCE, mImportance)
@@ -1313,14 +1297,6 @@
             lm.addTaggedData(MetricsEvent.FIELD_NOTIFICATION_IMPORTANCE_ASST,
                         mAssistantImportance);
         }
-        // Log the issuer of any adjustments that may have affected this notification. We only log
-        // the hash here as NotificationItem events are frequent, and the number of NAS
-        // implementations (and hence the chance of collisions) is low.
-        String adjustmentIssuer = getAdjustmentIssuer();
-        if (adjustmentIssuer != null) {
-            lm.addTaggedData(MetricsEvent.FIELD_NOTIFICATION_ASSISTANT_SERVICE_HASH,
-                    adjustmentIssuer.hashCode());
-        }
         return lm;
     }
 
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index ea65350..d4c8525 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -20921,6 +20921,12 @@
             Slog.wtf(TAG, "Calling thread " + Thread.currentThread().getName()
                     + " is holding mPackages", new Throwable());
         }
+        if (!mSystemReady) {
+            // We might get called before system is ready because of package changes etc, but
+            // finding preferred activity depends on settings provider, so we ignore the update
+            // before that.
+            return false;
+        }
         final Intent intent = getHomeIntent();
         final List<ResolveInfo> resolveInfos = queryIntentActivitiesInternal(intent, null,
                 PackageManager.GET_META_DATA, userId);
diff --git a/services/core/java/com/android/server/pm/permission/TEST_MAPPING b/services/core/java/com/android/server/pm/permission/TEST_MAPPING
index 9efb669..610c82f 100644
--- a/services/core/java/com/android/server/pm/permission/TEST_MAPPING
+++ b/services/core/java/com/android/server/pm/permission/TEST_MAPPING
@@ -21,9 +21,6 @@
             "name": "CtsAppSecurityHostTestCases",
             "options": [
                 {
-                    "include-filter": "android.appsecurity.cts.AppSecurityTests#testPermissionDiffCert"
-                },
-                {
                     "include-filter": "android.appsecurity.cts.AppSecurityTests#rebootWithDuplicatePermission"
                 }
             ]
@@ -53,5 +50,15 @@
                 }
             ]
         }
+    ],
+    "postsubmit": [
+        {
+            "name": "CtsAppSecurityHostTestCases",
+            "options": [
+                {
+                    "include-filter": "android.appsecurity.cts.AppSecurityTests#testPermissionDiffCert"
+                }
+            ]
+        }
     ]
 }
diff --git a/services/core/java/com/android/server/policy/PermissionPolicyInternal.java b/services/core/java/com/android/server/policy/PermissionPolicyInternal.java
index ea8616c..7760c1e 100644
--- a/services/core/java/com/android/server/policy/PermissionPolicyInternal.java
+++ b/services/core/java/com/android/server/policy/PermissionPolicyInternal.java
@@ -17,6 +17,7 @@
 package com.android.server.policy;
 
 import android.annotation.NonNull;
+import android.annotation.Nullable;
 import android.content.Intent;
 
 /**
@@ -34,5 +35,5 @@
      * @return whether the activity should be started
      */
     public abstract boolean checkStartActivity(@NonNull Intent intent, int callingUid,
-            @NonNull String callingPackage);
+            @Nullable String callingPackage);
 }
diff --git a/services/core/java/com/android/server/policy/PermissionPolicyService.java b/services/core/java/com/android/server/policy/PermissionPolicyService.java
index 570a153..c809aca 100644
--- a/services/core/java/com/android/server/policy/PermissionPolicyService.java
+++ b/services/core/java/com/android/server/policy/PermissionPolicyService.java
@@ -480,8 +480,9 @@
 
         @Override
         public boolean checkStartActivity(@NonNull Intent intent, int callingUid,
-                @NonNull String callingPackage) {
-            if (isActionRemovedForCallingPackage(intent.getAction(), callingPackage)) {
+                @Nullable String callingPackage) {
+            if (callingPackage != null && isActionRemovedForCallingPackage(intent.getAction(),
+                    callingPackage)) {
                 Slog.w(LOG_TAG, "Action Removed: starting " + intent.toString() + " from "
                         + callingPackage + " (uid=" + callingUid + ")");
                 return false;
diff --git a/services/core/java/com/android/server/rollback/RollbackManagerServiceImpl.java b/services/core/java/com/android/server/rollback/RollbackManagerServiceImpl.java
index 944e4b8..9a2778d 100644
--- a/services/core/java/com/android/server/rollback/RollbackManagerServiceImpl.java
+++ b/services/core/java/com/android/server/rollback/RollbackManagerServiceImpl.java
@@ -231,6 +231,20 @@
             }
         }, enableRollbackTimedOutFilter, null, getHandler());
 
+        IntentFilter userAddedIntentFilter = new IntentFilter(Intent.ACTION_USER_ADDED);
+        mContext.registerReceiver(new BroadcastReceiver() {
+            @Override
+            public void onReceive(Context context, Intent intent) {
+                if (Intent.ACTION_USER_ADDED.equals(intent.getAction())) {
+                    final int newUserId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, -1);
+                    if (newUserId == -1) {
+                        return;
+                    }
+                    registerUserCallbacks(UserHandle.of(newUserId));
+                }
+            }
+        }, userAddedIntentFilter, null, getHandler());
+
         registerTimeChangeReceiver();
     }
 
diff --git a/services/core/java/com/android/server/uri/UriGrantsManagerService.java b/services/core/java/com/android/server/uri/UriGrantsManagerService.java
index 332df95..8b332d2 100644
--- a/services/core/java/com/android/server/uri/UriGrantsManagerService.java
+++ b/services/core/java/com/android/server/uri/UriGrantsManagerService.java
@@ -211,9 +211,9 @@
     }
 
     @Override
-    public ParceledListSlice<android.content.UriPermission> getPersistedUriPermissions(
-            String packageName, boolean incoming) {
-        enforceNotIsolatedCaller("getPersistedUriPermissions");
+    public ParceledListSlice<android.content.UriPermission> getUriPermissions(
+            String packageName, boolean incoming, boolean persistedOnly) {
+        enforceNotIsolatedCaller("getUriPermissions");
         Preconditions.checkNotNull(packageName, "packageName");
 
         final int callingUid = Binder.getCallingUid();
@@ -240,7 +240,8 @@
                 } else {
                     for (int j = 0; j < perms.size(); j++) {
                         final UriPermission perm = perms.valueAt(j);
-                        if (packageName.equals(perm.targetPkg) && perm.persistedModeFlags != 0) {
+                        if (packageName.equals(perm.targetPkg)
+                                && (!persistedOnly || perm.persistedModeFlags != 0)) {
                             result.add(perm.buildPersistedPublicApiObject());
                         }
                     }
@@ -252,7 +253,8 @@
                             mGrantedUriPermissions.valueAt(i);
                     for (int j = 0; j < perms.size(); j++) {
                         final UriPermission perm = perms.valueAt(j);
-                        if (packageName.equals(perm.sourcePkg) && perm.persistedModeFlags != 0) {
+                        if (packageName.equals(perm.sourcePkg)
+                                && (!persistedOnly || perm.persistedModeFlags != 0)) {
                             result.add(perm.buildPersistedPublicApiObject());
                         }
                     }
diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java
index 82ea4fe..c3a769b 100644
--- a/services/core/java/com/android/server/wm/DisplayContent.java
+++ b/services/core/java/com/android/server/wm/DisplayContent.java
@@ -804,10 +804,11 @@
                     mTmpApplySurfaceChangesTransactionState.preferredRefreshRate
                             = w.mAttrs.preferredRefreshRate;
                 }
+                final int preferredModeId = getDisplayPolicy().getRefreshRatePolicy()
+                        .getPreferredModeId(w);
                 if (mTmpApplySurfaceChangesTransactionState.preferredModeId == 0
-                        && w.mAttrs.preferredDisplayModeId != 0) {
-                    mTmpApplySurfaceChangesTransactionState.preferredModeId
-                            = w.mAttrs.preferredDisplayModeId;
+                        && preferredModeId != 0) {
+                    mTmpApplySurfaceChangesTransactionState.preferredModeId = preferredModeId;
                 }
             }
         }
@@ -2636,17 +2637,25 @@
         final WindowState imeWin = mInputMethodWindow;
         final boolean imeVisible = imeWin != null && imeWin.isVisibleLw() && imeWin.isDisplayedLw()
                 && !mDividerControllerLocked.isImeHideRequested();
-        final boolean dockVisible = isStackVisible(WINDOWING_MODE_SPLIT_SCREEN_PRIMARY);
+        final TaskStack dockedStack = getSplitScreenPrimaryStack();
+        final boolean dockVisible = dockedStack != null;
+        final Task topDockedTask = dockVisible ? dockedStack.getTopChild() : null;
         final TaskStack imeTargetStack = mWmService.getImeFocusStackLocked();
         final int imeDockSide = (dockVisible && imeTargetStack != null) ?
                 imeTargetStack.getDockSide() : DOCKED_INVALID;
         final boolean imeOnTop = (imeDockSide == DOCKED_TOP);
         final boolean imeOnBottom = (imeDockSide == DOCKED_BOTTOM);
-        final boolean dockMinimized = mDividerControllerLocked.isMinimizedDock();
         final int imeHeight = mDisplayFrames.getInputMethodWindowVisibleHeight();
         final boolean imeHeightChanged = imeVisible &&
                 imeHeight != mDividerControllerLocked.getImeHeightAdjustedFor();
 
+        // This includes a case where the docked stack is unminimizing and IME is visible for the
+        // bottom side stack. The condition prevents adjusting the override task bounds for IME to
+        // the minimized docked stack bounds.
+        final boolean dockMinimized = mDividerControllerLocked.isMinimizedDock()
+                || (topDockedTask != null && imeOnBottom && !dockedStack.isAdjustedForIme()
+                        && dockedStack.getBounds().height() < topDockedTask.getBounds().height());
+
         // The divider could be adjusted for IME position, or be thinner than usual,
         // or both. There are three possible cases:
         // - If IME is visible, and focus is on top, divider is not moved for IME but thinner.
diff --git a/services/core/java/com/android/server/wm/DisplayPolicy.java b/services/core/java/com/android/server/wm/DisplayPolicy.java
index 197a3cf..e1dd352 100644
--- a/services/core/java/com/android/server/wm/DisplayPolicy.java
+++ b/services/core/java/com/android/server/wm/DisplayPolicy.java
@@ -381,6 +381,8 @@
      */
     @NonNull private Insets mForwardedInsets = Insets.NONE;
 
+    private RefreshRatePolicy mRefreshRatePolicy;
+
     // -------- PolicyHandler --------
     private static final int MSG_UPDATE_DREAMING_SLEEP_TOKEN = 1;
     private static final int MSG_REQUEST_TRANSIENT_BARS = 2;
@@ -591,6 +593,10 @@
             mHasStatusBar = false;
             mHasNavigationBar = mDisplayContent.supportsSystemDecorations();
         }
+
+        mRefreshRatePolicy = new RefreshRatePolicy(mService,
+                mDisplayContent.getDisplayInfo(),
+                mService.mHighRefreshRateBlacklist);
     }
 
     void systemReady() {
@@ -3596,6 +3602,10 @@
         }
     }
 
+    RefreshRatePolicy getRefreshRatePolicy() {
+        return mRefreshRatePolicy;
+    }
+
     void dump(String prefix, PrintWriter pw) {
         pw.print(prefix); pw.print("DisplayPolicy");
         prefix += "  ";
diff --git a/services/core/java/com/android/server/wm/HighRefreshRateBlacklist.java b/services/core/java/com/android/server/wm/HighRefreshRateBlacklist.java
new file mode 100644
index 0000000..c0f53b8
--- /dev/null
+++ b/services/core/java/com/android/server/wm/HighRefreshRateBlacklist.java
@@ -0,0 +1,75 @@
+/*
+ * Copyright (C) 2019 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.wm;
+
+import android.annotation.NonNull;
+import android.os.SystemProperties;
+import android.util.ArraySet;
+
+import com.android.internal.annotations.VisibleForTesting;
+
+/**
+ * A Blacklist for packages that should force the display out of high refresh rate.
+ */
+class HighRefreshRateBlacklist {
+
+    private static final String SYSPROP_KEY = "ro.window_manager.high_refresh_rate_blacklist";
+    private static final String SYSPROP_KEY_LENGTH_SUFFIX = "_length";
+    private static final String SYSPROP_KEY_ENTRY_SUFFIX = "_entry";
+    private static final int MAX_ENTRIES = 50;
+
+    private ArraySet<String> mBlacklistedPackages = new ArraySet<>();
+
+    static HighRefreshRateBlacklist create() {
+        return new HighRefreshRateBlacklist(new SystemPropertyGetter() {
+            @Override
+            public int getInt(String key, int def) {
+                return SystemProperties.getInt(key, def);
+            }
+
+            @Override
+            public String get(String key) {
+                return SystemProperties.get(key);
+            }
+        });
+    }
+
+    @VisibleForTesting
+    HighRefreshRateBlacklist(SystemPropertyGetter propertyGetter) {
+
+        // Read and populate the blacklist
+        final int length = Math.min(
+                propertyGetter.getInt(SYSPROP_KEY + SYSPROP_KEY_LENGTH_SUFFIX, 0),
+                MAX_ENTRIES);
+        for (int i = 1; i <= length; i++) {
+            final String packageName = propertyGetter.get(
+                    SYSPROP_KEY + SYSPROP_KEY_ENTRY_SUFFIX + i);
+            if (!packageName.isEmpty()) {
+                mBlacklistedPackages.add(packageName);
+            }
+        }
+    }
+
+    boolean isBlacklisted(String packageName) {
+        return mBlacklistedPackages.contains(packageName);
+    }
+
+    interface SystemPropertyGetter {
+        int getInt(String key, int def);
+        @NonNull String get(String key);
+    }
+}
diff --git a/services/core/java/com/android/server/wm/RefreshRatePolicy.java b/services/core/java/com/android/server/wm/RefreshRatePolicy.java
new file mode 100644
index 0000000..0c0cf92
--- /dev/null
+++ b/services/core/java/com/android/server/wm/RefreshRatePolicy.java
@@ -0,0 +1,92 @@
+/*
+ * Copyright (C) 2019 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.wm;
+
+import android.util.ArraySet;
+import android.view.Display.Mode;
+import android.view.DisplayInfo;
+
+/**
+ * Policy to select a lower refresh rate for the display if applicable.
+ */
+class RefreshRatePolicy {
+
+    private final int mLowRefreshRateId;
+    private final ArraySet<String> mNonHighRefreshRatePackages = new ArraySet<>();
+    private final HighRefreshRateBlacklist mHighRefreshRateBlacklist;
+    private final WindowManagerService mWmService;
+
+    RefreshRatePolicy(WindowManagerService wmService, DisplayInfo displayInfo,
+            HighRefreshRateBlacklist blacklist) {
+        mLowRefreshRateId = findLowRefreshRateModeId(displayInfo);
+        mHighRefreshRateBlacklist = blacklist;
+        mWmService = wmService;
+    }
+
+    /**
+     * Finds the mode id with the lowest refresh rate which is >= 60hz and same resolution as the
+     * default mode.
+     */
+    private int findLowRefreshRateModeId(DisplayInfo displayInfo) {
+        Mode mode = displayInfo.getDefaultMode();
+        float[] refreshRates = displayInfo.getDefaultRefreshRates();
+        float bestRefreshRate = mode.getRefreshRate();
+        for (int i = refreshRates.length - 1; i >= 0; i--) {
+            if (refreshRates[i] >= 60f && refreshRates[i] < bestRefreshRate) {
+                bestRefreshRate = refreshRates[i];
+            }
+        }
+        return displayInfo.findDefaultModeByRefreshRate(bestRefreshRate);
+    }
+
+    void addNonHighRefreshRatePackage(String packageName) {
+        mNonHighRefreshRatePackages.add(packageName);
+        mWmService.requestTraversal();
+    }
+
+    void removeNonHighRefreshRatePackage(String packageName) {
+        mNonHighRefreshRatePackages.remove(packageName);
+        mWmService.requestTraversal();
+    }
+
+    int getPreferredModeId(WindowState w) {
+
+        // If app is animating, it's not able to control refresh rate because we want the animation
+        // to run in default refresh rate.
+        if (w.isAnimating()) {
+            return 0;
+        }
+
+        // If app requests a certain refresh rate or mode, don't override it.
+        if (w.mAttrs.preferredRefreshRate != 0 || w.mAttrs.preferredDisplayModeId != 0) {
+            return w.mAttrs.preferredDisplayModeId;
+        }
+
+        final String packageName = w.getOwningPackage();
+
+        // If app is using Camera, force it to default (lower) refresh rate.
+        if (mNonHighRefreshRatePackages.contains(packageName)) {
+            return mLowRefreshRateId;
+        }
+
+        // If app is blacklisted using higher refresh rate, return default (lower) refresh rate
+        if (mHighRefreshRateBlacklist.isBlacklisted(packageName)) {
+            return mLowRefreshRateId;
+        }
+        return 0;
+    }
+}
diff --git a/services/core/java/com/android/server/wm/WindowManagerInternal.java b/services/core/java/com/android/server/wm/WindowManagerInternal.java
index 75a8dd5..40bec14 100644
--- a/services/core/java/com/android/server/wm/WindowManagerInternal.java
+++ b/services/core/java/com/android/server/wm/WindowManagerInternal.java
@@ -492,4 +492,18 @@
      * @return {@code true} if the display should show IME when an input field become focused on it.
      */
     public abstract boolean shouldShowIme(int displayId);
+
+    /**
+     * Tell window manager about a package that should not be running with high refresh rate
+     * setting until removeNonHighRefreshRatePackage is called for the same package.
+     *
+     * This must not be called again for the same package.
+     */
+    public abstract void addNonHighRefreshRatePackage(@NonNull String packageName);
+
+    /**
+     * Tell window manager to stop constraining refresh rate for the given package.
+     */
+    public abstract void removeNonHighRefreshRatePackage(@NonNull String packageName);
+
 }
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index 47df839..d39ee40 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -845,6 +845,8 @@
 
     final Configuration mTempConfiguration = new Configuration();
 
+    final HighRefreshRateBlacklist mHighRefreshRateBlacklist = HighRefreshRateBlacklist.create();
+
     // If true, only the core apps and services are being launched because the device
     // is in a special boot mode, such as being encrypted or waiting for a decryption password.
     // For example, when this flag is true, there will be no wallpaper service.
@@ -7446,6 +7448,22 @@
                 return WindowManagerService.this.shouldShowIme(displayId);
             }
         }
+
+        @Override
+        public void addNonHighRefreshRatePackage(@NonNull String packageName) {
+            synchronized (mGlobalLock) {
+                mRoot.forAllDisplays(dc -> dc.getDisplayPolicy().getRefreshRatePolicy()
+                        .addNonHighRefreshRatePackage(packageName));
+            }
+        }
+
+        @Override
+        public void removeNonHighRefreshRatePackage(@NonNull String packageName) {
+            synchronized (mGlobalLock) {
+                mRoot.forAllDisplays(dc -> dc.getDisplayPolicy().getRefreshRatePolicy()
+                        .removeNonHighRefreshRatePackage(packageName));
+            }
+        }
     }
 
     void registerAppFreezeListener(AppFreezeListener listener) {
diff --git a/services/tests/uiservicestests/AndroidManifest.xml b/services/tests/uiservicestests/AndroidManifest.xml
index 3ff85c8..7453c48 100644
--- a/services/tests/uiservicestests/AndroidManifest.xml
+++ b/services/tests/uiservicestests/AndroidManifest.xml
@@ -30,12 +30,14 @@
     <uses-permission android:name="android.permission.ACCESS_CONTENT_PROVIDERS_EXTERNALLY" />
     <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
     <uses-permission android:name="android.permission.OBSERVE_ROLE_HOLDERS" />
+    <uses-permission android:name="android.permission.GET_INTENT_SENDER_INTENT"/>
 
     <application android:debuggable="true">
         <uses-library android:name="android.test.runner" />
 
         <provider android:name=".DummyProvider"
             android:authorities="com.android.services.uitests" />
+
     </application>
 
     <instrumentation
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java b/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
index 3661e89..87f221a 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
@@ -304,6 +304,12 @@
             void onGranted(ComponentName assistant, int userId, boolean granted);
         }
 
+        @Override
+        protected boolean canLaunchInActivityView(Context context, PendingIntent pendingIntent,
+                String packageName) {
+            // Tests for this not being true are in CTS NotificationManagerTest
+            return true;
+        }
     }
 
     private class TestableToastCallback extends ITransientNotification.Stub {
@@ -412,6 +418,19 @@
         mTestableLooper.processAllMessages();
     }
 
+    private void setUpPrefsForBubbles(boolean globalEnabled, boolean pkgEnabled,
+            boolean channelEnabled) {
+        mService.setPreferencesHelper(mPreferencesHelper);
+        when(mPreferencesHelper.bubblesEnabled(any())).thenReturn(globalEnabled);
+        when(mPreferencesHelper.areBubblesAllowed(anyString(), anyInt())).thenReturn(pkgEnabled);
+        when(mPreferencesHelper.getNotificationChannel(
+                anyString(), anyInt(), anyString(), anyBoolean())).thenReturn(
+                mTestNotificationChannel);
+        when(mPreferencesHelper.getImportance(anyString(), anyInt())).thenReturn(
+                mTestNotificationChannel.getImportance());
+        mTestNotificationChannel.setAllowBubbles(channelEnabled);
+    }
+
     private StatusBarNotification generateSbn(String pkg, int uid, long postTime, int userId) {
         Notification.Builder nb = new Notification.Builder(mContext, "a")
                 .setContentTitle("foo")
@@ -4224,13 +4243,7 @@
     @Test
     public void testFlagBubble() throws RemoteException {
         // Bubbles are allowed!
-        mService.setPreferencesHelper(mPreferencesHelper);
-        when(mPreferencesHelper.areBubblesAllowed(anyString(), anyInt())).thenReturn(true);
-        when(mPreferencesHelper.getNotificationChannel(
-                anyString(), anyInt(), anyString(), anyBoolean())).thenReturn(
-                mTestNotificationChannel);
-        when(mPreferencesHelper.getImportance(anyString(), anyInt())).thenReturn(
-                mTestNotificationChannel.getImportance());
+        setUpPrefsForBubbles(true /* global */, true /* app */, true /* channel */);
 
         // Notif with bubble metadata but not our other misc requirements
         NotificationRecord nr = generateNotificationRecord(mTestNotificationChannel,
@@ -4252,15 +4265,33 @@
     }
 
     @Test
+    public void testFlagBubble_noFlag_appNotAllowed() throws RemoteException {
+        // Bubbles are allowed!
+        setUpPrefsForBubbles(true /* global */, false /* app */, true /* channel */);
+
+        // Notif with bubble metadata but not our other misc requirements
+        NotificationRecord nr = generateNotificationRecord(mTestNotificationChannel,
+                null /* tvExtender */, true /* isBubble */);
+
+        // Say we're foreground
+        when(mActivityManager.getPackageImportance(nr.sbn.getPackageName())).thenReturn(
+                IMPORTANCE_FOREGROUND);
+
+        mBinderService.enqueueNotificationWithTag(PKG, PKG, "tag",
+                nr.sbn.getId(), nr.sbn.getNotification(), nr.sbn.getUserId());
+        waitForIdle();
+
+        StatusBarNotification[] notifs = mBinderService.getActiveNotifications(PKG);
+        assertEquals(1, notifs.length);
+        assertEquals((notifs[0].getNotification().flags & FLAG_BUBBLE), 0);
+        assertFalse(mService.getNotificationRecord(
+                nr.sbn.getKey()).getNotification().isBubbleNotification());
+    }
+
+    @Test
     public void testFlagBubbleNotifs_flag_appForeground() throws RemoteException {
         // Bubbles are allowed!
-        mService.setPreferencesHelper(mPreferencesHelper);
-        when(mPreferencesHelper.areBubblesAllowed(anyString(), anyInt())).thenReturn(true);
-        when(mPreferencesHelper.getNotificationChannel(
-                anyString(), anyInt(), anyString(), anyBoolean())).thenReturn(
-                mTestNotificationChannel);
-        when(mPreferencesHelper.getImportance(anyString(), anyInt())).thenReturn(
-                mTestNotificationChannel.getImportance());
+        setUpPrefsForBubbles(true /* global */, true /* app */, true /* channel */);
 
         // Notif with bubble metadata but not our other misc requirements
         NotificationRecord nr = generateNotificationRecord(mTestNotificationChannel,
@@ -4282,13 +4313,7 @@
     @Test
     public void testFlagBubbleNotifs_noFlag_appNotForeground() throws RemoteException {
         // Bubbles are allowed!
-        mService.setPreferencesHelper(mPreferencesHelper);
-        when(mPreferencesHelper.areBubblesAllowed(anyString(), anyInt())).thenReturn(true);
-        when(mPreferencesHelper.getNotificationChannel(
-                anyString(), anyInt(), anyString(), anyBoolean())).thenReturn(
-                mTestNotificationChannel);
-        when(mPreferencesHelper.getImportance(anyString(), anyInt())).thenReturn(
-                mTestNotificationChannel.getImportance());
+        setUpPrefsForBubbles(true /* global */, true /* app */, true /* channel */);
 
         // Notif with bubble metadata but not our other misc requirements
         NotificationRecord nr = generateNotificationRecord(mTestNotificationChannel,
@@ -4310,13 +4335,7 @@
     @Test
     public void testFlagBubbleNotifs_flag_previousForegroundFlag() throws RemoteException {
         // Bubbles are allowed!
-        mService.setPreferencesHelper(mPreferencesHelper);
-        when(mPreferencesHelper.areBubblesAllowed(anyString(), anyInt())).thenReturn(true);
-        when(mPreferencesHelper.getNotificationChannel(
-                anyString(), anyInt(), anyString(), anyBoolean())).thenReturn(
-                mTestNotificationChannel);
-        when(mPreferencesHelper.getImportance(anyString(), anyInt())).thenReturn(
-                mTestNotificationChannel.getImportance());
+        setUpPrefsForBubbles(true /* global */, true /* app */, true /* channel */);
 
         // Notif with bubble metadata but not our other misc requirements
         NotificationRecord nr1 = generateNotificationRecord(mTestNotificationChannel,
@@ -4356,13 +4375,7 @@
     public void testFlagBubbleNotifs_noFlag_previousForegroundFlag_afterRemoval()
             throws RemoteException {
         // Bubbles are allowed!
-        mService.setPreferencesHelper(mPreferencesHelper);
-        when(mPreferencesHelper.areBubblesAllowed(anyString(), anyInt())).thenReturn(true);
-        when(mPreferencesHelper.getNotificationChannel(
-                anyString(), anyInt(), anyString(), anyBoolean())).thenReturn(
-                mTestNotificationChannel);
-        when(mPreferencesHelper.getImportance(anyString(), anyInt())).thenReturn(
-                mTestNotificationChannel.getImportance());
+        setUpPrefsForBubbles(true /* global */, true /* app */, true /* channel */);
 
         // Notif with bubble metadata but not our other misc requirements
         NotificationRecord nr1 = generateNotificationRecord(mTestNotificationChannel,
@@ -4410,13 +4423,7 @@
     @Test
     public void testFlagBubbleNotifs_flag_messaging() throws RemoteException {
         // Bubbles are allowed!
-        mService.setPreferencesHelper(mPreferencesHelper);
-        when(mPreferencesHelper.areBubblesAllowed(anyString(), anyInt())).thenReturn(true);
-        when(mPreferencesHelper.getNotificationChannel(
-                anyString(), anyInt(), anyString(), anyBoolean())).thenReturn(
-                mTestNotificationChannel);
-        when(mPreferencesHelper.getImportance(anyString(), anyInt())).thenReturn(
-                mTestNotificationChannel.getImportance());
+        setUpPrefsForBubbles(true /* global */, true /* app */, true /* channel */);
 
         // Give it bubble metadata
         Notification.BubbleMetadata data = getBasicBubbleMetadataBuilder().build();
@@ -4462,13 +4469,7 @@
     @Test
     public void testFlagBubbleNotifs_flag_phonecall() throws RemoteException {
         // Bubbles are allowed!
-        mService.setPreferencesHelper(mPreferencesHelper);
-        when(mPreferencesHelper.areBubblesAllowed(anyString(), anyInt())).thenReturn(true);
-        when(mPreferencesHelper.getNotificationChannel(
-                anyString(), anyInt(), anyString(), anyBoolean())).thenReturn(
-                mTestNotificationChannel);
-        when(mPreferencesHelper.getImportance(anyString(), anyInt())).thenReturn(
-                mTestNotificationChannel.getImportance());
+        setUpPrefsForBubbles(true /* global */, true /* app */, true /* channel */);
 
         // Give it bubble metadata
         Notification.BubbleMetadata data = getBasicBubbleMetadataBuilder().build();
@@ -4503,13 +4504,7 @@
     @Test
     public void testFlagBubbleNotifs_noFlag_phonecall_noForegroundService() throws RemoteException {
         // Bubbles are allowed!
-        mService.setPreferencesHelper(mPreferencesHelper);
-        when(mPreferencesHelper.areBubblesAllowed(anyString(), anyInt())).thenReturn(true);
-        when(mPreferencesHelper.getNotificationChannel(
-                anyString(), anyInt(), anyString(), anyBoolean())).thenReturn(
-                mTestNotificationChannel);
-        when(mPreferencesHelper.getImportance(anyString(), anyInt())).thenReturn(
-                mTestNotificationChannel.getImportance());
+        setUpPrefsForBubbles(true /* global */, true /* app */, true /* channel */);
 
         // Give it bubble metadata
         Notification.BubbleMetadata data = getBasicBubbleMetadataBuilder().build();
@@ -4542,13 +4537,7 @@
     @Test
     public void testFlagBubbleNotifs_noFlag_phonecall_noPerson() throws RemoteException {
         // Bubbles are allowed!
-        mService.setPreferencesHelper(mPreferencesHelper);
-        when(mPreferencesHelper.areBubblesAllowed(anyString(), anyInt())).thenReturn(true);
-        when(mPreferencesHelper.getNotificationChannel(
-                anyString(), anyInt(), anyString(), anyBoolean())).thenReturn(
-                mTestNotificationChannel);
-        when(mPreferencesHelper.getImportance(anyString(), anyInt())).thenReturn(
-                mTestNotificationChannel.getImportance());
+        setUpPrefsForBubbles(true /* global */, true /* app */, true /* channel */);
 
         // Give it bubble metadata
         Notification.BubbleMetadata data = getBasicBubbleMetadataBuilder().build();
@@ -4578,13 +4567,7 @@
     @Test
     public void testFlagBubbleNotifs_noFlag_phonecall_noCategory() throws RemoteException {
         // Bubbles are allowed!
-        mService.setPreferencesHelper(mPreferencesHelper);
-        when(mPreferencesHelper.areBubblesAllowed(anyString(), anyInt())).thenReturn(true);
-        when(mPreferencesHelper.getNotificationChannel(
-                anyString(), anyInt(), anyString(), anyBoolean())).thenReturn(
-                mTestNotificationChannel);
-        when(mPreferencesHelper.getImportance(anyString(), anyInt())).thenReturn(
-                mTestNotificationChannel.getImportance());
+        setUpPrefsForBubbles(true /* global */, true /* app */, true /* channel */);
 
         // Give it bubble metadata
         Notification.BubbleMetadata data = getBasicBubbleMetadataBuilder().build();
@@ -4618,13 +4601,7 @@
     @Test
     public void testFlagBubbleNotifs_noFlag_messaging_appNotAllowed() throws RemoteException {
         // Bubbles are NOT allowed!
-        mService.setPreferencesHelper(mPreferencesHelper);
-        when(mPreferencesHelper.areBubblesAllowed(anyString(), anyInt())).thenReturn(false);
-        when(mPreferencesHelper.getNotificationChannel(
-                anyString(), anyInt(), anyString(), anyBoolean())).thenReturn(
-                mTestNotificationChannel);
-        when(mPreferencesHelper.getImportance(anyString(), anyInt())).thenReturn(
-                mTestNotificationChannel.getImportance());
+        setUpPrefsForBubbles(false /* global */, true /* app */, true /* channel */);
 
         // Give it bubble metadata
         Notification.BubbleMetadata data = getBasicBubbleMetadataBuilder().build();
@@ -4663,13 +4640,7 @@
     @Test
     public void testFlagBubbleNotifs_noFlag_notBubble() throws RemoteException {
         // Bubbles are allowed!
-        mService.setPreferencesHelper(mPreferencesHelper);
-        when(mPreferencesHelper.areBubblesAllowed(anyString(), anyInt())).thenReturn(true);
-        when(mPreferencesHelper.getNotificationChannel(
-                anyString(), anyInt(), anyString(), anyBoolean())).thenReturn(
-                mTestNotificationChannel);
-        when(mPreferencesHelper.getImportance(anyString(), anyInt())).thenReturn(
-                mTestNotificationChannel.getImportance());
+        setUpPrefsForBubbles(true /* global */, true /* app */, true /* channel */);
 
         // Notif WITHOUT bubble metadata
         NotificationRecord nr = generateNotificationRecord(mTestNotificationChannel);
@@ -4686,17 +4657,8 @@
 
     @Test
     public void testFlagBubbleNotifs_noFlag_messaging_channelNotAllowed() throws RemoteException {
-        // Bubbles are allowed!
-        mService.setPreferencesHelper(mPreferencesHelper);
-        when(mPreferencesHelper.areBubblesAllowed(anyString(), anyInt())).thenReturn(true);
-        when(mPreferencesHelper.getNotificationChannel(
-                anyString(), anyInt(), anyString(), anyBoolean())).thenReturn(
-                mTestNotificationChannel);
-        when(mPreferencesHelper.getImportance(anyString(), anyInt())).thenReturn(
-                mTestNotificationChannel.getImportance());
-
-        // But not on this channel!
-        mTestNotificationChannel.setAllowBubbles(false);
+        // Bubbles are allowed except on this channel
+        setUpPrefsForBubbles(true /* global */, true /* app */, false /* channel */);
 
         // Give it bubble metadata
         Notification.BubbleMetadata data = getBasicBubbleMetadataBuilder().build();
@@ -4734,14 +4696,8 @@
 
     @Test
     public void testFlagBubbleNotifs_noFlag_phonecall_notAllowed() throws RemoteException {
-        // Bubbles are allowed!
-        mService.setPreferencesHelper(mPreferencesHelper);
-        when(mPreferencesHelper.areBubblesAllowed(anyString(), anyInt())).thenReturn(false);
-        when(mPreferencesHelper.getNotificationChannel(
-                anyString(), anyInt(), anyString(), anyBoolean())).thenReturn(
-                mTestNotificationChannel);
-        when(mPreferencesHelper.getImportance(anyString(), anyInt())).thenReturn(
-                mTestNotificationChannel.getImportance());
+        // Bubbles are not allowed!
+        setUpPrefsForBubbles(false /* global */, true /* app */, true /* channel */);
 
         // Give it bubble metadata
         Notification.BubbleMetadata data = getBasicBubbleMetadataBuilder().build();
@@ -4775,17 +4731,8 @@
 
     @Test
     public void testFlagBubbleNotifs_noFlag_phonecall_channelNotAllowed() throws RemoteException {
-        // Bubbles are allowed!
-        mService.setPreferencesHelper(mPreferencesHelper);
-        when(mPreferencesHelper.areBubblesAllowed(anyString(), anyInt())).thenReturn(false);
-        when(mPreferencesHelper.getNotificationChannel(
-                anyString(), anyInt(), anyString(), anyBoolean())).thenReturn(
-                mTestNotificationChannel);
-        when(mPreferencesHelper.getImportance(anyString(), anyInt())).thenReturn(
-                mTestNotificationChannel.getImportance());
-
-        // But not on this channel!
-        mTestNotificationChannel.setAllowBubbles(false);
+        // Bubbles are allowed, but not on channel.
+        setUpPrefsForBubbles(true /* global */, true /* app */, false /* channel */);
 
         // Give it bubble metadata
         Notification.BubbleMetadata data = getBasicBubbleMetadataBuilder().build();
@@ -4990,13 +4937,7 @@
     @Test
     public void testNotificationBubbleChanged_false() throws Exception {
         // Bubbles are allowed!
-        mService.setPreferencesHelper(mPreferencesHelper);
-        when(mPreferencesHelper.areBubblesAllowed(anyString(), anyInt())).thenReturn(true);
-        when(mPreferencesHelper.getNotificationChannel(
-                anyString(), anyInt(), anyString(), anyBoolean())).thenReturn(
-                mTestNotificationChannel);
-        when(mPreferencesHelper.getImportance(anyString(), anyInt())).thenReturn(
-                mTestNotificationChannel.getImportance());
+        setUpPrefsForBubbles(true /* global */, true /* app */, true /* channel */);
 
         // Notif with bubble metadata but not our other misc requirements
         NotificationRecord nr = generateNotificationRecord(mTestNotificationChannel,
@@ -5034,13 +4975,7 @@
     @Test
     public void testNotificationBubbleChanged_true() throws Exception {
         // Bubbles are allowed!
-        mService.setPreferencesHelper(mPreferencesHelper);
-        when(mPreferencesHelper.areBubblesAllowed(anyString(), anyInt())).thenReturn(true);
-        when(mPreferencesHelper.getNotificationChannel(
-                anyString(), anyInt(), anyString(), anyBoolean())).thenReturn(
-                mTestNotificationChannel);
-        when(mPreferencesHelper.getImportance(anyString(), anyInt())).thenReturn(
-                mTestNotificationChannel.getImportance());
+        setUpPrefsForBubbles(true /* global */, true /* app */, true /* channel */);
 
         // Plain notification that has bubble metadata
         NotificationRecord nr = generateNotificationRecord(mTestNotificationChannel,
@@ -5077,13 +5012,7 @@
     @Test
     public void testNotificationBubbleChanged_true_notAllowed() throws Exception {
         // Bubbles are allowed!
-        mService.setPreferencesHelper(mPreferencesHelper);
-        when(mPreferencesHelper.areBubblesAllowed(anyString(), anyInt())).thenReturn(true);
-        when(mPreferencesHelper.getNotificationChannel(
-                anyString(), anyInt(), anyString(), anyBoolean())).thenReturn(
-                mTestNotificationChannel);
-        when(mPreferencesHelper.getImportance(anyString(), anyInt())).thenReturn(
-                mTestNotificationChannel.getImportance());
+        setUpPrefsForBubbles(true /* global */, true /* app */, true /* channel */);
 
         // Notif that is not a bubble
         NotificationRecord nr = generateNotificationRecord(mTestNotificationChannel,
@@ -5114,13 +5043,7 @@
     @Test
     public void testNotificationBubbles_disabled_lowRamDevice() throws Exception {
         // Bubbles are allowed!
-        mService.setPreferencesHelper(mPreferencesHelper);
-        when(mPreferencesHelper.areBubblesAllowed(anyString(), anyInt())).thenReturn(true);
-        when(mPreferencesHelper.getNotificationChannel(
-                anyString(), anyInt(), anyString(), anyBoolean())).thenReturn(
-                mTestNotificationChannel);
-        when(mPreferencesHelper.getImportance(anyString(), anyInt())).thenReturn(
-                mTestNotificationChannel.getImportance());
+        setUpPrefsForBubbles(true /* global */, true /* app */, true /* channel */);
 
         // Plain notification that has bubble metadata
         NotificationRecord nr = generateNotificationRecord(mTestNotificationChannel,
@@ -5145,6 +5068,5 @@
         StatusBarNotification[] notifsAfter = mBinderService.getActiveNotifications(PKG);
         assertEquals(1, notifsAfter.length);
         assertEquals((notifsAfter[0].getNotification().flags & FLAG_BUBBLE), 0);
-
     }
 }
diff --git a/services/tests/wmtests/src/com/android/server/wm/HighRefreshRateBlacklistTest.java b/services/tests/wmtests/src/com/android/server/wm/HighRefreshRateBlacklistTest.java
new file mode 100644
index 0000000..5586726
--- /dev/null
+++ b/services/tests/wmtests/src/com/android/server/wm/HighRefreshRateBlacklistTest.java
@@ -0,0 +1,86 @@
+/*
+ * Copyright (C) 2019 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.wm;
+
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+import android.platform.test.annotations.Presubmit;
+
+import androidx.test.filters.FlakyTest;
+import androidx.test.filters.SmallTest;
+
+import com.android.server.wm.HighRefreshRateBlacklist.SystemPropertyGetter;
+
+import org.junit.Test;
+
+/**
+ * Build/Install/Run:
+ *  atest WmTests:HighRefreshRateBlacklistTest
+ */
+@SmallTest
+@Presubmit
+@FlakyTest
+public class HighRefreshRateBlacklistTest {
+
+    @Test
+    public void testBlacklist() {
+        HighRefreshRateBlacklist blacklist = new HighRefreshRateBlacklist(
+                new SystemPropertyGetter() {
+
+                    @Override
+                    public int getInt(String key, int def) {
+                        if ("ro.window_manager.high_refresh_rate_blacklist_length".equals(key)) {
+                            return 2;
+                        }
+                        return def;
+                    }
+
+                    @Override
+                    public String get(String key) {
+                        if ("ro.window_manager.high_refresh_rate_blacklist_entry1".equals(key)) {
+                            return "com.android.sample1";
+                        }
+                        if ("ro.window_manager.high_refresh_rate_blacklist_entry2".equals(key)) {
+                            return "com.android.sample2";
+                        }
+                        return "";
+                    }
+                });
+        assertTrue(blacklist.isBlacklisted("com.android.sample1"));
+        assertTrue(blacklist.isBlacklisted("com.android.sample2"));
+        assertFalse(blacklist.isBlacklisted("com.android.sample3"));
+    }
+
+    @Test
+    public void testNoBlacklist() {
+        HighRefreshRateBlacklist blacklist = new HighRefreshRateBlacklist(
+                new SystemPropertyGetter() {
+
+                    @Override
+                    public int getInt(String key, int def) {
+                        return def;
+                    }
+
+                    @Override
+                    public String get(String key) {
+                        return "";
+                    }
+                });
+        assertFalse(blacklist.isBlacklisted("com.android.sample1"));
+    }
+}
diff --git a/services/tests/wmtests/src/com/android/server/wm/RefreshRatePolicyTest.java b/services/tests/wmtests/src/com/android/server/wm/RefreshRatePolicyTest.java
new file mode 100644
index 0000000..efc2fd6
--- /dev/null
+++ b/services/tests/wmtests/src/com/android/server/wm/RefreshRatePolicyTest.java
@@ -0,0 +1,130 @@
+/*
+ * Copyright (C) 2019 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.wm;
+
+import static android.view.WindowManager.LayoutParams.TYPE_BASE_APPLICATION;
+
+import static org.junit.Assert.assertEquals;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+import android.platform.test.annotations.Presubmit;
+import android.view.Display.Mode;
+import android.view.DisplayInfo;
+
+import androidx.test.filters.FlakyTest;
+import androidx.test.filters.SmallTest;
+
+import org.junit.Before;
+import org.junit.Test;
+
+/**
+ * Build/Install/Run:
+ *  atest WmTests:RefreshRatePolicyTest
+ */
+@SmallTest
+@Presubmit
+@FlakyTest
+public class RefreshRatePolicyTest extends WindowTestsBase {
+
+    private static final int LOW_MODE_ID = 3;
+
+    private RefreshRatePolicy mPolicy;
+    private HighRefreshRateBlacklist mBlacklist = mock(HighRefreshRateBlacklist.class);
+
+    @Before
+    public void setUp() {
+        DisplayInfo di = new DisplayInfo(mDisplayInfo);
+        Mode defaultMode = di.getDefaultMode();
+        di.supportedModes = new Mode[] {
+                new Mode(1, defaultMode.getPhysicalWidth(), defaultMode.getPhysicalHeight(), 90),
+                new Mode(2, defaultMode.getPhysicalWidth(), defaultMode.getPhysicalHeight(), 70),
+                new Mode(LOW_MODE_ID,
+                        defaultMode.getPhysicalWidth(), defaultMode.getPhysicalHeight(), 60),
+        };
+        di.defaultModeId = 1;
+        mPolicy = new RefreshRatePolicy(mWm, di, mBlacklist);
+    }
+
+    @Test
+    public void testCamera() {
+        final WindowState cameraUsingWindow = createWindow(null, TYPE_BASE_APPLICATION,
+                "cameraUsingWindow");
+        cameraUsingWindow.mAttrs.packageName = "com.android.test";
+        assertEquals(0, mPolicy.getPreferredModeId(cameraUsingWindow));
+        mPolicy.addNonHighRefreshRatePackage("com.android.test");
+        assertEquals(LOW_MODE_ID, mPolicy.getPreferredModeId(cameraUsingWindow));
+        mPolicy.removeNonHighRefreshRatePackage("com.android.test");
+        assertEquals(0, mPolicy.getPreferredModeId(cameraUsingWindow));
+    }
+
+    @Test
+    public void testBlacklist() {
+        final WindowState blacklistedWindow = createWindow(null, TYPE_BASE_APPLICATION,
+                "blacklistedWindow");
+        blacklistedWindow.mAttrs.packageName = "com.android.test";
+        when(mBlacklist.isBlacklisted("com.android.test")).thenReturn(true);
+        assertEquals(LOW_MODE_ID, mPolicy.getPreferredModeId(blacklistedWindow));
+    }
+
+    @Test
+    public void testAppOverride_blacklist() {
+        final WindowState overrideWindow = createWindow(null, TYPE_BASE_APPLICATION,
+                "overrideWindow");
+        overrideWindow.mAttrs.preferredDisplayModeId = LOW_MODE_ID;
+        when(mBlacklist.isBlacklisted("com.android.test")).thenReturn(true);
+        assertEquals(LOW_MODE_ID, mPolicy.getPreferredModeId(overrideWindow));
+    }
+
+    @Test
+    public void testAppOverride_camera() {
+        final WindowState overrideWindow = createWindow(null, TYPE_BASE_APPLICATION,
+                "overrideWindow");
+        overrideWindow.mAttrs.packageName = "com.android.test";
+        overrideWindow.mAttrs.preferredDisplayModeId = LOW_MODE_ID;
+        mPolicy.addNonHighRefreshRatePackage("com.android.test");
+        assertEquals(LOW_MODE_ID, mPolicy.getPreferredModeId(overrideWindow));
+    }
+
+    @Test
+    public void testAnimatingAppOverride() {
+        final WindowState overrideWindow = createWindow(null, TYPE_BASE_APPLICATION,
+                "overrideWindow");
+        overrideWindow.mAttrs.packageName = "com.android.test";
+        overrideWindow.mAttrs.preferredDisplayModeId = LOW_MODE_ID;
+        overrideWindow.mAppToken.mSurfaceAnimator.startAnimation(
+                overrideWindow.getPendingTransaction(), mock(AnimationAdapter.class),
+                false /* hidden */);
+        mPolicy.addNonHighRefreshRatePackage("com.android.test");
+        assertEquals(0, mPolicy.getPreferredModeId(overrideWindow));
+    }
+
+    @Test
+    public void testAnimatingCamera() {
+        final WindowState cameraUsingWindow = createWindow(null, TYPE_BASE_APPLICATION,
+                "cameraUsingWindow");
+        cameraUsingWindow.mAttrs.packageName = "com.android.test";
+
+        mPolicy.addNonHighRefreshRatePackage("com.android.test");
+        assertEquals(LOW_MODE_ID, mPolicy.getPreferredModeId(cameraUsingWindow));
+
+        cameraUsingWindow.mAppToken.mSurfaceAnimator.startAnimation(
+                cameraUsingWindow.getPendingTransaction(), mock(AnimationAdapter.class),
+                false /* hidden */);
+        assertEquals(0, mPolicy.getPreferredModeId(cameraUsingWindow));
+    }
+}
diff --git a/telephony/java/android/telephony/CarrierConfigManager.java b/telephony/java/android/telephony/CarrierConfigManager.java
index 6ba359b..5175c1d 100755
--- a/telephony/java/android/telephony/CarrierConfigManager.java
+++ b/telephony/java/android/telephony/CarrierConfigManager.java
@@ -2794,14 +2794,6 @@
          */
         public static final String KEY_NFW_PROXY_APPS_STRING = KEY_PREFIX + "nfw_proxy_apps";
 
-        /**
-         * Specify whether to post a notification on the status bar whenever device location is
-         * provided for non-framework location requests in user-initiated emergency use cases.
-         * 0 - Do not post notification. This is default.
-         * 1 - Post notification for all request types.
-         */
-        public static final String KEY_ES_NOTIFY_INT = KEY_PREFIX + "es_notify_int";
-
         private static PersistableBundle getDefaults() {
             PersistableBundle defaults = new PersistableBundle();
             defaults.putBoolean(KEY_PERSIST_LPP_MODE_BOOL, true);
@@ -2816,7 +2808,6 @@
             defaults.putString(KEY_GPS_LOCK_STRING, "3");
             defaults.putString(KEY_ES_EXTENSION_SEC_STRING, "0");
             defaults.putString(KEY_NFW_PROXY_APPS_STRING, "");
-            defaults.putInt(KEY_ES_NOTIFY_INT, 0);
             return defaults;
         }
     }
diff --git a/tools/incident_report/main.cpp b/tools/incident_report/main.cpp
index 17a3c7a..974166a 100644
--- a/tools/incident_report/main.cpp
+++ b/tools/incident_report/main.cpp
@@ -292,6 +292,7 @@
     fprintf(out, "Take an incident report over adb (which must be in the PATH).\n");
     fprintf(out, "  -b          output the incident report raw protobuf format\n");
     fprintf(out, "  -o OUTPUT   the output file. OUTPUT may be '-' or omitted to use stdout\n");
+    fprintf(out, "  -r REASON   human readable description of why the report is taken.\n");
     fprintf(out, "  -s SERIAL   sent to adb to choose which device, instead of $ANDROID_SERIAL\n");
     fprintf(out, "  -t          output the incident report in pretty-printed text format\n");
     fprintf(out, "\n");
@@ -307,13 +308,14 @@
     enum { OUTPUT_TEXT, OUTPUT_PROTO } outputFormat = OUTPUT_TEXT;
     const char* inFilename = NULL;
     const char* outFilename = NULL;
+    const char* reason = NULL;
     const char* adbSerial = NULL;
     pid_t childPid = -1;
     vector<string> sections;
     const char* privacy = NULL;
 
     int opt;
-    while ((opt = getopt(argc, argv, "bhi:o:s:twp:")) != -1) {
+    while ((opt = getopt(argc, argv, "bhi:o:r:s:twp:")) != -1) {
         switch (opt) {
             case 'b':
                 outputFormat = OUTPUT_PROTO;
@@ -324,6 +326,9 @@
             case 'o':
                 outFilename = optarg;
                 break;
+            case 'r':
+                reason = optarg;
+                break;
             case 's':
                 adbSerial = optarg;
                 break;
@@ -376,7 +381,7 @@
             dup2(pfd[1], STDOUT_FILENO);
             close(pfd[0]);
             close(pfd[1]);
-            char const** args = (char const**)malloc(sizeof(char*) * (8 + sections.size()));
+            char const** args = (char const**)malloc(sizeof(char*) * (10 + sections.size()));
             int argpos = 0;
             args[argpos++] = "adb";
             if (adbSerial != NULL) {
@@ -389,6 +394,10 @@
                 args[argpos++] = "-p";
                 args[argpos++] = privacy;
             }
+            if (reason != NULL) {
+                args[argpos++] = "-r";
+                args[argpos++] = reason;
+            }
             for (vector<string>::const_iterator it=sections.begin(); it!=sections.end(); it++) {
                 args[argpos++] = it->c_str();
             }