Merge "Disable user animations on insets whose visible frame is empty" into rvc-dev
diff --git a/Android.bp b/Android.bp
index 632f49d..7c2d6eb 100644
--- a/Android.bp
+++ b/Android.bp
@@ -264,6 +264,7 @@
         ":libcamera_client_aidl",
         ":libcamera_client_framework_aidl",
         ":libupdate_engine_aidl",
+        ":resourcemanager_aidl",
         ":storaged_aidl",
         ":vold_aidl",
 
diff --git a/apct-tests/perftests/windowmanager/src/android/wm/RecentsAnimationPerfTest.java b/apct-tests/perftests/windowmanager/src/android/wm/RecentsAnimationPerfTest.java
index 1667c165..6122ef2 100644
--- a/apct-tests/perftests/windowmanager/src/android/wm/RecentsAnimationPerfTest.java
+++ b/apct-tests/perftests/windowmanager/src/android/wm/RecentsAnimationPerfTest.java
@@ -23,6 +23,7 @@
 import static org.hamcrest.core.AnyOf.anyOf;
 import static org.hamcrest.core.Is.is;
 
+import android.app.ActivityManager;
 import android.app.ActivityManager.TaskSnapshot;
 import android.app.ActivityTaskManager;
 import android.app.IActivityTaskManager;
@@ -121,6 +122,12 @@
     @AfterClass
     public static void tearDownClass() {
         sSetUpClassException = null;
+        try {
+            // Recents activity may stop app switches. Restore the state to avoid affecting
+            // the next test.
+            ActivityManager.resumeAppSwitches();
+        } catch (RemoteException ignored) {
+        }
         sUiAutomation.dropShellPermissionIdentity();
     }
 
diff --git a/apct-tests/perftests/windowmanager/src/android/wm/RelayoutPerfTest.java b/apct-tests/perftests/windowmanager/src/android/wm/RelayoutPerfTest.java
index 8139a2e..f04e555 100644
--- a/apct-tests/perftests/windowmanager/src/android/wm/RelayoutPerfTest.java
+++ b/apct-tests/perftests/windowmanager/src/android/wm/RelayoutPerfTest.java
@@ -88,10 +88,7 @@
     public void testRelayout() throws Throwable {
         final Activity activity = mActivityRule.getActivity();
         final ContentView contentView = new ContentView(activity);
-        mActivityRule.runOnUiThread(() -> {
-            activity.getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
-            activity.setContentView(contentView);
-        });
+        mActivityRule.runOnUiThread(() -> activity.setContentView(contentView));
         getInstrumentation().waitForIdleSync();
 
         final RelayoutRunner relayoutRunner = new RelayoutRunner(activity, contentView.getWindow(),
diff --git a/apct-tests/perftests/windowmanager/src/android/wm/WindowManagerPerfTestBase.java b/apct-tests/perftests/windowmanager/src/android/wm/WindowManagerPerfTestBase.java
index 9e17e94..655d2f7 100644
--- a/apct-tests/perftests/windowmanager/src/android/wm/WindowManagerPerfTestBase.java
+++ b/apct-tests/perftests/windowmanager/src/android/wm/WindowManagerPerfTestBase.java
@@ -19,11 +19,13 @@
 import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentation;
 
 import android.app.Activity;
+import android.app.KeyguardManager;
 import android.app.UiAutomation;
 import android.content.Context;
 import android.content.Intent;
 import android.os.BatteryManager;
 import android.os.ParcelFileDescriptor;
+import android.os.PowerManager;
 import android.perftests.utils.PerfTestActivity;
 import android.provider.Settings;
 
@@ -61,24 +63,32 @@
     @BeforeClass
     public static void setUpOnce() {
         final Context context = getInstrumentation().getContext();
-        sOriginalStayOnWhilePluggedIn = Settings.Global.getInt(context.getContentResolver(),
+        final int stayOnWhilePluggedIn = Settings.Global.getInt(context.getContentResolver(),
                 Settings.Global.STAY_ON_WHILE_PLUGGED_IN, 0);
-        // Keep the device awake during testing.
-        setStayOnWhilePluggedIn(BatteryManager.BATTERY_PLUGGED_USB);
+        sOriginalStayOnWhilePluggedIn = -1;
+        if (stayOnWhilePluggedIn != BatteryManager.BATTERY_PLUGGED_ANY) {
+            sOriginalStayOnWhilePluggedIn = stayOnWhilePluggedIn;
+            // Keep the device awake during testing.
+            setStayOnWhilePluggedIn(BatteryManager.BATTERY_PLUGGED_ANY);
+        }
 
         if (!BASE_OUT_PATH.exists()) {
             executeShellCommand("mkdir -p " + BASE_OUT_PATH);
         }
-        // In order to be closer to the real use case.
-        executeShellCommand("input keyevent KEYCODE_WAKEUP");
-        executeShellCommand("wm dismiss-keyguard");
+        if (!context.getSystemService(PowerManager.class).isInteractive()
+                || context.getSystemService(KeyguardManager.class).isKeyguardLocked()) {
+            executeShellCommand("input keyevent KEYCODE_WAKEUP");
+            executeShellCommand("wm dismiss-keyguard");
+        }
         context.startActivity(new Intent(Intent.ACTION_MAIN)
                 .addCategory(Intent.CATEGORY_HOME).setFlags(Intent.FLAG_ACTIVITY_NEW_TASK));
     }
 
     @AfterClass
     public static void tearDownOnce() {
-        setStayOnWhilePluggedIn(sOriginalStayOnWhilePluggedIn);
+        if (sOriginalStayOnWhilePluggedIn != -1) {
+            setStayOnWhilePluggedIn(sOriginalStayOnWhilePluggedIn);
+        }
     }
 
     private static void setStayOnWhilePluggedIn(int value) {
diff --git a/apex/Android.bp b/apex/Android.bp
index c1715a00..371bd7f 100644
--- a/apex/Android.bp
+++ b/apex/Android.bp
@@ -63,9 +63,9 @@
     "--hide-annotation android.annotation.Hide " +
     "--hide InternalClasses " // com.android.* classes are okay in this interface
 
-// Defaults for mainline module provided java_sdk_library instances.
+// Defaults common to all mainline module java_sdk_library instances.
 java_defaults {
-    name: "framework-module-defaults",
+    name: "framework-module-common-defaults",
 
     // Additional annotations used for compiling both the implementation and the
     // stubs libraries.
@@ -88,14 +88,6 @@
         enabled: true,
         sdk_version: "module_current",
     },
-    system: {
-        enabled: true,
-        sdk_version: "module_current",
-    },
-    module_lib: {
-        enabled: true,
-        sdk_version: "module_current",
-    },
 
     // Configure framework module specific metalava options.
     droiddoc_options: [mainline_stubs_args],
@@ -127,6 +119,32 @@
     sdk_version: "module_current",
 }
 
+// Defaults for mainline module provided java_sdk_library instances.
+java_defaults {
+    name: "framework-module-defaults",
+    defaults: ["framework-module-common-defaults"],
+
+    system: {
+        enabled: true,
+        sdk_version: "module_current",
+    },
+    module_lib: {
+        enabled: true,
+        sdk_version: "module_current",
+    },
+}
+
+// Defaults for mainline module system server provided java_sdk_library instances.
+java_defaults {
+    name: "framework-system-server-module-defaults",
+    defaults: ["framework-module-common-defaults"],
+
+    system_server: {
+        enabled: true,
+        sdk_version: "module_current",
+    },
+}
+
 stubs_defaults {
     name: "framework-module-stubs-defaults-publicapi",
     args: mainline_framework_stubs_args,
diff --git a/apex/blobstore/framework/java/android/app/blob/BlobHandle.java b/apex/blobstore/framework/java/android/app/blob/BlobHandle.java
index bcef8ce..ecc78ce 100644
--- a/apex/blobstore/framework/java/android/app/blob/BlobHandle.java
+++ b/apex/blobstore/framework/java/android/app/blob/BlobHandle.java
@@ -219,7 +219,7 @@
     public void dump(IndentingPrintWriter fout, boolean dumpFull) {
         if (dumpFull) {
             fout.println("algo: " + algorithm);
-            fout.println("digest: " + (dumpFull ? encodeDigest() : safeDigest()));
+            fout.println("digest: " + (dumpFull ? encodeDigest(digest) : safeDigest(digest)));
             fout.println("label: " + label);
             fout.println("expiryMs: " + expiryTimeMillis);
             fout.println("tag: " + tag);
@@ -243,19 +243,20 @@
     public String toString() {
         return "BlobHandle {"
                 + "algo:" + algorithm + ","
-                + "digest:" + safeDigest() + ","
+                + "digest:" + safeDigest(digest) + ","
                 + "label:" + label + ","
                 + "expiryMs:" + expiryTimeMillis + ","
                 + "tag:" + tag
                 + "}";
     }
 
-    private String safeDigest() {
-        final String digestStr = encodeDigest();
+    /** @hide */
+    public static String safeDigest(@NonNull byte[] digest) {
+        final String digestStr = encodeDigest(digest);
         return digestStr.substring(0, 2) + ".." + digestStr.substring(digestStr.length() - 2);
     }
 
-    private String encodeDigest() {
+    private static String encodeDigest(@NonNull byte[] digest) {
         return Base64.encodeToString(digest, Base64.NO_WRAP);
     }
 
diff --git a/apex/blobstore/framework/java/android/app/blob/BlobInfo.java b/apex/blobstore/framework/java/android/app/blob/BlobInfo.java
index 80062d5..ba92d95 100644
--- a/apex/blobstore/framework/java/android/app/blob/BlobInfo.java
+++ b/apex/blobstore/framework/java/android/app/blob/BlobInfo.java
@@ -16,9 +16,13 @@
 
 package android.app.blob;
 
+import static android.text.format.Formatter.FLAG_IEC_UNITS;
+
 import android.annotation.NonNull;
+import android.app.AppGlobals;
 import android.os.Parcel;
 import android.os.Parcelable;
+import android.text.format.Formatter;
 
 import java.util.Collections;
 import java.util.List;
@@ -32,13 +36,15 @@
     private final long mId;
     private final long mExpiryTimeMs;
     private final CharSequence mLabel;
+    private final long mSizeBytes;
     private final List<LeaseInfo> mLeaseInfos;
 
-    public BlobInfo(long id, long expiryTimeMs, CharSequence label,
+    public BlobInfo(long id, long expiryTimeMs, CharSequence label, long sizeBytes,
             List<LeaseInfo> leaseInfos) {
         mId = id;
         mExpiryTimeMs = expiryTimeMs;
         mLabel = label;
+        mSizeBytes = sizeBytes;
         mLeaseInfos = leaseInfos;
     }
 
@@ -46,6 +52,7 @@
         mId = in.readLong();
         mExpiryTimeMs = in.readLong();
         mLabel = in.readCharSequence();
+        mSizeBytes = in.readLong();
         mLeaseInfos = in.readArrayList(null /* classloader */);
     }
 
@@ -61,6 +68,10 @@
         return mLabel;
     }
 
+    public long getSizeBytes() {
+        return mSizeBytes;
+    }
+
     public List<LeaseInfo> getLeases() {
         return Collections.unmodifiableList(mLeaseInfos);
     }
@@ -70,6 +81,7 @@
         dest.writeLong(mId);
         dest.writeLong(mExpiryTimeMs);
         dest.writeCharSequence(mLabel);
+        dest.writeLong(mSizeBytes);
         dest.writeList(mLeaseInfos);
     }
 
@@ -83,10 +95,16 @@
                 + "id: " + mId + ","
                 + "expiryMs: " + mExpiryTimeMs + ","
                 + "label: " + mLabel + ","
+                + "size: " + formatBlobSize(mSizeBytes) + ","
                 + "leases: " + LeaseInfo.toShortString(mLeaseInfos) + ","
                 + "}";
     }
 
+    private static String formatBlobSize(long sizeBytes) {
+        return Formatter.formatFileSize(AppGlobals.getInitialApplication(),
+                sizeBytes, FLAG_IEC_UNITS);
+    }
+
     @Override
     public int describeContents() {
         return 0;
diff --git a/apex/blobstore/service/java/com/android/server/blob/BlobAccessMode.java b/apex/blobstore/service/java/com/android/server/blob/BlobAccessMode.java
index ec7ba28..ba0fab6 100644
--- a/apex/blobstore/service/java/com/android/server/blob/BlobAccessMode.java
+++ b/apex/blobstore/service/java/com/android/server/blob/BlobAccessMode.java
@@ -44,7 +44,7 @@
 /**
  * Class for representing how a blob can be shared.
  *
- * Note that this class is not thread-safe, callers need to take of synchronizing access.
+ * Note that this class is not thread-safe, callers need to take care of synchronizing access.
  */
 class BlobAccessMode {
     @Retention(RetentionPolicy.SOURCE)
@@ -127,6 +127,14 @@
         return false;
     }
 
+    int getAccessType() {
+        return mAccessType;
+    }
+
+    int getNumWhitelistedPackages() {
+        return mWhitelistedPackages.size();
+    }
+
     void dump(IndentingPrintWriter fout) {
         fout.println("accessType: " + DebugUtils.flagsToString(
                 BlobAccessMode.class, "ACCESS_TYPE_", mAccessType));
diff --git a/apex/blobstore/service/java/com/android/server/blob/BlobMetadata.java b/apex/blobstore/service/java/com/android/server/blob/BlobMetadata.java
index cea7fcc..7e8c906 100644
--- a/apex/blobstore/service/java/com/android/server/blob/BlobMetadata.java
+++ b/apex/blobstore/service/java/com/android/server/blob/BlobMetadata.java
@@ -54,6 +54,8 @@
 import android.util.ArraySet;
 import android.util.Slog;
 import android.util.SparseArray;
+import android.util.StatsEvent;
+import android.util.proto.ProtoOutputStream;
 
 import com.android.internal.annotations.GuardedBy;
 import com.android.internal.annotations.VisibleForTesting;
@@ -61,6 +63,8 @@
 import com.android.internal.util.XmlUtils;
 import com.android.server.blob.BlobStoreManagerService.DumpArgs;
 
+import libcore.io.IoUtils;
+
 import org.xmlpull.v1.XmlPullParser;
 import org.xmlpull.v1.XmlPullParserException;
 import org.xmlpull.v1.XmlSerializer;
@@ -349,14 +353,16 @@
         } catch (ErrnoException e) {
             throw e.rethrowAsIOException();
         }
-        synchronized (mMetadataLock) {
-            return createRevocableFdLocked(fd, callingPackage);
+        try {
+            return createRevocableFd(fd, callingPackage);
+        } catch (IOException e) {
+            IoUtils.closeQuietly(fd);
+            throw e;
         }
     }
 
-    @GuardedBy("mMetadataLock")
     @NonNull
-    private ParcelFileDescriptor createRevocableFdLocked(FileDescriptor fd,
+    private ParcelFileDescriptor createRevocableFd(FileDescriptor fd,
             String callingPackage) throws IOException {
         final RevocableFileDescriptor revocableFd =
                 new RevocableFileDescriptor(mContext, fd);
@@ -410,6 +416,49 @@
         return true;
     }
 
+    StatsEvent dumpAsStatsEvent(int atomTag) {
+        synchronized (mMetadataLock) {
+            ProtoOutputStream proto = new ProtoOutputStream();
+            // Write Committer data to proto format
+            for (int i = 0, size = mCommitters.size(); i < size; ++i) {
+                final Committer committer = mCommitters.valueAt(i);
+                final long token = proto.start(
+                        BlobStatsEventProto.BlobCommitterListProto.COMMITTER);
+                proto.write(BlobStatsEventProto.BlobCommitterProto.UID, committer.uid);
+                proto.write(BlobStatsEventProto.BlobCommitterProto.COMMIT_TIMESTAMP_MILLIS,
+                        committer.commitTimeMs);
+                proto.write(BlobStatsEventProto.BlobCommitterProto.ACCESS_MODE,
+                        committer.blobAccessMode.getAccessType());
+                proto.write(BlobStatsEventProto.BlobCommitterProto.NUM_WHITELISTED_PACKAGE,
+                        committer.blobAccessMode.getNumWhitelistedPackages());
+                proto.end(token);
+            }
+            final byte[] committersBytes = proto.getBytes();
+
+            proto = new ProtoOutputStream();
+            // Write Leasee data to proto format
+            for (int i = 0, size = mLeasees.size(); i < size; ++i) {
+                final Leasee leasee = mLeasees.valueAt(i);
+                final long token = proto.start(BlobStatsEventProto.BlobLeaseeListProto.LEASEE);
+                proto.write(BlobStatsEventProto.BlobLeaseeProto.UID, leasee.uid);
+                proto.write(BlobStatsEventProto.BlobLeaseeProto.LEASE_EXPIRY_TIMESTAMP_MILLIS,
+                        leasee.expiryTimeMillis);
+                proto.end(token);
+            }
+            final byte[] leaseesBytes = proto.getBytes();
+
+            // Construct the StatsEvent to represent this Blob
+            return StatsEvent.newBuilder()
+                    .setAtomId(atomTag)
+                    .writeLong(mBlobId)
+                    .writeLong(getSize())
+                    .writeLong(mBlobHandle.getExpiryTimeMillis())
+                    .writeByteArray(committersBytes)
+                    .writeByteArray(leaseesBytes)
+                    .build();
+        }
+    }
+
     void dump(IndentingPrintWriter fout, DumpArgs dumpArgs) {
         fout.println("blobHandle:");
         fout.increaseIndent();
diff --git a/apex/blobstore/service/java/com/android/server/blob/BlobStoreConfig.java b/apex/blobstore/service/java/com/android/server/blob/BlobStoreConfig.java
index 6567266..08ee244 100644
--- a/apex/blobstore/service/java/com/android/server/blob/BlobStoreConfig.java
+++ b/apex/blobstore/service/java/com/android/server/blob/BlobStoreConfig.java
@@ -49,6 +49,9 @@
 
     public static final int XML_VERSION_CURRENT = XML_VERSION_ADD_SESSION_CREATION_TIME;
 
+    public static final long INVALID_BLOB_ID = 0;
+    public static final long INVALID_BLOB_SIZE = 0;
+
     private static final String ROOT_DIR_NAME = "blobstore";
     private static final String BLOBS_DIR_NAME = "blobs";
     private static final String SESSIONS_INDEX_FILE_NAME = "sessions_index.xml";
diff --git a/apex/blobstore/service/java/com/android/server/blob/BlobStoreManagerService.java b/apex/blobstore/service/java/com/android/server/blob/BlobStoreManagerService.java
index 8fff0d9..381efc1 100644
--- a/apex/blobstore/service/java/com/android/server/blob/BlobStoreManagerService.java
+++ b/apex/blobstore/service/java/com/android/server/blob/BlobStoreManagerService.java
@@ -28,6 +28,8 @@
 import static android.os.UserHandle.USER_CURRENT;
 import static android.os.UserHandle.USER_NULL;
 
+import static com.android.server.blob.BlobStoreConfig.INVALID_BLOB_ID;
+import static com.android.server.blob.BlobStoreConfig.INVALID_BLOB_SIZE;
 import static com.android.server.blob.BlobStoreConfig.LOGV;
 import static com.android.server.blob.BlobStoreConfig.TAG;
 import static com.android.server.blob.BlobStoreConfig.XML_VERSION_CURRENT;
@@ -48,6 +50,7 @@
 import android.annotation.UserIdInt;
 import android.app.ActivityManager;
 import android.app.ActivityManagerInternal;
+import android.app.StatsManager;
 import android.app.blob.BlobHandle;
 import android.app.blob.BlobInfo;
 import android.app.blob.IBlobStoreManager;
@@ -80,6 +83,7 @@
 import android.util.LongSparseArray;
 import android.util.Slog;
 import android.util.SparseArray;
+import android.util.StatsEvent;
 import android.util.Xml;
 
 import com.android.internal.annotations.GuardedBy;
@@ -88,6 +92,7 @@
 import com.android.internal.util.CollectionUtils;
 import com.android.internal.util.DumpUtils;
 import com.android.internal.util.FastXmlSerializer;
+import com.android.internal.util.FrameworkStatsLog;
 import com.android.internal.util.IndentingPrintWriter;
 import com.android.internal.util.Preconditions;
 import com.android.internal.util.XmlUtils;
@@ -159,6 +164,8 @@
             new SessionStateChangeListener();
 
     private PackageManagerInternal mPackageManagerInternal;
+    private StatsManager mStatsManager;
+    private StatsPullAtomCallbackImpl mStatsCallbackImpl = new StatsPullAtomCallbackImpl();
 
     private final Runnable mSaveBlobsInfoRunnable = this::writeBlobsInfo;
     private final Runnable mSaveSessionsRunnable = this::writeBlobSessions;
@@ -192,6 +199,7 @@
         LocalServices.addService(BlobStoreManagerInternal.class, new LocalService());
 
         mPackageManagerInternal = LocalServices.getService(PackageManagerInternal.class);
+        mStatsManager = getContext().getSystemService(StatsManager.class);
         registerReceivers();
         LocalServices.getService(StorageStatsManagerInternal.class)
                 .registerStorageStatsAugmenter(new BlobStorageStatsAugmenter(), TAG);
@@ -207,6 +215,7 @@
                 readBlobSessionsLocked(allPackages);
                 readBlobsInfoLocked(allPackages);
             }
+            registerBlobStorePuller();
         } else if (phase == PHASE_BOOT_COMPLETED) {
             BlobStoreIdleJobService.schedule(mContext);
         }
@@ -218,8 +227,9 @@
         int n = 0;
         long sessionId;
         do {
-            sessionId = Math.abs(mRandom.nextLong());
-            if (mKnownBlobIds.indexOf(sessionId) < 0 && sessionId != 0) {
+            final long randomLong = mRandom.nextLong();
+            sessionId = (randomLong == Long.MIN_VALUE) ? INVALID_BLOB_ID : Math.abs(randomLong);
+            if (mKnownBlobIds.indexOf(sessionId) < 0 && sessionId != INVALID_BLOB_ID) {
                 return sessionId;
             }
         } while (n++ < 32);
@@ -376,9 +386,23 @@
                     .get(blobHandle);
             if (blobMetadata == null || !blobMetadata.isAccessAllowedForCaller(
                     callingPackage, callingUid)) {
+                if (blobMetadata == null) {
+                    FrameworkStatsLog.write(FrameworkStatsLog.BLOB_OPENED, callingUid,
+                            INVALID_BLOB_ID, INVALID_BLOB_SIZE,
+                            FrameworkStatsLog.BLOB_OPENED__RESULT__BLOB_DNE);
+                } else {
+                    FrameworkStatsLog.write(FrameworkStatsLog.BLOB_OPENED, callingUid,
+                            blobMetadata.getBlobId(), blobMetadata.getSize(),
+                            FrameworkStatsLog.BLOB_LEASED__RESULT__ACCESS_NOT_ALLOWED);
+                }
                 throw new SecurityException("Caller not allowed to access " + blobHandle
                         + "; callingUid=" + callingUid + ", callingPackage=" + callingPackage);
             }
+
+            FrameworkStatsLog.write(FrameworkStatsLog.BLOB_OPENED, callingUid,
+                    blobMetadata.getBlobId(), blobMetadata.getSize(),
+                    FrameworkStatsLog.BLOB_OPENED__RESULT__SUCCESS);
+
             return blobMetadata.openForRead(callingPackage);
         }
     }
@@ -391,19 +415,41 @@
                     .get(blobHandle);
             if (blobMetadata == null || !blobMetadata.isAccessAllowedForCaller(
                     callingPackage, callingUid)) {
+                if (blobMetadata == null) {
+                    FrameworkStatsLog.write(FrameworkStatsLog.BLOB_LEASED, callingUid,
+                            INVALID_BLOB_ID, INVALID_BLOB_SIZE,
+                            FrameworkStatsLog.BLOB_LEASED__RESULT__BLOB_DNE);
+                } else {
+                    FrameworkStatsLog.write(FrameworkStatsLog.BLOB_LEASED, callingUid,
+                            blobMetadata.getBlobId(), blobMetadata.getSize(),
+                            FrameworkStatsLog.BLOB_LEASED__RESULT__ACCESS_NOT_ALLOWED);
+                }
                 throw new SecurityException("Caller not allowed to access " + blobHandle
                         + "; callingUid=" + callingUid + ", callingPackage=" + callingPackage);
             }
             if (leaseExpiryTimeMillis != 0 && blobHandle.expiryTimeMillis != 0
                     && leaseExpiryTimeMillis > blobHandle.expiryTimeMillis) {
+
+                FrameworkStatsLog.write(FrameworkStatsLog.BLOB_LEASED, callingUid,
+                        blobMetadata.getBlobId(), blobMetadata.getSize(),
+                        FrameworkStatsLog.BLOB_LEASED__RESULT__LEASE_EXPIRY_INVALID);
                 throw new IllegalArgumentException(
                         "Lease expiry cannot be later than blobs expiry time");
             }
             if (blobMetadata.getSize()
                     > getRemainingLeaseQuotaBytesInternal(callingUid, callingPackage)) {
+
+                FrameworkStatsLog.write(FrameworkStatsLog.BLOB_LEASED, callingUid,
+                        blobMetadata.getBlobId(), blobMetadata.getSize(),
+                        FrameworkStatsLog.BLOB_LEASED__RESULT__DATA_SIZE_LIMIT_EXCEEDED);
                 throw new LimitExceededException("Total amount of data with an active lease"
                         + " is exceeding the max limit");
             }
+
+            FrameworkStatsLog.write(FrameworkStatsLog.BLOB_LEASED, callingUid,
+                    blobMetadata.getBlobId(), blobMetadata.getSize(),
+                    FrameworkStatsLog.BLOB_LEASED__RESULT__SUCCESS);
+
             blobMetadata.addOrReplaceLeasee(callingPackage, callingUid,
                     descriptionResId, description, leaseExpiryTimeMillis);
             if (LOGV) {
@@ -478,11 +524,14 @@
                             ? Resources.ID_NULL
                             : getDescriptionResourceId(resourcesGetter.apply(leasee.packageName),
                                     leasee.descriptionResEntryName, leasee.packageName);
-                    leaseInfos.add(new LeaseInfo(leasee.packageName, leasee.expiryTimeMillis,
+                    final long expiryTimeMs = leasee.expiryTimeMillis == 0
+                            ? blobHandle.getExpiryTimeMillis() : leasee.expiryTimeMillis;
+                    leaseInfos.add(new LeaseInfo(leasee.packageName, expiryTimeMs,
                             descriptionResId, leasee.description));
                 });
                 blobInfos.add(new BlobInfo(blobMetadata.getBlobId(),
-                        blobHandle.getExpiryTimeMillis(), blobHandle.getLabel(), leaseInfos));
+                        blobHandle.getExpiryTimeMillis(), blobHandle.getLabel(),
+                        blobMetadata.getSize(), leaseInfos));
             });
         }
         return blobInfos;
@@ -584,6 +633,9 @@
                     blob.addOrReplaceCommitter(newCommitter);
                     try {
                         writeBlobsInfoLocked();
+                        FrameworkStatsLog.write(FrameworkStatsLog.BLOB_COMMITTED,
+                                session.getOwnerUid(), blob.getBlobId(), blob.getSize(),
+                                FrameworkStatsLog.BLOB_COMMITTED__RESULT__SUCCESS);
                         session.sendCommitCallbackResult(COMMIT_RESULT_SUCCESS);
                     } catch (Exception e) {
                         if (existingCommitter == null) {
@@ -591,7 +643,22 @@
                         } else {
                             blob.addOrReplaceCommitter(existingCommitter);
                         }
+                        Slog.d(TAG, "Error committing the blob", e);
+                        FrameworkStatsLog.write(FrameworkStatsLog.BLOB_COMMITTED,
+                                session.getOwnerUid(), blob.getBlobId(), blob.getSize(),
+                                FrameworkStatsLog.BLOB_COMMITTED__RESULT__ERROR_DURING_COMMIT);
                         session.sendCommitCallbackResult(COMMIT_RESULT_ERROR);
+                        // If the commit fails and this blob data didn't exist before, delete it.
+                        // But if it is a recommit, just leave it as is.
+                        if (session.getSessionId() == blob.getBlobId()) {
+                            deleteBlobLocked(blob);
+                            userBlobs.remove(blob.getBlobHandle());
+                        }
+                    }
+                    // Delete redundant data from recommits.
+                    if (session.getSessionId() != blob.getBlobId()) {
+                        session.getSessionFile().delete();
+                        mActiveBlobIds.remove(session.getSessionId());
                     }
                     getUserSessionsLocked(UserHandle.getUserId(session.getOwnerUid()))
                             .remove(session.getSessionId());
@@ -1488,7 +1555,7 @@
         public int handleShellCommand(@NonNull ParcelFileDescriptor in,
                 @NonNull ParcelFileDescriptor out, @NonNull ParcelFileDescriptor err,
                 @NonNull String[] args) {
-            return (new BlobStoreManagerShellCommand(BlobStoreManagerService.this)).exec(this,
+            return new BlobStoreManagerShellCommand(BlobStoreManagerService.this).exec(this,
                     in.getFileDescriptor(), out.getFileDescriptor(), err.getFileDescriptor(), args);
         }
     }
@@ -1680,6 +1747,40 @@
         }
     }
 
+    private void registerBlobStorePuller() {
+        mStatsManager.setPullAtomCallback(
+                FrameworkStatsLog.BLOB_INFO,
+                null, // use default PullAtomMetadata values
+                BackgroundThread.getExecutor(),
+                mStatsCallbackImpl
+        );
+    }
+
+    private class StatsPullAtomCallbackImpl implements StatsManager.StatsPullAtomCallback {
+        @Override
+        public int onPullAtom(int atomTag, List<StatsEvent> data) {
+            switch (atomTag) {
+                case FrameworkStatsLog.BLOB_INFO:
+                    return pullBlobData(atomTag, data);
+                default:
+                    throw new UnsupportedOperationException("Unknown tagId=" + atomTag);
+            }
+        }
+    }
+
+    private int pullBlobData(int atomTag, List<StatsEvent> data) {
+        synchronized (mBlobsLock) {
+            for (int i = 0, userCount = mBlobsMap.size(); i < userCount; ++i) {
+                final ArrayMap<BlobHandle, BlobMetadata> userBlobs = mBlobsMap.valueAt(i);
+                for (int j = 0, blobsCount = userBlobs.size(); j < blobsCount; ++j) {
+                    final BlobMetadata blob = userBlobs.valueAt(j);
+                    data.add(blob.dumpAsStatsEvent(atomTag));
+                }
+            }
+        }
+        return StatsManager.PULL_SUCCESS;
+    }
+
     private class LocalService extends BlobStoreManagerInternal {
         @Override
         public void onIdleMaintenance() {
diff --git a/apex/blobstore/service/java/com/android/server/blob/BlobStoreSession.java b/apex/blobstore/service/java/com/android/server/blob/BlobStoreSession.java
index 2b04583..77ca4aa 100644
--- a/apex/blobstore/service/java/com/android/server/blob/BlobStoreSession.java
+++ b/apex/blobstore/service/java/com/android/server/blob/BlobStoreSession.java
@@ -28,7 +28,6 @@
 import static android.system.OsConstants.O_RDWR;
 import static android.system.OsConstants.SEEK_SET;
 
-import static com.android.server.blob.BlobStoreConfig.LOGV;
 import static com.android.server.blob.BlobStoreConfig.TAG;
 import static com.android.server.blob.BlobStoreConfig.XML_VERSION_ADD_SESSION_CREATION_TIME;
 import static com.android.server.blob.BlobStoreConfig.hasSessionExpired;
@@ -54,12 +53,15 @@
 
 import com.android.internal.annotations.GuardedBy;
 import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.util.FrameworkStatsLog;
 import com.android.internal.util.IndentingPrintWriter;
 import com.android.internal.util.Preconditions;
 import com.android.internal.util.XmlUtils;
 import com.android.server.blob.BlobStoreManagerService.DumpArgs;
 import com.android.server.blob.BlobStoreManagerService.SessionStateChangeListener;
 
+import libcore.io.IoUtils;
+
 import org.xmlpull.v1.XmlPullParser;
 import org.xmlpull.v1.XmlPullParserException;
 import org.xmlpull.v1.XmlSerializer;
@@ -98,7 +100,7 @@
     private File mSessionFile;
 
     @GuardedBy("mRevocableFds")
-    private ArrayList<RevocableFileDescriptor> mRevocableFds = new ArrayList<>();
+    private final ArrayList<RevocableFileDescriptor> mRevocableFds = new ArrayList<>();
 
     // This will be accessed from only one thread at any point of time, so no need to grab
     // a lock for this.
@@ -208,27 +210,37 @@
                 throw new IllegalStateException("Not allowed to write in state: "
                         + stateToString(mState));
             }
+        }
 
-            try {
-                return openWriteLocked(offsetBytes, lengthBytes);
-            } catch (IOException e) {
-                throw ExceptionUtils.wrap(e);
+        FileDescriptor fd = null;
+        try {
+            fd = openWriteInternal(offsetBytes, lengthBytes);
+            final RevocableFileDescriptor revocableFd = new RevocableFileDescriptor(mContext, fd);
+            synchronized (mSessionLock) {
+                if (mState != STATE_OPENED) {
+                    IoUtils.closeQuietly(fd);
+                    throw new IllegalStateException("Not allowed to write in state: "
+                            + stateToString(mState));
+                }
+                trackRevocableFdLocked(revocableFd);
+                return revocableFd.getRevocableFileDescriptor();
             }
+        } catch (IOException e) {
+            IoUtils.closeQuietly(fd);
+            throw ExceptionUtils.wrap(e);
         }
     }
 
-    @GuardedBy("mSessionLock")
     @NonNull
-    private ParcelFileDescriptor openWriteLocked(@BytesLong long offsetBytes,
+    private FileDescriptor openWriteInternal(@BytesLong long offsetBytes,
             @BytesLong long lengthBytes) throws IOException {
         // TODO: Add limit on active open sessions/writes/reads
-        FileDescriptor fd = null;
         try {
             final File sessionFile = getSessionFile();
             if (sessionFile == null) {
                 throw new IllegalStateException("Couldn't get the file for this session");
             }
-            fd = Os.open(sessionFile.getPath(), O_CREAT | O_RDWR, 0600);
+            final FileDescriptor fd = Os.open(sessionFile.getPath(), O_CREAT | O_RDWR, 0600);
             if (offsetBytes > 0) {
                 final long curOffset = Os.lseek(fd, offsetBytes, SEEK_SET);
                 if (curOffset != offsetBytes) {
@@ -239,10 +251,10 @@
             if (lengthBytes > 0) {
                 mContext.getSystemService(StorageManager.class).allocateBytes(fd, lengthBytes);
             }
+            return fd;
         } catch (ErrnoException e) {
-            e.rethrowAsIOException();
+            throw e.rethrowAsIOException();
         }
-        return createRevocableFdLocked(fd);
     }
 
     @Override
@@ -254,29 +266,40 @@
                 throw new IllegalStateException("Not allowed to read in state: "
                         + stateToString(mState));
             }
+        }
 
-            try {
-                return openReadLocked();
-            } catch (IOException e) {
-                throw ExceptionUtils.wrap(e);
+        FileDescriptor fd = null;
+        try {
+            fd = openReadInternal();
+            final RevocableFileDescriptor revocableFd = new RevocableFileDescriptor(mContext, fd);
+            synchronized (mSessionLock) {
+                if (mState != STATE_OPENED) {
+                    IoUtils.closeQuietly(fd);
+                    throw new IllegalStateException("Not allowed to read in state: "
+                            + stateToString(mState));
+                }
+                trackRevocableFdLocked(revocableFd);
+                return revocableFd.getRevocableFileDescriptor();
             }
+
+        } catch (IOException e) {
+            IoUtils.closeQuietly(fd);
+            throw ExceptionUtils.wrap(e);
         }
     }
 
-    @GuardedBy("mSessionLock")
     @NonNull
-    private ParcelFileDescriptor openReadLocked() throws IOException {
-        FileDescriptor fd = null;
+    private FileDescriptor openReadInternal() throws IOException {
         try {
             final File sessionFile = getSessionFile();
             if (sessionFile == null) {
                 throw new IllegalStateException("Couldn't get the file for this session");
             }
-            fd = Os.open(sessionFile.getPath(), O_RDONLY, 0);
+            final FileDescriptor fd = Os.open(sessionFile.getPath(), O_RDONLY, 0);
+            return fd;
         } catch (ErrnoException e) {
-            e.rethrowAsIOException();
+            throw e.rethrowAsIOException();
         }
-        return createRevocableFdLocked(fd);
     }
 
     @Override
@@ -397,7 +420,7 @@
             }
 
             mState = state;
-            revokeAllFdsLocked();
+            revokeAllFds();
 
             if (sendCallback) {
                 mListener.onStateChanged(this);
@@ -423,30 +446,31 @@
                 mState = STATE_VERIFIED_VALID;
                 // Commit callback will be sent once the data is persisted.
             } else {
-                if (LOGV) {
-                    Slog.v(TAG, "Digest of the data didn't match the given BlobHandle.digest");
-                }
+                Slog.d(TAG, "Digest of the data ("
+                        + (mDataDigest == null ? "null" : BlobHandle.safeDigest(mDataDigest))
+                        + ") didn't match the given BlobHandle.digest ("
+                        + BlobHandle.safeDigest(mBlobHandle.digest) + ")");
                 mState = STATE_VERIFIED_INVALID;
+
+                FrameworkStatsLog.write(FrameworkStatsLog.BLOB_COMMITTED, getOwnerUid(), mSessionId,
+                        getSize(), FrameworkStatsLog.BLOB_COMMITTED__RESULT__DIGEST_MISMATCH);
                 sendCommitCallbackResult(COMMIT_RESULT_ERROR);
             }
             mListener.onStateChanged(this);
         }
     }
 
-    @GuardedBy("mSessionLock")
-    private void revokeAllFdsLocked() {
-        for (int i = mRevocableFds.size() - 1; i >= 0; --i) {
-            mRevocableFds.get(i).revoke();
+    private void revokeAllFds() {
+        synchronized (mRevocableFds) {
+            for (int i = mRevocableFds.size() - 1; i >= 0; --i) {
+                mRevocableFds.get(i).revoke();
+            }
+            mRevocableFds.clear();
         }
-        mRevocableFds.clear();
     }
 
     @GuardedBy("mSessionLock")
-    @NonNull
-    private ParcelFileDescriptor createRevocableFdLocked(FileDescriptor fd)
-            throws IOException {
-        final RevocableFileDescriptor revocableFd =
-                new RevocableFileDescriptor(mContext, fd);
+    private void trackRevocableFdLocked(RevocableFileDescriptor revocableFd) {
         synchronized (mRevocableFds) {
             mRevocableFds.add(revocableFd);
         }
@@ -455,7 +479,6 @@
                 mRevocableFds.remove(revocableFd);
             }
         });
-        return revocableFd.getRevocableFileDescriptor();
     }
 
     @Nullable
diff --git a/apex/jobscheduler/service/java/com/android/server/usage/AppStandbyController.java b/apex/jobscheduler/service/java/com/android/server/usage/AppStandbyController.java
index 280a687..0621087 100644
--- a/apex/jobscheduler/service/java/com/android/server/usage/AppStandbyController.java
+++ b/apex/jobscheduler/service/java/com/android/server/usage/AppStandbyController.java
@@ -233,7 +233,7 @@
      * Set of system apps that are headless (don't have any declared activities, enabled or
      * disabled). Presence in this map indicates that the app is a headless system app.
      */
-    @GuardedBy("mAppIdleLock")
+    @GuardedBy("mHeadlessSystemApps")
     private final ArrayMap<String, Boolean> mHeadlessSystemApps = new ArrayMap<>();
 
     private final CountDownLatch mAdminDataAvailableLatch = new CountDownLatch(1);
@@ -447,7 +447,8 @@
                 userFileExists = mAppIdleHistory.userFileExists(UserHandle.USER_SYSTEM);
             }
 
-            loadHeadlessSystemAppCache();
+            // Offload to handler thread to avoid boottime impact.
+            mHandler.post(this::loadHeadlessSystemAppCache);
 
             if (mPendingInitializeDefaults || !userFileExists) {
                 initializeDefaultsForSystemApps(UserHandle.USER_SYSTEM);
@@ -1121,7 +1122,9 @@
     }
 
     private boolean isHeadlessSystemApp(String packageName) {
-        return mHeadlessSystemApps.containsKey(packageName);
+        synchronized (mHeadlessSystemApps) {
+            return mHeadlessSystemApps.containsKey(packageName);
+        }
     }
 
     @Override
@@ -1697,19 +1700,24 @@
                     userId);
             evaluateSystemAppException(pi);
         } catch (PackageManager.NameNotFoundException e) {
-            mHeadlessSystemApps.remove(packageName);
+            synchronized (mHeadlessSystemApps) {
+                mHeadlessSystemApps.remove(packageName);
+            }
         }
     }
 
-    private void evaluateSystemAppException(@Nullable PackageInfo pkgInfo) {
-        if (pkgInfo.applicationInfo != null && pkgInfo.applicationInfo.isSystemApp()) {
-            synchronized (mAppIdleLock) {
-                if (pkgInfo.activities == null || pkgInfo.activities.length == 0) {
-                    // Headless system app.
-                    mHeadlessSystemApps.put(pkgInfo.packageName, true);
-                } else {
-                    mHeadlessSystemApps.remove(pkgInfo.packageName);
-                }
+    /** Returns true if the exception status changed. */
+    private boolean evaluateSystemAppException(@Nullable PackageInfo pkgInfo) {
+        if (pkgInfo == null || pkgInfo.applicationInfo == null
+                || !pkgInfo.applicationInfo.isSystemApp()) {
+            return false;
+        }
+        synchronized (mHeadlessSystemApps) {
+            if (pkgInfo.activities == null || pkgInfo.activities.length == 0) {
+                // Headless system app.
+                return mHeadlessSystemApps.put(pkgInfo.packageName, true) == null;
+            } else {
+                return mHeadlessSystemApps.remove(pkgInfo.packageName) != null;
             }
         }
     }
@@ -1754,7 +1762,12 @@
                 UserHandle.USER_SYSTEM);
         final int packageCount = packages.size();
         for (int i = 0; i < packageCount; i++) {
-            evaluateSystemAppException(packages.get(i));
+            PackageInfo pkgInfo = packages.get(i);
+            if (pkgInfo != null && evaluateSystemAppException(pkgInfo)) {
+                mHandler.obtainMessage(MSG_CHECK_PACKAGE_IDLE_STATE,
+                        UserHandle.USER_SYSTEM, -1, pkgInfo.packageName)
+                    .sendToTarget();
+            }
         }
     }
 
@@ -1852,9 +1865,12 @@
         pw.println();
 
         pw.println("mHeadlessSystemApps=[");
-        for (int i = mHeadlessSystemApps.size() - 1; i >= 0; --i) {
-            pw.print(mHeadlessSystemApps.keyAt(i));
-            pw.println(",");
+        synchronized (mHeadlessSystemApps) {
+            for (int i = mHeadlessSystemApps.size() - 1; i >= 0; --i) {
+                pw.print("  ");
+                pw.print(mHeadlessSystemApps.keyAt(i));
+                pw.println(",");
+            }
         }
         pw.println("]");
         pw.println();
diff --git a/apex/media/framework/java/android/media/MediaParser.java b/apex/media/framework/java/android/media/MediaParser.java
index 7cbb98e..19f578e 100644
--- a/apex/media/framework/java/android/media/MediaParser.java
+++ b/apex/media/framework/java/android/media/MediaParser.java
@@ -203,6 +203,15 @@
         /** Returned by {@link #getDurationMicros()} when the duration is unknown. */
         public static final int UNKNOWN_DURATION = Integer.MIN_VALUE;
 
+        /**
+         * For each {@link #getSeekPoints} call, returns a single {@link SeekPoint} whose {@link
+         * SeekPoint#timeMicros} matches the requested timestamp, and whose {@link
+         * SeekPoint#position} is 0.
+         *
+         * @hide
+         */
+        public static final SeekMap DUMMY = new SeekMap(new DummyExoPlayerSeekMap());
+
         private final com.google.android.exoplayer2.extractor.SeekMap mExoPlayerSeekMap;
 
         private SeekMap(com.google.android.exoplayer2.extractor.SeekMap exoplayerSeekMap) {
@@ -795,6 +804,18 @@
      */
     public static final String PARAMETER_EAGERLY_EXPOSE_TRACKTYPE =
             "android.media.mediaparser.eagerlyExposeTrackType";
+    /**
+     * Sets whether a dummy {@link SeekMap} should be exposed before starting extraction. {@code
+     * boolean} expected. Default value is {@code false}.
+     *
+     * <p>For each {@link SeekMap#getSeekPoints} call, the dummy {@link SeekMap} returns a single
+     * {@link SeekPoint} whose {@link SeekPoint#timeMicros} matches the requested timestamp, and
+     * whose {@link SeekPoint#position} is 0.
+     *
+     * @hide
+     */
+    public static final String PARAMETER_EXPOSE_DUMMY_SEEKMAP =
+            "android.media.mediaparser.exposeDummySeekMap";
 
     // Private constants.
 
@@ -958,6 +979,7 @@
     private boolean mIncludeSupplementalData;
     private boolean mIgnoreTimestampOffset;
     private boolean mEagerlyExposeTrackType;
+    private boolean mExposeDummySeekMap;
     private String mParserName;
     private Extractor mExtractor;
     private ExtractorInput mExtractorInput;
@@ -1017,6 +1039,9 @@
         if (PARAMETER_EAGERLY_EXPOSE_TRACKTYPE.equals(parameterName)) {
             mEagerlyExposeTrackType = (boolean) value;
         }
+        if (PARAMETER_EXPOSE_DUMMY_SEEKMAP.equals(parameterName)) {
+            mExposeDummySeekMap = (boolean) value;
+        }
         mParserParameters.put(parameterName, value);
         return this;
     }
@@ -1078,11 +1103,10 @@
         }
         mExoDataReader.mInputReader = seekableInputReader;
 
-        // TODO: Apply parameters when creating extractor instances.
         if (mExtractor == null) {
+            mPendingExtractorInit = true;
             if (!mParserName.equals(PARSER_NAME_UNKNOWN)) {
                 mExtractor = createExtractor(mParserName);
-                mExtractor.init(new ExtractorOutputAdapter());
             } else {
                 for (String parserName : mParserNamesPool) {
                     Extractor extractor = createExtractor(parserName);
@@ -1107,9 +1131,18 @@
         }
 
         if (mPendingExtractorInit) {
+            if (mExposeDummySeekMap) {
+                // We propagate the dummy seek map before initializing the extractor, in case the
+                // extractor initialization outputs a seek map.
+                mOutputConsumer.onSeekMapFound(SeekMap.DUMMY);
+            }
             mExtractor.init(new ExtractorOutputAdapter());
             mPendingExtractorInit = false;
+            // We return after initialization to allow clients use any output information before
+            // starting actual extraction.
+            return true;
         }
+
         if (isPendingSeek()) {
             mExtractor.seek(mPendingSeekPosition, mPendingSeekTimeMicros);
             removePendingSeek();
@@ -1683,6 +1716,28 @@
         }
     }
 
+    private static final class DummyExoPlayerSeekMap
+            implements com.google.android.exoplayer2.extractor.SeekMap {
+
+        @Override
+        public boolean isSeekable() {
+            return true;
+        }
+
+        @Override
+        public long getDurationUs() {
+            return C.TIME_UNSET;
+        }
+
+        @Override
+        public SeekPoints getSeekPoints(long timeUs) {
+            com.google.android.exoplayer2.extractor.SeekPoint seekPoint =
+                    new com.google.android.exoplayer2.extractor.SeekPoint(
+                            timeUs, /* position= */ 0);
+            return new SeekPoints(seekPoint, seekPoint);
+        }
+    }
+
     /** Creates extractor instances. */
     private interface ExtractorFactory {
 
@@ -1923,6 +1978,7 @@
         expectedTypeByParameterName.put(PARAMETER_INCLUDE_SUPPLEMENTAL_DATA, Boolean.class);
         expectedTypeByParameterName.put(PARAMETER_IGNORE_TIMESTAMP_OFFSET, Boolean.class);
         expectedTypeByParameterName.put(PARAMETER_EAGERLY_EXPOSE_TRACKTYPE, Boolean.class);
+        expectedTypeByParameterName.put(PARAMETER_EXPOSE_DUMMY_SEEKMAP, Boolean.class);
         EXPECTED_TYPE_BY_PARAMETER_NAME = Collections.unmodifiableMap(expectedTypeByParameterName);
     }
 }
diff --git a/apex/permission/service/Android.bp b/apex/permission/service/Android.bp
index 6144976..7f31879 100644
--- a/apex/permission/service/Android.bp
+++ b/apex/permission/service/Android.bp
@@ -20,14 +20,26 @@
     path: "java",
 }
 
-java_library {
+java_sdk_library {
     name: "service-permission",
+    defaults: ["framework-system-server-module-defaults"],
+    visibility: [
+        "//frameworks/base/services/core",
+        "//frameworks/base/apex/permission",
+        "//frameworks/base/apex/permission/testing",
+        "//frameworks/base/apex/permission/tests",
+        "//frameworks/base/services/tests/mockingservicestests",
+    ],
+    impl_library_visibility: [
+        "//visibility:override",
+        "//frameworks/base/apex/permission/tests",
+        "//frameworks/base/services/tests/mockingservicestests",
+        "//frameworks/base/services/tests/servicestests",
+    ],
     srcs: [
         ":service-permission-sources",
     ],
-    sdk_version: "module_current",
     libs: [
-        "framework-annotations-lib",
         "framework-permission",
     ],
     apex_available: [
@@ -36,28 +48,3 @@
     ],
     installable: true,
 }
-
-droidstubs {
-    name: "service-permission-stubs-srcs",
-    srcs: [ ":service-permission-sources" ],
-    defaults: ["service-module-stubs-srcs-defaults"],
-    check_api: {
-        last_released: {
-            api_file: ":service-permission.api.system-server.latest",
-            removed_api_file: ":service-permission-removed.api.system-server.latest",
-        },
-        api_lint: {
-            new_since: ":service-permission.api.system-server.latest",
-        },
-    },
-    visibility: ["//visibility:private"],
-    dist: { dest: "service-permission.txt" },
-}
-
-java_library {
-    name: "service-permission-stubs",
-    srcs: [":service-permission-stubs-srcs"],
-    defaults: ["service-module-stubs-defaults"],
-    visibility: ["//frameworks/base/services/core"],
-    dist: { dest: "service-permission.jar" },
-}
diff --git a/apex/permission/service/api/current.txt b/apex/permission/service/api/current.txt
index c76cc32..d802177 100644
--- a/apex/permission/service/api/current.txt
+++ b/apex/permission/service/api/current.txt
@@ -1,46 +1 @@
 // Signature format: 2.0
-package com.android.permission.persistence {
-
-  public interface RuntimePermissionsPersistence {
-    method @NonNull public static com.android.permission.persistence.RuntimePermissionsPersistence createInstance();
-    method public void deleteForUser(@NonNull android.os.UserHandle);
-    method @Nullable public com.android.permission.persistence.RuntimePermissionsState readForUser(@NonNull android.os.UserHandle);
-    method public void writeForUser(@NonNull com.android.permission.persistence.RuntimePermissionsState, @NonNull android.os.UserHandle);
-  }
-
-  public final class RuntimePermissionsState {
-    ctor public RuntimePermissionsState(int, @Nullable String, @NonNull java.util.Map<java.lang.String,java.util.List<com.android.permission.persistence.RuntimePermissionsState.PermissionState>>, @NonNull java.util.Map<java.lang.String,java.util.List<com.android.permission.persistence.RuntimePermissionsState.PermissionState>>);
-    method @Nullable public String getFingerprint();
-    method @NonNull public java.util.Map<java.lang.String,java.util.List<com.android.permission.persistence.RuntimePermissionsState.PermissionState>> getPackagePermissions();
-    method @NonNull public java.util.Map<java.lang.String,java.util.List<com.android.permission.persistence.RuntimePermissionsState.PermissionState>> getSharedUserPermissions();
-    method public int getVersion();
-    field public static final int NO_VERSION = -1; // 0xffffffff
-  }
-
-  public static final class RuntimePermissionsState.PermissionState {
-    ctor public RuntimePermissionsState.PermissionState(@NonNull String, boolean, int);
-    method public int getFlags();
-    method @NonNull public String getName();
-    method public boolean isGranted();
-  }
-
-}
-
-package com.android.role.persistence {
-
-  public interface RolesPersistence {
-    method @NonNull public static com.android.role.persistence.RolesPersistence createInstance();
-    method public void deleteForUser(@NonNull android.os.UserHandle);
-    method @Nullable public com.android.role.persistence.RolesState readForUser(@NonNull android.os.UserHandle);
-    method public void writeForUser(@NonNull com.android.role.persistence.RolesState, @NonNull android.os.UserHandle);
-  }
-
-  public final class RolesState {
-    ctor public RolesState(int, @Nullable String, @NonNull java.util.Map<java.lang.String,java.util.Set<java.lang.String>>);
-    method @Nullable public String getPackagesHash();
-    method @NonNull public java.util.Map<java.lang.String,java.util.Set<java.lang.String>> getRoles();
-    method public int getVersion();
-  }
-
-}
-
diff --git a/apex/permission/service/api/system-server-current.txt b/apex/permission/service/api/system-server-current.txt
new file mode 100644
index 0000000..c76cc32
--- /dev/null
+++ b/apex/permission/service/api/system-server-current.txt
@@ -0,0 +1,46 @@
+// Signature format: 2.0
+package com.android.permission.persistence {
+
+  public interface RuntimePermissionsPersistence {
+    method @NonNull public static com.android.permission.persistence.RuntimePermissionsPersistence createInstance();
+    method public void deleteForUser(@NonNull android.os.UserHandle);
+    method @Nullable public com.android.permission.persistence.RuntimePermissionsState readForUser(@NonNull android.os.UserHandle);
+    method public void writeForUser(@NonNull com.android.permission.persistence.RuntimePermissionsState, @NonNull android.os.UserHandle);
+  }
+
+  public final class RuntimePermissionsState {
+    ctor public RuntimePermissionsState(int, @Nullable String, @NonNull java.util.Map<java.lang.String,java.util.List<com.android.permission.persistence.RuntimePermissionsState.PermissionState>>, @NonNull java.util.Map<java.lang.String,java.util.List<com.android.permission.persistence.RuntimePermissionsState.PermissionState>>);
+    method @Nullable public String getFingerprint();
+    method @NonNull public java.util.Map<java.lang.String,java.util.List<com.android.permission.persistence.RuntimePermissionsState.PermissionState>> getPackagePermissions();
+    method @NonNull public java.util.Map<java.lang.String,java.util.List<com.android.permission.persistence.RuntimePermissionsState.PermissionState>> getSharedUserPermissions();
+    method public int getVersion();
+    field public static final int NO_VERSION = -1; // 0xffffffff
+  }
+
+  public static final class RuntimePermissionsState.PermissionState {
+    ctor public RuntimePermissionsState.PermissionState(@NonNull String, boolean, int);
+    method public int getFlags();
+    method @NonNull public String getName();
+    method public boolean isGranted();
+  }
+
+}
+
+package com.android.role.persistence {
+
+  public interface RolesPersistence {
+    method @NonNull public static com.android.role.persistence.RolesPersistence createInstance();
+    method public void deleteForUser(@NonNull android.os.UserHandle);
+    method @Nullable public com.android.role.persistence.RolesState readForUser(@NonNull android.os.UserHandle);
+    method public void writeForUser(@NonNull com.android.role.persistence.RolesState, @NonNull android.os.UserHandle);
+  }
+
+  public final class RolesState {
+    ctor public RolesState(int, @Nullable String, @NonNull java.util.Map<java.lang.String,java.util.Set<java.lang.String>>);
+    method @Nullable public String getPackagesHash();
+    method @NonNull public java.util.Map<java.lang.String,java.util.Set<java.lang.String>> getRoles();
+    method public int getVersion();
+  }
+
+}
+
diff --git a/apex/permission/service/api/system-server-removed.txt b/apex/permission/service/api/system-server-removed.txt
new file mode 100644
index 0000000..d802177
--- /dev/null
+++ b/apex/permission/service/api/system-server-removed.txt
@@ -0,0 +1 @@
+// Signature format: 2.0
diff --git a/apex/permission/tests/Android.bp b/apex/permission/tests/Android.bp
index a1f7a54..271e328 100644
--- a/apex/permission/tests/Android.bp
+++ b/apex/permission/tests/Android.bp
@@ -19,7 +19,7 @@
         "java/**/*.kt",
     ],
     static_libs: [
-        "service-permission",
+        "service-permission.impl",
         "androidx.test.rules",
         "androidx.test.ext.junit",
         "androidx.test.ext.truth",
diff --git a/api/test-current.txt b/api/test-current.txt
index 1142fb6..795d873 100644
--- a/api/test-current.txt
+++ b/api/test-current.txt
@@ -3323,6 +3323,7 @@
     field public static final String NFC_PAYMENT_DEFAULT_COMPONENT = "nfc_payment_default_component";
     field public static final String NOTIFICATION_BADGING = "notification_badging";
     field public static final String POWER_MENU_LOCKED_SHOW_CONTENT = "power_menu_locked_show_content";
+    field public static final String SHOW_IME_WITH_HARD_KEYBOARD = "show_ime_with_hard_keyboard";
     field @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) public static final String SYNC_PARENT_SOUNDS = "sync_parent_sounds";
     field public static final String USER_SETUP_COMPLETE = "user_setup_complete";
     field public static final String VOICE_INTERACTION_SERVICE = "voice_interaction_service";
diff --git a/cmds/idmap2/Android.bp b/cmds/idmap2/Android.bp
index fb58305..878cef9 100644
--- a/cmds/idmap2/Android.bp
+++ b/cmds/idmap2/Android.bp
@@ -23,9 +23,16 @@
         "misc-*",
         "readability-*",
     ],
+    tidy_checks_as_errors: [
+        "modernize-*",
+        "-modernize-avoid-c-arrays",
+        "-modernize-use-trailing-return-type",
+        "android-*",
+        "misc-*",
+        "readability-*",
+    ],
     tidy_flags: [
         "-system-headers",
-        "-warnings-as-errors=*",
     ],
 }
 
diff --git a/cmds/idmap2/idmap2/CommandUtils.cpp b/cmds/idmap2/idmap2/CommandUtils.cpp
index e058cd6e..8f5845b 100644
--- a/cmds/idmap2/idmap2/CommandUtils.cpp
+++ b/cmds/idmap2/idmap2/CommandUtils.cpp
@@ -29,7 +29,7 @@
 using android::idmap2::Unit;
 
 Result<Unit> Verify(const std::string& idmap_path, const std::string& target_path,
-                    const std::string& overlay_path, uint32_t fulfilled_policies,
+                    const std::string& overlay_path, PolicyBitmask fulfilled_policies,
                     bool enforce_overlayable) {
   SYSTRACE << "Verify " << idmap_path;
   std::ifstream fin(idmap_path);
diff --git a/cmds/idmap2/idmap2/CommandUtils.h b/cmds/idmap2/idmap2/CommandUtils.h
index 99605de..e717e04 100644
--- a/cmds/idmap2/idmap2/CommandUtils.h
+++ b/cmds/idmap2/idmap2/CommandUtils.h
@@ -17,12 +17,13 @@
 #ifndef IDMAP2_IDMAP2_COMMAND_UTILS_H_
 #define IDMAP2_IDMAP2_COMMAND_UTILS_H_
 
+#include "idmap2/PolicyUtils.h"
 #include "idmap2/Result.h"
 
 android::idmap2::Result<android::idmap2::Unit> Verify(const std::string& idmap_path,
                                                       const std::string& target_path,
                                                       const std::string& overlay_path,
-                                                      uint32_t fulfilled_policies,
+                                                      PolicyBitmask fulfilled_policies,
                                                       bool enforce_overlayable);
 
 #endif  // IDMAP2_IDMAP2_COMMAND_UTILS_H_
diff --git a/cmds/idmap2/idmap2d/Idmap2Service.cpp b/cmds/idmap2/idmap2d/Idmap2Service.cpp
index 908d966..f95b73f 100644
--- a/cmds/idmap2/idmap2d/Idmap2Service.cpp
+++ b/cmds/idmap2/idmap2d/Idmap2Service.cpp
@@ -70,12 +70,12 @@
 }
 
 Status GetCrc(const std::string& apk_path, uint32_t* out_crc) {
-  const auto overlay_zip = ZipFile::Open(apk_path);
-  if (!overlay_zip) {
+  const auto zip = ZipFile::Open(apk_path);
+  if (!zip) {
     return error(StringPrintf("failed to open apk %s", apk_path.c_str()));
   }
 
-  const auto crc = GetPackageCrc(*overlay_zip);
+  const auto crc = GetPackageCrc(*zip);
   if (!crc) {
     return error(crc.GetErrorMessage());
   }
@@ -121,6 +121,7 @@
                                   bool* _aidl_return) {
   SYSTRACE << "Idmap2Service::verifyIdmap " << overlay_apk_path;
   assert(_aidl_return);
+
   const std::string idmap_path = Idmap::CanonicalIdmapPathFor(kIdmapCacheDir, overlay_apk_path);
   std::ifstream fin(idmap_path);
   const std::unique_ptr<const IdmapHeader> header = IdmapHeader::FromBinaryStream(fin);
@@ -156,13 +157,10 @@
 
   auto up_to_date =
       header->IsUpToDate(target_apk_path.c_str(), overlay_apk_path.c_str(), target_crc, overlay_crc,
-                         fulfilled_policies, enforce_overlayable);
-  if (!up_to_date) {
-    *_aidl_return = false;
-    return error(up_to_date.GetErrorMessage());
-  }
+                         ConvertAidlArgToPolicyBitmask(fulfilled_policies), enforce_overlayable);
 
-  return ok();
+  *_aidl_return = static_cast<bool>(up_to_date);
+  return *_aidl_return ? ok() : error(up_to_date.GetErrorMessage());
 }
 
 Status Idmap2Service::createIdmap(const std::string& target_apk_path,
diff --git a/cmds/idmap2/include/idmap2/Idmap.h b/cmds/idmap2/include/idmap2/Idmap.h
index 8f25b8d..0f05592 100644
--- a/cmds/idmap2/include/idmap2/Idmap.h
+++ b/cmds/idmap2/include/idmap2/Idmap.h
@@ -141,9 +141,9 @@
   // field *must* be incremented. Because of this, we know that if the idmap
   // header is up-to-date the entire file is up-to-date.
   Result<Unit> IsUpToDate(const char* target_path, const char* overlay_path,
-                          uint32_t fulfilled_policies, bool enforce_overlayable) const;
+                          PolicyBitmask fulfilled_policies, bool enforce_overlayable) const;
   Result<Unit> IsUpToDate(const char* target_path, const char* overlay_path, uint32_t target_crc,
-                          uint32_t overlay_crc, uint32_t fulfilled_policies,
+                          uint32_t overlay_crc, PolicyBitmask fulfilled_policies,
                           bool enforce_overlayable) const;
 
   void accept(Visitor* v) const;
diff --git a/cmds/idmap2/libidmap2/Idmap.cpp b/cmds/idmap2/libidmap2/Idmap.cpp
index 0bea217..23c25a7 100644
--- a/cmds/idmap2/libidmap2/Idmap.cpp
+++ b/cmds/idmap2/libidmap2/Idmap.cpp
@@ -115,8 +115,7 @@
   uint8_t enforce_overlayable;
   if (!Read32(stream, &idmap_header->magic_) || !Read32(stream, &idmap_header->version_) ||
       !Read32(stream, &idmap_header->target_crc_) || !Read32(stream, &idmap_header->overlay_crc_) ||
-      !Read32(stream, &idmap_header->fulfilled_policies_) ||
-      !Read8(stream, &enforce_overlayable) ||
+      !Read32(stream, &idmap_header->fulfilled_policies_) || !Read8(stream, &enforce_overlayable) ||
       !ReadString256(stream, idmap_header->target_path_) ||
       !ReadString256(stream, idmap_header->overlay_path_)) {
     return nullptr;
@@ -134,7 +133,8 @@
 }
 
 Result<Unit> IdmapHeader::IsUpToDate(const char* target_path, const char* overlay_path,
-                                     uint32_t fulfilled_policies, bool enforce_overlayable) const {
+                                     PolicyBitmask fulfilled_policies,
+                                     bool enforce_overlayable) const {
   const std::unique_ptr<const ZipFile> target_zip = ZipFile::Open(target_path);
   if (!target_zip) {
     return Error("failed to open target %s", target_path);
@@ -161,7 +161,8 @@
 
 Result<Unit> IdmapHeader::IsUpToDate(const char* target_path, const char* overlay_path,
                                      uint32_t target_crc, uint32_t overlay_crc,
-                                     uint32_t fulfilled_policies, bool enforce_overlayable) const {
+                                     PolicyBitmask fulfilled_policies,
+                                     bool enforce_overlayable) const {
   if (magic_ != kIdmapMagic) {
     return Error("bad magic: actual 0x%08x, expected 0x%08x", magic_, kIdmapMagic);
   }
@@ -187,8 +188,7 @@
 
   if (enforce_overlayable != enforce_overlayable_) {
     return Error("bad enforce overlayable: idmap version %s, file system version %s",
-                 enforce_overlayable ? "true" : "false",
-                 enforce_overlayable_ ? "true" : "false");
+                 enforce_overlayable ? "true" : "false", enforce_overlayable_ ? "true" : "false");
   }
 
   if (strcmp(target_path, target_path_) != 0) {
diff --git a/cmds/statsd/src/StatsLogProcessor.cpp b/cmds/statsd/src/StatsLogProcessor.cpp
index 095dd1e..e7b32c5 100644
--- a/cmds/statsd/src/StatsLogProcessor.cpp
+++ b/cmds/statsd/src/StatsLogProcessor.cpp
@@ -529,7 +529,9 @@
         VLOG("StatsdConfig valid");
     } else {
         // If there is any error in the config, don't use it.
+        // Remove any existing config with the same key.
         ALOGE("StatsdConfig NOT valid");
+        mMetricsManagers.erase(key);
     }
 }
 
diff --git a/cmds/statsd/src/StatsLogProcessor.h b/cmds/statsd/src/StatsLogProcessor.h
index 7090bd4..23f2584 100644
--- a/cmds/statsd/src/StatsLogProcessor.h
+++ b/cmds/statsd/src/StatsLogProcessor.h
@@ -284,6 +284,7 @@
     FRIEND_TEST(StatsLogProcessorTest, TestRateLimitByteSize);
     FRIEND_TEST(StatsLogProcessorTest, TestRateLimitBroadcast);
     FRIEND_TEST(StatsLogProcessorTest, TestDropWhenByteSizeTooLarge);
+    FRIEND_TEST(StatsLogProcessorTest, InvalidConfigRemoved);
     FRIEND_TEST(StatsLogProcessorTest, TestActiveConfigMetricDiskWriteRead);
     FRIEND_TEST(StatsLogProcessorTest, TestActivationOnBoot);
     FRIEND_TEST(StatsLogProcessorTest, TestActivationOnBootMultipleActivations);
diff --git a/cmds/statsd/src/StatsService.cpp b/cmds/statsd/src/StatsService.cpp
index 47bab29..6f952f6 100644
--- a/cmds/statsd/src/StatsService.cpp
+++ b/cmds/statsd/src/StatsService.cpp
@@ -267,8 +267,11 @@
     for (const ConfigKey& configKey : mConfigManager->GetAllConfigKeys()) {
         uint64_t reportsListToken =
                 proto.start(FIELD_TYPE_MESSAGE | FIELD_COUNT_REPEATED | FIELD_ID_REPORTS_LIST);
+        // Don't include the current bucket to avoid skipping buckets.
+        // If we need to include the current bucket later, consider changing to NO_TIME_CONSTRAINTS
+        // or other alternatives to avoid skipping buckets for pulled metrics.
         mProcessor->onDumpReport(configKey, getElapsedRealtimeNs(),
-                                 true /* includeCurrentBucket */, false /* erase_data */,
+                                 false /* includeCurrentBucket */, false /* erase_data */,
                                  ADB_DUMP,
                                  FAST,
                                  &proto);
diff --git a/cmds/statsd/src/atoms.proto b/cmds/statsd/src/atoms.proto
index 2216633..278278f 100644
--- a/cmds/statsd/src/atoms.proto
+++ b/cmds/statsd/src/atoms.proto
@@ -193,7 +193,7 @@
         BiometricAcquired biometric_acquired = 87 [(module) = "framework"];
         BiometricAuthenticated biometric_authenticated = 88 [(module) = "framework"];
         BiometricErrorOccurred biometric_error_occurred = 89 [(module) = "framework"];
-        UiEventReported ui_event_reported = 90 [(module) = "framework"];
+        UiEventReported ui_event_reported = 90 [(module) = "framework", (module) = "sysui"];
         BatteryHealthSnapshot battery_health_snapshot = 91;
         SlowIo slow_io = 92;
         BatteryCausedShutdown battery_caused_shutdown = 93;
@@ -419,7 +419,7 @@
         DisplayJankReported display_jank_reported = 257;
         AppStandbyBucketChanged app_standby_bucket_changed = 258 [(module) = "framework"];
         SharesheetStarted sharesheet_started = 259 [(module) = "framework"];
-        RankingSelected ranking_selected = 260 [(module) = "framework"];
+        RankingSelected ranking_selected = 260 [(module) = "framework", (module) = "sysui"];
         TvSettingsUIInteracted tvsettings_ui_interacted = 261 [(module) = "tv_settings"];
         LauncherStaticLayout launcher_snapshot = 262 [(module) = "sysui"];
         PackageInstallerV2Reported package_installer_v2_reported = 263 [(module) = "framework"];
@@ -450,6 +450,37 @@
         TvCasSessionOpenStatus tv_cas_session_open_status =
             280 [(module) = "framework"];
         AssistantInvocationReported assistant_invocation_reported = 281 [(module) = "framework"];
+        DisplayWakeReported display_wake_reported = 282 [(module) = "framework"];
+        CarUserHalModifyUserRequestReported car_user_hal_modify_user_request_reported =
+            283 [(module) = "car"];
+        CarUserHalModifyUserResponseReported car_user_hal_modify_user_response_reported =
+            284 [(module) = "car"];
+        CarUserHalPostSwitchResponseReported car_user_hal_post_switch_response_reported =
+            285 [(module) = "car"];
+        CarUserHalInitialUserInfoRequestReported car_user_hal_initial_user_info_request_reported =
+            286 [(module) = "car"];
+        CarUserHalInitialUserInfoResponseReported car_user_hal_initial_user_info_response_reported =
+            287 [(module) = "car"];
+        CarUserHalUserAssociationRequestReported car_user_hal_user_association_request_reported =
+            288 [(module) = "car"];
+        CarUserHalSetUserAssociationResponseReported car_user_hal_set_user_association_response_reported =
+            289 [(module) = "car"];
+        NetworkIpProvisioningReported network_ip_provisioning_reported =
+            290 [(module) = "network_stack"];
+        NetworkDhcpRenewReported network_dhcp_renew_reported = 291 [(module) = "network_stack"];
+        NetworkValidationReported network_validation_reported = 292 [(module) = "network_stack"];
+        NetworkStackQuirkReported network_stack_quirk_reported = 293 [(module) = "network_stack"];
+        MediametricsAudioRecordDeviceUsageReported mediametrics_audiorecorddeviceusage_reported =
+            294;
+        MediametricsAudioThreadDeviceUsageReported mediametrics_audiothreaddeviceusage_reported =
+            295;
+        MediametricsAudioTrackDeviceUsageReported mediametrics_audiotrackdeviceusage_reported =
+            296;
+        MediametricsAudioDeviceConnectionReported mediametrics_audiodeviceconnection_reported =
+            297;
+        BlobCommitted blob_committed = 298 [(module) = "framework"];
+        BlobLeased blob_leased = 299 [(module) = "framework"];
+        BlobOpened blob_opened = 300 [(module) = "framework"];
 
         // StatsdStats tracks platform atoms with ids upto 500.
         // Update StatsdStats::kMaxPushedAtomId when atom ids here approach that value.
@@ -547,10 +578,11 @@
         SimSlotState sim_slot_state = 10078 [(module) = "telephony"];
         SupportedRadioAccessFamily supported_radio_access_family = 10079 [(module) = "telephony"];
         SettingSnapshot setting_snapshot = 10080 [(module) = "framework"];
-        DisplayWakeReason display_wake_reason = 10081 [(module) = "framework"];
+        BlobInfo blob_info = 10081 [(module) = "framework"];
         DataUsageBytesTransfer data_usage_bytes_transfer = 10082 [(module) = "framework"];
         BytesTransferByTagAndMetered bytes_transfer_by_tag_and_metered =
                 10083 [(module) = "framework"];
+        DNDModeProto dnd_mode_rule = 10084 [(module) = "framework"];
     }
 
     // DO NOT USE field numbers above 100,000 in AOSP.
@@ -4876,6 +4908,94 @@
     optional int64 cow_file_size_bytes = 5;
 }
 
+/**
+ * Event representing when BlobStoreManager.Session#commit() is called
+ *
+ * Logged from:
+ *  frameworks/base/apex/blobstore/service/java/com/android/server/blob/BlobStoreManagerService.java
+ */
+message BlobCommitted {
+    // Uid of the Blob committer
+    optional int32 uid = 1 [(is_uid) = true];
+
+    // Id of the Blob committed
+    optional int64 blob_id = 2;
+
+    // Size of the Blob
+    optional int64 size = 3;
+
+    enum Result {
+        UNKNOWN = 0;
+        // Commit Succeeded
+        SUCCESS = 1;
+        // Commit Failed: Error occurred during commit
+        ERROR_DURING_COMMIT = 2;
+        // Commit Failed: Digest of the data did not match Blob digest
+        DIGEST_MISMATCH = 3;
+    }
+    optional Result result = 4;
+}
+
+/**
+ * Event representing when BlobStoreManager#acquireLease() is called
+ *
+ * Logged from:
+ *  frameworks/base/apex/blobstore/service/java/com/android/server/blob/BlobStoreManagerService.java
+ */
+message BlobLeased{
+    // Uid of the Blob leasee
+    optional int32 uid = 1 [(is_uid) = true];
+
+    // Id of the Blob leased or 0 if the Blob does not exist
+    optional int64 blob_id = 2;
+
+    // Size of the Blob or 0 if the Blob does not exist
+    optional int64 size = 3;
+
+    enum Result {
+        UNKNOWN = 0;
+        // Lease Succeeded
+        SUCCESS = 1;
+        // Lease Failed: Blob does not exist
+        BLOB_DNE = 2;
+        // Lease Failed: Leasee does not have access to the Blob
+        ACCESS_NOT_ALLOWED = 3;
+        // Lease Failed: Leasee requested an invalid expiry duration
+        LEASE_EXPIRY_INVALID = 4;
+        // Lease Failed: Leasee has exceeded the total data lease limit
+        DATA_SIZE_LIMIT_EXCEEDED = 5;
+    }
+    optional Result result = 4;
+}
+
+/**
+ * Event representing when BlobStoreManager#openBlob() is called
+ *
+ * Logged from:
+ *  frameworks/base/apex/blobstore/service/java/com/android/server/blob/BlobStoreManagerService.java
+ */
+message BlobOpened{
+    // Uid of the Blob opener
+    optional int32 uid = 1 [(is_uid) = true];
+
+    // Id of the Blob opened or 0 if the Blob does not exist
+    optional int64 blob_id = 2;
+
+    // Size of the Blob or 0 if the Blob does not exist
+    optional int64 size = 3;
+
+    enum Result {
+        UNKNOWN = 0;
+        // Open Succeeded
+        SUCCESS = 1;
+        // Open Failed: Blob does not exist
+        BLOB_DNE = 2;
+        // Open Failed: Opener does not have access to the Blob
+        ACCESS_NOT_ALLOWED = 3;
+    }
+    optional Result result = 4;
+}
+
 //////////////////////////////////////////////////////////////////////
 // Pulled atoms below this line //
 //////////////////////////////////////////////////////////////////////
@@ -6068,6 +6188,76 @@
 }
 
 /**
+ * Atom that represents an item in the list of Do Not Disturb rules, pulled from
+ * NotificationManagerService.java.
+ */
+message DNDModeProto {
+    enum Mode {
+        ROOT_CONFIG = -1;  // Used to distinguish the config (one per user) from the rules.
+        ZEN_MODE_OFF = 0;
+        ZEN_MODE_IMPORTANT_INTERRUPTIONS = 1;
+        ZEN_MODE_NO_INTERRUPTIONS = 2;
+        ZEN_MODE_ALARMS = 3;
+    }
+    optional int32 user = 1;  // Android user ID (0, 1, 10, ...)
+    optional bool enabled = 2;  // true for ROOT_CONFIG if a manualRule is enabled
+    optional bool channels_bypassing = 3; // only valid for ROOT_CONFIG
+    optional Mode zen_mode = 4;
+    // id is one of the system default rule IDs, or empty
+    // May also be "MANUAL_RULE" to indicate app-activation of the manual rule.
+    optional string id = 5;
+    optional int32 uid = 6 [(is_uid) = true]; // currently only SYSTEM_UID or 0 for other
+    optional DNDPolicyProto policy = 7;
+}
+
+/**
+ * Atom that represents a Do Not Disturb policy, an optional detail proto for DNDModeProto.
+ */
+message DNDPolicyProto {
+    enum State {
+        STATE_UNSET = 0;
+        STATE_ALLOW = 1;
+        STATE_DISALLOW = 2;
+    }
+    optional State calls = 1;
+    optional State repeat_callers = 2;
+    optional State messages = 3;
+    optional State conversations = 4;
+    optional State reminders = 5;
+    optional State events = 6;
+    optional State alarms = 7;
+    optional State media = 8;
+    optional State system = 9;
+    optional State fullscreen = 10;
+    optional State lights = 11;
+    optional State peek = 12;
+    optional State status_bar = 13;
+    optional State badge = 14;
+    optional State ambient = 15;
+    optional State notification_list = 16;
+
+    enum PeopleType {
+        PEOPLE_UNSET = 0;
+        PEOPLE_ANYONE = 1;
+        PEOPLE_CONTACTS = 2;
+        PEOPLE_STARRED = 3;
+        PEOPLE_NONE = 4;
+    }
+
+    optional PeopleType allow_calls_from = 17;
+    optional PeopleType allow_messages_from = 18;
+
+    enum ConversationType {
+        CONV_UNSET = 0;
+        CONV_ANYONE = 1;
+        CONV_IMPORTANT = 2;
+        CONV_NONE = 3;
+    }
+
+    optional ConversationType allow_conversations_from = 19;
+}
+
+/**
  * Atom that contains a list of a package's channel group preferences, pulled from
  * NotificationManagerService.java.
  */
@@ -6318,6 +6508,16 @@
         SET_WHITELIST = 3;
         SET_DISABLED = 4;
         ON_USER_DATA_REMOVED = 5;
+        ON_DATA_SHARE_REQUEST = 6;
+        ACCEPT_DATA_SHARE_REQUEST = 7;
+        REJECT_DATA_SHARE_REQUEST = 8;
+        DATA_SHARE_WRITE_FINISHED = 9;
+        DATA_SHARE_ERROR_IOEXCEPTION = 10;
+        DATA_SHARE_ERROR_EMPTY_DATA = 11;
+        DATA_SHARE_ERROR_CLIENT_PIPE_FAIL = 12;
+        DATA_SHARE_ERROR_SERVICE_PIPE_FAIL = 13;
+        DATA_SHARE_ERROR_CONCURRENT_REQUEST = 14;
+        DATA_SHARE_ERROR_TIMEOUT_INTERRUPTED = 15;
     }
     optional Event event = 1;
     // component/package of content capture service.
@@ -6726,6 +6926,172 @@
 }
 
 /**
+ * logs the CapportApiData info
+ * Logged from:
+ * packages/modules/NetworkStack/src/com/android/server/connectivity/NetworkMonitor.java
+ */
+message CapportApiData {
+    // The TTL of the network connection provided by captive portal
+    optional int32 remaining_ttl_secs = 1;
+
+    // The limit traffic data of the network connection provided by captive portal
+    optional int32 remaining_bytes = 2;
+
+    // Is portal url option included in the DHCP packet (Yes, No)
+    optional bool has_portal_url = 3;
+
+    // Is venue info (e.g. store info, maps, flight status) included (Yes, No)
+    optional bool has_venue_info = 4;
+}
+
+/**
+ * logs a network Probe Event
+ * Logged from:
+ * packages/modules/NetworkStack/src/com/android/server/connectivity/NetworkMonitor.java
+ */
+message ProbeEvent {
+    // The probe type (http or https, or captive portal API...)
+    optional android.stats.connectivity.ProbeType probe_type = 1;
+
+    // The latency in microseconds of the probe event
+    optional int32 latency_micros = 2;
+
+    // The result of the probe event
+    optional android.stats.connectivity.ProbeResult probe_result = 3;
+
+    // The CaptivePortal API info
+    optional CapportApiData capport_api_data = 4;
+}
+
+/**
+ * log each ProbeEvent in ProbeEvents
+ * Logged from:
+ * packages/modules/NetworkStack/src/com/android/server/connectivity/NetworkMonitor.java
+ */
+message ProbeEvents {
+    // Record probe event during the validation
+    repeated ProbeEvent probe_event = 1;
+}
+
+/**
+ * The DHCP (Dynamic Host Configuration Protocol) session info
+ * Logged from:
+ * packages/modules/NetworkStack/src/android/net/dhcp/DhcpClient.java
+ */
+message DhcpSession {
+    // The DHCP Feature(s) enabled in this session
+    repeated android.stats.connectivity.DhcpFeature used_features = 1;
+
+    // The discover packet (re)transmit count
+    optional int32 discover_count = 2;
+
+    // The request packet (re)transmit count
+    optional int32 request_count = 3;
+
+    // The IPv4 address conflict count
+    // (only be meaningful when duplicate address detection is enabled)
+    optional int32 conflict_count = 4;
+
+    // The DHCP packet parsing error code in this session
+    // (defined in android.net.metrics.DhcpErrorEvent)
+    repeated android.stats.connectivity.DhcpErrorCode error_code = 5;
+
+    // The result of DHCP hostname transliteration
+    optional android.stats.connectivity.HostnameTransResult ht_result = 6;
+}
+
+/**
+ * Logs Network IP provisioning event
+ * Logged from:
+ * packages/modules/NetworkStack/src/com/android/networkstack/metrics/NetworkIpProvisioningMetrics.java
+ */
+message NetworkIpProvisioningReported {
+    // Transport type (WIFI, CELLULAR, BLUETOOTH, ..)
+    optional android.stats.connectivity.TransportType transport_type = 1;
+
+    // The latency in microseconds of IP Provisioning over IPV4
+    optional int32 ipv4_latency_micros = 2;
+
+    // The latency in microseconds of IP Provisioning over IPV6
+    optional int32 ipv6_latency_micros = 3;
+
+    // The time duration between provisioning start and end (success or failure)
+    optional int64 provisioning_duration_micros = 4;
+
+    // The specific disconnect reason for this IP provisioning
+    optional android.stats.connectivity.DisconnectCode disconnect_code = 5;
+
+    // Log DHCP session info (Only valid for IPv4)
+    optional DhcpSession dhcp_session = 6 [(log_mode) = MODE_BYTES];
+
+    // The random number between 0 ~ 999 for sampling
+    optional int32 random_number = 7;
+}
+
+/**
+ * Logs Network DHCP Renew event
+ * Logged from:
+ * packages/modules/NetworkStack/src/android/net/dhcp/DhcpClient.java
+ */
+message NetworkDhcpRenewReported {
+    // Transport type (WIFI, CELLULAR, BLUETOOTH, ..)
+    optional android.stats.connectivity.TransportType transport_type = 1;
+
+    // The request packet (re)transmit count
+    optional int32 request_count = 2;
+
+    // The latency in microseconds of DHCP Renew
+    optional int32 latency_micros = 3;
+
+    // The DHCP error code is defined in android.net.metrics.DhcpErrorEvent
+    optional android.stats.connectivity.DhcpErrorCode error_code = 4;
+
+    // The result of DHCP renew
+    optional android.stats.connectivity.DhcpRenewResult renew_result = 5;
+
+    // The random number between 0 ~ 999 for sampling
+    optional int32 random_number = 6;
+}
+
+/**
+ * Logs Network Validation event
+ * Logged from:
+ * packages/modules/NetworkStack/src/com/android/server/connectivity/NetworkMonitor.java
+ */
+message NetworkValidationReported {
+    // Transport type (WIFI, CELLULAR, BLUETOOTH, ..)
+    optional android.stats.connectivity.TransportType transport_type = 1;
+
+    // Record each probe event
+    optional ProbeEvents probe_events = 2 [(log_mode) = MODE_BYTES];
+
+    // The result of the network validation
+    optional android.stats.connectivity.ValidationResult validation_result = 3;
+
+    // The latency in microseconds of network validation
+    optional int32 latency_micros = 4;
+
+    // The validation index (the first validation attempt or second, third...)
+    optional int32 validation_index = 5;
+
+    // The random number between 0 ~ 999 for sampling
+    optional int32 random_number = 6;
+}
+
+/**
+ * Logs NetworkStack Quirk event
+ * Logged from:
+ * packages/modules/NetworkStack/src/com/android/networkstack/
+ */
+message NetworkStackQuirkReported {
+    // Transport type (WIFI, CELLULAR, BLUETOOTH, ..)
+    optional android.stats.connectivity.TransportType transport_type = 1;
+
+    // Record each Quirk event
+    optional android.stats.connectivity.NetworkQuirkEvent event = 2;
+}
+
+/**
  * Logs when a data stall event occurs.
  *
  * Log from:
@@ -8001,6 +8367,245 @@
 }
 
 /**
+ * Logs when Car User Hal is requested to switch/create/remove user.
+ *
+ * Logged from:
+ *   packages/services/Car/service/src/com/android/car/hal/UserHalService.java
+ */
+message CarUserHalModifyUserRequestReported {
+    // Request id for the request.
+    optional int32 request_id = 1;
+    // Request type.
+    enum RequestType {
+        UNKNOWN = 0;
+        // Car user manager requested user switch.
+        SWITCH_REQUEST_ANDROID = 1;
+        // OEM requested User switch.
+        SWITCH_REQUEST_OEM = 2;
+        // Hal switch requested after android switch using activity manager.
+        SWITCH_REQUEST_LEGACY = 3;
+        // Create User
+        CREATE_REQUEST = 4;
+        // Remove User
+        REMOVE_REQUEST = 5;
+    }
+    optional RequestType request_type = 2;
+    // Android User id of the current user which can only be 0, 10, 11 and so on.
+    // -1 if not available.
+    optional int32 user_id = 3;
+    // VHAL flags of the current user. (-1 if not available)
+    optional int32 user_flags = 4;
+    // Android User id of the target user for switch/create/remove. It can only
+    // be 0, 10, 11 and so on. -1 if not available.
+    optional int32 target_user_id = 5;
+    // VHAL flags of the target user for switch/create/remove. (-1 if not available)
+    optional int32 target_user_flags = 6;
+    // Request timeout Milliseconds (-1 if not available)
+    optional int32 timeout_millis = 7;
+}
+
+/**
+ * Logs when Car User Hal responds to switch/create user request.
+ *
+ * Logged from:
+ *   packages/services/Car/service/src/com/android/car/hal/UserHalService.java
+ */
+message CarUserHalModifyUserResponseReported {
+    // Request id of the request associated with the response.
+    optional int32 request_id = 1;
+    // Car user hal callback status.
+    enum CallbackStatus {
+        UNKNOWN = 0;
+        // Hal response was invalid.
+        INVALID = 1;
+        // Hal response was ok.
+        OK = 2;
+        // Hal timeout during set call.
+        HAL_SET_TIMEOUT = 3;
+        // Hal response timeout.
+        HAL_RESPONSE_TIMEOUT = 4;
+        // Hal responded with wrong info.
+        WRONG_HAL_RESPONSE = 5;
+        // Hal is processing multiple requests simultaneously.
+        CONCURRENT_OPERATION = 6;
+    }
+    optional CallbackStatus callback_status = 2;
+
+    // Hal request status for user switch/create/remove.
+    enum HalRequestStatus {
+        UNSPECIFIED = 0;
+        // Hal request for user switch/create is successful.
+        SUCCESS = 1;
+        // Hal request for user switch/create failed.
+        FAILURE = 2;
+    }
+    optional HalRequestStatus request_status = 3;
+}
+
+/**
+ * Logs when post switch response is posted to Car User Hal.
+ *
+ * Logged from:
+ *   packages/services/Car/service/src/com/android/car/hal/UserHalService.java
+ */
+message CarUserHalPostSwitchResponseReported {
+    // Request id.
+    optional int32 request_id = 1;
+
+    // Android user switch status.
+    enum UserSwitchStatus {
+        UNKNOWN = 0;
+        // Android user switch is successful.
+        SUCCESS = 1;
+        // Android user switch failed.
+        FAILURE = 2;
+    }
+    optional UserSwitchStatus switch_status = 2;
+}
+
+/**
+ * Logs when initial user information is requested from Car User Hal.
+ *
+ * Logged from:
+ *   packages/services/Car/service/src/com/android/car/hal/UserHalService.java
+ */
+message CarUserHalInitialUserInfoRequestReported {
+    // Request id for the request.
+    optional int32 request_id = 1;
+
+    // Request type for initial user information.
+    enum InitialUserInfoRequestType {
+        UNKNOWN = 0;
+        // At the first time Android was booted (or after a factory reset).
+        FIRST_BOOT = 1;
+        // At the first time Android was booted after the system was updated.
+        FIRST_BOOT_AFTER_OTA = 2;
+        // When Android was booted "from scratch".
+        COLD_BOOT = 3;
+        // When Android was resumed after the system was suspended to memory.
+        RESUME = 4;
+    }
+    optional InitialUserInfoRequestType request_type = 2;
+    // Request timeout Milliseconds (-1 if not available)
+    optional int32 timeout_millis = 3;
+}
+
+/**
+ * Logs when Car User Hal responds to initial user information requests.
+ *
+ * Logged from:
+ *   packages/services/Car/service/src/com/android/car/hal/UserHalService.java
+ */
+message CarUserHalInitialUserInfoResponseReported {
+    // Request id of the request associated with the response.
+    optional int32 request_id = 1;
+    // Car user hal callback status.
+    enum CallbackStatus {
+        UNKNOWN = 0;
+        // Hal response was invalid.
+        INVALID = 1;
+        // Hal response was ok.
+        OK = 2;
+        // Hal timeout during set call.
+        HAL_SET_TIMEOUT = 3;
+        // Hal response timeout.
+        HAL_RESPONSE_TIMEOUT = 4;
+        // Hal responded with wrong info.
+        WRONG_HAL_RESPONSE = 5;
+        // Hal is processing multiple requests simultaneously.
+        CONCURRENT_OPERATION = 6;
+    }
+    optional CallbackStatus callback_status = 2;
+    // Response for initial user information request.
+    enum InitialUserInfoResponseAction {
+        UNSPECIFIED = 0;
+        // Let the Android System decide what to do.
+        DEFAULT = 1;
+        // Switch to an existing Android user.
+        SWITCH = 2;
+        // Create a new Android user (and switch to it).
+        CREATE = 3;
+    }
+    optional InitialUserInfoResponseAction response_action = 3;
+    // Android User id of the target user which can only be 0, 10, 11 and so on.
+    // -1 if not available.
+    optional int32 target_user = 4;
+    // VHAL flags of the current user. (-1 if not available)
+    optional int32 target_user_flags = 5;
+    // User locales
+    optional string user_locales = 6;
+}
+
+/**
+ * Logs when set user association is requested from Car User Hal.
+ *
+ * Logged from:
+ *   packages/services/Car/service/src/com/android/car/hal/UserHalService.java
+ */
+message CarUserHalUserAssociationRequestReported {
+    // Request id for the request.
+    optional int32 request_id = 1;
+    // Request type.
+    enum RequestType {
+        UNKNOWN = 0;
+        // For setting user association information.
+        SET = 1;
+        // For getting user association information.
+        GET = 2;
+    }
+    optional RequestType request_type = 2;
+    // Android User id of the current user which can only be 0, 10, 11 and so on.
+    // -1 if not available.
+    optional int32 current_user_id = 3;
+    // VHAL flags of the current user. (-1 if not available)
+    optional int32 current_user_flags = 4;
+    // Number of the set associations requested.
+    optional int32 number_associations = 5;
+    // Concatenated string for the types from set associations request.
+    // This is a string converted from an array of integers.
+    optional string user_identification_association_types = 6;
+    // Concatenated string for the values from set associations request.
+    // This is a string converted from an array of integers.
+    optional string user_identification_association_values = 7;
+}
+
+/**
+ * Logs when Car User Hal responds to set user association requests.
+ *
+ * Logged from:
+ *   packages/services/Car/service/src/com/android/car/hal/UserHalService.java
+ */
+message CarUserHalSetUserAssociationResponseReported {
+    // Request id of the request associated with the response.
+    optional int32 request_id = 1;
+    // Car user hal callback status.
+    enum CallbackStatus {
+        UNKNOWN = 0;
+        // Hal response was invalid.
+        INVALID = 1;
+        // Hal response was ok.
+        OK = 2;
+        // Hal timeout during set call.
+        HAL_SET_TIMEOUT = 3;
+        // Hal response timeout.
+        HAL_RESPONSE_TIMEOUT = 4;
+        // Hal responded with wrong info.
+        WRONG_HAL_RESPONSE = 5;
+        // Hal is processing multiple requests simultaneously.
+        CONCURRENT_OPERATION = 6;
+    }
+    optional CallbackStatus callback_status = 2;
+    // Number of the set associations in the response.
+    optional int32 number_associations = 3;
+    // Concatenated string for the types from set associations request.
+    // This is a string converted from an array of integers.
+    optional string user_identification_association_types = 4;
+    // Concatenated string for the values from set associations request.
+    // This is a string converted from an array of integers.
+    optional string user_identification_association_values = 5;
+}
+
+/**
  * Logs whether GarageMode is entered.
  *
  * Logged from:
@@ -9494,7 +10099,7 @@
     optional int64 time_to_first_fix_reports = 3;
 
     // Total pulled reported time to first fix (in milli-seconds) since boot
-    optional int64 time_to_first_fix_milli_s = 4;
+    optional int64 time_to_first_fix_millis = 4;
 
     // Number of position accuracy reports since boot
     optional int64 position_accuracy_reports = 5;
@@ -9817,15 +10422,20 @@
     optional android.stats.accessibility.ServiceStatus service_status = 2;
 }
 
-message DisplayWakeReason {
+/**
+ * Logs when display wake up.
+ *
+ * Logged from:
+ *   services/core/java/com/android/server/power/Notifier.java
+ */
+
+message DisplayWakeReported {
     // Wake_up_reason code
     // If LOWORD(wake_up_reason) = 0
     //     reference to HIWORD(wake_up_reason) PowerManager.WAKE_REASON_XXX
     //     else reference wake_up_reason to
-    //     frameworks/base/services/core/java/com/android/server/power/Notifier.java#DispWakeupReason
+    //     services/core/java/com/android/server/power/Notifier.java#onWakeUp
     optional int32 wake_up_reason = 1;
-    // Count of wake up by reason
-    optional int32 wake_times = 2;
 }
 
 /**
@@ -10038,3 +10648,306 @@
     // Whether the Assistant handles were showing at the time of invocation.
     optional bool assistant_handles_showing = 6;
 }
+
+/**
+ * Logs when an AudioRecord finishes running on an audio device
+ *
+ * Logged from:
+ *   frameworks/av/services/mediametrics/AudioAnalytics.cpp
+ */
+message MediametricsAudioRecordDeviceUsageReported {
+    // The devices connected to this AudioRecord.
+    // A string OR of various input device categories, e.g. "DEVICE1|DEVICE2".
+    // See lookup<INPUT_DEVICE>() in frameworks/av/services/mediametrics/AudioTypes.cpp
+    // See audio_device_t in system/media/audio/include/system/audio-base.h
+    optional string devices = 1;
+
+    // The name of the remote device attached to the device, typically available for USB or BT.
+    // This may be empty for a fixed device, or separated by "|" if more than one.
+    optional string device_names = 2;
+
+    // The amount of time spent in the device as measured by the active track in AudioFlinger.
+    optional int64 device_time_nanos = 3;
+
+    // The audio data format used for encoding.
+    // An enumeration from system/media/audio/include/system/audio-base.h audio_format_t
+    optional string encoding = 4;
+
+    // The client-server buffer framecount.
+    // The framecount is generally between 960 - 48000 for PCM encoding.
+    // The framecount represents raw buffer size in bytes for non-PCM encoding.
+    optional int32 frame_count = 5;
+
+    // The number of audio intervals (contiguous, continuous playbacks).
+    optional int32 interval_count = 6;
+
+    // The sample rate of the AudioRecord.
+    // A number generally between 8000-96000 (frames per second).
+    optional int32 sample_rate = 7;
+
+    // The audio input flags used to construct the AudioRecord.
+    // A string OR from system/media/audio/include/system/audio-base.h audio_input_flags_t
+    optional string flags = 8;
+
+    // The santized package name of the audio client associated with the AudioRecord.
+    // See getSanitizedPackageNameAndVersionCode() in
+    // frameworks/av/services/mediametrics/MediaMetricsService.cpp
+    optional string package_name = 9;
+
+    // The selected device id (nonzero if a non-default device is selected)
+    optional int32 selected_device_id = 10;
+
+    // The caller of the AudioRecord.
+    // See lookup<CALLER_NAME>() in frameworks/av/services/mediametrics/AudioTypes.cpp
+    optional string caller = 11;
+
+    // The audio source for AudioRecord.
+    // An enumeration from system/media/audio/include/system/audio-base.h audio_source_t
+    optional string source = 12;
+}
+
+/**
+ * Logs when an AudioThread finishes running on an audio device
+ *
+ * Logged from:
+ *   frameworks/av/services/mediametrics/AudioAnalytics.cpp
+ */
+message MediametricsAudioThreadDeviceUsageReported {
+    // The devices connected to this audio thread.
+    // A string OR of various input device categories, e.g. "DEVICE1|DEVICE2".
+    // (for record threads):
+    // See lookup<INPUT_DEVICE> in frameworks/av/services/mediametrics/AudioTypes.cpp
+    // (for playback threads):
+    // See lookup<OUTPUT_DEVICE>() in frameworks/av/services/mediametrics/AudioTypes.cpp
+    // See audio_device_t in system/media/audio/include/system/audio-base.h
+    optional string devices = 1;
+
+    // The name of the remote device attached to the device, typically available for USB or BT.
+    // This may be empty for a fixed device, or separated by "|" if more than one.
+    optional string device_names = 2;
+
+    // The amount of time spent in the device as measured by the active track in AudioFlinger.
+    optional int64 device_time_nanos = 3;
+
+    // The audio data format used for encoding.
+    // An enumeration from system/media/audio/include/system/audio-base.h audio_format_t
+    optional string encoding = 4;
+
+    // The framecount of the buffer delivered to (or from) the HAL.
+    // The framecount is generally ~960 for PCM encoding.
+    // The framecount represents raw buffer size in bytes for non-PCM encoding.
+    optional int32 frame_count = 5;
+
+    // The number of audio intervals (contiguous, continuous playbacks).
+    optional int32 interval_count = 6;
+
+    // The sample rate of the audio thread.
+    // A number generally between 8000-96000 (frames per second).
+    optional int32 sample_rate = 7;
+
+    // The audio flags used to construct the thread
+    // (for record threads):
+    // A string OR from system/media/audio/include/system/audio-base.h audio_input_flags_t
+    // (for playback threads):
+    // A string OR from system/media/audio/include/system/audio-base.h audio_output_flags_t
+    optional string flags = 8;
+
+    // The number of underruns encountered for a playback thread or the
+    // number of overruns encountered for a capture thread.
+    optional int32 xruns = 9;
+
+    // The type of thread
+    // A thread type enumeration from
+    // frameworks/av/mediametrics/services/Translate.h
+    optional string type = 10;
+}
+
+/**
+ * Logs when an AudioTrack finishes running on an audio device
+ *
+ * Logged from:
+ *   frameworks/av/services/mediametrics/AudioAnalytics.cpp
+ */
+message MediametricsAudioTrackDeviceUsageReported {
+    // The output devices connected to this AudioTrack.
+    // A string OR of various output device categories, e.g. "DEVICE1|DEVICE2".
+    // See lookup<OUTPUT_DEVICE>() in frameworks/av/services/mediametrics/AudioTypes.cpp
+    // See audio_device_t in system/media/audio/include/system/audio-base.h
+    optional string devices = 1;
+
+    // The name of the remote device attached to the device, typically available for USB or BT.
+    // This may be empty for a fixed device, or separated by "|" if more than one.
+    optional string device_names = 2;
+
+    // The amount of time spent in the device as measured by the active track in AudioFlinger.
+    optional int64 device_time_nanos = 3;
+
+    // The audio data format used for encoding.
+    // An enumeration from system/media/audio/include/system/audio-base.h audio_format_t
+    optional string encoding = 4;
+
+    // The client-server buffer framecount.
+    // The framecount is generally between 960 - 48000 for PCM encoding.
+    // The framecount represents raw buffer size in bytes for non-PCM encoding.
+    // A static track (see traits) may have a very large framecount.
+    optional int32 frame_count = 5;
+
+    // The number of audio intervals (contiguous, continuous playbacks).
+    optional int32 interval_count = 6;
+
+    // The sample rate of the AudioTrack.
+    // A number generally between 8000-96000 (frames per second).
+    optional int32 sample_rate = 7;
+
+    // The audio flags used to construct the AudioTrack.
+    // A string OR from system/media/audio/include/system/audio-base.h audio_output_flags_t
+    optional string flags = 8;
+
+    // The number of underruns encountered.
+    optional int32 xruns = 9;
+
+    // The santized package name of the audio client associated with the AudioTrack.
+    // See getSanitizedPackageNameAndVersionCode() in
+    // frameworks/av/services/mediametrics/MediaMetricsService.cpp
+    optional string package_name = 10;
+
+    // The latency of the last sample in the buffer in milliseconds.
+    optional float device_latency_millis = 11;
+
+    // The startup time in milliseconds from start() to sample played.
+    optional float device_startup_millis = 12;
+
+    // The average volume of the track on the device [ 0.f - 1.f ]
+    optional float device_volume = 13;
+
+    // The selected device id (nonzero if a non-default device is selected)
+    optional int32 selected_device_id = 14;
+
+    // The stream_type category for the AudioTrack.
+    // An enumeration from system/media/audio/include/system/audio-base.h audio_stream_type_t
+    optional string stream_type = 15;
+
+    // The usage for the AudioTrack.
+    // An enumeration from system/media/audio/include/system/audio-base.h audio_usage_t
+    optional string usage = 16;
+
+    // The content type of the AudioTrack.
+    // An enumeration from system/media/audio/include/system/audio-base.h audio_content_type_t
+    optional string content_type = 17;
+
+    // The caller of the AudioTrack.
+    // See lookup<CALLER_NAME>() in frameworks/av/services/mediametrics/AudioTypes.cpp
+    optional string caller = 18;
+
+    // The traits of the AudioTrack.
+    // A string OR of different traits, may be empty string.
+    // Only "static" is supported for R.
+    // See lookup<TRACK_TRAITS>() in frameworks/av/services/mediametrics/AudioTypes.cpp
+    optional string traits = 19;
+}
+
+/**
+ * Logs the status of an audio device connection attempt.
+ *
+ * Logged from:
+ *   frameworks/av/services/mediametrics/AudioAnalytics.cpp
+ */
+message MediametricsAudioDeviceConnectionReported {
+    // The input devices represented by this report.
+    // A string OR of various input device categories, e.g. "DEVICE1|DEVICE2".
+    // See lookup<INPUT_DEVICE>() in frameworks/av/services/mediametrics/AudioTypes.cpp
+    // See audio_device_t in system/media/audio/include/system/audio-base.h
+    optional string input_devices = 1;
+
+    // The output devices represented by this report.
+    // A string OR of various output device categories.
+    // See lookup<OUTPUT_DEVICE>() in frameworks/av/services/mediametrics/AudioTypes.cpp
+    // See audio_device_t in system/media/audio/include/system/audio-base.h
+    optional string output_devices = 2;
+
+    // The name of the remote device attached to the device, typically available for USB or BT.
+    // This may be empty for a fixed device, or separated by "|" if more than one.
+    optional string device_names = 3;
+
+    // The result of the audio device connection.
+    // 0 indicates success: connection verified.
+    // 1 indicates unknown: connection not verified or not known if diverted properly.
+    // Other values indicate specific status.
+    // See DeviceConnectionResult in frameworks/av/services/mediametrics/AudioTypes.h
+    optional int32 result = 4;
+
+    // Average milliseconds of time to connect
+    optional float time_to_connect_millis = 5;
+
+    // Number of connections if aggregated statistics, otherwise 1.
+    optional int32 connection_count = 6;
+}
+
+// Blob Committer stats
+// Keep in sync between:
+//     frameworks/base/core/proto/android/server/blobstoremanagerservice.proto
+//     frameworks/base/cmds/statsd/src/atoms.proto
+message BlobCommitterProto {
+    // Committer app's uid
+    optional int32 uid = 1 [(is_uid) = true];
+
+    // Unix epoch timestamp of the commit in milliseconds
+    optional int64 commit_timestamp_millis = 2;
+
+    // Flags of what access types the committer has set for the Blob
+    optional int32 access_mode = 3;
+
+    // Number of packages that have been whitelisted for ACCESS_TYPE_WHITELIST
+    optional int32 num_whitelisted_package = 4;
+}
+
+// Blob Leasee stats
+// Keep in sync between:
+//     frameworks/base/core/proto/android/server/blobstoremanagerservice.proto
+//     frameworks/base/cmds/statsd/src/atoms.proto
+message BlobLeaseeProto {
+    // Leasee app's uid
+    optional int32 uid = 1 [(is_uid) = true];
+
+    // Unix epoch timestamp for lease expiration in milliseconds
+    optional int64 lease_expiry_timestamp_millis = 2;
+}
+
+// List of Blob Committers
+// Keep in sync between:
+//     frameworks/base/core/proto/android/server/blobstoremanagerservice.proto
+//     frameworks/base/cmds/statsd/src/atoms.proto
+message BlobCommitterListProto {
+    repeated BlobCommitterProto committer = 1;
+}
+
+// List of Blob Leasees
+// Keep in sync between:
+//     frameworks/base/core/proto/android/server/blobstoremanagerservice.proto
+//     frameworks/base/cmds/statsd/src/atoms.proto
+message BlobLeaseeListProto {
+    repeated BlobLeaseeProto leasee = 1;
+}
+
+/**
+ * Logs the current state of a Blob committed with BlobStoreManager
+ *
+ * Pulled from:
+ *  frameworks/base/apex/blobstore/service/java/com/android/server/blob/BlobStoreManagerService.java
+ */
+message BlobInfo {
+    // Id of the Blob
+    optional int64 blob_id = 1;
+
+    // Size of the Blob data
+    optional int64 size = 2;
+
+    // Unix epoch timestamp of the Blob's expiration in milliseconds
+    optional int64 expiry_timestamp_millis = 3;
+
+    // List of committers of this Blob
+    optional BlobCommitterListProto committers = 4;
+
+    // List of leasees of this Blob
+    optional BlobLeaseeListProto leasees = 5;
+}
diff --git a/cmds/statsd/src/guardrail/StatsdStats.h b/cmds/statsd/src/guardrail/StatsdStats.h
index 8587e145..9d46dcea 100644
--- a/cmds/statsd/src/guardrail/StatsdStats.h
+++ b/cmds/statsd/src/guardrail/StatsdStats.h
@@ -101,7 +101,7 @@
     // Per atom dimension key size limit
     static const std::map<int, std::pair<size_t, size_t>> kAtomDimensionKeySizeLimitMap;
 
-    const static int kMaxConfigCountPerUid = 10;
+    const static int kMaxConfigCountPerUid = 20;
     const static int kMaxAlertCountPerConfig = 100;
     const static int kMaxConditionCountPerConfig = 300;
     const static int kMaxMetricCountPerConfig = 1000;
@@ -660,6 +660,8 @@
     FRIEND_TEST(StatsdStatsTest, TestAtomMetricsStats);
     FRIEND_TEST(StatsdStatsTest, TestActivationBroadcastGuardrailHit);
     FRIEND_TEST(StatsdStatsTest, TestAtomErrorStats);
+
+    FRIEND_TEST(StatsLogProcessorTest, InvalidConfigRemoved);
 };
 
 }  // namespace statsd
diff --git a/cmds/statsd/src/metrics/MetricsManager.cpp b/cmds/statsd/src/metrics/MetricsManager.cpp
index e8c575a..7e825ef 100644
--- a/cmds/statsd/src/metrics/MetricsManager.cpp
+++ b/cmds/statsd/src/metrics/MetricsManager.cpp
@@ -361,8 +361,12 @@
         protoOutput->end(token);
     }
 
-    mLastReportTimeNs = dumpTimeStampNs;
-    mLastReportWallClockNs = getWallClockNs();
+    // Do not update the timestamps when data is not cleared to avoid timestamps from being
+    // misaligned.
+    if (erase_data) {
+        mLastReportTimeNs = dumpTimeStampNs;
+        mLastReportWallClockNs = getWallClockNs();
+    }
     VLOG("=========================Metric Reports End==========================");
 }
 
diff --git a/cmds/statsd/src/metrics/ValueMetricProducer.cpp b/cmds/statsd/src/metrics/ValueMetricProducer.cpp
index 8203f38..5987a72 100644
--- a/cmds/statsd/src/metrics/ValueMetricProducer.cpp
+++ b/cmds/statsd/src/metrics/ValueMetricProducer.cpp
@@ -951,6 +951,7 @@
                                                    const int64_t& nextBucketStartTimeNs) {
     if (mCondition == ConditionState::kUnknown) {
         StatsdStats::getInstance().noteBucketUnknownCondition(mMetricId);
+        invalidateCurrentBucketWithoutResetBase(eventTimeNs, BucketDropReason::CONDITION_UNKNOWN);
     }
 
     VLOG("finalizing bucket for %ld, dumping %d slices", (long)mCurrentBucketStartTimeNs,
@@ -959,7 +960,10 @@
     int64_t fullBucketEndTimeNs = getCurrentBucketEndTimeNs();
     int64_t bucketEndTime = fullBucketEndTimeNs;
     int64_t numBucketsForward = calcBucketsForwardCount(eventTimeNs);
-    if (numBucketsForward > 1) {
+
+    // Skip buckets if this is a pulled metric or a pushed metric that is diffed.
+    if (numBucketsForward > 1 && (mIsPulled || mUseDiff)) {
+
         VLOG("Skipping forward %lld buckets", (long long)numBucketsForward);
         StatsdStats::getInstance().noteSkippedForwardBuckets(mMetricId);
         // Something went wrong. Maybe the device was sleeping for a long time. It is better
diff --git a/cmds/statsd/src/statsd_config.proto b/cmds/statsd/src/statsd_config.proto
index 72decf2..acdffd3 100644
--- a/cmds/statsd/src/statsd_config.proto
+++ b/cmds/statsd/src/statsd_config.proto
@@ -198,6 +198,9 @@
   optional int64 condition = 3;
 
   repeated MetricConditionLink links = 4;
+
+  reserved 100;
+  reserved 101;
 }
 
 message CountMetric {
@@ -218,6 +221,9 @@
   repeated MetricStateLink state_link = 9;
 
   optional FieldMatcher dimensions_in_condition = 7 [deprecated = true];
+
+  reserved 100;
+  reserved 101;
 }
 
 message DurationMetric {
@@ -245,6 +251,9 @@
   optional TimeUnit bucket = 7;
 
   optional FieldMatcher dimensions_in_condition = 8 [deprecated = true];
+
+  reserved 100;
+  reserved 101;
 }
 
 message GaugeMetric {
@@ -281,6 +290,9 @@
   optional int32 max_pull_delay_sec = 13 [default = 30];
 
   optional bool split_bucket_for_app_upgrade = 14 [default = true];
+
+  reserved 100;
+  reserved 101;
 }
 
 message ValueMetric {
@@ -333,6 +345,9 @@
   optional bool split_bucket_for_app_upgrade = 17 [default = true];
 
   optional FieldMatcher dimensions_in_condition = 9 [deprecated = true];
+
+  reserved 100;
+  reserved 101;
 }
 
 message Alert {
diff --git a/cmds/statsd/tests/StatsLogProcessor_test.cpp b/cmds/statsd/tests/StatsLogProcessor_test.cpp
index 076f327..1e6680c 100644
--- a/cmds/statsd/tests/StatsLogProcessor_test.cpp
+++ b/cmds/statsd/tests/StatsLogProcessor_test.cpp
@@ -13,6 +13,11 @@
 // limitations under the License.
 
 #include "StatsLogProcessor.h"
+
+#include <gmock/gmock.h>
+#include <gtest/gtest.h>
+#include <stdio.h>
+
 #include "StatsService.h"
 #include "config/ConfigKey.h"
 #include "frameworks/base/cmds/statsd/src/stats_log.pb.h"
@@ -20,16 +25,10 @@
 #include "guardrail/StatsdStats.h"
 #include "logd/LogEvent.h"
 #include "packages/UidMap.h"
-#include "storage/StorageManager.h"
 #include "statslog_statsdtest.h"
-
-#include <gmock/gmock.h>
-#include <gtest/gtest.h>
-
+#include "storage/StorageManager.h"
 #include "tests/statsd_test_util.h"
 
-#include <stdio.h>
-
 using namespace android;
 using namespace testing;
 using ::ndk::SharedRefBase;
@@ -324,6 +323,41 @@
     EXPECT_EQ(pullerManager->mPullUidProviders.find(key), pullerManager->mPullUidProviders.end());
 }
 
+TEST(StatsLogProcessorTest, InvalidConfigRemoved) {
+    // Setup simple config key corresponding to empty config.
+    StatsdStats::getInstance().reset();
+    sp<UidMap> m = new UidMap();
+    sp<StatsPullerManager> pullerManager = new StatsPullerManager();
+    m->updateMap(1, {1, 2}, {1, 2}, {String16("v1"), String16("v2")},
+                 {String16("p1"), String16("p2")}, {String16(""), String16("")});
+    sp<AlarmMonitor> anomalyAlarmMonitor;
+    sp<AlarmMonitor> subscriberAlarmMonitor;
+    StatsLogProcessor p(m, pullerManager, anomalyAlarmMonitor, subscriberAlarmMonitor, 0,
+                        [](const ConfigKey& key) { return true; },
+                        [](const int&, const vector<int64_t>&) {return true;});
+    ConfigKey key(3, 4);
+    StatsdConfig config = MakeConfig(true);
+    p.OnConfigUpdated(0, key, config);
+    EXPECT_EQ(1, p.mMetricsManagers.size());
+    EXPECT_NE(p.mMetricsManagers.find(key), p.mMetricsManagers.end());
+    // Cannot assert the size of mConfigStats since it is static and does not get cleared on reset.
+    EXPECT_NE(StatsdStats::getInstance().mConfigStats.end(),
+              StatsdStats::getInstance().mConfigStats.find(key));
+    EXPECT_EQ(0, StatsdStats::getInstance().mIceBox.size());
+
+    StatsdConfig invalidConfig = MakeConfig(true);
+    invalidConfig.clear_allowed_log_source();
+    p.OnConfigUpdated(0, key, invalidConfig);
+    EXPECT_EQ(0, p.mMetricsManagers.size());
+    // The current configs should not contain the invalid config.
+    EXPECT_EQ(StatsdStats::getInstance().mConfigStats.end(),
+              StatsdStats::getInstance().mConfigStats.find(key));
+    // Both "config" and "invalidConfig" should be in the icebox.
+    EXPECT_EQ(2, StatsdStats::getInstance().mIceBox.size());
+
+}
+
+
 TEST(StatsLogProcessorTest, TestActiveConfigMetricDiskWriteRead) {
     int uid = 1111;
 
@@ -1796,6 +1830,53 @@
     EXPECT_EQ(field2, actualFieldValues->at(5).mValue.int_value);
 }
 
+TEST(StatsLogProcessorTest, TestDumpReportWithoutErasingDataDoesNotUpdateTimestamp) {
+    int hostUid = 20;
+    int isolatedUid = 30;
+    sp<MockUidMap> mockUidMap = makeMockUidMapForOneHost(hostUid, {isolatedUid});
+    ConfigKey key(3, 4);
+
+    // TODO: All tests should not persist state on disk. This removes any reports that were present.
+    ProtoOutputStream proto;
+    StorageManager::appendConfigMetricsReport(key, &proto, /*erase data=*/true, /*isAdb=*/false);
+
+    StatsdConfig config = MakeConfig(false);
+    sp<StatsLogProcessor> processor =
+            CreateStatsLogProcessor(1, 1, config, key, nullptr, 0, mockUidMap);
+    vector<uint8_t> bytes;
+
+    int64_t dumpTime1Ns = 1 * NS_PER_SEC;
+    processor->onDumpReport(key, dumpTime1Ns, false /* include_current_bucket */,
+            true /* erase_data */, ADB_DUMP, FAST, &bytes);
+
+    ConfigMetricsReportList output;
+    output.ParseFromArray(bytes.data(), bytes.size());
+    EXPECT_EQ(output.reports_size(), 1);
+    EXPECT_EQ(output.reports(0).current_report_elapsed_nanos(), dumpTime1Ns);
+
+    int64_t dumpTime2Ns = 5 * NS_PER_SEC;
+    processor->onDumpReport(key, dumpTime2Ns, false /* include_current_bucket */,
+            false /* erase_data */, ADB_DUMP, FAST, &bytes);
+
+    // Check that the dump report without clearing data is successful.
+    output.ParseFromArray(bytes.data(), bytes.size());
+    EXPECT_EQ(output.reports_size(), 1);
+    EXPECT_EQ(output.reports(0).current_report_elapsed_nanos(), dumpTime2Ns);
+    EXPECT_EQ(output.reports(0).last_report_elapsed_nanos(), dumpTime1Ns);
+
+    int64_t dumpTime3Ns = 10 * NS_PER_SEC;
+    processor->onDumpReport(key, dumpTime3Ns, false /* include_current_bucket */,
+            true /* erase_data */, ADB_DUMP, FAST, &bytes);
+
+    // Check that the previous dump report that didn't clear data did not overwrite the first dump's
+    // timestamps.
+    output.ParseFromArray(bytes.data(), bytes.size());
+    EXPECT_EQ(output.reports_size(), 1);
+    EXPECT_EQ(output.reports(0).current_report_elapsed_nanos(), dumpTime3Ns);
+    EXPECT_EQ(output.reports(0).last_report_elapsed_nanos(), dumpTime1Ns);
+
+}
+
 #else
 GTEST_LOG_(INFO) << "This test does nothing.\n";
 #endif
diff --git a/cmds/statsd/tests/metrics/ValueMetricProducer_test.cpp b/cmds/statsd/tests/metrics/ValueMetricProducer_test.cpp
index f041996..5666501 100644
--- a/cmds/statsd/tests/metrics/ValueMetricProducer_test.cpp
+++ b/cmds/statsd/tests/metrics/ValueMetricProducer_test.cpp
@@ -3295,11 +3295,15 @@
               report.value_metrics().skipped(0).start_bucket_elapsed_millis());
     EXPECT_EQ(NanoToMillis(bucket2StartTimeNs + 100),
               report.value_metrics().skipped(0).end_bucket_elapsed_millis());
-    ASSERT_EQ(1, report.value_metrics().skipped(0).drop_event_size());
+    ASSERT_EQ(2, report.value_metrics().skipped(0).drop_event_size());
 
     auto dropEvent = report.value_metrics().skipped(0).drop_event(0);
     EXPECT_EQ(BucketDropReason::EVENT_IN_WRONG_BUCKET, dropEvent.drop_reason());
     EXPECT_EQ(NanoToMillis(bucket2StartTimeNs - 100), dropEvent.drop_time_millis());
+
+    dropEvent = report.value_metrics().skipped(0).drop_event(1);
+    EXPECT_EQ(BucketDropReason::CONDITION_UNKNOWN, dropEvent.drop_reason());
+    EXPECT_EQ(NanoToMillis(bucket2StartTimeNs + 100), dropEvent.drop_time_millis());
 }
 
 /*
@@ -3615,7 +3619,7 @@
 
     sp<ValueMetricProducer> valueProducer =
             ValueMetricProducerTestHelper::createValueProducerWithCondition(
-                    pullerManager, metric, ConditionState::kUnknown);
+                    pullerManager, metric, ConditionState::kFalse);
 
     // Check dump report.
     ProtoOutputStream output;
@@ -3641,6 +3645,94 @@
 }
 
 /*
+ * Test that all buckets are dropped due to condition unknown until the first onConditionChanged.
+ */
+TEST(ValueMetricProducerTest_BucketDrop, TestConditionUnknownMultipleBuckets) {
+    ValueMetric metric = ValueMetricProducerTestHelper::createMetricWithCondition();
+
+    sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
+    EXPECT_CALL(*pullerManager, Pull(tagId, kConfigKey, _, _, _))
+            // Condition change to true.
+            .WillOnce(Invoke([](int tagId, const ConfigKey&, const int64_t eventTimeNs,
+                                vector<std::shared_ptr<LogEvent>>* data, bool) {
+                EXPECT_EQ(eventTimeNs, bucket2StartTimeNs + 10 * NS_PER_SEC);
+                data->clear();
+                data->push_back(CreateRepeatedValueLogEvent(
+                        tagId, bucket2StartTimeNs + 10 * NS_PER_SEC, 10));
+                return true;
+            }))
+            // Dump report requested.
+            .WillOnce(Invoke([](int tagId, const ConfigKey&, const int64_t eventTimeNs,
+                                vector<std::shared_ptr<LogEvent>>* data, bool) {
+                EXPECT_EQ(eventTimeNs, bucket2StartTimeNs + 15 * NS_PER_SEC);
+                data->clear();
+                data->push_back(CreateRepeatedValueLogEvent(
+                        tagId, bucket2StartTimeNs + 15 * NS_PER_SEC, 15));
+                return true;
+            }));
+
+    sp<ValueMetricProducer> valueProducer =
+            ValueMetricProducerTestHelper::createValueProducerWithCondition(
+                    pullerManager, metric, ConditionState::kUnknown);
+
+    // Bucket should be dropped because of condition unknown.
+    int64_t appUpgradeTimeNs = bucketStartTimeNs + 5 * NS_PER_SEC;
+    valueProducer->notifyAppUpgrade(appUpgradeTimeNs);
+
+    // Bucket also dropped due to condition unknown
+    vector<shared_ptr<LogEvent>> allData;
+    allData.clear();
+    allData.push_back(CreateRepeatedValueLogEvent(tagId, bucket2StartTimeNs + 1, 3));
+    valueProducer->onDataPulled(allData, /** succeed */ true, bucket2StartTimeNs);
+
+    // This bucket is also dropped due to condition unknown.
+    int64_t conditionChangeTimeNs = bucket2StartTimeNs + 10 * NS_PER_SEC;
+    valueProducer->onConditionChanged(true, conditionChangeTimeNs);
+
+    // Check dump report.
+    ProtoOutputStream output;
+    std::set<string> strSet;
+    int64_t dumpReportTimeNs = bucket2StartTimeNs + 15 * NS_PER_SEC; // 15 seconds
+    valueProducer->onDumpReport(dumpReportTimeNs, true /* include current bucket */, true,
+                                NO_TIME_CONSTRAINTS /* dumpLatency */, &strSet, &output);
+
+    StatsLogReport report = outputStreamToProto(&output);
+    EXPECT_TRUE(report.has_value_metrics());
+    ASSERT_EQ(0, report.value_metrics().data_size());
+    ASSERT_EQ(3, report.value_metrics().skipped_size());
+
+    EXPECT_EQ(NanoToMillis(bucketStartTimeNs),
+              report.value_metrics().skipped(0).start_bucket_elapsed_millis());
+    EXPECT_EQ(NanoToMillis(appUpgradeTimeNs),
+              report.value_metrics().skipped(0).end_bucket_elapsed_millis());
+    ASSERT_EQ(1, report.value_metrics().skipped(0).drop_event_size());
+
+    auto dropEvent = report.value_metrics().skipped(0).drop_event(0);
+    EXPECT_EQ(BucketDropReason::CONDITION_UNKNOWN, dropEvent.drop_reason());
+    EXPECT_EQ(NanoToMillis(appUpgradeTimeNs), dropEvent.drop_time_millis());
+
+    EXPECT_EQ(NanoToMillis(appUpgradeTimeNs),
+              report.value_metrics().skipped(1).start_bucket_elapsed_millis());
+    EXPECT_EQ(NanoToMillis(bucket2StartTimeNs),
+              report.value_metrics().skipped(1).end_bucket_elapsed_millis());
+    ASSERT_EQ(1, report.value_metrics().skipped(1).drop_event_size());
+
+    dropEvent = report.value_metrics().skipped(1).drop_event(0);
+    EXPECT_EQ(BucketDropReason::CONDITION_UNKNOWN, dropEvent.drop_reason());
+    EXPECT_EQ(NanoToMillis(bucket2StartTimeNs), dropEvent.drop_time_millis());
+
+    EXPECT_EQ(NanoToMillis(bucket2StartTimeNs),
+              report.value_metrics().skipped(2).start_bucket_elapsed_millis());
+    EXPECT_EQ(NanoToMillis(dumpReportTimeNs),
+              report.value_metrics().skipped(2).end_bucket_elapsed_millis());
+    ASSERT_EQ(1, report.value_metrics().skipped(2).drop_event_size());
+
+    dropEvent = report.value_metrics().skipped(2).drop_event(0);
+    EXPECT_EQ(BucketDropReason::CONDITION_UNKNOWN, dropEvent.drop_reason());
+    EXPECT_EQ(NanoToMillis(conditionChangeTimeNs), dropEvent.drop_time_millis());
+}
+
+/*
  * Test that a skipped bucket is logged when a forced bucket split occurs when the previous bucket
  * was not flushed in time.
  */
@@ -4957,7 +5049,7 @@
     ASSERT_EQ(1, report.value_metrics().skipped(0).drop_event_size());
 
     auto dropEvent = report.value_metrics().skipped(0).drop_event(0);
-    EXPECT_EQ(BucketDropReason::NO_DATA, dropEvent.drop_reason());
+    EXPECT_EQ(BucketDropReason::CONDITION_UNKNOWN, dropEvent.drop_reason());
     EXPECT_EQ(NanoToMillis(appUpdateTimeNs), dropEvent.drop_time_millis());
 }
 
diff --git a/cmds/statsd/tests/utils/MultiConditionTrigger_test.cpp b/cmds/statsd/tests/utils/MultiConditionTrigger_test.cpp
index db402a0..32cecd3 100644
--- a/cmds/statsd/tests/utils/MultiConditionTrigger_test.cpp
+++ b/cmds/statsd/tests/utils/MultiConditionTrigger_test.cpp
@@ -50,13 +50,13 @@
     });
 
     vector<thread> threads;
-    vector<bool> done(numConditions, false);
+    vector<int> done(numConditions, 0);
 
     int i = 0;
     for (const string& conditionName : conditionNames) {
         threads.emplace_back([&done, &conditionName, &trigger, i] {
             sleep_for(chrono::milliseconds(3));
-            done[i] = true;
+            done[i] = 1;
             trigger.markComplete(conditionName);
         });
         i++;
diff --git a/core/java/android/app/ActivityManager.java b/core/java/android/app/ActivityManager.java
index 97b704c..b608a34 100644
--- a/core/java/android/app/ActivityManager.java
+++ b/core/java/android/app/ActivityManager.java
@@ -601,20 +601,6 @@
     @TestApi
     public static final int PROCESS_CAPABILITY_FOREGROUND_MICROPHONE = 1 << 2;
 
-    // TODO: remove this when development is done.
-    // These are debug flags used between OomAdjuster and AppOpsService to detect and report absence
-    // of the real flags.
-    /** @hide */
-    public static final int DEBUG_PROCESS_CAPABILITY_FOREGROUND_MICROPHONE_Q = 1 << 27;
-    /** @hide */
-    public static final int DEBUG_PROCESS_CAPABILITY_FOREGROUND_CAMERA_Q = 1 << 28;
-    /** @hide */
-    public static final int DEBUG_PROCESS_CAPABILITY_FOREGROUND_MICROPHONE = 1 << 29;
-    /** @hide */
-    public static final int DEBUG_PROCESS_CAPABILITY_FOREGROUND_CAMERA = 1 << 30;
-    /** @hide */
-    public static final int DEBUG_PROCESS_CAPABILITY_FOREGROUND_LOCATION = 1 << 31;
-
     /** @hide all capabilities, the ORing of all flags in {@link ProcessCapability}*/
     @TestApi
     public static final int PROCESS_CAPABILITY_ALL = PROCESS_CAPABILITY_FOREGROUND_LOCATION
@@ -653,29 +639,9 @@
      */
     public static void printCapabilitiesFull(PrintWriter pw, @ProcessCapability int caps) {
         printCapabilitiesSummary(pw, caps);
-        if ((caps & DEBUG_PROCESS_CAPABILITY_FOREGROUND_LOCATION) != 0) {
-            pw.print(" !L");
-        }
-        if ((caps & DEBUG_PROCESS_CAPABILITY_FOREGROUND_CAMERA) != 0) {
-            pw.print(" !C");
-        }
-        if ((caps & DEBUG_PROCESS_CAPABILITY_FOREGROUND_CAMERA_Q) != 0) {
-            pw.print(" !Cq");
-        }
-        if ((caps & DEBUG_PROCESS_CAPABILITY_FOREGROUND_MICROPHONE) != 0) {
-            pw.print(" !M");
-        }
-        if ((caps & DEBUG_PROCESS_CAPABILITY_FOREGROUND_MICROPHONE_Q) != 0) {
-            pw.print(" !Mq");
-        }
         final int remain = caps & ~(PROCESS_CAPABILITY_FOREGROUND_LOCATION
                 | PROCESS_CAPABILITY_FOREGROUND_CAMERA
-                | PROCESS_CAPABILITY_FOREGROUND_MICROPHONE
-                | DEBUG_PROCESS_CAPABILITY_FOREGROUND_LOCATION
-                | DEBUG_PROCESS_CAPABILITY_FOREGROUND_CAMERA
-                | DEBUG_PROCESS_CAPABILITY_FOREGROUND_CAMERA_Q
-                | DEBUG_PROCESS_CAPABILITY_FOREGROUND_MICROPHONE
-                | DEBUG_PROCESS_CAPABILITY_FOREGROUND_MICROPHONE_Q);
+                | PROCESS_CAPABILITY_FOREGROUND_MICROPHONE);
         if (remain != 0) {
             pw.print('+');
             pw.print(remain);
diff --git a/core/java/android/app/ActivityManagerInternal.java b/core/java/android/app/ActivityManagerInternal.java
index c491eea..a5965bc 100644
--- a/core/java/android/app/ActivityManagerInternal.java
+++ b/core/java/android/app/ActivityManagerInternal.java
@@ -398,13 +398,6 @@
      */
     public abstract boolean isUidCurrentlyInstrumented(int uid);
 
-    /**
-     * Show a debug toast, asking user to file a bugreport.
-     */
-    // TODO: remove this toast after feature development is done
-    public abstract void showWhileInUseDebugToast(int uid, int op, int mode);
-
-
     /** Is this a device owner app? */
     public abstract boolean isDeviceOwner(int uid);
 
@@ -429,11 +422,17 @@
             int userId, int[] appIdWhitelist);
 
     /**
-     * Add or delete uid from the ActivityManagerService PendingStartActivityUids list.
+     * Add uid to the ActivityManagerService PendingStartActivityUids list.
      * @param uid uid
-     * @param pending add to the list if true, delete from list if false.
+     * @param pid pid of the ProcessRecord that is pending top.
      */
-    public abstract void updatePendingTopUid(int uid, boolean pending);
+    public abstract void addPendingTopUid(int uid, int pid);
+
+    /**
+     * Delete uid from the ActivityManagerService PendingStartActivityUids list.
+     * @param uid uid
+     */
+    public abstract void deletePendingTopUid(int uid);
 
     /**
      * Is the uid in ActivityManagerService PendingStartActivityUids list?
diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java
index 108b9ee..812ca4a 100644
--- a/core/java/android/app/ActivityThread.java
+++ b/core/java/android/app/ActivityThread.java
@@ -123,6 +123,7 @@
 import android.os.TelephonyServiceManager;
 import android.os.Trace;
 import android.os.UserHandle;
+import android.os.UserManager;
 import android.permission.IPermissionManager;
 import android.provider.BlockedNumberContract;
 import android.provider.CalendarContract;
@@ -6816,7 +6817,11 @@
             throw ex.rethrowFromSystemServer();
         }
         if (holder == null) {
-            Slog.e(TAG, "Failed to find provider info for " + auth);
+            if (UserManager.get(c).isUserUnlocked(userId)) {
+                Slog.e(TAG, "Failed to find provider info for " + auth);
+            } else {
+                Slog.w(TAG, "Failed to find provider info for " + auth + " (user not unlocked)");
+            }
             return null;
         }
 
diff --git a/core/java/android/app/AppOpsManager.java b/core/java/android/app/AppOpsManager.java
index ddc5747..e620f16 100644
--- a/core/java/android/app/AppOpsManager.java
+++ b/core/java/android/app/AppOpsManager.java
@@ -261,8 +261,9 @@
                             < SystemClock.elapsedRealtime()) {
                         String stackTrace = getFormattedStackTrace();
                         try {
+                            String packageName = ActivityThread.currentOpPackageName();
                             sConfig = getService().reportRuntimeAppOpAccessMessageAndGetConfig(
-                                    ActivityThread.currentOpPackageName(), op, stackTrace);
+                                    packageName == null ? "" : packageName, op, stackTrace);
                         } catch (RemoteException e) {
                             e.rethrowFromSystemServer();
                         }
diff --git a/core/java/android/app/Notification.java b/core/java/android/app/Notification.java
index f881616..0e3f35e 100644
--- a/core/java/android/app/Notification.java
+++ b/core/java/android/app/Notification.java
@@ -7495,6 +7495,7 @@
             mHistoricMessages = Message.getMessagesFromBundleArray(histMessages);
             mIsGroupConversation = extras.getBoolean(EXTRA_IS_GROUP_CONVERSATION);
             mUnreadMessageCount = extras.getInt(EXTRA_CONVERSATION_UNREAD_MESSAGE_COUNT);
+            mShortcutIcon = extras.getParcelable(EXTRA_CONVERSATION_ICON);
         }
 
         /**
diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java
index c650643..322cac8 100644
--- a/core/java/android/app/admin/DevicePolicyManager.java
+++ b/core/java/android/app/admin/DevicePolicyManager.java
@@ -4247,6 +4247,12 @@
      * device. After this method is called, the device must be unlocked using strong authentication
      * (PIN, pattern, or password). This API is intended for use only by device admins.
      * <p>
+     * From version {@link android.os.Build.VERSION_CODES#R} onwards, the caller must either have
+     * the LOCK_DEVICE permission or the device must have the device admin feature; if neither is
+     * true, then the method will return without completing any action. Before version
+     * {@link android.os.Build.VERSION_CODES#R}, the device needed the device admin feature,
+     * regardless of the caller's permissions.
+     * <p>
      * The calling device admin must have requested {@link DeviceAdminInfo#USES_POLICY_FORCE_LOCK}
      * to be able to call this method; if it has not, a security exception will be thrown.
      * <p>
@@ -4274,6 +4280,12 @@
      * device. After this method is called, the device must be unlocked using strong authentication
      * (PIN, pattern, or password). This API is intended for use only by device admins.
      * <p>
+     * From version {@link android.os.Build.VERSION_CODES#R} onwards, the caller must either have
+     * the LOCK_DEVICE permission or the device must have the device admin feature; if neither is
+     * true, then the method will return without completing any action. Before version
+     * {@link android.os.Build.VERSION_CODES#R}, the device needed the device admin feature,
+     * regardless of the caller's permissions.
+     * <p>
      * The calling device admin must have requested {@link DeviceAdminInfo#USES_POLICY_FORCE_LOCK}
      * to be able to call this method; if it has not, a security exception will be thrown.
      * <p>
@@ -5868,12 +5880,22 @@
      * returned by {@link #getParentProfileInstance(ComponentName)}, where the caller must be
      * the profile owner of an organization-owned managed profile.
      * <p>
-     * If the caller is device owner or called on the parent instance, then the
-     * restriction will be applied to all users.
+     * If the caller is device owner, then the restriction will be applied to all users. If
+     * called on the parent instance, then the restriction will be applied on the personal profile.
      * <p>
      * The calling device admin must have requested
      * {@link DeviceAdminInfo#USES_POLICY_DISABLE_CAMERA} to be able to call this method; if it has
      * not, a security exception will be thrown.
+     * <p>
+     * <b>Note</b>, this policy type is deprecated for legacy device admins since
+     * {@link android.os.Build.VERSION_CODES#Q}. On Android
+     * {@link android.os.Build.VERSION_CODES#Q} devices, legacy device admins targeting SDK
+     * version {@link android.os.Build.VERSION_CODES#P} or below can still call this API to
+     * disable camera, while legacy device admins targeting SDK version
+     * {@link android.os.Build.VERSION_CODES#Q} will receive a SecurityException. Starting
+     * from Android {@link android.os.Build.VERSION_CODES#R}, requests to disable camera from
+     * legacy device admins targeting SDK version {@link android.os.Build.VERSION_CODES#P} or
+     * below will be silently ignored.
      *
      * @param admin Which {@link DeviceAdminReceiver} this request is associated with.
      * @param disabled Whether or not the camera should be disabled.
diff --git a/core/java/android/app/contentsuggestions/ContentSuggestionsManager.java b/core/java/android/app/contentsuggestions/ContentSuggestionsManager.java
index bea1bd6e..b3f9e31 100644
--- a/core/java/android/app/contentsuggestions/ContentSuggestionsManager.java
+++ b/core/java/android/app/contentsuggestions/ContentSuggestionsManager.java
@@ -95,7 +95,7 @@
         try {
             mService.provideContextBitmap(mUser, bitmap, imageContextRequestExtras);
         } catch (RemoteException e) {
-            e.rethrowFromSystemServer();
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -117,7 +117,7 @@
         try {
             mService.provideContextImage(mUser, taskId, imageContextRequestExtras);
         } catch (RemoteException e) {
-            e.rethrowFromSystemServer();
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -146,7 +146,7 @@
             mService.suggestContentSelections(
                     mUser, request, new SelectionsCallbackWrapper(callback, callbackExecutor));
         } catch (RemoteException e) {
-            e.rethrowFromSystemServer();
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -173,7 +173,7 @@
             mService.classifyContentSelections(
                     mUser, request, new ClassificationsCallbackWrapper(callback, callbackExecutor));
         } catch (RemoteException e) {
-            e.rethrowFromSystemServer();
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -193,7 +193,7 @@
         try {
             mService.notifyInteraction(mUser, requestId, interaction);
         } catch (RemoteException e) {
-            e.rethrowFromSystemServer();
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -213,9 +213,10 @@
             mService.isEnabled(mUser, receiver);
             return receiver.getIntResult() != 0;
         } catch (RemoteException e) {
-            e.rethrowFromSystemServer();
+            throw e.rethrowFromSystemServer();
+        } catch (SyncResultReceiver.TimeoutException e) {
+            throw new RuntimeException("Fail to get the enable status.");
         }
-        return false;
     }
 
     /**
diff --git a/core/java/android/app/usage/UsageEvents.java b/core/java/android/app/usage/UsageEvents.java
index 0f999ad..3522b1b 100644
--- a/core/java/android/app/usage/UsageEvents.java
+++ b/core/java/android/app/usage/UsageEvents.java
@@ -133,6 +133,7 @@
         /**
          * An event type denoting that a component was in the foreground when the stats
          * rolled-over. This is effectively treated as a {@link #ACTIVITY_PAUSED}.
+         * This event has a non-null packageName, and a null className.
          * {@hide}
          */
         public static final int END_OF_DAY = 3;
diff --git a/core/java/android/content/pm/LauncherApps.java b/core/java/android/content/pm/LauncherApps.java
index bd1ee27..1a694b34 100644
--- a/core/java/android/content/pm/LauncherApps.java
+++ b/core/java/android/content/pm/LauncherApps.java
@@ -1243,14 +1243,7 @@
 
     private ParcelFileDescriptor getUriShortcutIconFd(@NonNull String packageName,
             @NonNull String shortcutId, int userId) {
-        String uri = null;
-        try {
-            uri = mService.getShortcutIconUri(mContext.getPackageName(), packageName, shortcutId,
-                    userId);
-        } catch (RemoteException e) {
-            throw e.rethrowFromSystemServer();
-        }
-
+        String uri = getShortcutIconUri(packageName, shortcutId, userId);
         if (uri == null) {
             return null;
         }
@@ -1262,6 +1255,18 @@
         }
     }
 
+    private String getShortcutIconUri(@NonNull String packageName,
+            @NonNull String shortcutId, int userId) {
+        String uri = null;
+        try {
+            uri = mService.getShortcutIconUri(mContext.getPackageName(), packageName, shortcutId,
+                    userId);
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+        return uri;
+    }
+
     /**
      * Returns the icon for this shortcut, without any badging for the profile.
      *
@@ -1357,6 +1362,17 @@
                 } catch (IOException ignore) {
                 }
             }
+        } else if (shortcut.hasIconUri()) {
+            String uri = getShortcutIconUri(shortcut.getPackage(), shortcut.getId(),
+                    shortcut.getUserId());
+            if (uri == null) {
+                return null;
+            }
+            if (shortcut.hasAdaptiveBitmap()) {
+                return Icon.createWithAdaptiveBitmapContentUri(uri);
+            } else {
+                return Icon.createWithContentUri(uri);
+            }
         } else if (shortcut.hasIconResource()) {
             return Icon.createWithResource(shortcut.getPackage(), shortcut.getIconResourceId());
         } else {
diff --git a/core/java/android/content/pm/PackageParser.java b/core/java/android/content/pm/PackageParser.java
index c8dd4d9..885ffba 100644
--- a/core/java/android/content/pm/PackageParser.java
+++ b/core/java/android/content/pm/PackageParser.java
@@ -205,6 +205,7 @@
     public static final String TAG_USES_PERMISSION_SDK_M = "uses-permission-sdk-m";
     public static final String TAG_USES_SDK = "uses-sdk";
     public static final String TAG_USES_SPLIT = "uses-split";
+    public static final String TAG_PROFILEABLE = "profileable";
 
     public static final String METADATA_MAX_ASPECT_RATIO = "android.max_aspect";
     public static final String METADATA_SUPPORTS_SIZE_CHANGES = "android.supports_size_changes";
@@ -459,6 +460,9 @@
         public final SigningDetails signingDetails;
         public final boolean coreApp;
         public final boolean debuggable;
+        // This does not represent the actual manifest structure since the 'profilable' tag
+        // could be used with attributes other than 'shell'. Extend if necessary.
+        public final boolean profilableByShell;
         public final boolean multiArch;
         public final boolean use32bitAbi;
         public final boolean extractNativeLibs;
@@ -470,15 +474,13 @@
         public final int overlayPriority;
 
         public ApkLite(String codePath, String packageName, String splitName,
-                boolean isFeatureSplit,
-                String configForSplit, String usesSplitName, boolean isSplitRequired,
-                int versionCode, int versionCodeMajor,
-                int revisionCode, int installLocation, List<VerifierInfo> verifiers,
-                SigningDetails signingDetails, boolean coreApp,
-                boolean debuggable, boolean multiArch, boolean use32bitAbi,
-                boolean useEmbeddedDex, boolean extractNativeLibs, boolean isolatedSplits,
-                String targetPackageName, boolean overlayIsStatic, int overlayPriority,
-                int minSdkVersion, int targetSdkVersion) {
+                boolean isFeatureSplit, String configForSplit, String usesSplitName,
+                boolean isSplitRequired, int versionCode, int versionCodeMajor, int revisionCode,
+                int installLocation, List<VerifierInfo> verifiers, SigningDetails signingDetails,
+                boolean coreApp, boolean debuggable, boolean profilableByShell, boolean multiArch,
+                boolean use32bitAbi, boolean useEmbeddedDex, boolean extractNativeLibs,
+                boolean isolatedSplits, String targetPackageName, boolean overlayIsStatic,
+                int overlayPriority, int minSdkVersion, int targetSdkVersion) {
             this.codePath = codePath;
             this.packageName = packageName;
             this.splitName = splitName;
@@ -493,6 +495,7 @@
             this.verifiers = verifiers.toArray(new VerifierInfo[verifiers.size()]);
             this.coreApp = coreApp;
             this.debuggable = debuggable;
+            this.profilableByShell = profilableByShell;
             this.multiArch = multiArch;
             this.use32bitAbi = use32bitAbi;
             this.useEmbeddedDex = useEmbeddedDex;
@@ -1573,6 +1576,7 @@
         int revisionCode = 0;
         boolean coreApp = false;
         boolean debuggable = false;
+        boolean profilableByShell = false;
         boolean multiArch = false;
         boolean use32bitAbi = false;
         boolean extractNativeLibs = true;
@@ -1638,6 +1642,10 @@
                     final String attr = attrs.getAttributeName(i);
                     if ("debuggable".equals(attr)) {
                         debuggable = attrs.getAttributeBooleanValue(i, false);
+                        if (debuggable) {
+                            // Debuggable implies profileable
+                            profilableByShell = true;
+                        }
                     }
                     if ("multiArch".equals(attr)) {
                         multiArch = attrs.getAttributeBooleanValue(i, false);
@@ -1690,6 +1698,13 @@
                         minSdkVersion = attrs.getAttributeIntValue(i, DEFAULT_MIN_SDK_VERSION);
                     }
                 }
+            } else if (TAG_PROFILEABLE.equals(parser.getName())) {
+                for (int i = 0; i < attrs.getAttributeCount(); ++i) {
+                    final String attr = attrs.getAttributeName(i);
+                    if ("shell".equals(attr)) {
+                        profilableByShell = attrs.getAttributeBooleanValue(i, profilableByShell);
+                    }
+                }
             }
         }
 
@@ -1707,8 +1722,9 @@
         return new ApkLite(codePath, packageSplit.first, packageSplit.second, isFeatureSplit,
                 configForSplit, usesSplitName, isSplitRequired, versionCode, versionCodeMajor,
                 revisionCode, installLocation, verifiers, signingDetails, coreApp, debuggable,
-                multiArch, use32bitAbi, useEmbeddedDex, extractNativeLibs, isolatedSplits,
-                targetPackage, overlayIsStatic, overlayPriority, minSdkVersion, targetSdkVersion);
+                profilableByShell, multiArch, use32bitAbi, useEmbeddedDex, extractNativeLibs,
+                isolatedSplits, targetPackage, overlayIsStatic, overlayPriority, minSdkVersion,
+                targetSdkVersion);
     }
 
     /**
diff --git a/core/java/android/content/pm/PackagePartitions.java b/core/java/android/content/pm/PackagePartitions.java
index 653b9ec..98a20f7 100644
--- a/core/java/android/content/pm/PackagePartitions.java
+++ b/core/java/android/content/pm/PackagePartitions.java
@@ -183,17 +183,20 @@
 
         /** Returns whether the partition contains the specified file in its priv-app folder. */
         public boolean containsPrivApp(@NonNull File scanFile) {
-            return FileUtils.contains(mPrivAppFolder.getFile(), canonicalize(scanFile));
+            return mPrivAppFolder != null
+                    && FileUtils.contains(mPrivAppFolder.getFile(), canonicalize(scanFile));
         }
 
         /** Returns whether the partition contains the specified file in its app folder. */
         public boolean containsApp(@NonNull File scanFile) {
-            return FileUtils.contains(mAppFolder.getFile(), canonicalize(scanFile));
+            return mAppFolder != null
+                    && FileUtils.contains(mAppFolder.getFile(), canonicalize(scanFile));
         }
 
         /** Returns whether the partition contains the specified file in its overlay folder. */
         public boolean containsOverlay(@NonNull File scanFile) {
-            return FileUtils.contains(mOverlayFolder.getFile(), canonicalize(scanFile));
+            return mOverlayFolder != null
+                    && FileUtils.contains(mOverlayFolder.getFile(), canonicalize(scanFile));
         }
     }
 
diff --git a/core/java/android/content/pm/dex/ArtManagerInternal.java b/core/java/android/content/pm/dex/ArtManagerInternal.java
index 62ab9e0..23fef29 100644
--- a/core/java/android/content/pm/dex/ArtManagerInternal.java
+++ b/core/java/android/content/pm/dex/ArtManagerInternal.java
@@ -30,5 +30,5 @@
      * in executes using the specified {@code abi}.
      */
     public abstract PackageOptimizationInfo getPackageOptimizationInfo(
-            ApplicationInfo info, String abi);
+            ApplicationInfo info, String abi, String activityName);
 }
diff --git a/core/java/android/content/pm/parsing/ApkLiteParseUtils.java b/core/java/android/content/pm/parsing/ApkLiteParseUtils.java
index d2172d3..c3e9402 100644
--- a/core/java/android/content/pm/parsing/ApkLiteParseUtils.java
+++ b/core/java/android/content/pm/parsing/ApkLiteParseUtils.java
@@ -20,7 +20,6 @@
 import static android.content.pm.PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
 import static android.os.Trace.TRACE_TAG_PACKAGE_MANAGER;
 
-import android.compat.annotation.UnsupportedAppUsage;
 import android.content.pm.PackageInfo;
 import android.content.pm.PackageManager;
 import android.content.pm.PackageParser;
@@ -303,6 +302,7 @@
         int revisionCode = 0;
         boolean coreApp = false;
         boolean debuggable = false;
+        boolean profilableByShell = false;
         boolean multiArch = false;
         boolean use32bitAbi = false;
         boolean extractNativeLibs = true;
@@ -379,6 +379,10 @@
                     switch (attr) {
                         case "debuggable":
                             debuggable = attrs.getAttributeBooleanValue(i, false);
+                            if (debuggable) {
+                                // Debuggable implies profileable
+                                profilableByShell = true;
+                            }
                             break;
                         case "multiArch":
                             multiArch = attrs.getAttributeBooleanValue(i, false);
@@ -431,6 +435,13 @@
                         minSdkVersion = attrs.getAttributeIntValue(i, DEFAULT_MIN_SDK_VERSION);
                     }
                 }
+            } else if (PackageParser.TAG_PROFILEABLE.equals(parser.getName())) {
+                for (int i = 0; i < attrs.getAttributeCount(); ++i) {
+                    final String attr = attrs.getAttributeName(i);
+                    if ("shell".equals(attr)) {
+                        profilableByShell = attrs.getAttributeBooleanValue(i, profilableByShell);
+                    }
+                }
             }
         }
 
@@ -445,12 +456,13 @@
             overlayPriority = 0;
         }
 
-        return input.success(new PackageParser.ApkLite(codePath, packageSplit.first,
-                packageSplit.second, isFeatureSplit, configForSplit, usesSplitName, isSplitRequired,
-                versionCode, versionCodeMajor, revisionCode, installLocation, verifiers,
-                signingDetails, coreApp, debuggable, multiArch, use32bitAbi, useEmbeddedDex,
-                extractNativeLibs, isolatedSplits, targetPackage, overlayIsStatic, overlayPriority,
-                minSdkVersion, targetSdkVersion));
+        return input.success(
+                new PackageParser.ApkLite(codePath, packageSplit.first, packageSplit.second,
+                        isFeatureSplit, configForSplit, usesSplitName, isSplitRequired, versionCode,
+                        versionCodeMajor, revisionCode, installLocation, verifiers, signingDetails,
+                        coreApp, debuggable, profilableByShell, multiArch, use32bitAbi,
+                        useEmbeddedDex, extractNativeLibs, isolatedSplits, targetPackage,
+                        overlayIsStatic, overlayPriority, minSdkVersion, targetSdkVersion));
     }
 
     public static ParseResult<Pair<String, String>> parsePackageSplitNames(ParseInput input,
diff --git a/core/java/android/hardware/camera2/CameraManager.java b/core/java/android/hardware/camera2/CameraManager.java
index 6bbc37a..7f834af 100644
--- a/core/java/android/hardware/camera2/CameraManager.java
+++ b/core/java/android/hardware/camera2/CameraManager.java
@@ -586,13 +586,27 @@
      * priority when accessing the camera, and this method will succeed even if the camera device is
      * in use by another camera API client. Any lower-priority application that loses control of the
      * camera in this way will receive an
-     * {@link android.hardware.camera2.CameraDevice.StateCallback#onDisconnected} callback.</p>
+     * {@link android.hardware.camera2.CameraDevice.StateCallback#onDisconnected} callback.
+     * Opening the same camera ID twice in the same application will similarly cause the
+     * {@link android.hardware.camera2.CameraDevice.StateCallback#onDisconnected} callback
+     * being fired for the {@link CameraDevice} from the first open call and all ongoing tasks
+     * being droppped.</p>
      *
      * <p>Once the camera is successfully opened, {@link CameraDevice.StateCallback#onOpened} will
      * be invoked with the newly opened {@link CameraDevice}. The camera device can then be set up
      * for operation by calling {@link CameraDevice#createCaptureSession} and
      * {@link CameraDevice#createCaptureRequest}</p>
      *
+     * <p>Before API level 30, when the application tries to open multiple {@link CameraDevice} of
+     * different IDs and the device does not support opening such combination, either the
+     * {@link #openCamera} will fail and throw a {@link CameraAccessException} or one or more of
+     * already opened {@link CameraDevice} will be disconnected and receive
+     * {@link android.hardware.camera2.CameraDevice.StateCallback#onDisconnected} callback. Which
+     * behavior will happen depends on the device implementation and can vary on different devices.
+     * Starting in API level 30, if the device does not support the combination of cameras being
+     * opened, it is guaranteed the {@link #openCamera} call will fail and none of existing
+     * {@link CameraDevice} will be disconnected.</p>
+     *
      * <!--
      * <p>Since the camera device will be opened asynchronously, any asynchronous operations done
      * on the returned CameraDevice instance will be queued up until the device startup has
@@ -618,7 +632,8 @@
      *             {@code null} to use the current thread's {@link android.os.Looper looper}.
      *
      * @throws CameraAccessException if the camera is disabled by device policy,
-     * has been disconnected, or is being used by a higher-priority camera API client.
+     * has been disconnected, is being used by a higher-priority camera API client, or the device
+     * has reached its maximal resource and cannot open this camera device.
      *
      * @throws IllegalArgumentException if cameraId or the callback was null,
      * or the cameraId does not match any currently or previously available
diff --git a/core/java/android/hardware/soundtrigger/ConversionUtil.java b/core/java/android/hardware/soundtrigger/ConversionUtil.java
index 425218a..c4d123c 100644
--- a/core/java/android/hardware/soundtrigger/ConversionUtil.java
+++ b/core/java/android/hardware/soundtrigger/ConversionUtil.java
@@ -195,11 +195,14 @@
 
     public static SoundTrigger.RecognitionEvent aidl2apiRecognitionEvent(
             int modelHandle, RecognitionEvent aidlEvent) {
+        // The API recognition event doesn't allow for a null audio format, even though it doesn't
+        // always make sense. We thus replace it with a default.
+        AudioFormat audioFormat = aidl2apiAudioFormatWithDefault(aidlEvent.audioConfig);
         return new SoundTrigger.GenericRecognitionEvent(
                 aidlEvent.status,
                 modelHandle, aidlEvent.captureAvailable, aidlEvent.captureSession,
                 aidlEvent.captureDelayMs, aidlEvent.capturePreambleMs, aidlEvent.triggerInData,
-                aidl2apiAudioFormat(aidlEvent.audioConfig), aidlEvent.data);
+                audioFormat, aidlEvent.data);
     }
 
     public static SoundTrigger.RecognitionEvent aidl2apiPhraseRecognitionEvent(
@@ -210,11 +213,14 @@
         for (int i = 0; i < aidlEvent.phraseExtras.length; ++i) {
             apiExtras[i] = aidl2apiPhraseRecognitionExtra(aidlEvent.phraseExtras[i]);
         }
+        // The API recognition event doesn't allow for a null audio format, even though it doesn't
+        // always make sense. We thus replace it with a default.
+        AudioFormat audioFormat = aidl2apiAudioFormatWithDefault(aidlEvent.common.audioConfig);
         return new SoundTrigger.KeyphraseRecognitionEvent(aidlEvent.common.status, modelHandle,
                 aidlEvent.common.captureAvailable,
                 aidlEvent.common.captureSession, aidlEvent.common.captureDelayMs,
                 aidlEvent.common.capturePreambleMs, aidlEvent.common.triggerInData,
-                aidl2apiAudioFormat(aidlEvent.common.audioConfig), aidlEvent.common.data,
+                audioFormat, aidlEvent.common.data,
                 apiExtras);
     }
 
@@ -226,6 +232,14 @@
         return apiBuilder.build();
     }
 
+    // Same as above, but in case of a null input returns a non-null valid output.
+    public static AudioFormat aidl2apiAudioFormatWithDefault(@Nullable AudioConfig audioConfig) {
+        if (audioConfig != null) {
+            return aidl2apiAudioFormat(audioConfig);
+        }
+        return new AudioFormat.Builder().build();
+    }
+
     public static int aidl2apiEncoding(int aidlFormat) {
         switch (aidlFormat) {
             case android.media.audio.common.AudioFormat.PCM
diff --git a/core/java/android/hardware/soundtrigger/SoundTriggerModule.java b/core/java/android/hardware/soundtrigger/SoundTriggerModule.java
index c1df5b6..a2a15b3 100644
--- a/core/java/android/hardware/soundtrigger/SoundTriggerModule.java
+++ b/core/java/android/hardware/soundtrigger/SoundTriggerModule.java
@@ -303,7 +303,7 @@
                                     (SoundTrigger.RecognitionEvent) msg.obj);
                             break;
                         case EVENT_SERVICE_STATE_CHANGE:
-                            listener.onServiceStateChange(msg.arg1);
+                            listener.onServiceStateChange((int) msg.obj);
                             break;
                         case EVENT_SERVICE_DIED:
                             listener.onServiceDied();
diff --git a/core/java/android/net/ConnectivityDiagnosticsManager.java b/core/java/android/net/ConnectivityDiagnosticsManager.java
index 275e38c..704f31d 100644
--- a/core/java/android/net/ConnectivityDiagnosticsManager.java
+++ b/core/java/android/net/ConnectivityDiagnosticsManager.java
@@ -711,6 +711,13 @@
      * not currently registered. If a ConnectivityDiagnosticsCallback instance is registered with
      * multiple NetworkRequests, an IllegalArgumentException will be thrown.
      *
+     * <p>To avoid performance issues due to apps leaking callbacks, the system will limit the
+     * number of outstanding requests to 100 per app (identified by their UID), shared with
+     * callbacks in {@link ConnectivityManager}. Registering a callback with this method will count
+     * toward this limit. If this limit is exceeded, an exception will be thrown. To avoid hitting
+     * this issue and to conserve resources, make sure to unregister the callbacks with
+     * {@link #unregisterConnectivityDiagnosticsCallback}.
+     *
      * @param request The NetworkRequest that will be used to match with Networks for which
      *     callbacks will be fired
      * @param e The Executor to be used for running the callback method invocations
@@ -718,6 +725,7 @@
      *     System
      * @throws IllegalArgumentException if the same callback instance is registered with multiple
      *     NetworkRequests
+     * @throws RuntimeException if the app already has too many callbacks registered.
      */
     public void registerConnectivityDiagnosticsCallback(
             @NonNull NetworkRequest request,
diff --git a/core/java/android/net/ConnectivityManager.java b/core/java/android/net/ConnectivityManager.java
index 36ffe50..a29f878 100644
--- a/core/java/android/net/ConnectivityManager.java
+++ b/core/java/android/net/ConnectivityManager.java
@@ -2246,26 +2246,6 @@
                 .getPackageNameForUid(context, uid), true /* throwException */);
     }
 
-    /** {@hide} */
-    public static final void enforceTetherChangePermission(Context context, String callingPkg) {
-        Preconditions.checkNotNull(context, "Context cannot be null");
-        Preconditions.checkNotNull(callingPkg, "callingPkg cannot be null");
-
-        if (context.getResources().getStringArray(
-                com.android.internal.R.array.config_mobile_hotspot_provision_app).length == 2) {
-            // Have a provisioning app - must only let system apps (which check this app)
-            // turn on tethering
-            context.enforceCallingOrSelfPermission(
-                    android.Manifest.permission.TETHER_PRIVILEGED, "ConnectivityService");
-        } else {
-            int uid = Binder.getCallingUid();
-            // If callingPkg's uid is not same as Binder.getCallingUid(),
-            // AppOpsService throws SecurityException.
-            Settings.checkAndNoteWriteSettingsOperation(context, uid, callingPkg,
-                    true /* throwException */);
-        }
-    }
-
     /**
      * @deprecated - use getSystemService. This is a kludge to support static access in certain
      *               situations where a Context pointer is unavailable.
@@ -3814,13 +3794,22 @@
      * or the ability to modify system settings as determined by
      * {@link android.provider.Settings.System#canWrite}.</p>
      *
+     * <p>To avoid performance issues due to apps leaking callbacks, the system will limit the
+     * number of outstanding requests to 100 per app (identified by their UID), shared with
+     * all variants of this method, of {@link #registerNetworkCallback} as well as
+     * {@link ConnectivityDiagnosticsManager#registerConnectivityDiagnosticsCallback}.
+     * Requesting a network with this method will count toward this limit. If this limit is
+     * exceeded, an exception will be thrown. To avoid hitting this issue and to conserve resources,
+     * make sure to unregister the callbacks with
+     * {@link #unregisterNetworkCallback(NetworkCallback)}.
+     *
      * @param request {@link NetworkRequest} describing this request.
      * @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} contains invalid network capabilities.
      * @throws SecurityException if missing the appropriate permissions.
-     * @throws RuntimeException if request limit per UID is exceeded.
+     * @throws RuntimeException if the app already has too many callbacks registered.
      */
     public void requestNetwork(@NonNull NetworkRequest request,
             @NonNull NetworkCallback networkCallback) {
@@ -3834,8 +3823,8 @@
      * but runs all the callbacks on the passed Handler.
      *
      * <p>This method has the same permission requirements as
-     * {@link #requestNetwork(NetworkRequest, NetworkCallback)} and throws the same exceptions in
-     * the same conditions.
+     * {@link #requestNetwork(NetworkRequest, NetworkCallback)}, is subject to the same limitations,
+     * and throws the same exceptions in the same conditions.
      *
      * @param request {@link NetworkRequest} describing this request.
      * @param networkCallback The {@link NetworkCallback} to be utilized for this request. Note
@@ -3866,8 +3855,8 @@
      * for that purpose. Calling this method will attempt to bring up the requested network.
      *
      * <p>This method has the same permission requirements as
-     * {@link #requestNetwork(NetworkRequest, NetworkCallback)} and throws the same exceptions in
-     * the same conditions.
+     * {@link #requestNetwork(NetworkRequest, NetworkCallback)}, is subject to the same limitations,
+     * and throws the same exceptions in the same conditions.
      *
      * @param request {@link NetworkRequest} describing this request.
      * @param networkCallback The {@link NetworkCallback} to be utilized for this request. Note
@@ -3893,8 +3882,8 @@
      * on the passed Handler.
      *
      * <p>This method has the same permission requirements as
-     * {@link #requestNetwork(NetworkRequest, NetworkCallback, int)} and throws the same exceptions
-     * in the same conditions.
+     * {@link #requestNetwork(NetworkRequest, NetworkCallback)}, is subject to the same limitations,
+     * and throws the same exceptions in the same conditions.
      *
      * @param request {@link NetworkRequest} describing this request.
      * @param networkCallback The {@link NetworkCallback} to be utilized for this request. Note
@@ -3963,6 +3952,15 @@
      * is unknown prior to bringing up the network so the framework does not
      * know how to go about satisfying a request with these capabilities.
      *
+     * <p>To avoid performance issues due to apps leaking callbacks, the system will limit the
+     * number of outstanding requests to 100 per app (identified by their UID), shared with
+     * all variants of this method, of {@link #registerNetworkCallback} as well as
+     * {@link ConnectivityDiagnosticsManager#registerConnectivityDiagnosticsCallback}.
+     * Requesting a network with this method will count toward this limit. If this limit is
+     * exceeded, an exception will be thrown. To avoid hitting this issue and to conserve resources,
+     * make sure to unregister the callbacks with {@link #unregisterNetworkCallback(PendingIntent)}
+     * or {@link #releaseNetworkRequest(PendingIntent)}.
+     *
      * <p>This method requires the caller to hold either the
      * {@link android.Manifest.permission#CHANGE_NETWORK_STATE} permission
      * or the ability to modify system settings as determined by
@@ -3974,7 +3972,7 @@
      *                  comes from {@link PendingIntent#getBroadcast}. Cannot be null.
      * @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.
+     * @throws RuntimeException if the app already has too many callbacks registered.
      */
     public void requestNetwork(@NonNull NetworkRequest request,
             @NonNull PendingIntent operation) {
@@ -4030,10 +4028,20 @@
      * either the application exits or {@link #unregisterNetworkCallback(NetworkCallback)} is
      * called.
      *
+     * <p>To avoid performance issues due to apps leaking callbacks, the system will limit the
+     * number of outstanding requests to 100 per app (identified by their UID), shared with
+     * all variants of this method, of {@link #requestNetwork} as well as
+     * {@link ConnectivityDiagnosticsManager#registerConnectivityDiagnosticsCallback}.
+     * Requesting a network with this method will count toward this limit. If this limit is
+     * exceeded, an exception will be thrown. To avoid hitting this issue and to conserve resources,
+     * make sure to unregister the callbacks with
+     * {@link #unregisterNetworkCallback(NetworkCallback)}.
+     *
      * @param request {@link NetworkRequest} describing this request.
      * @param networkCallback The {@link NetworkCallback} that the system will call as suitable
      *                        networks change state.
      *                        The callback is invoked on the default internal Handler.
+     * @throws RuntimeException if the app already has too many callbacks registered.
      */
     @RequiresPermission(android.Manifest.permission.ACCESS_NETWORK_STATE)
     public void registerNetworkCallback(@NonNull NetworkRequest request,
@@ -4047,10 +4055,21 @@
      * either the application exits or {@link #unregisterNetworkCallback(NetworkCallback)} is
      * called.
      *
+     * <p>To avoid performance issues due to apps leaking callbacks, the system will limit the
+     * number of outstanding requests to 100 per app (identified by their UID), shared with
+     * all variants of this method, of {@link #requestNetwork} as well as
+     * {@link ConnectivityDiagnosticsManager#registerConnectivityDiagnosticsCallback}.
+     * Requesting a network with this method will count toward this limit. If this limit is
+     * exceeded, an exception will be thrown. To avoid hitting this issue and to conserve resources,
+     * make sure to unregister the callbacks with
+     * {@link #unregisterNetworkCallback(NetworkCallback)}.
+     *
+     *
      * @param request {@link NetworkRequest} describing this request.
      * @param networkCallback The {@link NetworkCallback} that the system will call as suitable
      *                        networks change state.
      * @param handler {@link Handler} to specify the thread upon which the callback will be invoked.
+     * @throws RuntimeException if the app already has too many callbacks registered.
      */
     @RequiresPermission(android.Manifest.permission.ACCESS_NETWORK_STATE)
     public void registerNetworkCallback(@NonNull NetworkRequest request,
@@ -4084,10 +4103,21 @@
      * <p>
      * The request may be released normally by calling
      * {@link #unregisterNetworkCallback(android.app.PendingIntent)}.
+     *
+     * <p>To avoid performance issues due to apps leaking callbacks, the system will limit the
+     * number of outstanding requests to 100 per app (identified by their UID), shared with
+     * all variants of this method, of {@link #requestNetwork} as well as
+     * {@link ConnectivityDiagnosticsManager#registerConnectivityDiagnosticsCallback}.
+     * Requesting a network with this method will count toward this limit. If this limit is
+     * exceeded, an exception will be thrown. To avoid hitting this issue and to conserve resources,
+     * make sure to unregister the callbacks with {@link #unregisterNetworkCallback(PendingIntent)}
+     * or {@link #releaseNetworkRequest(PendingIntent)}.
+     *
      * @param request {@link NetworkRequest} describing this request.
      * @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 RuntimeException if the app already has too many callbacks registered.
      */
     @RequiresPermission(android.Manifest.permission.ACCESS_NETWORK_STATE)
     public void registerNetworkCallback(@NonNull NetworkRequest request,
@@ -4109,9 +4139,19 @@
      * will continue to be called until either the application exits or
      * {@link #unregisterNetworkCallback(NetworkCallback)} is called.
      *
+     * <p>To avoid performance issues due to apps leaking callbacks, the system will limit the
+     * number of outstanding requests to 100 per app (identified by their UID), shared with
+     * all variants of this method, of {@link #requestNetwork} as well as
+     * {@link ConnectivityDiagnosticsManager#registerConnectivityDiagnosticsCallback}.
+     * Requesting a network with this method will count toward this limit. If this limit is
+     * exceeded, an exception will be thrown. To avoid hitting this issue and to conserve resources,
+     * make sure to unregister the callbacks with
+     * {@link #unregisterNetworkCallback(NetworkCallback)}.
+     *
      * @param networkCallback The {@link NetworkCallback} that the system will call as the
      *                        system default network changes.
      *                        The callback is invoked on the default internal Handler.
+     * @throws RuntimeException if the app already has too many callbacks registered.
      */
     @RequiresPermission(android.Manifest.permission.ACCESS_NETWORK_STATE)
     public void registerDefaultNetworkCallback(@NonNull NetworkCallback networkCallback) {
@@ -4123,9 +4163,19 @@
      * will continue to be called until either the application exits or
      * {@link #unregisterNetworkCallback(NetworkCallback)} is called.
      *
+     * <p>To avoid performance issues due to apps leaking callbacks, the system will limit the
+     * number of outstanding requests to 100 per app (identified by their UID), shared with
+     * all variants of this method, of {@link #requestNetwork} as well as
+     * {@link ConnectivityDiagnosticsManager#registerConnectivityDiagnosticsCallback}.
+     * Requesting a network with this method will count toward this limit. If this limit is
+     * exceeded, an exception will be thrown. To avoid hitting this issue and to conserve resources,
+     * make sure to unregister the callbacks with
+     * {@link #unregisterNetworkCallback(NetworkCallback)}.
+     *
      * @param networkCallback The {@link NetworkCallback} that the system will call as the
      *                        system default network changes.
      * @param handler {@link Handler} to specify the thread upon which the callback will be invoked.
+     * @throws RuntimeException if the app already has too many callbacks registered.
      */
     @RequiresPermission(android.Manifest.permission.ACCESS_NETWORK_STATE)
     public void registerDefaultNetworkCallback(@NonNull NetworkCallback networkCallback,
@@ -4217,7 +4267,6 @@
      *                  Cannot be null.
      */
     public void unregisterNetworkCallback(@NonNull PendingIntent operation) {
-        checkPendingIntentNotNull(operation);
         releaseNetworkRequest(operation);
     }
 
diff --git a/core/java/android/net/NetworkAgent.java b/core/java/android/net/NetworkAgent.java
index 65e772cb..482d2d2 100644
--- a/core/java/android/net/NetworkAgent.java
+++ b/core/java/android/net/NetworkAgent.java
@@ -357,6 +357,7 @@
         final NetworkInfo ni = new NetworkInfo(config.legacyType, config.legacyType,
                 config.legacyTypeName, "");
         ni.setIsAvailable(true);
+        ni.setExtraInfo(config.getLegacyExtraInfo());
         return ni;
     }
 
diff --git a/core/java/android/net/NetworkAgentConfig.java b/core/java/android/net/NetworkAgentConfig.java
index fee868a..fe1268d 100644
--- a/core/java/android/net/NetworkAgentConfig.java
+++ b/core/java/android/net/NetworkAgentConfig.java
@@ -185,6 +185,26 @@
         return legacyTypeName;
     }
 
+    /**
+     * The legacy extra info of the agent. The extra info should only be :
+     * <ul>
+     *   <li>For cellular agents, the APN name.</li>
+     *   <li>For ethernet agents, the interface name.</li>
+     * </ul>
+     * @hide
+     */
+    @NonNull
+    private String mLegacyExtraInfo = "";
+
+    /**
+     * The legacy extra info of the agent.
+     * @hide
+     */
+    @NonNull
+    public String getLegacyExtraInfo() {
+        return mLegacyExtraInfo;
+    }
+
     /** @hide */
     public NetworkAgentConfig() {
     }
@@ -201,6 +221,7 @@
             skip464xlat = nac.skip464xlat;
             legacyType = nac.legacyType;
             legacyTypeName = nac.legacyTypeName;
+            mLegacyExtraInfo = nac.mLegacyExtraInfo;
         }
     }
 
@@ -309,6 +330,18 @@
         }
 
         /**
+         * Sets the legacy extra info of the agent.
+         * @param legacyExtraInfo the legacy extra info.
+         * @return this builder, to facilitate chaining.
+         * @hide
+         */
+        @NonNull
+        public Builder setLegacyExtraInfo(@NonNull String legacyExtraInfo) {
+            mConfig.mLegacyExtraInfo = legacyExtraInfo;
+            return this;
+        }
+
+        /**
          * Returns the constructed {@link NetworkAgentConfig} object.
          */
         @NonNull
@@ -330,14 +363,15 @@
                 && skip464xlat == that.skip464xlat
                 && legacyType == that.legacyType
                 && Objects.equals(subscriberId, that.subscriberId)
-                && Objects.equals(legacyTypeName, that.legacyTypeName);
+                && Objects.equals(legacyTypeName, that.legacyTypeName)
+                && Objects.equals(mLegacyExtraInfo, that.mLegacyExtraInfo);
     }
 
     @Override
     public int hashCode() {
         return Objects.hash(allowBypass, explicitlySelected, acceptUnvalidated,
                 acceptPartialConnectivity, provisioningNotificationDisabled, subscriberId,
-                skip464xlat, legacyType, legacyTypeName);
+                skip464xlat, legacyType, legacyTypeName, mLegacyExtraInfo);
     }
 
     @Override
@@ -353,6 +387,7 @@
                 + ", legacyType = " + legacyType
                 + ", hasShownBroken = " + hasShownBroken
                 + ", legacyTypeName = '" + legacyTypeName + '\''
+                + ", legacyExtraInfo = '" + mLegacyExtraInfo + '\''
                 + "}";
     }
 
@@ -372,6 +407,7 @@
         out.writeInt(skip464xlat ? 1 : 0);
         out.writeInt(legacyType);
         out.writeString(legacyTypeName);
+        out.writeString(mLegacyExtraInfo);
     }
 
     public static final @NonNull Creator<NetworkAgentConfig> CREATOR =
@@ -388,6 +424,7 @@
             networkAgentConfig.skip464xlat = in.readInt() != 0;
             networkAgentConfig.legacyType = in.readInt();
             networkAgentConfig.legacyTypeName = in.readString();
+            networkAgentConfig.mLegacyExtraInfo = in.readString();
             return networkAgentConfig;
         }
 
diff --git a/core/java/android/os/UserManager.java b/core/java/android/os/UserManager.java
index a8391c2..a415dc5 100644
--- a/core/java/android/os/UserManager.java
+++ b/core/java/android/os/UserManager.java
@@ -4095,14 +4095,14 @@
     }
 
     /**
-     * Returns true if the user switcher should be shown.
-     * I.e., returns whether the user switcher is enabled and there is something actionable to show.
+     * Returns true if the user switcher is enabled (regardless of whether there is anything
+     * interesting for it to show).
      *
-     * @return true if user switcher should be shown.
+     * @return true if user switcher is enabled
      * @hide
      */
     public boolean isUserSwitcherEnabled() {
-        return isUserSwitcherEnabled(false);
+        return isUserSwitcherEnabled(true);
     }
 
     /**
diff --git a/core/java/android/os/VibrationEffect.java b/core/java/android/os/VibrationEffect.java
index fd7cdda..0625457 100644
--- a/core/java/android/os/VibrationEffect.java
+++ b/core/java/android/os/VibrationEffect.java
@@ -221,15 +221,16 @@
      *
      * Waveform vibrations are a potentially repeating series of timing and amplitude pairs. For
      * each pair, the value in the amplitude array determines the strength of the vibration and the
-     * value in the timing array determines how long it vibrates for. An amplitude of 0 implies no
-     * vibration (i.e. off), and any pairs with a timing value of 0 will be ignored.
+     * value in the timing array determines how long it vibrates for, in milliseconds. Amplitude
+     * values must be between 0 and 255, and an amplitude of 0 implies no vibration (i.e. off). Any
+     * pairs with a timing value of 0 will be ignored.
      * </p><p>
      * To cause the pattern to repeat, pass the index into the timings array at which to start the
      * repetition, or -1 to disable repeating.
      * </p>
      *
-     * @param timings The timing values of the timing / amplitude pairs. Timing values of 0
-     *                will cause the pair to be ignored.
+     * @param timings The timing values, in milliseconds, of the timing / amplitude pairs. Timing
+     *                values of 0 will cause the pair to be ignored.
      * @param amplitudes The amplitude values of the timing / amplitude pairs. Amplitude values
      *                   must be between 0 and 255, or equal to {@link #DEFAULT_AMPLITUDE}. An
      *                   amplitude value of 0 implies the motor is off.
diff --git a/core/java/android/os/incremental/IIncrementalService.aidl b/core/java/android/os/incremental/IIncrementalService.aidl
index 220ce22..61e6a05 100644
--- a/core/java/android/os/incremental/IIncrementalService.aidl
+++ b/core/java/android/os/incremental/IIncrementalService.aidl
@@ -111,6 +111,11 @@
     void deleteStorage(int storageId);
 
     /**
+     * Permanently disable readlogs reporting for a storage given its ID.
+     */
+    void disableReadLogs(int storageId);
+
+    /**
      * Setting up native library directories and extract native libs onto a storage if needed.
      */
     boolean configureNativeBinaries(int storageId, in @utf8InCpp String apkFullPath, in @utf8InCpp String libDirRelativePath, in @utf8InCpp String abi, boolean extractNativeLibs);
diff --git a/core/java/android/os/incremental/IncrementalFileStorages.java b/core/java/android/os/incremental/IncrementalFileStorages.java
index 863d86ef..31ccf95 100644
--- a/core/java/android/os/incremental/IncrementalFileStorages.java
+++ b/core/java/android/os/incremental/IncrementalFileStorages.java
@@ -153,6 +153,13 @@
     }
 
     /**
+     * Permanently disables readlogs.
+     */
+    public void disableReadLogs() {
+        mDefaultStorage.disableReadLogs();
+    }
+
+    /**
      * Resets the states and unbinds storage instances for an installation session.
      * TODO(b/136132412): make sure unnecessary binds are removed but useful storages are kept
      */
diff --git a/core/java/android/os/incremental/IncrementalStorage.java b/core/java/android/os/incremental/IncrementalStorage.java
index 6200a38..ca6114f 100644
--- a/core/java/android/os/incremental/IncrementalStorage.java
+++ b/core/java/android/os/incremental/IncrementalStorage.java
@@ -418,6 +418,17 @@
     private static final int INCFS_MAX_ADD_DATA_SIZE = 128;
 
     /**
+     * Permanently disable readlogs collection.
+     */
+    public void disableReadLogs() {
+        try {
+            mService.disableReadLogs(mId);
+        } catch (RemoteException e) {
+            e.rethrowFromSystemServer();
+        }
+    }
+
+    /**
      * Deserialize and validate v4 signature bytes.
      */
     private static void validateV4Signature(@Nullable byte[] v4signatureBytes)
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index e10fcea..4f0a972 100755
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -24,6 +24,7 @@
 import android.annotation.RequiresPermission;
 import android.annotation.SdkConstant;
 import android.annotation.SdkConstant.SdkConstantType;
+import android.annotation.SuppressLint;
 import android.annotation.SystemApi;
 import android.annotation.TestApi;
 import android.annotation.UserIdInt;
@@ -6238,6 +6239,8 @@
          * determines if the IME should be shown when a hard keyboard is attached.
          * @hide
          */
+        @TestApi
+        @SuppressLint("NoSettingsProvider")
         public static final String SHOW_IME_WITH_HARD_KEYBOARD = "show_ime_with_hard_keyboard";
 
         /**
diff --git a/core/java/android/service/autofill/augmented/FillCallback.java b/core/java/android/service/autofill/augmented/FillCallback.java
index 21738d80..8ba5c17 100644
--- a/core/java/android/service/autofill/augmented/FillCallback.java
+++ b/core/java/android/service/autofill/augmented/FillCallback.java
@@ -62,9 +62,10 @@
 
         List<Dataset> inlineSuggestions = response.getInlineSuggestions();
         Bundle clientState = response.getClientState();
+        // We need to report result regardless of whether inline suggestions are returned or not.
+        mProxy.reportResult(inlineSuggestions, clientState);
         if (inlineSuggestions != null && !inlineSuggestions.isEmpty()) {
             mProxy.logEvent(AutofillProxy.REPORT_EVENT_INLINE_RESPONSE);
-            mProxy.reportResult(inlineSuggestions, clientState);
             return;
         }
 
diff --git a/core/java/android/service/controls/templates/ControlTemplate.java b/core/java/android/service/controls/templates/ControlTemplate.java
index 1e16273..e592fad 100644
--- a/core/java/android/service/controls/templates/ControlTemplate.java
+++ b/core/java/android/service/controls/templates/ControlTemplate.java
@@ -214,10 +214,13 @@
     }
 
     /**
-     * Get a singleton {@link ControlTemplate} that has no features.
+     * Get a singleton {@link ControlTemplate}, which supports no direct user input.
      *
-     * This template has no distinctive field, not even an identifier. Used for a {@link Control}
-     * that accepts no type of input, or when there is no known state.
+     * Used by {@link Control.StatelessBuilder} when there is no known state. Can also be used
+     * in {@link Control.StatefulBuilder} for conveying information to a user about the
+     * {@link Control} but direct user interaction is not desired. Since this template has no
+     * corresponding {@link ControlAction}, any user interaction will launch the
+     * {@link Control#getAppIntent()}.
      *
      * @return a singleton {@link ControlTemplate} to indicate no specific template is used by
      *         this {@link Control}
diff --git a/core/java/android/service/notification/ZenModeConfig.java b/core/java/android/service/notification/ZenModeConfig.java
index 1f6555c..0827fef 100644
--- a/core/java/android/service/notification/ZenModeConfig.java
+++ b/core/java/android/service/notification/ZenModeConfig.java
@@ -78,6 +78,7 @@
     private static final int DEFAULT_SOURCE = SOURCE_CONTACT;
     private static final int DEFAULT_CALLS_SOURCE = SOURCE_STAR;
 
+    public static final String MANUAL_RULE_ID = "MANUAL_RULE";
     public static final String EVENTS_DEFAULT_RULE_ID = "EVENTS_DEFAULT_RULE";
     public static final String EVERY_NIGHT_DEFAULT_RULE_ID = "EVERY_NIGHT_DEFAULT_RULE";
     public static final List<String> DEFAULT_RULE_IDS = Arrays.asList(EVERY_NIGHT_DEFAULT_RULE_ID,
@@ -959,6 +960,48 @@
     };
 
     /**
+     * Converts a ZenModeConfig to a ZenPolicy
+     */
+    public ZenPolicy toZenPolicy() {
+        ZenPolicy.Builder builder = new ZenPolicy.Builder()
+                .allowCalls(allowCalls
+                        ? ZenModeConfig.getZenPolicySenders(allowCallsFrom)
+                        : ZenPolicy.PEOPLE_TYPE_NONE)
+                .allowRepeatCallers(allowRepeatCallers)
+                .allowMessages(allowMessages
+                        ? ZenModeConfig.getZenPolicySenders(allowMessagesFrom)
+                        : ZenPolicy.PEOPLE_TYPE_NONE)
+                .allowReminders(allowReminders)
+                .allowEvents(allowEvents)
+                .allowAlarms(allowAlarms)
+                .allowMedia(allowMedia)
+                .allowSystem(allowSystem)
+                .allowConversations(allowConversations
+                        ? ZenModeConfig.getZenPolicySenders(allowConversationsFrom)
+                        : ZenPolicy.PEOPLE_TYPE_NONE);
+        if (suppressedVisualEffects == 0) {
+            builder.showAllVisualEffects();
+        } else {
+            // configs don't have an unset state: wither true or false.
+            builder.showFullScreenIntent(
+                    (suppressedVisualEffects & Policy.SUPPRESSED_EFFECT_FULL_SCREEN_INTENT) == 0);
+            builder.showLights(
+                    (suppressedVisualEffects & SUPPRESSED_EFFECT_LIGHTS) == 0);
+            builder.showPeeking(
+                    (suppressedVisualEffects & SUPPRESSED_EFFECT_PEEK) == 0);
+            builder.showStatusBarIcons(
+                    (suppressedVisualEffects & Policy.SUPPRESSED_EFFECT_STATUS_BAR) == 0);
+            builder.showBadges(
+                    (suppressedVisualEffects & Policy.SUPPRESSED_EFFECT_BADGE) == 0);
+            builder.showInAmbientDisplay(
+                    (suppressedVisualEffects & Policy.SUPPRESSED_EFFECT_AMBIENT) == 0);
+            builder.showInNotificationList(
+                    (suppressedVisualEffects & Policy.SUPPRESSED_EFFECT_NOTIFICATION_LIST) == 0);
+        }
+        return builder.build();
+    }
+
+    /**
      * Converts a zenPolicy to a notificationPolicy using this ZenModeConfig's values as its
      * defaults for all unset values in zenPolicy
      */
diff --git a/core/java/android/service/notification/ZenPolicy.java b/core/java/android/service/notification/ZenPolicy.java
index 87295e1..6d0bcff 100644
--- a/core/java/android/service/notification/ZenPolicy.java
+++ b/core/java/android/service/notification/ZenPolicy.java
@@ -24,6 +24,7 @@
 import android.os.Parcelable;
 import android.util.proto.ProtoOutputStream;
 
+import java.io.ByteArrayOutputStream;
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
 import java.util.ArrayList;
@@ -1111,6 +1112,40 @@
     }
 
     /**
+     * Converts a policy to a statsd proto.
+     * @hides
+     */
+    public byte[] toProto() {
+        ByteArrayOutputStream bytes = new ByteArrayOutputStream();
+        ProtoOutputStream proto = new ProtoOutputStream(bytes);
+
+        proto.write(DNDPolicyProto.CALLS, getPriorityCategoryCalls());
+        proto.write(DNDPolicyProto.REPEAT_CALLERS, getPriorityCategoryRepeatCallers());
+        proto.write(DNDPolicyProto.MESSAGES, getPriorityCategoryMessages());
+        proto.write(DNDPolicyProto.CONVERSATIONS, getPriorityCategoryConversations());
+        proto.write(DNDPolicyProto.REMINDERS, getPriorityCategoryReminders());
+        proto.write(DNDPolicyProto.EVENTS, getPriorityCategoryEvents());
+        proto.write(DNDPolicyProto.ALARMS, getPriorityCategoryAlarms());
+        proto.write(DNDPolicyProto.MEDIA, getPriorityCategoryMedia());
+        proto.write(DNDPolicyProto.SYSTEM, getPriorityCategorySystem());
+
+        proto.write(DNDPolicyProto.FULLSCREEN, getVisualEffectFullScreenIntent());
+        proto.write(DNDPolicyProto.LIGHTS, getVisualEffectLights());
+        proto.write(DNDPolicyProto.PEEK, getVisualEffectPeek());
+        proto.write(DNDPolicyProto.STATUS_BAR, getVisualEffectStatusBar());
+        proto.write(DNDPolicyProto.BADGE, getVisualEffectBadge());
+        proto.write(DNDPolicyProto.AMBIENT, getVisualEffectAmbient());
+        proto.write(DNDPolicyProto.NOTIFICATION_LIST, getVisualEffectNotificationList());
+
+        proto.write(DNDPolicyProto.ALLOW_CALLS_FROM, getPriorityCallSenders());
+        proto.write(DNDPolicyProto.ALLOW_MESSAGES_FROM, getPriorityMessageSenders());
+        proto.write(DNDPolicyProto.ALLOW_CONVERSATIONS_FROM, getPriorityConversationSenders());
+
+        proto.flush();
+        return bytes.toByteArray();
+    }
+
+    /**
      * Makes deep copy of this ZenPolicy.
      * @hide
      */
diff --git a/core/java/android/telephony/PhoneStateListener.java b/core/java/android/telephony/PhoneStateListener.java
index 9b293eb..4adcd69 100644
--- a/core/java/android/telephony/PhoneStateListener.java
+++ b/core/java/android/telephony/PhoneStateListener.java
@@ -157,8 +157,8 @@
      * Listen for changes to the device's cell location. Note that
      * this will result in frequent callbacks to the listener.
      * {@more}
-     * Requires Permission: {@link android.Manifest.permission#ACCESS_COARSE_LOCATION
-     * ACCESS_COARSE_LOCATION}
+     * Requires Permission: {@link android.Manifest.permission#ACCESS_FINE_LOCATION
+     * ACCESS_FINE_LOCATION}
      * <p>
      * If you need regular location updates but want more control over
      * the update interval or location precision, you can set up a listener
@@ -219,6 +219,9 @@
     /**
      * Listen for changes to observed cell info.
      *
+     * Listening to this event requires the {@link Manifest.permission#ACCESS_FINE_LOCATION}
+     * permission.
+     *
      * @see #onCellInfoChanged
      */
     public static final int LISTEN_CELL_INFO = 0x00000400;
@@ -461,6 +464,9 @@
      * <p>Requires permission {@link android.Manifest.permission#READ_PRECISE_PHONE_STATE} or
      * the calling app has carrier privileges (see {@link TelephonyManager#hasCarrierPrivileges}).
      *
+     * <p>Also requires the {@link Manifest.permission#ACCESS_FINE_LOCATION} permission, regardless
+     * of whether the calling app has carrier privileges.
+     *
      * @see #onRegistrationFailed
      */
     @RequiresPermission(Manifest.permission.READ_PRECISE_PHONE_STATE)
@@ -472,6 +478,9 @@
      * <p>Requires permission {@link android.Manifest.permission#READ_PRECISE_PHONE_STATE} or
      * the calling app has carrier privileges (see {@link TelephonyManager#hasCarrierPrivileges}).
      *
+     * <p>Also requires the {@link Manifest.permission#ACCESS_FINE_LOCATION} permission, regardless
+     * of whether the calling app has carrier privileges.
+     *
      * @see #onBarringInfoChanged
      */
     @RequiresPermission(Manifest.permission.READ_PRECISE_PHONE_STATE)
@@ -569,6 +578,11 @@
      * subId. Otherwise, this callback applies to
      * {@link SubscriptionManager#getDefaultSubscriptionId()}.
      *
+     * The instance of {@link ServiceState} passed as an argument here will have various levels of
+     * location information stripped from it depending on the location permissions that your app
+     * holds. Only apps holding the {@link Manifest.permission#ACCESS_FINE_LOCATION} permission will
+     * receive all the information in {@link ServiceState}.
+     *
      * @see ServiceState#STATE_EMERGENCY_ONLY
      * @see ServiceState#STATE_IN_SERVICE
      * @see ServiceState#STATE_OUT_OF_SERVICE
diff --git a/core/java/android/view/ImeFocusController.java b/core/java/android/view/ImeFocusController.java
index a480072..825077ff 100644
--- a/core/java/android/view/ImeFocusController.java
+++ b/core/java/android/view/ImeFocusController.java
@@ -125,6 +125,13 @@
         final View viewForWindowFocus = focusedView != null ? focusedView : mViewRootImpl.mView;
         onViewFocusChanged(viewForWindowFocus, true);
 
+        // Skip starting input when the next focused view is same as served view and the served
+        // input connection still exists.
+        final boolean nextFocusIsServedView = mServedView != null && mServedView == focusedView;
+        if (nextFocusIsServedView && immDelegate.isAcceptingText()) {
+            forceFocus = false;
+        }
+
         immDelegate.startInputAsyncOnWindowFocusGain(viewForWindowFocus,
                 windowAttribute.softInputMode, windowAttribute.flags, forceFocus);
     }
@@ -247,6 +254,7 @@
         void setCurrentRootView(ViewRootImpl rootView);
         boolean isCurrentRootView(ViewRootImpl rootView);
         boolean isRestartOnNextWindowFocus(boolean reset);
+        boolean isAcceptingText();
     }
 
     public View getServedView() {
diff --git a/core/java/android/view/InsetsController.java b/core/java/android/view/InsetsController.java
index 57a0c4f..8a21543 100644
--- a/core/java/android/view/InsetsController.java
+++ b/core/java/android/view/InsetsController.java
@@ -581,21 +581,23 @@
 
     @VisibleForTesting
     public boolean onStateChanged(InsetsState state) {
-        boolean localStateChanged = !mState.equals(state, true /* excludingCaptionInsets */)
+        boolean stateChanged = !mState.equals(state, true /* excludingCaptionInsets */,
+                        false /* excludeInvisibleIme */)
                 || !captionInsetsUnchanged();
-        if (!localStateChanged && mLastDispatchedState.equals(state)) {
+        if (!stateChanged && mLastDispatchedState.equals(state)) {
             return false;
         }
         if (DEBUG) Log.d(TAG, "onStateChanged: " + state);
         updateState(state);
+
+        boolean localStateChanged = !mState.equals(mLastDispatchedState,
+                true /* excludingCaptionInsets */, true /* excludeInvisibleIme */);
         mLastDispatchedState.set(state, true /* copySources */);
+
         applyLocalVisibilityOverride();
         if (localStateChanged) {
-            if (DEBUG) Log.d(TAG, "onStateChanged, notifyInsetsChanged");
+            if (DEBUG) Log.d(TAG, "onStateChanged, notifyInsetsChanged, send state to WM: " + mState);
             mHost.notifyInsetsChanged();
-        }
-        if (!mState.equals(mLastDispatchedState, true /* excludingCaptionInsets */)) {
-            if (DEBUG) Log.d(TAG, "onStateChanged, send state to WM: " + mState);
             updateRequestedState();
         }
         return true;
@@ -832,7 +834,7 @@
             WindowInsetsAnimationControlListener listener,
             boolean fromIme, long durationMs, @Nullable Interpolator interpolator,
             @AnimationType int animationType) {
-        if (!checkDisplayFramesForControlling()) {
+        if ((mState.calculateUncontrollableInsetsFromFrame(mFrame) & types) != 0) {
             listener.onCancelled(null);
             return;
         }
@@ -842,13 +844,6 @@
                 false /* useInsetsAnimationThread */);
     }
 
-    private boolean checkDisplayFramesForControlling() {
-
-        // If the frame of our window doesn't span the entire display, the control API makes very
-        // little sense, as we don't deal with negative insets. So just cancel immediately.
-        return mState.getDisplayFrame().equals(mFrame);
-    }
-
     private void controlAnimationUnchecked(@InsetsType int types,
             @Nullable CancellationSignal cancellationSignal,
             WindowInsetsAnimationControlListener listener, Rect frame, boolean fromIme,
@@ -1335,9 +1330,6 @@
     }
 
     private @InsetsType int calculateControllableTypes() {
-        if (!checkDisplayFramesForControlling()) {
-            return 0;
-        }
         @InsetsType int result = 0;
         for (int i = mSourceConsumers.size() - 1; i >= 0; i--) {
             InsetsSourceConsumer consumer = mSourceConsumers.valueAt(i);
@@ -1346,7 +1338,7 @@
                 result |= toPublicType(consumer.mType);
             }
         }
-        return result;
+        return result & ~mState.calculateUncontrollableInsetsFromFrame(mFrame);
     }
 
     /**
diff --git a/core/java/android/view/InsetsSource.java b/core/java/android/view/InsetsSource.java
index c40518b..c8394d2 100644
--- a/core/java/android/view/InsetsSource.java
+++ b/core/java/android/view/InsetsSource.java
@@ -195,6 +195,14 @@
 
     @Override
     public boolean equals(Object o) {
+        return equals(o, false);
+    }
+
+    /**
+     * @param excludeInvisibleImeFrames If {@link InsetsState#ITYPE_IME} frames should be ignored
+     *                                  when IME is not visible.
+     */
+    public boolean equals(Object o, boolean excludeInvisibleImeFrames) {
         if (this == o) return true;
         if (o == null || getClass() != o.getClass()) return false;
 
@@ -202,6 +210,7 @@
 
         if (mType != that.mType) return false;
         if (mVisible != that.mVisible) return false;
+        if (excludeInvisibleImeFrames && !mVisible && mType == ITYPE_IME) return true;
         if (!Objects.equals(mVisibleFrame, that.mVisibleFrame)) return false;
         return mFrame.equals(that.mFrame);
     }
diff --git a/core/java/android/view/InsetsSourceConsumer.java b/core/java/android/view/InsetsSourceConsumer.java
index 4dc20b0..8d92d7b 100644
--- a/core/java/android/view/InsetsSourceConsumer.java
+++ b/core/java/android/view/InsetsSourceConsumer.java
@@ -221,9 +221,10 @@
         final boolean hasControl = mSourceControl != null;
 
         // We still need to let the legacy app know the visibility change even if we don't have the
-        // control.
+        // control. If we don't have the source, we don't change the requested visibility for making
+        // the callback behavior compatible.
         mController.updateCompatSysUiVisibility(
-                mType, hasControl ? mRequestedVisible : isVisible, hasControl);
+                mType, (hasControl || source == null) ? mRequestedVisible : isVisible, hasControl);
 
         // If we don't have control, we are not able to change the visibility.
         if (!hasControl) {
diff --git a/core/java/android/view/InsetsState.java b/core/java/android/view/InsetsState.java
index 3822ee5..17620fa 100644
--- a/core/java/android/view/InsetsState.java
+++ b/core/java/android/view/InsetsState.java
@@ -245,6 +245,44 @@
         return insets.toRect();
     }
 
+    /**
+     * Calculate which insets *cannot* be controlled, because the frame does not cover the
+     * respective side of the inset.
+     *
+     * If the frame of our window doesn't cover the entire inset, the control API makes very
+     * little sense, as we don't deal with negative insets.
+     */
+    @InsetsType
+    public int calculateUncontrollableInsetsFromFrame(Rect frame) {
+        int blocked = 0;
+        for (int type = FIRST_TYPE; type <= LAST_TYPE; type++) {
+            InsetsSource source = mSources.get(type);
+            if (source == null) {
+                continue;
+            }
+            if (!canControlSide(frame, getInsetSide(
+                    source.calculateInsets(frame, true /* ignoreVisibility */)))) {
+                blocked |= toPublicType(type);
+            }
+        }
+        return blocked;
+    }
+
+    private boolean canControlSide(Rect frame, int side) {
+        switch (side) {
+            case ISIDE_LEFT:
+            case ISIDE_RIGHT:
+                return frame.left == mDisplayFrame.left && frame.right == mDisplayFrame.right;
+            case ISIDE_TOP:
+            case ISIDE_BOTTOM:
+                return frame.top == mDisplayFrame.top && frame.bottom == mDisplayFrame.bottom;
+            case ISIDE_FLOATING:
+                return true;
+            default:
+                return false;
+        }
+    }
+
     private void processSource(InsetsSource source, Rect relativeFrame, boolean ignoreVisibility,
             Insets[] typeInsetsMap, @Nullable @InternalInsetsSide SparseIntArray typeSideMap,
             @Nullable boolean[] typeVisibilityMap) {
@@ -319,6 +357,19 @@
         return mSources.get(type);
     }
 
+    /**
+     * Returns the source visibility or the default visibility if the source doesn't exist. This is
+     * useful if when treating this object as a request.
+     *
+     * @param type The {@link InternalInsetsType} to query.
+     * @return {@code true} if the source is visible or the type is default visible and the source
+     *         doesn't exist.
+     */
+    public boolean getSourceOrDefaultVisibility(@InternalInsetsType int type) {
+        final InsetsSource source = mSources.get(type);
+        return source != null ? source.isVisible() : getDefaultVisibility(type);
+    }
+
     public void setDisplayFrame(Rect frame) {
         mDisplayFrame.set(frame);
     }
@@ -350,20 +401,6 @@
         }
     }
 
-    /**
-     * A shortcut for setting the visibility of the source.
-     *
-     * @param type The {@link InternalInsetsType} of the source to set the visibility
-     * @param referenceState The {@link InsetsState} for reference
-     */
-    public void setSourceVisible(@InternalInsetsType int type, InsetsState referenceState) {
-        InsetsSource source = mSources.get(type);
-        InsetsSource referenceSource = referenceState.mSources.get(type);
-        if (source != null && referenceSource != null) {
-            source.setVisible(referenceSource.isVisible());
-        }
-    }
-
     public void set(InsetsState other) {
         set(other, false /* copySources */);
     }
@@ -452,7 +489,7 @@
         }
     }
 
-    public static boolean getDefaultVisibility(@InsetsType int type) {
+    public static boolean getDefaultVisibility(@InternalInsetsType int type) {
         return type != ITYPE_IME;
     }
 
@@ -517,7 +554,7 @@
 
     @Override
     public boolean equals(Object o) {
-        return equals(o, false);
+        return equals(o, false, false);
     }
 
     /**
@@ -526,10 +563,13 @@
      * excluded.
      * @param excludingCaptionInsets {@code true} if we want to compare two InsetsState objects but
      *                                           ignore the caption insets source value.
+     * @param excludeInvisibleImeFrames If {@link #ITYPE_IME} frames should be ignored when IME is
+     *                                  not visible.
      * @return {@code true} if the two InsetsState objects are equal, {@code false} otherwise.
      */
     @VisibleForTesting
-    public boolean equals(Object o, boolean excludingCaptionInsets) {
+    public boolean equals(Object o, boolean excludingCaptionInsets,
+            boolean excludeInvisibleImeFrames) {
         if (this == o) { return true; }
         if (o == null || getClass() != o.getClass()) { return false; }
 
@@ -560,7 +600,7 @@
             if (otherSource == null) {
                 return false;
             }
-            if (!otherSource.equals(source)) {
+            if (!otherSource.equals(source, excludeInvisibleImeFrames)) {
                 return false;
             }
         }
diff --git a/core/java/android/view/SurfaceView.java b/core/java/android/view/SurfaceView.java
index 57f91ed..c098fae 100644
--- a/core/java/android/view/SurfaceView.java
+++ b/core/java/android/view/SurfaceView.java
@@ -893,12 +893,15 @@
             }
             return;
         }
-        ViewRootImpl viewRoot = getViewRootImpl();
-        if (viewRoot == null || viewRoot.mSurface == null || !viewRoot.mSurface.isValid()) {
-            if (DEBUG) {
-                Log.d(TAG, System.identityHashCode(this)
-                        + " updateSurface: no valid surface");
-            }
+        final ViewRootImpl viewRoot = getViewRootImpl();
+
+        if (viewRoot == null) {
+            return;
+        }
+
+        if (viewRoot.mSurface == null || !viewRoot.mSurface.isValid()) {
+            notifySurfaceDestroyed();
+            releaseSurfaces();
             return;
         }
 
@@ -1109,28 +1112,7 @@
                     final boolean surfaceChanged = creating;
                     if (mSurfaceCreated && (surfaceChanged || (!visible && visibleChanged))) {
                         mSurfaceCreated = false;
-                        if (mSurface.isValid()) {
-                            if (DEBUG) Log.i(TAG, System.identityHashCode(this) + " "
-                                    + "visibleChanged -- surfaceDestroyed");
-                            callbacks = getSurfaceCallbacks();
-                            for (SurfaceHolder.Callback c : callbacks) {
-                                c.surfaceDestroyed(mSurfaceHolder);
-                            }
-                            // Since Android N the same surface may be reused and given to us
-                            // again by the system server at a later point. However
-                            // as we didn't do this in previous releases, clients weren't
-                            // necessarily required to clean up properly in
-                            // surfaceDestroyed. This leads to problems for example when
-                            // clients don't destroy their EGL context, and try
-                            // and create a new one on the same surface following reuse.
-                            // Since there is no valid use of the surface in-between
-                            // surfaceDestroyed and surfaceCreated, we force a disconnect,
-                            // so the next connect will always work if we end up reusing
-                            // the surface.
-                            if (mSurface.isValid()) {
-                                mSurface.forceScopedDisconnect();
-                            }
-                        }
+                        notifySurfaceDestroyed();
                     }
 
                     if (creating) {
@@ -1786,6 +1768,31 @@
         }
     }
 
+    private void notifySurfaceDestroyed() {
+        if (mSurface.isValid()) {
+            if (DEBUG) Log.i(TAG, System.identityHashCode(this) + " "
+                    + "surfaceDestroyed");
+            SurfaceHolder.Callback[] callbacks = getSurfaceCallbacks();
+            for (SurfaceHolder.Callback c : callbacks) {
+                c.surfaceDestroyed(mSurfaceHolder);
+            }
+            // Since Android N the same surface may be reused and given to us
+            // again by the system server at a later point. However
+            // as we didn't do this in previous releases, clients weren't
+            // necessarily required to clean up properly in
+            // surfaceDestroyed. This leads to problems for example when
+            // clients don't destroy their EGL context, and try
+            // and create a new one on the same surface following reuse.
+            // Since there is no valid use of the surface in-between
+            // surfaceDestroyed and surfaceCreated, we force a disconnect,
+            // so the next connect will always work if we end up reusing
+            // the surface.
+            if (mSurface.isValid()) {
+                mSurface.forceScopedDisconnect();
+            }
+        }
+    }
+
     /**
      * Wrapper of accessibility embedded connection for embedded view hierarchy.
      */
diff --git a/core/java/android/view/WindowlessWindowManager.java b/core/java/android/view/WindowlessWindowManager.java
index a5ec4e9..d2e506e 100644
--- a/core/java/android/view/WindowlessWindowManager.java
+++ b/core/java/android/view/WindowlessWindowManager.java
@@ -41,7 +41,6 @@
     private final static String TAG = "WindowlessWindowManager";
 
     private class State {
-        //TODO : b/150190730 we should create it when view show and release it when view invisible.
         SurfaceControl mSurfaceControl;
         WindowManager.LayoutParams mParams = new WindowManager.LayoutParams();
         int mDisplayId;
diff --git a/core/java/android/view/accessibility/AccessibilityNodeInfo.java b/core/java/android/view/accessibility/AccessibilityNodeInfo.java
index eaaaa80..214da38 100644
--- a/core/java/android/view/accessibility/AccessibilityNodeInfo.java
+++ b/core/java/android/view/accessibility/AccessibilityNodeInfo.java
@@ -635,7 +635,7 @@
             "android.view.accessibility.extra.DATA_TEXT_CHARACTER_LOCATION_ARG_LENGTH";
 
     /**
-     * Key used to request extra data for accessibility scanning tool's purposes.
+     * Key used to request extra data for the rendering information.
      * The key requests that a {@link AccessibilityNodeInfo.ExtraRenderingInfo} be added to this
      * info. This request is made with {@link #refreshWithExtraData(String, Bundle)} without
      * argument.
@@ -5847,12 +5847,15 @@
         }
 
         /**
-         * Gets the size object containing the height and the width of layout params if the node is
-         * a {@link ViewGroup} or a {@link TextView}, or null otherwise. Useful for accessibility
-         * scanning tool to understand whether the text is scalable and fits the view or not.
+         * Gets the size object containing the height and the width of
+         * {@link android.view.ViewGroup.LayoutParams}  if the node is a {@link ViewGroup} or
+         * a {@link TextView}, or null otherwise. Useful for some accessibility services to
+         * understand whether the text is scalable and fits the view or not.
          *
-         * @return a {@link Size} stores layout height and layout width of the view,
-         *         or null otherwise.
+         * @return a {@link Size} stores layout height and layout width of the view, or null
+         * otherwise. And the size value may be in pixels,
+         * {@link android.view.ViewGroup.LayoutParams#MATCH_PARENT},
+         * or {@link android.view.ViewGroup.LayoutParams#WRAP_CONTENT}
          */
         public @Nullable Size getLayoutSize() {
             return mLayoutSize;
@@ -5870,9 +5873,9 @@
         }
 
         /**
-         * Gets the text size if the node is a {@link TextView}, or -1 otherwise.  Useful for
-         * accessibility scanning tool to understand whether the text is scalable and fits the view
-         * or not.
+         * Gets the text size if the node is a {@link TextView}, or -1 otherwise. Useful for some
+         * accessibility services to understand whether the text is scalable and fits the view or
+         * not.
          *
          * @return the text size of a {@code TextView}, or -1 otherwise.
          */
@@ -5893,7 +5896,7 @@
         /**
          * Gets the text size unit if the node is a {@link TextView}, or -1 otherwise.
          * Text size returned from {@link #getTextSizeInPx} in raw pixels may scale by factors and
-         * convert from other units. Useful for accessibility scanning tool to understand whether
+         * convert from other units. Useful for some accessibility services to understand whether
          * the text is scalable and fits the view or not.
          *
          * @return the text size unit which type is {@link TypedValue#TYPE_DIMENSION} of a
diff --git a/core/java/android/view/autofill/AutofillManager.java b/core/java/android/view/autofill/AutofillManager.java
index 3112039..fbfeda6 100644
--- a/core/java/android/view/autofill/AutofillManager.java
+++ b/core/java/android/view/autofill/AutofillManager.java
@@ -751,6 +751,8 @@
                         }
                     } catch (RemoteException e) {
                         Log.e(TAG, "Could not figure out if there was an autofill session", e);
+                    } catch (SyncResultReceiver.TimeoutException e) {
+                        Log.e(TAG, "Fail to get session restore status: " + e);
                     }
                 }
             }
@@ -864,7 +866,9 @@
             mService.getFillEventHistory(receiver);
             return receiver.getParcelableResult();
         } catch (RemoteException e) {
-            e.rethrowFromSystemServer();
+            throw e.rethrowFromSystemServer();
+        } catch (SyncResultReceiver.TimeoutException e) {
+            Log.e(TAG, "Fail to get fill event history: " + e);
             return null;
         }
     }
@@ -1477,10 +1481,13 @@
 
         final SyncResultReceiver receiver = new SyncResultReceiver(SYNC_CALLS_TIMEOUT_MS);
         try {
-            mService.isServiceEnabled(mContext.getUserId(), mContext.getPackageName(), receiver);
+            mService.isServiceEnabled(mContext.getUserId(), mContext.getPackageName(),
+                    receiver);
             return receiver.getIntResult() == 1;
         } catch (RemoteException e) {
             throw e.rethrowFromSystemServer();
+        } catch (SyncResultReceiver.TimeoutException e) {
+            throw new RuntimeException("Fail to get enabled autofill services status.");
         }
     }
 
@@ -1498,6 +1505,8 @@
             return receiver.getParcelableResult();
         } catch (RemoteException e) {
             throw e.rethrowFromSystemServer();
+        } catch (SyncResultReceiver.TimeoutException e) {
+            throw new RuntimeException("Fail to get autofill services component name.");
         }
     }
 
@@ -1522,8 +1531,9 @@
             mService.getUserDataId(receiver);
             return receiver.getStringResult();
         } catch (RemoteException e) {
-            e.rethrowFromSystemServer();
-            return null;
+            throw e.rethrowFromSystemServer();
+        } catch (SyncResultReceiver.TimeoutException e) {
+            throw new RuntimeException("Fail to get user data id for field classification.");
         }
     }
 
@@ -1544,8 +1554,9 @@
             mService.getUserData(receiver);
             return receiver.getParcelableResult();
         } catch (RemoteException e) {
-            e.rethrowFromSystemServer();
-            return null;
+            throw e.rethrowFromSystemServer();
+        } catch (SyncResultReceiver.TimeoutException e) {
+            throw new RuntimeException("Fail to get user data for field classification.");
         }
     }
 
@@ -1561,7 +1572,7 @@
         try {
             mService.setUserData(userData);
         } catch (RemoteException e) {
-            e.rethrowFromSystemServer();
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -1583,8 +1594,9 @@
             mService.isFieldClassificationEnabled(receiver);
             return receiver.getIntResult() == 1;
         } catch (RemoteException e) {
-            e.rethrowFromSystemServer();
-            return false;
+            throw e.rethrowFromSystemServer();
+        } catch (SyncResultReceiver.TimeoutException e) {
+            throw new RuntimeException("Fail to get field classification enabled status.");
         }
     }
 
@@ -1606,8 +1618,9 @@
             mService.getDefaultFieldClassificationAlgorithm(receiver);
             return receiver.getStringResult();
         } catch (RemoteException e) {
-            e.rethrowFromSystemServer();
-            return null;
+            throw e.rethrowFromSystemServer();
+        } catch (SyncResultReceiver.TimeoutException e) {
+            throw new RuntimeException("Fail to get default field classification algorithm.");
         }
     }
 
@@ -1627,8 +1640,9 @@
             final String[] algorithms = receiver.getStringArrayResult();
             return algorithms != null ? Arrays.asList(algorithms) : Collections.emptyList();
         } catch (RemoteException e) {
-            e.rethrowFromSystemServer();
-            return null;
+            throw e.rethrowFromSystemServer();
+        } catch (SyncResultReceiver.TimeoutException e) {
+            throw new RuntimeException("Fail to get available field classification algorithms.");
         }
     }
 
@@ -1651,6 +1665,8 @@
             return receiver.getIntResult() == 1;
         } catch (RemoteException e) {
             throw e.rethrowFromSystemServer();
+        } catch (SyncResultReceiver.TimeoutException e) {
+            throw new RuntimeException("Fail to get autofill supported status.");
         }
     }
 
@@ -2040,13 +2056,16 @@
         }
 
         final SyncResultReceiver resultReceiver = new SyncResultReceiver(SYNC_CALLS_TIMEOUT_MS);
-        final int resultCode;
+        int resultCode;
         try {
             mService.setAugmentedAutofillWhitelist(toList(packages), toList(activities),
                     resultReceiver);
             resultCode = resultReceiver.getIntResult();
         } catch (RemoteException e) {
             throw e.rethrowFromSystemServer();
+        } catch (SyncResultReceiver.TimeoutException e) {
+            Log.e(TAG, "Fail to get the result of set AugmentedAutofill whitelist. " + e);
+            return;
         }
         switch (resultCode) {
             case RESULT_OK:
@@ -2283,7 +2302,7 @@
                     // In theory, we could ignore this error since it's not a big deal, but
                     // in reality, we rather crash the app anyways, as the failure could be
                     // a consequence of something going wrong on the server side...
-                    e.rethrowFromSystemServer();
+                    throw e.rethrowFromSystemServer();
                 }
             }
 
@@ -2661,7 +2680,7 @@
             try {
                 mService.onPendingSaveUi(operation, token);
             } catch (RemoteException e) {
-                e.rethrowFromSystemServer();
+                Log.e(TAG, "Error in onPendingSaveUi: ", e);
             }
         }
     }
diff --git a/core/java/android/view/contentcapture/ContentCaptureManager.java b/core/java/android/view/contentcapture/ContentCaptureManager.java
index 756ff78..484b1c1 100644
--- a/core/java/android/view/contentcapture/ContentCaptureManager.java
+++ b/core/java/android/view/contentcapture/ContentCaptureManager.java
@@ -487,6 +487,8 @@
             return resultReceiver.getParcelableResult();
         } catch (RemoteException e) {
             throw e.rethrowFromSystemServer();
+        } catch (SyncResultReceiver.TimeoutException e) {
+            throw new RuntimeException("Fail to get service componentName.");
         }
     }
 
@@ -516,6 +518,9 @@
             return resultReceiver.getParcelableResult();
         } catch (RemoteException e) {
             throw e.rethrowFromSystemServer();
+        } catch (SyncResultReceiver.TimeoutException e) {
+            Log.e(TAG, "Fail to get service settings componentName: " + e);
+            return null;
         }
     }
 
@@ -567,9 +572,13 @@
         final SyncResultReceiver resultReceiver = syncRun(
                 (r) -> mService.getContentCaptureConditions(mContext.getPackageName(), r));
 
-        final ArrayList<ContentCaptureCondition> result = resultReceiver
-                .getParcelableListResult();
-        return toSet(result);
+        try {
+            final ArrayList<ContentCaptureCondition> result = resultReceiver
+                    .getParcelableListResult();
+            return toSet(result);
+        } catch (SyncResultReceiver.TimeoutException e) {
+            throw new RuntimeException("Fail to get content capture conditions.");
+        }
     }
 
     /**
@@ -639,15 +648,21 @@
     public boolean isContentCaptureFeatureEnabled() {
         final SyncResultReceiver resultReceiver = syncRun(
                 (r) -> mService.isContentCaptureFeatureEnabled(r));
-        final int resultCode = resultReceiver.getIntResult();
-        switch (resultCode) {
-            case RESULT_CODE_TRUE:
-                return true;
-            case RESULT_CODE_FALSE:
-                return false;
-            default:
-                Log.wtf(TAG, "received invalid result: " + resultCode);
-                return false;
+
+        try {
+            final int resultCode = resultReceiver.getIntResult();
+            switch (resultCode) {
+                case RESULT_CODE_TRUE:
+                    return true;
+                case RESULT_CODE_FALSE:
+                    return false;
+                default:
+                    Log.wtf(TAG, "received invalid result: " + resultCode);
+                    return false;
+            }
+        } catch (SyncResultReceiver.TimeoutException e) {
+            Log.e(TAG, "Fail to get content capture feature enable status: " + e);
+            return false;
         }
     }
 
@@ -663,7 +678,7 @@
         try {
             mService.removeData(request);
         } catch (RemoteException e) {
-            e.rethrowFromSystemServer();
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -691,7 +706,7 @@
                     new DataShareAdapterDelegate(executor, dataShareWriteAdapter,
                             mDataShareAdapterResourceManager));
         } catch (RemoteException e) {
-            e.rethrowFromSystemServer();
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -709,10 +724,12 @@
             if (resultCode == RESULT_CODE_SECURITY_EXCEPTION) {
                 throw new SecurityException(resultReceiver.getStringResult());
             }
-            return resultReceiver;
         } catch (RemoteException e) {
             throw e.rethrowFromSystemServer();
+        } catch (SyncResultReceiver.TimeoutException e) {
+            throw new RuntimeException("Fail to get syn run result from SyncResultReceiver.");
         }
+        return resultReceiver;
     }
 
     /** @hide */
diff --git a/core/java/android/view/contentcapture/ContentCaptureSession.java b/core/java/android/view/contentcapture/ContentCaptureSession.java
index 301ce9f..3f5ef5a 100644
--- a/core/java/android/view/contentcapture/ContentCaptureSession.java
+++ b/core/java/android/view/contentcapture/ContentCaptureSession.java
@@ -39,8 +39,8 @@
 import java.io.PrintWriter;
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
+import java.security.SecureRandom;
 import java.util.ArrayList;
-import java.util.Random;
 
 /**
  * Session used when the Android a system-provided content capture service
@@ -50,7 +50,9 @@
 
     private static final String TAG = ContentCaptureSession.class.getSimpleName();
 
-    private static final Random sIdGenerator = new Random();
+    // TODO(b/158778794): to make the session ids truly globally unique across
+    //  processes, we may need to explore other options.
+    private static final SecureRandom ID_GENERATOR = new SecureRandom();
 
     /**
      * Initial state, when there is no session.
@@ -622,7 +624,7 @@
     private static int getRandomSessionId() {
         int id;
         do {
-            id = sIdGenerator.nextInt();
+            id = ID_GENERATOR.nextInt();
         } while (id == NO_SESSION_ID);
         return id;
     }
diff --git a/core/java/android/view/inputmethod/InlineSuggestion.java b/core/java/android/view/inputmethod/InlineSuggestion.java
index e4ac588..b8893ce 100644
--- a/core/java/android/view/inputmethod/InlineSuggestion.java
+++ b/core/java/android/view/inputmethod/InlineSuggestion.java
@@ -317,8 +317,24 @@
          */
         @MainThread
         private void handleOnSurfacePackage(SurfaceControlViewHost.SurfacePackage surfacePackage) {
+            if (surfacePackage == null) {
+                return;
+            }
+            if (mSurfacePackage != null || mSurfacePackageConsumer == null) {
+                // The surface package is not consumed, release it immediately.
+                surfacePackage.release();
+                try {
+                    mInlineContentProvider.onSurfacePackageReleased();
+                } catch (RemoteException e) {
+                    Slog.w(TAG, "Error calling onSurfacePackageReleased(): " + e);
+                }
+                return;
+            }
             mSurfacePackage = surfacePackage;
-            if (mSurfacePackage != null && mSurfacePackageConsumer != null) {
+            if (mSurfacePackage == null) {
+                return;
+            }
+            if (mSurfacePackageConsumer != null) {
                 mSurfacePackageConsumer.accept(mSurfacePackage);
                 mSurfacePackageConsumer = null;
             }
@@ -334,6 +350,10 @@
                 }
                 mSurfacePackage = null;
             }
+            // Clear the pending surface package consumer, if any. This can happen if the IME
+            // attaches the view to window and then quickly detaches it from the window, before
+            // the surface package requested upon attaching to window was returned.
+            mSurfacePackageConsumer = null;
         }
 
         @MainThread
diff --git a/core/java/android/view/inputmethod/InputMethodManager.java b/core/java/android/view/inputmethod/InputMethodManager.java
index 71dd665..477dd1d 100644
--- a/core/java/android/view/inputmethod/InputMethodManager.java
+++ b/core/java/android/view/inputmethod/InputMethodManager.java
@@ -616,12 +616,19 @@
                 // For some reason we didn't do a startInput + windowFocusGain, so
                 // we'll just do a window focus gain and call it a day.
                 try {
-                    if (DEBUG) Log.v(TAG, "Reporting focus gain, without startInput");
+                    View servedView = controller.getServedView();
+                    boolean nextFocusIsServedView = servedView != null && servedView == focusedView;
+                    if (DEBUG) {
+                        Log.v(TAG, "Reporting focus gain, without startInput"
+                                + ", nextFocusIsServedView=" + nextFocusIsServedView);
+                    }
                     mService.startInputOrWindowGainedFocus(
                             StartInputReason.WINDOW_FOCUS_GAIN_REPORT_ONLY, mClient,
                             focusedView.getWindowToken(), startInputFlags, softInputMode,
                             windowFlags,
-                            null, null, 0 /* missingMethodFlags */,
+                            nextFocusIsServedView ? mCurrentTextBoxAttribute : null,
+                            nextFocusIsServedView ? mServedInputConnectionWrapper : null,
+                            0 /* missingMethodFlags */,
                             mCurRootView.mContext.getApplicationInfo().targetSdkVersion);
                 } catch (RemoteException e) {
                     throw e.rethrowFromSystemServer();
@@ -646,8 +653,7 @@
         public void setCurrentRootView(ViewRootImpl rootView) {
             synchronized (mH) {
                 if (mCurRootView != null) {
-                    // Reset the last served view and restart window focus state of the root view.
-                    mCurRootView.getImeFocusController().setServedView(null);
+                    // Restart the input when the next window focus state of the root view changed.
                     mRestartOnNextWindowFocus = true;
                 }
                 mCurRootView = rootView;
@@ -677,6 +683,18 @@
             }
             return result;
         }
+
+        /**
+         * For {@link ImeFocusController} to check if the currently served view is accepting full
+         * text edits.
+         */
+        @Override
+        public boolean isAcceptingText() {
+            synchronized (mH) {
+                return mServedInputConnectionWrapper != null
+                        && mServedInputConnectionWrapper.getInputConnection() != null;
+            }
+        }
     }
 
     /** @hide */
diff --git a/core/java/android/widget/SelectionActionModeHelper.java b/core/java/android/widget/SelectionActionModeHelper.java
index e07181a..843700c 100644
--- a/core/java/android/widget/SelectionActionModeHelper.java
+++ b/core/java/android/widget/SelectionActionModeHelper.java
@@ -971,7 +971,8 @@
             return new TextClassifierEvent.LanguageDetectionEvent.Builder(eventType)
                     .setEventContext(classificationContext)
                     .setResultId(classification.getId())
-                    .setEntityTypes(language)
+                    // b/158481016: Disable language logging.
+                    //.setEntityTypes(language)
                     .setScores(score)
                     .setActionIndices(classification.getActions().indexOf(translateAction))
                     .setModelName(model)
diff --git a/core/java/android/widget/inline/InlineContentView.java b/core/java/android/widget/inline/InlineContentView.java
index 8657e82..6a85de5 100644
--- a/core/java/android/widget/inline/InlineContentView.java
+++ b/core/java/android/widget/inline/InlineContentView.java
@@ -197,7 +197,9 @@
             mSurfacePackageUpdater.getSurfacePackage(
                     sp -> {
                         if (DEBUG) Log.v(TAG, "Received new SurfacePackage");
-                        mSurfaceView.setChildSurfacePackage(sp);
+                        if (getViewRootImpl() != null) {
+                            mSurfaceView.setChildSurfacePackage(sp);
+                        }
                     });
         }
     }
diff --git a/core/java/com/android/internal/app/ChooserActivity.java b/core/java/com/android/internal/app/ChooserActivity.java
index b36c71f..0a1e3a0 100644
--- a/core/java/com/android/internal/app/ChooserActivity.java
+++ b/core/java/com/android/internal/app/ChooserActivity.java
@@ -1121,7 +1121,7 @@
         final ComponentName cn = getNearbySharingComponent();
         if (cn == null) return null;
 
-        final Intent resolveIntent = new Intent();
+        final Intent resolveIntent = new Intent(originalIntent);
         resolveIntent.setComponent(cn);
         final ResolveInfo ri = getPackageManager().resolveActivity(
                 resolveIntent, PackageManager.GET_META_DATA);
@@ -1285,6 +1285,12 @@
             ViewGroup parent) {
         ViewGroup contentPreviewLayout = (ViewGroup) layoutInflater.inflate(
                 R.layout.chooser_grid_preview_image, parent, false);
+
+        final ViewGroup actionRow =
+                (ViewGroup) contentPreviewLayout.findViewById(R.id.chooser_action_row);
+        //TODO: addActionButton(actionRow, createCopyButton());
+        addActionButton(actionRow, createNearbyButton(targetIntent));
+
         mPreviewCoord = new ContentPreviewCoordinator(contentPreviewLayout, true);
 
         String action = targetIntent.getAction();
@@ -1395,10 +1401,11 @@
         ViewGroup contentPreviewLayout = (ViewGroup) layoutInflater.inflate(
                 R.layout.chooser_grid_preview_file, parent, false);
 
-        // TODO(b/120417119): Disable file copy until after moving to sysui,
-        // due to permissions issues
-        //((ViewGroup) contentPreviewLayout.findViewById(R.id.chooser_action_row))
-        //        .addView(createCopyButton());
+        final ViewGroup actionRow =
+                (ViewGroup) contentPreviewLayout.findViewById(R.id.chooser_action_row);
+        //TODO(b/120417119): addActionButton(actionRow, createCopyButton());
+        addActionButton(actionRow, createNearbyButton(targetIntent));
+
 
         String action = targetIntent.getAction();
         if (Intent.ACTION_SEND.equals(action)) {
@@ -2809,8 +2816,7 @@
         }
 
         // no need to query direct share for work profile when its turned off
-        UserManager userManager = getSystemService(UserManager.class);
-        if (userManager.isQuietModeEnabled(chooserListAdapter.getUserHandle())) {
+        if (isQuietModeEnabled(chooserListAdapter.getUserHandle())) {
             getChooserActivityLogger().logSharesheetAppLoadComplete();
             return;
         }
@@ -2834,6 +2840,12 @@
         getChooserActivityLogger().logSharesheetAppLoadComplete();
     }
 
+    @VisibleForTesting
+    protected boolean isQuietModeEnabled(UserHandle userHandle) {
+        UserManager userManager = getSystemService(UserManager.class);
+        return userManager.isQuietModeEnabled(userHandle);
+    }
+
     private void setupScrollListener() {
         if (mResolverDrawerLayout == null) {
             return;
@@ -3088,7 +3100,7 @@
                 setVerticalScrollEnabled(false);
             }
         } else if (state == ViewPager.SCROLL_STATE_IDLE) {
-            if (mScrollStatus == SCROLL_STATUS_SCROLLING_VERTICAL) {
+            if (mScrollStatus == SCROLL_STATUS_SCROLLING_HORIZONTAL) {
                 mScrollStatus = SCROLL_STATUS_IDLE;
                 setVerticalScrollEnabled(true);
             }
@@ -3585,10 +3597,9 @@
          * Only expand direct share area if there is a minimum number of targets.
          */
         private boolean canExpandDirectShare() {
-            int orientation = getResources().getConfiguration().orientation;
-            return mChooserListAdapter.getNumServiceTargetsForExpand() > getMaxTargetsPerRow()
-                    && orientation == Configuration.ORIENTATION_PORTRAIT
-                    && !isInMultiWindowMode();
+            // Do not enable until we have confirmed more apps are using sharing shortcuts
+            // Check git history for enablement logic
+            return false;
         }
 
         public ChooserListAdapter getListAdapter() {
diff --git a/core/java/com/android/internal/app/ChooserListAdapter.java b/core/java/com/android/internal/app/ChooserListAdapter.java
index f4fb993..d6ff7b1 100644
--- a/core/java/com/android/internal/app/ChooserListAdapter.java
+++ b/core/java/com/android/internal/app/ChooserListAdapter.java
@@ -181,6 +181,7 @@
                     ri.icon = 0;
                 }
                 mCallerTargets.add(new DisplayResolveInfo(ii, ri, ii, makePresentationGetter(ri)));
+                if (mCallerTargets.size() == MAX_SUGGESTED_APP_TARGETS) break;
             }
         }
     }
@@ -320,7 +321,7 @@
 
 
     public int getCallerTargetCount() {
-        return Math.min(mCallerTargets.size(), MAX_SUGGESTED_APP_TARGETS);
+        return mCallerTargets.size();
     }
 
     /**
@@ -346,8 +347,9 @@
     }
 
     int getAlphaTargetCount() {
-        int standardCount = mSortedList.size();
-        return standardCount > mChooserListCommunicator.getMaxRankedTargets() ? standardCount : 0;
+        int groupedCount = mSortedList.size();
+        int ungroupedCount = mCallerTargets.size() + mDisplayList.size();
+        return ungroupedCount > mChooserListCommunicator.getMaxRankedTargets() ? groupedCount : 0;
     }
 
     /**
diff --git a/core/java/com/android/internal/app/PlatLogoActivity.java b/core/java/com/android/internal/app/PlatLogoActivity.java
index 157e0a7..2a7eae6 100644
--- a/core/java/com/android/internal/app/PlatLogoActivity.java
+++ b/core/java/com/android/internal/app/PlatLogoActivity.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2018 The Android Open Source Project
+ * Copyright (C) 2020 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.
@@ -17,29 +17,32 @@
 package com.android.internal.app;
 
 import android.animation.ObjectAnimator;
-import android.animation.TimeAnimator;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.app.ActionBar;
 import android.app.Activity;
 import android.content.ActivityNotFoundException;
 import android.content.ContentResolver;
+import android.content.Context;
 import android.content.Intent;
-import android.content.res.ColorStateList;
-import android.graphics.Bitmap;
-import android.graphics.BitmapShader;
 import android.graphics.Canvas;
+import android.graphics.Color;
 import android.graphics.ColorFilter;
-import android.graphics.Matrix;
+import android.graphics.LinearGradient;
 import android.graphics.Paint;
-import android.graphics.Path;
 import android.graphics.PixelFormat;
+import android.graphics.Rect;
 import android.graphics.Shader;
 import android.graphics.drawable.Drawable;
 import android.os.Bundle;
 import android.provider.Settings;
+import android.util.AttributeSet;
 import android.util.Log;
 import android.view.HapticFeedbackConstants;
 import android.view.MotionEvent;
 import android.view.View;
-import android.view.ViewGroup;
+import android.view.animation.PathInterpolator;
+import android.widget.FrameLayout;
 import android.widget.ImageView;
 
 import com.android.internal.R;
@@ -50,23 +53,12 @@
  * @hide
  */
 public class PlatLogoActivity extends Activity {
-    ImageView mZeroView, mOneView;
-    BackslashDrawable mBackslash;
-    int mClicks;
+    private static final boolean WRITE_SETTINGS = true;
 
-    static final Paint sPaint = new Paint();
-    static {
-        sPaint.setStyle(Paint.Style.STROKE);
-        sPaint.setStrokeWidth(4f);
-        sPaint.setStrokeCap(Paint.Cap.SQUARE);
-    }
+    BigDialView mDialView;
 
     @Override
     protected void onPause() {
-        if (mBackslash != null) {
-            mBackslash.stopAnimating();
-        }
-        mClicks = 0;
         super.onPause();
     }
 
@@ -80,101 +72,33 @@
         getWindow().setNavigationBarColor(0);
         getWindow().setStatusBarColor(0);
 
-        getActionBar().hide();
+        final ActionBar ab = getActionBar();
+        if (ab != null) ab.hide();
 
-        setContentView(R.layout.platlogo_layout);
-
-        mBackslash = new BackslashDrawable((int) (50 * dp));
-
-        mOneView = findViewById(R.id.one);
-        mOneView.setImageDrawable(new OneDrawable());
-        mZeroView = findViewById(R.id.zero);
-        mZeroView.setImageDrawable(new ZeroDrawable());
-
-        final ViewGroup root = (ViewGroup) mOneView.getParent();
-        root.setClipChildren(false);
-        root.setBackground(mBackslash);
-        root.getBackground().setAlpha(0x20);
-
-        View.OnTouchListener tl = new View.OnTouchListener() {
-            float mOffsetX, mOffsetY;
-            long mClickTime;
-            ObjectAnimator mRotAnim;
-            @Override
-            public boolean onTouch(View v, MotionEvent event) {
-                measureTouchPressure(event);
-                switch (event.getActionMasked()) {
-                    case MotionEvent.ACTION_DOWN:
-                        v.animate().scaleX(1.1f).scaleY(1.1f);
-                        v.getParent().bringChildToFront(v);
-                        mOffsetX = event.getRawX() - v.getX();
-                        mOffsetY = event.getRawY() - v.getY();
-                        long now = System.currentTimeMillis();
-                        if (now - mClickTime < 350) {
-                            mRotAnim = ObjectAnimator.ofFloat(v, View.ROTATION,
-                                    v.getRotation(), v.getRotation() + 3600);
-                            mRotAnim.setDuration(10000);
-                            mRotAnim.start();
-                            mClickTime = 0;
-                        } else {
-                            mClickTime = now;
-                        }
-                        break;
-                    case MotionEvent.ACTION_MOVE:
-                        v.setX(event.getRawX() - mOffsetX);
-                        v.setY(event.getRawY() - mOffsetY);
-                        v.performHapticFeedback(HapticFeedbackConstants.TEXT_HANDLE_MOVE);
-                        break;
-                    case MotionEvent.ACTION_UP:
-                        v.performClick();
-                        // fall through
-                    case MotionEvent.ACTION_CANCEL:
-                        v.animate().scaleX(1f).scaleY(1f);
-                        if (mRotAnim != null) mRotAnim.cancel();
-                        testOverlap();
-                        break;
-                }
-                return true;
-            }
-        };
-
-        findViewById(R.id.one).setOnTouchListener(tl);
-        findViewById(R.id.zero).setOnTouchListener(tl);
-        findViewById(R.id.text).setOnTouchListener(tl);
-    }
-
-    private void testOverlap() {
-        final float width = mZeroView.getWidth();
-        final float targetX = mZeroView.getX() + width * .2f;
-        final float targetY = mZeroView.getY() + width * .3f;
-        if (Math.hypot(targetX - mOneView.getX(), targetY - mOneView.getY()) < width * .2f
-                && Math.abs(mOneView.getRotation() % 360 - 315) < 15) {
-            mOneView.animate().x(mZeroView.getX() + width * .2f);
-            mOneView.animate().y(mZeroView.getY() + width * .3f);
-            mOneView.setRotation(mOneView.getRotation() % 360);
-            mOneView.animate().rotation(315);
-            mOneView.performHapticFeedback(HapticFeedbackConstants.CONFIRM);
-
-            mBackslash.startAnimating();
-
-            mClicks++;
-            if (mClicks >= 7) {
-                launchNextStage();
-            }
-        } else {
-            mBackslash.stopAnimating();
+        mDialView = new BigDialView(this, null);
+        if (Settings.System.getLong(getContentResolver(),
+                "egg_mode" /* Settings.System.EGG_MODE */, 0) == 0) {
+            mDialView.setUnlockTries(3);
         }
+
+        final FrameLayout layout = new FrameLayout(this);
+        layout.setBackgroundColor(0xFFFF0000);
+        layout.addView(mDialView, FrameLayout.LayoutParams.MATCH_PARENT,
+                FrameLayout.LayoutParams.MATCH_PARENT);
+        setContentView(layout);
     }
 
-    private void launchNextStage() {
+    private void launchNextStage(boolean locked) {
         final ContentResolver cr = getContentResolver();
 
         if (Settings.System.getLong(cr, "egg_mode" /* Settings.System.EGG_MODE */, 0) == 0) {
             // For posterity: the moment this user unlocked the easter egg
             try {
-                Settings.System.putLong(cr,
-                        "egg_mode", // Settings.System.EGG_MODE,
-                        System.currentTimeMillis());
+                if (WRITE_SETTINGS) {
+                    Settings.System.putLong(cr,
+                            "egg_mode", // Settings.System.EGG_MODE,
+                            locked ? 0 : System.currentTimeMillis());
+                }
             } catch (RuntimeException e) {
                 Log.e("com.android.internal.app.PlatLogoActivity", "Can't write settings", e);
             }
@@ -182,12 +106,12 @@
         try {
             startActivity(new Intent(Intent.ACTION_MAIN)
                     .setFlags(Intent.FLAG_ACTIVITY_NEW_TASK
-                        | Intent.FLAG_ACTIVITY_CLEAR_TASK)
+                            | Intent.FLAG_ACTIVITY_CLEAR_TASK)
                     .addCategory("com.android.internal.category.PLATLOGO"));
         } catch (ActivityNotFoundException ex) {
             Log.e("com.android.internal.app.PlatLogoActivity", "No more eggs.");
         }
-        finish();
+        //finish(); // no longer finish upon unlock; it's fun to frob the dial
     }
 
     static final String TOUCH_STATS = "touch.stats";
@@ -223,7 +147,10 @@
             if (mPressureMax >= 0) {
                 touchData.put("min", mPressureMin);
                 touchData.put("max", mPressureMax);
-                Settings.System.putString(getContentResolver(), TOUCH_STATS, touchData.toString());
+                if (WRITE_SETTINGS) {
+                    Settings.System.putString(getContentResolver(), TOUCH_STATS,
+                            touchData.toString());
+                }
             }
         } catch (Exception e) {
             Log.e("com.android.internal.app.PlatLogoActivity", "Can't write touch settings", e);
@@ -242,149 +169,272 @@
         super.onStop();
     }
 
-    static class ZeroDrawable extends Drawable {
-        int mTintColor;
+    class BigDialView extends ImageView {
+        private static final int COLOR_GREEN = 0xff3ddc84;
+        private static final int COLOR_BLUE = 0xff4285f4;
+        private static final int COLOR_NAVY = 0xff073042;
+        private static final int COLOR_ORANGE = 0xfff86734;
+        private static final int COLOR_CHARTREUSE = 0xffeff7cf;
+        private static final int COLOR_LIGHTBLUE = 0xffd7effe;
 
-        @Override
-        public void draw(Canvas canvas) {
-            sPaint.setColor(mTintColor | 0xFF000000);
+        private static final int STEPS = 11;
+        private static final float VALUE_CHANGE_MAX = 1f / STEPS;
 
-            canvas.save();
-            canvas.scale(canvas.getWidth() / 24f, canvas.getHeight() / 24f);
+        private BigDialDrawable mDialDrawable;
+        private boolean mWasLocked;
 
-            canvas.drawCircle(12f, 12f, 10f, sPaint);
-            canvas.restore();
+        BigDialView(Context context, @Nullable AttributeSet attrs) {
+            super(context, attrs);
+            init();
+        }
+
+        BigDialView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
+            super(context, attrs, defStyleAttr);
+            init();
+        }
+
+        BigDialView(Context context, @Nullable AttributeSet attrs, int defStyleAttr,
+                int defStyleRes) {
+            super(context, attrs, defStyleAttr, defStyleRes);
+            init();
+        }
+
+        private void init() {
+            mDialDrawable = new BigDialDrawable();
+            setImageDrawable(mDialDrawable);
         }
 
         @Override
-        public void setAlpha(int alpha) { }
+        public void onDraw(Canvas c) {
+            super.onDraw(c);
+        }
 
-        @Override
-        public void setColorFilter(ColorFilter colorFilter) { }
-
-        @Override
-        public void setTintList(ColorStateList tint) {
-            mTintColor = tint.getDefaultColor();
+        double toPositiveDegrees(double rad) {
+            return (Math.toDegrees(rad) + 360 - 90) % 360;
         }
 
         @Override
-        public int getOpacity() {
-            return PixelFormat.TRANSLUCENT;
-        }
-    }
-
-    static class OneDrawable extends Drawable {
-        int mTintColor;
-
-        @Override
-        public void draw(Canvas canvas) {
-            sPaint.setColor(mTintColor | 0xFF000000);
-
-            canvas.save();
-            canvas.scale(canvas.getWidth() / 24f, canvas.getHeight() / 24f);
-
-            final Path p = new Path();
-            p.moveTo(12f, 21.83f);
-            p.rLineTo(0f, -19.67f);
-            p.rLineTo(-5f, 0f);
-            canvas.drawPath(p, sPaint);
-            canvas.restore();
-        }
-
-        @Override
-        public void setAlpha(int alpha) { }
-
-        @Override
-        public void setColorFilter(ColorFilter colorFilter) { }
-
-        @Override
-        public void setTintList(ColorStateList tint) {
-            mTintColor = tint.getDefaultColor();
-        }
-
-        @Override
-        public int getOpacity() {
-            return PixelFormat.TRANSLUCENT;
-        }
-    }
-
-    private static class BackslashDrawable extends Drawable implements TimeAnimator.TimeListener {
-        Bitmap mTile;
-        Paint mPaint = new Paint();
-        BitmapShader mShader;
-        TimeAnimator mAnimator = new TimeAnimator();
-        Matrix mMatrix = new Matrix();
-
-        public void draw(Canvas canvas) {
-            canvas.drawPaint(mPaint);
-        }
-
-        BackslashDrawable(int width) {
-            mTile = Bitmap.createBitmap(width, width, Bitmap.Config.ALPHA_8);
-            mAnimator.setTimeListener(this);
-
-            final Canvas tileCanvas = new Canvas(mTile);
-            final float w = tileCanvas.getWidth();
-            final float h = tileCanvas.getHeight();
-
-            final Path path = new Path();
-            path.moveTo(0, 0);
-            path.lineTo(w / 2, 0);
-            path.lineTo(w, h / 2);
-            path.lineTo(w, h);
-            path.close();
-
-            path.moveTo(0, h / 2);
-            path.lineTo(w / 2, h);
-            path.lineTo(0, h);
-            path.close();
-
-            final Paint slashPaint = new Paint();
-            slashPaint.setAntiAlias(true);
-            slashPaint.setStyle(Paint.Style.FILL);
-            slashPaint.setColor(0xFF000000);
-            tileCanvas.drawPath(path, slashPaint);
-
-            //mPaint.setColor(0xFF0000FF);
-            mShader = new BitmapShader(mTile, Shader.TileMode.REPEAT, Shader.TileMode.REPEAT);
-            mPaint.setShader(mShader);
-        }
-
-        public void startAnimating() {
-            if (!mAnimator.isStarted()) {
-                mAnimator.start();
+        public boolean onTouchEvent(MotionEvent ev) {
+            switch (ev.getActionMasked()) {
+                case MotionEvent.ACTION_DOWN:
+                    mWasLocked = mDialDrawable.isLocked();
+                    // pass through
+                case MotionEvent.ACTION_MOVE:
+                    float x = ev.getX();
+                    float y = ev.getY();
+                    float cx = (getLeft() + getRight()) / 2f;
+                    float cy = (getTop() + getBottom()) / 2f;
+                    float angle = (float) toPositiveDegrees(Math.atan2(x - cx, y - cy));
+                    final int oldLevel = mDialDrawable.getUserLevel();
+                    mDialDrawable.touchAngle(angle);
+                    final int newLevel = mDialDrawable.getUserLevel();
+                    if (oldLevel != newLevel) {
+                        performHapticFeedback(newLevel == STEPS
+                                ? HapticFeedbackConstants.CONFIRM
+                                : HapticFeedbackConstants.CLOCK_TICK);
+                    }
+                    return true;
+                case MotionEvent.ACTION_UP:
+                    if (mWasLocked && !mDialDrawable.isLocked()) {
+                        launchNextStage(false);
+                    }
+                    return true;
             }
+            return false;
         }
 
-        public void stopAnimating() {
-            if (mAnimator.isStarted()) {
-                mAnimator.cancel();
+        @Override
+        public boolean performClick() {
+            if (mDialDrawable.getUserLevel() < STEPS - 1) {
+                mDialDrawable.setUserLevel(mDialDrawable.getUserLevel() + 1);
+                performHapticFeedback(HapticFeedbackConstants.CLOCK_TICK);
             }
+            return true;
         }
 
-        @Override
-        public void setAlpha(int alpha) {
-            mPaint.setAlpha(alpha);
+        void setUnlockTries(int tries) {
+            mDialDrawable.setUnlockTries(tries);
         }
 
-        @Override
-        public void setColorFilter(ColorFilter colorFilter) {
-            mPaint.setColorFilter(colorFilter);
-        }
+        private class BigDialDrawable extends Drawable {
+            public final int STEPS = 10;
+            private int mUnlockTries = 0;
+            final Paint mPaint = new Paint();
+            final Drawable mEleven;
+            private boolean mNightMode;
+            private float mValue = 0f;
+            float mElevenAnim = 0f;
+            ObjectAnimator mElevenShowAnimator = ObjectAnimator.ofFloat(this, "elevenAnim", 0f,
+                    1f).setDuration(300);
+            ObjectAnimator mElevenHideAnimator = ObjectAnimator.ofFloat(this, "elevenAnim", 1f,
+                    0f).setDuration(500);
 
-        @Override
-        public int getOpacity() {
-            return PixelFormat.TRANSLUCENT;
-        }
+            BigDialDrawable() {
+                mNightMode = getContext().getResources().getConfiguration().isNightModeActive();
+                mEleven = getContext().getDrawable(R.drawable.ic_number11);
+                mElevenShowAnimator.setInterpolator(new PathInterpolator(0.4f, 0f, 0.2f, 1f));
+                mElevenHideAnimator.setInterpolator(new PathInterpolator(0.8f, 0.2f, 0.6f, 1f));
+            }
 
-        @Override
-        public void onTimeUpdate(TimeAnimator animation, long totalTime, long deltaTime) {
-            if (mShader != null) {
-                mMatrix.postTranslate(deltaTime / 4f, 0);
-                mShader.setLocalMatrix(mMatrix);
+            public void setUnlockTries(int count) {
+                if (mUnlockTries != count) {
+                    mUnlockTries = count;
+                    setValue(getValue());
+                    invalidateSelf();
+                }
+            }
+
+            boolean isLocked() {
+                return mUnlockTries > 0;
+            }
+
+            public void setValue(float v) {
+                // until the dial is "unlocked", you can't turn it all the way to 11
+                final float max = isLocked() ? 1f - 1f / STEPS : 1f;
+                mValue = v < 0f ? 0f : v > max ? max : v;
                 invalidateSelf();
             }
+
+            public float getValue() {
+                return mValue;
+            }
+
+            public int getUserLevel() {
+                return Math.round(getValue() * STEPS - 0.25f);
+            }
+
+            public void setUserLevel(int i) {
+                setValue(getValue() + ((float) i) / STEPS);
+            }
+
+            public float getElevenAnim() {
+                return mElevenAnim;
+            }
+
+            public void setElevenAnim(float f) {
+                if (mElevenAnim != f) {
+                    mElevenAnim = f;
+                    invalidateSelf();
+                }
+            }
+
+            @Override
+            public void draw(@NonNull Canvas canvas) {
+                final Rect bounds = getBounds();
+                final int w = bounds.width();
+                final int h = bounds.height();
+                final float w2 = w / 2f;
+                final float h2 = h / 2f;
+                final float radius = w / 4f;
+
+                canvas.drawColor(mNightMode ? COLOR_NAVY : COLOR_LIGHTBLUE);
+
+                canvas.save();
+                canvas.rotate(45, w2, h2);
+                canvas.clipRect(w2, h2 - radius, Math.min(w, h), h2 + radius);
+                final int gradientColor = mNightMode ? 0x60000020 : (0x10FFFFFF & COLOR_NAVY);
+                mPaint.setShader(
+                        new LinearGradient(w2, h2, Math.min(w, h), h2, gradientColor,
+                                0x00FFFFFF & gradientColor, Shader.TileMode.CLAMP));
+                mPaint.setColor(Color.BLACK);
+                canvas.drawPaint(mPaint);
+                mPaint.setShader(null);
+                canvas.restore();
+
+                mPaint.setStyle(Paint.Style.FILL);
+                mPaint.setColor(COLOR_GREEN);
+
+                canvas.drawCircle(w2, h2, radius, mPaint);
+
+                mPaint.setColor(mNightMode ? COLOR_LIGHTBLUE : COLOR_NAVY);
+                final float cx = w * 0.85f;
+                for (int i = 0; i < STEPS; i++) {
+                    final float f = (float) i / STEPS;
+                    canvas.save();
+                    final float angle = valueToAngle(f);
+                    canvas.rotate(-angle, w2, h2);
+                    canvas.drawCircle(cx, h2, (i <= getUserLevel()) ? 20 : 5, mPaint);
+                    canvas.restore();
+                }
+
+                if (mElevenAnim > 0f) {
+                    final int color = COLOR_ORANGE;
+                    final int size2 = (int) ((0.5 + 0.5f * mElevenAnim) * w / 14);
+                    final float cx11 = cx + size2 / 4f;
+                    mEleven.setBounds((int) cx11 - size2, (int) h2 - size2,
+                            (int) cx11 + size2, (int) h2 + size2);
+                    final int alpha = 0xFFFFFF | ((int) clamp(0xFF * 2 * mElevenAnim, 0, 0xFF)
+                            << 24);
+                    mEleven.setTint(alpha & color);
+                    mEleven.draw(canvas);
+                }
+
+                // don't want to use the rounded value here since the quantization will be visible
+                final float angle = valueToAngle(mValue);
+
+                // it's easier to draw at far-right and rotate backwards
+                canvas.rotate(-angle, w2, h2);
+                mPaint.setColor(Color.WHITE);
+                final float dimple = w2 / 12f;
+                canvas.drawCircle(w - radius - dimple * 2, h2, dimple, mPaint);
+            }
+
+            float clamp(float x, float a, float b) {
+                return x < a ? a : x > b ? b : x;
+            }
+
+            float angleToValue(float a) {
+                return 1f - clamp(a / (360 - 45), 0f, 1f);
+            }
+
+            // rotation: min is at 4:30, max is at 3:00
+            float valueToAngle(float v) {
+                return (1f - v) * (360 - 45);
+            }
+
+            public void touchAngle(float a) {
+                final int oldUserLevel = getUserLevel();
+                final float newValue = angleToValue(a);
+                // this is how we prevent the knob from snapping from max back to min, or from
+                // jumping around wherever the user presses. The new value must be pretty close
+                // to the
+                // previous one.
+                if (Math.abs(newValue - getValue()) < VALUE_CHANGE_MAX) {
+                    setValue(newValue);
+
+                    if (isLocked() && oldUserLevel != STEPS - 1 && getUserLevel() == STEPS - 1) {
+                        mUnlockTries--;
+                    }
+
+                    if (!isLocked()) {
+                        if (getUserLevel() == STEPS && mElevenAnim != 1f
+                                && !mElevenShowAnimator.isRunning()) {
+                            mElevenHideAnimator.cancel();
+                            mElevenShowAnimator.start();
+                        } else if (getUserLevel() != STEPS && mElevenAnim == 1f
+                                && !mElevenHideAnimator.isRunning()) {
+                            mElevenShowAnimator.cancel();
+                            mElevenHideAnimator.start();
+                        }
+                    }
+                }
+            }
+
+            @Override
+            public void setAlpha(int i) {
+            }
+
+            @Override
+            public void setColorFilter(@Nullable ColorFilter colorFilter) {
+            }
+
+            @Override
+            public int getOpacity() {
+                return PixelFormat.TRANSLUCENT;
+            }
         }
     }
 }
 
+
+
diff --git a/core/java/com/android/internal/app/ResolverListAdapter.java b/core/java/com/android/internal/app/ResolverListAdapter.java
index b1e8ed1..fc8cafd 100644
--- a/core/java/com/android/internal/app/ResolverListAdapter.java
+++ b/core/java/com/android/internal/app/ResolverListAdapter.java
@@ -427,6 +427,8 @@
                 && dri.getResolveInfo().targetUserId == UserHandle.USER_CURRENT) {
             if (shouldAddResolveInfo(dri)) {
                 mDisplayList.add(dri);
+                Log.i(TAG, "Add DisplayResolveInfo component: " + dri.getResolvedComponentName()
+                        + ", intent component: " + dri.getResolvedIntent().getComponent());
             }
         }
     }
@@ -617,7 +619,8 @@
         }
     }
 
-    UserHandle getUserHandle() {
+    @VisibleForTesting
+    public UserHandle getUserHandle() {
         return mResolverListController.getUserHandle();
     }
 
diff --git a/core/java/com/android/internal/app/SimpleIconFactory.java b/core/java/com/android/internal/app/SimpleIconFactory.java
index ffe2dbe..2d91e64 100644
--- a/core/java/com/android/internal/app/SimpleIconFactory.java
+++ b/core/java/com/android/internal/app/SimpleIconFactory.java
@@ -19,6 +19,7 @@
 import static android.content.Context.ACTIVITY_SERVICE;
 import static android.graphics.Paint.DITHER_FLAG;
 import static android.graphics.Paint.FILTER_BITMAP_FLAG;
+import static android.graphics.drawable.AdaptiveIconDrawable.getExtraInsetFraction;
 
 import android.annotation.AttrRes;
 import android.annotation.NonNull;
@@ -54,6 +55,7 @@
 import org.xmlpull.v1.XmlPullParser;
 
 import java.nio.ByteBuffer;
+import java.util.Optional;
 
 
 /**
@@ -64,6 +66,7 @@
 @Deprecated
 public class SimpleIconFactory {
 
+
     private static final SynchronizedPool<SimpleIconFactory> sPool =
             new SynchronizedPool<>(Runtime.getRuntime().availableProcessors());
 
@@ -251,7 +254,7 @@
         } else if (w > h && h > 0) {
             scale = (float) w / h;
         }
-        Bitmap bitmap = createIconBitmap(icon, scale);
+        Bitmap bitmap = createIconBitmapNoInsetOrMask(icon, scale);
         bitmap = maskBitmapToCircle(bitmap);
         icon = new BitmapDrawable(mContext.getResources(), bitmap);
 
@@ -281,15 +284,19 @@
         final Bitmap output = Bitmap.createBitmap(bitmap.getWidth(),
                 bitmap.getHeight(), Bitmap.Config.ARGB_8888);
         final Canvas canvas = new Canvas(output);
-        final Paint paint = new Paint();
-        paint.setAntiAlias(true);
+        final Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG | Paint.DITHER_FLAG
+                | Paint.FILTER_BITMAP_FLAG);
+
+        // Apply an offset to enable shadow to be drawn
+        final int size = bitmap.getWidth();
+        int offset = Math.max((int) Math.ceil(BLUR_FACTOR * size), 1);
 
         // Draw mask
         paint.setColor(0xffffffff);
         canvas.drawARGB(0, 0, 0, 0);
         canvas.drawCircle(bitmap.getWidth() / 2f,
                 bitmap.getHeight() / 2f,
-                bitmap.getWidth() / 2f - 1 /* -1 to avoid circles with flat sides */,
+                bitmap.getWidth() / 2f - offset,
                 paint);
 
         // Draw masked bitmap
@@ -306,24 +313,61 @@
     }
 
     private Bitmap createIconBitmap(Drawable icon, float scale) {
-        return createIconBitmap(icon, scale, mIconBitmapSize);
+        return createIconBitmap(icon, scale, mIconBitmapSize, true, false);
+    }
+
+    private Bitmap createIconBitmapNoInsetOrMask(Drawable icon, float scale) {
+        return createIconBitmap(icon, scale, mIconBitmapSize, false, true);
     }
 
     /**
      * @param icon drawable that should be flattened to a bitmap
      * @param scale the scale to apply before drawing {@param icon} on the canvas
+     * @param insetAdiForShadow when rendering AdaptiveIconDrawables inset to make room for a shadow
+     * @param ignoreAdiMask when rendering AdaptiveIconDrawables ignore the current system mask
      */
-    private Bitmap createIconBitmap(Drawable icon, float scale, int size) {
+    private Bitmap createIconBitmap(Drawable icon, float scale, int size, boolean insetAdiForShadow,
+            boolean ignoreAdiMask) {
         Bitmap bitmap = Bitmap.createBitmap(size, size, Bitmap.Config.ARGB_8888);
 
         mCanvas.setBitmap(bitmap);
         mOldBounds.set(icon.getBounds());
 
         if (icon instanceof AdaptiveIconDrawable) {
-            int offset = Math.max((int) Math.ceil(BLUR_FACTOR * size),
-                    Math.round(size * (1 - scale) / 2));
-            icon.setBounds(offset, offset, size - offset, size - offset);
-            icon.draw(mCanvas);
+            final AdaptiveIconDrawable adi = (AdaptiveIconDrawable) icon;
+
+            // By default assumes the output bitmap will have a shadow directly applied and makes
+            // room for it by insetting. If there are intermediate steps before applying the shadow
+            // insetting is disableable.
+            int offset = Math.round(size * (1 - scale) / 2);
+            if (insetAdiForShadow) {
+                offset = Math.max((int) Math.ceil(BLUR_FACTOR * size), offset);
+            }
+            Rect bounds = new Rect(offset, offset, size - offset, size - offset);
+
+            // AdaptiveIconDrawables are by default masked by the user's icon shape selection.
+            // If further masking is to be done, directly render to avoid the system masking.
+            if (ignoreAdiMask) {
+                final int cX = bounds.width() / 2;
+                final int cY = bounds.height() / 2;
+                final float portScale = 1f / (1 + 2 * getExtraInsetFraction());
+                final int insetWidth = (int) (bounds.width() / (portScale * 2));
+                final int insetHeight = (int) (bounds.height() / (portScale * 2));
+
+                Rect childRect = new Rect(cX - insetWidth, cY - insetHeight, cX + insetWidth,
+                        cY + insetHeight);
+                Optional.ofNullable(adi.getBackground()).ifPresent(drawable -> {
+                    drawable.setBounds(childRect);
+                    drawable.draw(mCanvas);
+                });
+                Optional.ofNullable(adi.getForeground()).ifPresent(drawable -> {
+                    drawable.setBounds(childRect);
+                    drawable.draw(mCanvas);
+                });
+            } else {
+                adi.setBounds(bounds);
+                adi.draw(mCanvas);
+            }
         } else {
             if (icon instanceof BitmapDrawable) {
                 BitmapDrawable bitmapDrawable = (BitmapDrawable) icon;
diff --git a/core/java/com/android/internal/app/chooser/DisplayResolveInfo.java b/core/java/com/android/internal/app/chooser/DisplayResolveInfo.java
index 86a9af3..fe0e7d0 100644
--- a/core/java/com/android/internal/app/chooser/DisplayResolveInfo.java
+++ b/core/java/com/android/internal/app/chooser/DisplayResolveInfo.java
@@ -40,8 +40,10 @@
  * resolve it to an activity.
  */
 public class DisplayResolveInfo implements TargetInfo {
-    // Temporary flag for new chooser delegate behavior.
-    private static final boolean ENABLE_CHOOSER_DELEGATE = true;
+    // Temporary flag for new chooser delegate behavior. There are occassional token
+    // permission errors from bouncing through the delegate. Watch out before reenabling:
+    // b/157272342 is one example but this issue has been reported many times
+    private static final boolean ENABLE_CHOOSER_DELEGATE = false;
 
     private final ResolveInfo mResolveInfo;
     private CharSequence mDisplayLabel;
diff --git a/core/java/com/android/internal/inputmethod/StartInputReason.java b/core/java/com/android/internal/inputmethod/StartInputReason.java
index a01c459..a4eaa21 100644
--- a/core/java/com/android/internal/inputmethod/StartInputReason.java
+++ b/core/java/com/android/internal/inputmethod/StartInputReason.java
@@ -50,8 +50,9 @@
     int WINDOW_FOCUS_GAIN = 1;
     /**
      * {@link android.view.Window} gained focus but there is no {@link android.view.View} that is
-     * eligible to have IME focus. {@link android.view.inputmethod.InputMethodManager} just reports
-     * this window focus change event.
+     * eligible to have IME focus, or the focused view is same as current served view and its
+     * input connection remains. {@link android.view.inputmethod.InputMethodManager} just reports
+     * this window focus change event to sync IME input target for system.
      */
     int WINDOW_FOCUS_GAIN_REPORT_ONLY = 2;
     /**
diff --git a/core/java/com/android/internal/util/ScreenshotHelper.java b/core/java/com/android/internal/util/ScreenshotHelper.java
index d0052ab..9bf0513 100644
--- a/core/java/com/android/internal/util/ScreenshotHelper.java
+++ b/core/java/com/android/internal/util/ScreenshotHelper.java
@@ -316,7 +316,7 @@
             };
             msg.replyTo = new Messenger(h);
 
-            if (mScreenshotConnection == null) {
+            if (mScreenshotConnection == null || mScreenshotService == null) {
                 final ComponentName serviceComponent = ComponentName.unflattenFromString(
                         mContext.getResources().getString(
                                 com.android.internal.R.string.config_screenshotServiceComponent));
diff --git a/core/java/com/android/internal/util/SyncResultReceiver.java b/core/java/com/android/internal/util/SyncResultReceiver.java
index 00e9101..6b13582 100644
--- a/core/java/com/android/internal/util/SyncResultReceiver.java
+++ b/core/java/com/android/internal/util/SyncResultReceiver.java
@@ -182,7 +182,7 @@
     }
 
     /** @hide */
-    public static final class TimeoutException extends RuntimeException {
+    public static final class TimeoutException extends Exception {
         private TimeoutException(String msg) {
             super(msg);
         }
diff --git a/core/java/com/android/internal/widget/ConversationLayout.java b/core/java/com/android/internal/widget/ConversationLayout.java
index 1f2ae5f..b64923f 100644
--- a/core/java/com/android/internal/widget/ConversationLayout.java
+++ b/core/java/com/android/internal/widget/ConversationLayout.java
@@ -21,6 +21,10 @@
 import static com.android.internal.widget.MessagingPropertyAnimator.ALPHA_IN;
 import static com.android.internal.widget.MessagingPropertyAnimator.ALPHA_OUT;
 
+import android.animation.Animator;
+import android.animation.AnimatorListenerAdapter;
+import android.animation.AnimatorSet;
+import android.animation.ValueAnimator;
 import android.annotation.AttrRes;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
@@ -36,6 +40,7 @@
 import android.graphics.Paint;
 import android.graphics.Rect;
 import android.graphics.Typeface;
+import android.graphics.drawable.GradientDrawable;
 import android.graphics.drawable.Icon;
 import android.os.Bundle;
 import android.os.Parcelable;
@@ -67,6 +72,7 @@
 import java.util.ArrayList;
 import java.util.List;
 import java.util.Locale;
+import java.util.Objects;
 import java.util.function.Consumer;
 import java.util.regex.Pattern;
 
@@ -80,7 +86,7 @@
 
     private static final float COLOR_SHIFT_AMOUNT = 60;
     /**
-     *  Pattren for filter some ingonable characters.
+     *  Pattern for filter some ignorable characters.
      *  p{Z} for any kind of whitespace or invisible separator.
      *  p{C} for any kind of punctuation character.
      */
@@ -93,8 +99,12 @@
     public static final Interpolator LINEAR_OUT_SLOW_IN = new PathInterpolator(0f, 0f, 0.2f, 1f);
     public static final Interpolator FAST_OUT_LINEAR_IN = new PathInterpolator(0.4f, 0f, 1f, 1f);
     public static final Interpolator FAST_OUT_SLOW_IN = new PathInterpolator(0.4f, 0f, 0.2f, 1f);
+    public static final Interpolator OVERSHOOT = new PathInterpolator(0.4f, 0f, 0.2f, 1.4f);
     public static final OnLayoutChangeListener MESSAGING_PROPERTY_ANIMATOR
             = new MessagingPropertyAnimator();
+    public static final int IMPORTANCE_ANIM_GROW_DURATION = 250;
+    public static final int IMPORTANCE_ANIM_SHRINK_DURATION = 200;
+    public static final int IMPORTANCE_ANIM_SHRINK_DELAY = 25;
     private List<MessagingMessage> mMessages = new ArrayList<>();
     private List<MessagingMessage> mHistoricMessages = new ArrayList<>();
     private MessagingLinearLayout mMessagingLinearLayout;
@@ -331,14 +341,74 @@
         mNameReplacement = nameReplacement;
     }
 
-    /**
-     * Sets this conversation as "important", adding some additional UI treatment.
-     */
+    /** Sets this conversation as "important", adding some additional UI treatment. */
     @RemotableViewMethod
     public void setIsImportantConversation(boolean isImportantConversation) {
+        setIsImportantConversation(isImportantConversation, false);
+    }
+
+    /** @hide **/
+    public void setIsImportantConversation(boolean isImportantConversation, boolean animate) {
         mImportantConversation = isImportantConversation;
-        mImportanceRingView.setVisibility(isImportantConversation
-                && mIcon.getVisibility() != GONE ? VISIBLE : GONE);
+        mImportanceRingView.setVisibility(isImportantConversation && mIcon.getVisibility() != GONE
+                ? VISIBLE : GONE);
+
+        if (animate && isImportantConversation) {
+            GradientDrawable ring = (GradientDrawable) mImportanceRingView.getDrawable();
+            ring.mutate();
+            GradientDrawable bg = (GradientDrawable) mConversationIconBadgeBg.getDrawable();
+            bg.mutate();
+            int ringColor = getResources()
+                    .getColor(R.color.conversation_important_highlight);
+            int standardThickness = getResources()
+                    .getDimensionPixelSize(R.dimen.importance_ring_stroke_width);
+            int largeThickness = getResources()
+                    .getDimensionPixelSize(R.dimen.importance_ring_anim_max_stroke_width);
+            int standardSize = getResources().getDimensionPixelSize(
+                    R.dimen.importance_ring_size);
+            int baseSize = standardSize - standardThickness * 2;
+            int bgSize = getResources()
+                    .getDimensionPixelSize(R.dimen.conversation_icon_size_badged);
+
+            ValueAnimator.AnimatorUpdateListener animatorUpdateListener = animation -> {
+                int strokeWidth = Math.round((float) animation.getAnimatedValue());
+                ring.setStroke(strokeWidth, ringColor);
+                int newSize = baseSize + strokeWidth * 2;
+                ring.setSize(newSize, newSize);
+                mImportanceRingView.invalidate();
+            };
+
+            ValueAnimator growAnimation = ValueAnimator.ofFloat(0, largeThickness);
+            growAnimation.setInterpolator(LINEAR_OUT_SLOW_IN);
+            growAnimation.setDuration(IMPORTANCE_ANIM_GROW_DURATION);
+            growAnimation.addUpdateListener(animatorUpdateListener);
+
+            ValueAnimator shrinkAnimation =
+                    ValueAnimator.ofFloat(largeThickness, standardThickness);
+            shrinkAnimation.setDuration(IMPORTANCE_ANIM_SHRINK_DURATION);
+            shrinkAnimation.setStartDelay(IMPORTANCE_ANIM_SHRINK_DELAY);
+            shrinkAnimation.setInterpolator(OVERSHOOT);
+            shrinkAnimation.addUpdateListener(animatorUpdateListener);
+            shrinkAnimation.addListener(new AnimatorListenerAdapter() {
+                @Override
+                public void onAnimationStart(Animator animation) {
+                    // Shrink the badge bg so that it doesn't peek behind the animation
+                    bg.setSize(baseSize, baseSize);
+                    mConversationIconBadgeBg.invalidate();
+                }
+
+                @Override
+                public void onAnimationEnd(Animator animation) {
+                    // Reset bg back to normal size
+                    bg.setSize(bgSize, bgSize);
+                    mConversationIconBadgeBg.invalidate();
+                }
+            });
+
+            AnimatorSet anims = new AnimatorSet();
+            anims.playSequentially(growAnimation, shrinkAnimation);
+            anims.start();
+        }
     }
 
     public boolean isImportantConversation() {
@@ -692,9 +762,13 @@
                 // group
                 : mExpandedGroupMessagePadding;
 
+        int iconPadding = mIsOneToOne || mIsCollapsed
+                ? mConversationIconTopPadding
+                : mConversationIconTopPaddingExpandedGroup;
+
         mConversationIconContainer.setPaddingRelative(
                 mConversationIconContainer.getPaddingStart(),
-                mConversationIconTopPadding,
+                iconPadding,
                 mConversationIconContainer.getPaddingEnd(),
                 mConversationIconContainer.getPaddingBottom());
 
@@ -711,8 +785,8 @@
     }
 
     @RemotableViewMethod
-    public void setShortcutIcon(Icon conversationIcon) {
-        mConversationIcon = conversationIcon;
+    public void setShortcutIcon(Icon shortcutIcon) {
+        mShortcutIcon = shortcutIcon;
     }
 
     /**
@@ -722,7 +796,8 @@
      */
     @RemotableViewMethod
     public void setConversationTitle(CharSequence conversationTitle) {
-        mConversationTitle = conversationTitle;
+        // Remove formatting from the title.
+        mConversationTitle = conversationTitle != null ? conversationTitle.toString() : null;
     }
 
     public CharSequence getConversationTitle() {
@@ -979,6 +1054,9 @@
                 groups.add(currentGroup);
                 if (sender == null) {
                     sender = mUser;
+                } else {
+                    // Remove all formatting from the sender name
+                    sender = sender.toBuilder().setName(Objects.toString(sender.getName())).build();
                 }
                 senders.add(sender);
                 currentSenderKey = key;
@@ -1176,7 +1254,6 @@
     }
 
     private void updateContentEndPaddings() {
-
         // Let's make sure the conversation header can't run into the expand button when we're
         // collapsed and update the paddings of the content
         int headerPaddingEnd;
diff --git a/core/java/com/android/internal/widget/LockPatternUtils.java b/core/java/com/android/internal/widget/LockPatternUtils.java
index 03a7b3d..93690cd 100644
--- a/core/java/com/android/internal/widget/LockPatternUtils.java
+++ b/core/java/com/android/internal/widget/LockPatternUtils.java
@@ -1430,6 +1430,32 @@
                 == StrongAuthTracker.STRONG_AUTH_REQUIRED_AFTER_USER_LOCKDOWN;
     }
 
+    private static class WrappedCallback extends ICheckCredentialProgressCallback.Stub {
+
+        private Handler mHandler;
+        private CheckCredentialProgressCallback mCallback;
+
+        WrappedCallback(Handler handler, CheckCredentialProgressCallback callback) {
+            mHandler = handler;
+            mCallback = callback;
+        }
+
+        @Override
+        public void onCredentialVerified() throws RemoteException {
+            if (mHandler == null) {
+                Log.e(TAG, "Handler is null during callback");
+            }
+            // Kill reference immediately to allow early GC at client side independent of
+            // when system_server decides to lose its reference to the
+            // ICheckCredentialProgressCallback binder object.
+            mHandler.post(() -> {
+                mCallback.onEarlyMatched();
+                mCallback = null;
+            });
+            mHandler = null;
+        }
+    }
+
     private ICheckCredentialProgressCallback wrapCallback(
             final CheckCredentialProgressCallback callback) {
         if (callback == null) {
@@ -1439,13 +1465,7 @@
                 throw new IllegalStateException("Must construct LockPatternUtils on a looper thread"
                         + " to use progress callbacks.");
             }
-            return new ICheckCredentialProgressCallback.Stub() {
-
-                @Override
-                public void onCredentialVerified() throws RemoteException {
-                    mHandler.post(callback::onEarlyMatched);
-                }
-            };
+            return new WrappedCallback(mHandler, callback);
         }
     }
 
diff --git a/core/java/com/android/server/SystemConfig.java b/core/java/com/android/server/SystemConfig.java
index 21ca948..d9ca9c2 100644
--- a/core/java/com/android/server/SystemConfig.java
+++ b/core/java/com/android/server/SystemConfig.java
@@ -1197,6 +1197,10 @@
             addFeature(PackageManager.FEATURE_APP_ENUMERATION, 0);
         }
 
+        if (Build.VERSION.FIRST_SDK_INT >= Build.VERSION_CODES.Q) {
+            addFeature(PackageManager.FEATURE_IPSEC_TUNNELS, 0);
+        }
+
         for (String featureName : mUnavailableFeatures) {
             removeFeature(featureName);
         }
diff --git a/core/proto/android/server/blobstoremanagerservice.proto b/core/proto/android/server/blobstoremanagerservice.proto
new file mode 100644
index 0000000..583b646
--- /dev/null
+++ b/core/proto/android/server/blobstoremanagerservice.proto
@@ -0,0 +1,70 @@
+/*
+ * Copyright (C) 2020 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.
+ */
+
+syntax = "proto2";
+package com.android.server.blob;
+
+option java_multiple_files = true;
+
+// The nested messages are used for statsd logging and should be kept in sync with the messages
+// of the same name in frameworks/base/cmds/statsd/src/atoms.proto
+message BlobStatsEventProto {
+  // Blob Committer stats
+  // Keep in sync between:
+  //     frameworks/base/core/proto/android/server/blobstoremanagerservice.proto
+  //     frameworks/base/cmds/statsd/src/atoms.proto
+  message BlobCommitterProto {
+    // Committer app's uid
+    optional int32 uid = 1;
+
+    // Unix epoch timestamp of the commit in milliseconds
+    optional int64 commit_timestamp_millis = 2;
+
+    // Flags of what access types the committer has set for the Blob
+    optional int32 access_mode = 3;
+
+    // Number of packages that have been whitelisted for ACCESS_TYPE_WHITELIST
+    optional int32 num_whitelisted_package = 4;
+  }
+
+  // Blob Leasee stats
+  // Keep in sync between:
+  //     frameworks/base/core/proto/android/server/blobstoremanagerservice.proto
+  //     frameworks/base/cmds/statsd/src/atoms.proto
+  message BlobLeaseeProto {
+    // Leasee app's uid
+    optional int32 uid = 1;
+
+    // Unix epoch timestamp for lease expiration in milliseconds
+    optional int64 lease_expiry_timestamp_millis = 2;
+  }
+
+  // List of Blob Committers
+  // Keep in sync between:
+  //     frameworks/base/core/proto/android/server/blobstoremanagerservice.proto
+  //     frameworks/base/cmds/statsd/src/atoms.proto
+  message BlobCommitterListProto {
+    repeated BlobCommitterProto committer = 1;
+  }
+
+  // List of Blob Leasees
+  // Keep in sync between:
+  //     frameworks/base/core/proto/android/server/blobstoremanagerservice.proto
+  //     frameworks/base/cmds/statsd/src/atoms.proto
+  message BlobLeaseeListProto {
+    repeated BlobLeaseeProto leasee = 1;
+  }
+}
\ No newline at end of file
diff --git a/core/proto/android/service/notification.proto b/core/proto/android/service/notification.proto
index ecb4193..8e4006a 100644
--- a/core/proto/android/service/notification.proto
+++ b/core/proto/android/service/notification.proto
@@ -274,4 +274,74 @@
 // Next Tag: 2
 message NotificationRemoteViewsProto {
     repeated PackageRemoteViewInfoProto package_remote_view_info = 1;
-}
\ No newline at end of file
+}
+
+/**
+ * Atom that represents an item in the list of Do Not Disturb rules, pulled from
+ * NotificationManagerService.java.
+ */
+message DNDModeProto {
+    enum Mode {
+        ROOT_CONFIG = -1;  // Used to distinguish the config (one per user) from the rules.
+        ZEN_MODE_OFF = 0;
+        ZEN_MODE_IMPORTANT_INTERRUPTIONS = 1;
+        ZEN_MODE_NO_INTERRUPTIONS = 2;
+        ZEN_MODE_ALARMS = 3;
+    }
+    optional int32 user = 1;  // Android user ID (0, 1, 10, ...)
+    optional bool enabled = 2;  // true for ROOT_CONFIG if a manualRule is enabled
+    optional bool channels_bypassing = 3; // only valid for ROOT_CONFIG
+    optional Mode zen_mode = 4;
+    // id is one of the system default rule IDs, or empty
+    // May also be "MANUAL_RULE" to indicate app-activation of the manual rule.
+    optional string id = 5;
+    optional int32 uid = 6; // currently only SYSTEM_UID or 0 for other
+    optional DNDPolicyProto policy = 7;
+}
+
+/**
+ * Atom that represents a Do Not Disturb policy, an optional detail proto for DNDModeProto.
+ */
+message DNDPolicyProto {
+    enum State {
+        STATE_UNSET = 0;
+        STATE_ALLOW = 1;
+        STATE_DISALLOW = 2;
+    }
+    optional State calls = 1;
+    optional State repeat_callers = 2;
+    optional State messages = 3;
+    optional State conversations = 4;
+    optional State reminders = 5;
+    optional State events = 6;
+    optional State alarms = 7;
+    optional State media = 8;
+    optional State system = 9;
+    optional State fullscreen = 10;
+    optional State lights = 11;
+    optional State peek = 12;
+    optional State status_bar = 13;
+    optional State badge = 14;
+    optional State ambient = 15;
+    optional State notification_list = 16;
+
+    enum PeopleType {
+        PEOPLE_UNSET = 0;
+        PEOPLE_ANYONE = 1;
+        PEOPLE_CONTACTS = 2;
+        PEOPLE_STARRED = 3;
+        PEOPLE_NONE = 4;
+    }
+
+    optional PeopleType allow_calls_from = 17;
+    optional PeopleType allow_messages_from = 18;
+
+    enum ConversationType {
+        CONV_UNSET = 0;
+        CONV_ANYONE = 1;
+        CONV_IMPORTANT = 2;
+        CONV_NONE = 3;
+    }
+
+    optional ConversationType allow_conversations_from = 19;
+}
diff --git a/core/proto/android/stats/connectivity/Android.bp b/core/proto/android/stats/connectivity/Android.bp
index 5d642d38..9cd233e 100644
--- a/core/proto/android/stats/connectivity/Android.bp
+++ b/core/proto/android/stats/connectivity/Android.bp
@@ -13,12 +13,12 @@
 // limitations under the License.
 
 java_library_static {
-    name: "networkstackprotosnano",
+    name: "networkstackprotos",
     proto: {
-        type: "nano",
+        type: "lite",
     },
     srcs: [
         "network_stack.proto",
     ],
-    sdk_version: "system_current",
+    sdk_version: "system_29",
 }
diff --git a/core/proto/android/stats/connectivity/network_stack.proto b/core/proto/android/stats/connectivity/network_stack.proto
index 7d9aa1c..e9726d7 100644
--- a/core/proto/android/stats/connectivity/network_stack.proto
+++ b/core/proto/android/stats/connectivity/network_stack.proto
@@ -20,6 +20,160 @@
 option java_multiple_files = true;
 option java_outer_classname = "NetworkStackProto";
 
+enum DhcpRenewResult {
+    RR_UNKNOWN = 0;
+    RR_SUCCESS = 1;
+    RR_ERROR_NAK = 2;
+    RR_ERROR_IP_MISMATCH = 3;
+    RR_ERROR_IP_EXPIRE = 4;
+}
+
+enum DisconnectCode {
+    DC_NONE = 0;
+    DC_NORMAL_TERMINATION = 1;
+    DC_PROVISIONING_FAIL = 2;
+    DC_ERROR_STARTING_IPV4 = 4;
+    DC_ERROR_STARTING_IPV6 = 5;
+    DC_ERROR_STARTING_IPREACHABILITYMONITOR = 6;
+    DC_INVALID_PROVISIONING = 7;
+    DC_INTERFACE_NOT_FOUND = 8;
+    DC_PROVISIONING_TIMEOUT = 9;
+}
+
+enum TransportType {
+    TT_UNKNOWN = 0;
+    // Indicates this network uses a Cellular transport
+    TT_CELLULAR = 1;
+    // Indicates this network uses a Wi-Fi transport
+    TT_WIFI = 2;
+    // Indicates this network uses a Bluetooth transport
+    TT_BLUETOOTH = 3;
+    // Indicates this network uses an Ethernet transport
+    TT_ETHERNET = 4;
+    // Indicates this network uses a Wi-Fi Aware transport
+    TT_WIFI_AWARE = 5;
+    // Indicates this network uses a LoWPAN transport
+    TT_LOWPAN = 6;
+    // Indicates this network uses a Cellular+VPN transport
+    TT_CELLULAR_VPN = 7;
+    // Indicates this network uses a Wi-Fi+VPN transport
+    TT_WIFI_VPN = 8;
+    // Indicates this network uses a Bluetooth+VPN transport
+    TT_BLUETOOTH_VPN = 9;
+    // Indicates this network uses an Ethernet+VPN transport
+    TT_ETHERNET_VPN = 10;
+    // Indicates this network uses a Wi-Fi+Cellular+VPN transport
+    TT_WIFI_CELLULAR_VPN = 11;
+    // Indicates this network uses for test only
+    TT_TEST = 12;
+}
+
+enum DhcpFeature {
+    DF_UNKNOWN = 0;
+    // DHCP INIT-REBOOT state
+    DF_INITREBOOT = 1;
+    // DHCP rapid commit option
+    DF_RAPIDCOMMIT  = 2;
+    // Duplicate address detection
+    DF_DAD = 3;
+    // Fast initial Link setup
+    DF_FILS = 4;
+}
+
+enum HostnameTransResult {
+    HTR_UNKNOWN = 0;
+    HTR_SUCCESS = 1;
+    HTR_FAILURE = 2;
+    HTR_DISABLE = 3;
+}
+
+enum ProbeResult {
+    PR_UNKNOWN = 0;
+    PR_SUCCESS = 1;
+    PR_FAILURE = 2;
+    PR_PORTAL = 3;
+    // DNS query for the probe host returned a private IP address
+    PR_PRIVATE_IP_DNS = 4;
+}
+
+enum ValidationResult {
+    VR_UNKNOWN = 0;
+    VR_SUCCESS = 1;
+    VR_FAILURE = 2;
+    VR_PORTAL = 3;
+    VR_PARTIAL = 4;
+}
+
+enum ProbeType {
+    PT_UNKNOWN = 0;
+    PT_DNS       = 1;
+    PT_HTTP      = 2;
+    PT_HTTPS     = 3;
+    PT_PAC       = 4;
+    PT_FALLBACK  = 5;
+    PT_PRIVDNS   = 6;
+    PT_CAPPORT_API = 7;
+}
+
+// The Dhcp error code is defined in android.net.metrics.DhcpErrorEvent
+enum DhcpErrorCode {
+    ET_UNKNOWN = 0;
+    ET_L2_ERROR = 1;
+    ET_L3_ERROR = 2;
+    ET_L4_ERROR = 3;
+    ET_DHCP_ERROR = 4;
+    ET_MISC_ERROR = 5;
+    /* Reserve for error type
+    // ET_L2_ERROR_TYPE = ET_L2_ERROR << 8;
+    ET_L2_ERROR_TYPE = 256;
+    // ET_L3_ERROR_TYPE = ET_L3_ERROR << 8;
+    ET_L3_ERROR_TYPE = 512;
+    // ET_L4_ERROR_TYPE = ET_L4_ERROR << 8;
+    ET_L4_ERROR_TYPE = 768;
+    // ET_DHCP_ERROR_TYPE = ET_DHCP_ERROR << 8;
+    ET_DHCP_ERROR_TYPE = 1024;
+    // ET_MISC_ERROR_TYPE = ET_MISC_ERROR << 8;
+    ET_MISC_ERROR_TYPE = 1280;
+    */
+    // ET_L2_TOO_SHORT = (ET_L2_ERROR_TYPE | 0x1) << 16;
+    ET_L2_TOO_SHORT = 16842752;
+    // ET_L2_WRONG_ETH_TYPE = (ET_L2_ERROR_TYPE | 0x2) << 16;
+    ET_L2_WRONG_ETH_TYPE = 16908288;
+    // ET_L3_TOO_SHORT = (ET_L3_ERROR_TYPE | 0x1) << 16;
+    ET_L3_TOO_SHORT = 33619968;
+    // ET_L3_NOT_IPV4 = (ET_L3_ERROR_TYPE | 0x2) << 16;
+    ET_L3_NOT_IPV4 = 33685504;
+    // ET_L3_INVALID_IP = (ET_L3_ERROR_TYPE | 0x3) << 16;
+    ET_L3_INVALID_IP = 33751040;
+    // ET_L4_NOT_UDP = (ET_L4_ERROR_TYPE | 0x1) << 16;
+    ET_L4_NOT_UDP = 50397184;
+    // ET_L4_WRONG_PORT = (ET_L4_ERROR_TYPE | 0x2) << 16;
+    ET_L4_WRONG_PORT = 50462720;
+    // ET_BOOTP_TOO_SHORT = (ET_DHCP_ERROR_TYPE | 0x1) << 16;
+    ET_BOOTP_TOO_SHORT = 67174400;
+    // ET_DHCP_BAD_MAGIC_COOKIE = (ET_DHCP_ERROR_TYPE | 0x2) << 16;
+    ET_DHCP_BAD_MAGIC_COOKIE = 67239936;
+    // ET_DHCP_INVALID_OPTION_LENGTH = (ET_DHCP_ERROR_TYPE | 0x3) << 16;
+    ET_DHCP_INVALID_OPTION_LENGTH = 67305472;
+    // ET_DHCP_NO_MSG_TYPE = (ET_DHCP_ERROR_TYPE | 0x4) << 16;
+    ET_DHCP_NO_MSG_TYPE = 67371008;
+    // ET_DHCP_UNKNOWN_MSG_TYPE = (ET_DHCP_ERROR_TYPE | 0x5) << 16;
+    ET_DHCP_UNKNOWN_MSG_TYPE = 67436544;
+    // ET_DHCP_NO_COOKIE = (ET_DHCP_ERROR_TYPE | 0x6) << 16;
+    ET_DHCP_NO_COOKIE = 67502080;
+    // ET_BUFFER_UNDERFLOW = (ET_MISC_ERROR_TYPE | 0x1) << 16;
+    ET_BUFFER_UNDERFLOW = 83951616;
+    // ET_RECEIVE_ERROR = (ET_MISC_ERROR_TYPE | 0x2) << 16;
+    ET_RECEIVE_ERROR = 84017152;
+    // ET_PARSING_ERROR = (ET_MISC_ERROR_TYPE | 0x3) << 16;
+    ET_PARSING_ERROR = 84082688;
+}
+
+enum NetworkQuirkEvent {
+    QE_UNKNOWN = 0;
+    QE_IPV6_PROVISIONING_ROUTER_LOST = 1;
+}
+
 message NetworkStackEventData {
 
 }
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index f71d406..99b46ec 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -3534,6 +3534,8 @@
          @hide -->
     <permission android:name="android.permission.MEDIA_RESOURCE_OVERRIDE_PID"
          android:protectionLevel="signature" />
+    <uses-permission android:name="android.permission.MEDIA_RESOURCE_OVERRIDE_PID" />
+
 
     <!-- Must be required by a {@link android.media.routing.MediaRouteService}
          to ensure that only the system can interact with it.
diff --git a/core/res/res/drawable-nodpi/ic_number11.xml b/core/res/res/drawable-nodpi/ic_number11.xml
new file mode 100644
index 0000000..daad611
--- /dev/null
+++ b/core/res/res/drawable-nodpi/ic_number11.xml
@@ -0,0 +1,12 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="24dp"
+    android:height="24dp"
+    android:viewportWidth="24"
+    android:viewportHeight="24">
+  <path
+      android:pathData="M5.14,5H1.59a0.88,0.88 0,0 1,-0.88 -0.89V0.88A0.87,0.87 0,0 1,1.59 0H9.36a0.87,0.87 0,0 1,0.88 0.88V23.12a0.88,0.88 0,0 1,-0.88 0.88H6a0.88,0.88 0,0 1,-0.88 -0.88Z"
+      android:fillColor="#000000"/>
+  <path
+      android:pathData="M18.19,5H14.64a0.89,0.89 0,0 1,-0.88 -0.89V0.88A0.88,0.88 0,0 1,14.64 0h7.78a0.87,0.87 0,0 1,0.87 0.88V23.12a0.88,0.88 0,0 1,-0.87 0.88H19.08a0.89,0.89 0,0 1,-0.89 -0.88Z"
+      android:fillColor="#000000"/>
+</vector>
diff --git a/core/res/res/drawable/conversation_badge_background.xml b/core/res/res/drawable/conversation_badge_background.xml
index 0dd0dcd..9e6405d 100644
--- a/core/res/res/drawable/conversation_badge_background.xml
+++ b/core/res/res/drawable/conversation_badge_background.xml
@@ -22,7 +22,7 @@
         android:color="#ffffff"/>
 
     <size
-        android:width="26dp"
-        android:height="26dp"/>
+        android:width="20dp"
+        android:height="20dp"/>
 </shape>
 
diff --git a/core/res/res/drawable/conversation_badge_ring.xml b/core/res/res/drawable/conversation_badge_ring.xml
index 11ba8ad..eee53d1 100644
--- a/core/res/res/drawable/conversation_badge_ring.xml
+++ b/core/res/res/drawable/conversation_badge_ring.xml
@@ -16,17 +16,18 @@
   -->
 
 <shape xmlns:android="http://schemas.android.com/apk/res/android"
-    android:shape="oval">
-
-    <solid
-        android:color="@color/transparent"/>
+    android:shape="oval"
+>
+    <solid android:color="@color/transparent" />
 
     <stroke
         android:color="@color/conversation_important_highlight"
-        android:width="2dp"/>
+        android:width="@dimen/importance_ring_stroke_width"
+    />
 
     <size
-        android:width="26dp"
-        android:height="26dp"/>
+        android:width="@dimen/importance_ring_size"
+        android:height="@dimen/importance_ring_size"
+    />
 </shape>
 
diff --git a/core/res/res/layout-car/car_alert_dialog.xml b/core/res/res/layout-car/car_alert_dialog.xml
new file mode 100644
index 0000000..569e594
--- /dev/null
+++ b/core/res/res/layout-car/car_alert_dialog.xml
@@ -0,0 +1,85 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright (C) 2020 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.internal.widget.AlertDialogLayout
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:id="@+id/parentPanel"
+    android:layout_width="match_parent"
+    android:layout_height="wrap_content"
+    android:gravity="start|top"
+    android:orientation="vertical">
+
+    <include layout="@layout/car_alert_dialog_title" />
+
+    <FrameLayout
+        android:id="@+id/contentPanel"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:minHeight="48dp">
+
+        <ScrollView
+            android:id="@+id/scrollView"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:clipToPadding="false">
+
+            <LinearLayout
+                android:layout_width="match_parent"
+                android:layout_height="wrap_content"
+                android:orientation="vertical">
+
+                <Space
+                    android:id="@+id/textSpacerNoTitle"
+                    android:visibility="gone"
+                    android:layout_width="match_parent"
+                    android:layout_height="@dimen/dialog_no_title_padding_top" />
+
+                <TextView
+                    android:id="@+id/message"
+                    android:layout_width="match_parent"
+                    android:layout_height="wrap_content"
+                    android:layout_marginStart="@dimen/text_view_start_margin"
+                    android:layout_marginEnd="@dimen/text_view_end_margin"
+                    style="@style/CarBody2"/>
+
+                <!-- we don't need this spacer, but the id needs to be here for compatibility -->
+                <Space
+                    android:id="@+id/textSpacerNoButtons"
+                    android:visibility="gone"
+                    android:layout_width="match_parent"
+                    android:layout_height="0dp" />
+            </LinearLayout>
+        </ScrollView>
+    </FrameLayout>
+
+    <FrameLayout
+        android:id="@+id/customPanel"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:minHeight="48dp">
+
+        <FrameLayout
+            android:id="@+id/custom"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content" />
+    </FrameLayout>
+
+    <include
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        layout="@layout/car_alert_dialog_button_bar" />
+</com.android.internal.widget.AlertDialogLayout>
diff --git a/core/res/res/layout-car/car_alert_dialog_button_bar.xml b/core/res/res/layout-car/car_alert_dialog_button_bar.xml
new file mode 100644
index 0000000..277b0dc
--- /dev/null
+++ b/core/res/res/layout-car/car_alert_dialog_button_bar.xml
@@ -0,0 +1,64 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright (C) 2020 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.
+  -->
+
+<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
+            android:id="@+id/buttonPanel"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:scrollbarAlwaysDrawVerticalTrack="true"
+            android:scrollIndicators="top|bottom"
+            android:fillViewport="true"
+            style="?attr/buttonBarStyle">
+    <com.android.internal.widget.ButtonBarLayout
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:paddingStart="@dimen/button_bar_layout_start_padding"
+        android:paddingEnd="@dimen/button_bar_layout_end_padding"
+        android:paddingTop="@dimen/button_bar_layout_top_padding"
+        android:layoutDirection="locale"
+        android:orientation="horizontal"
+        android:gravity="left|center_vertical">
+
+        <Button
+            android:id="@+id/button3"
+            style="@style/CarAction1"
+            android:background="@drawable/car_dialog_button_background"
+            android:layout_marginRight="@dimen/button_end_margin"
+            android:layout_width="wrap_content"
+            android:layout_height="@dimen/button_layout_height" />
+
+        <Button
+            android:id="@+id/button2"
+            style="@style/CarAction1"
+            android:background="@drawable/car_dialog_button_background"
+            android:layout_marginRight="@dimen/button_end_margin"
+            android:layout_width="wrap_content"
+            android:layout_height="@dimen/button_layout_height" />
+
+        <Button
+            android:id="@+id/button1"
+            style="@style/CarAction1"
+            android:background="@drawable/car_dialog_button_background"
+            android:layout_width="wrap_content"
+            android:layout_height="@dimen/button_layout_height" />
+        <Space
+            android:id="@+id/spacer"
+            android:layout_width="0dp"
+            android:layout_height="0dp"
+            android:visibility="invisible" />
+    </com.android.internal.widget.ButtonBarLayout>
+</ScrollView>
diff --git a/core/res/res/layout-car/car_alert_dialog_title.xml b/core/res/res/layout-car/car_alert_dialog_title.xml
new file mode 100644
index 0000000..ba735a6
--- /dev/null
+++ b/core/res/res/layout-car/car_alert_dialog_title.xml
@@ -0,0 +1,62 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright (C) 2020 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.
+  -->
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+              android:id="@+id/topPanel"
+              android:layout_width="match_parent"
+              android:layout_height="wrap_content"
+              android:gravity="center_vertical"
+              android:orientation="vertical">
+
+    <!-- If the client uses a customTitle, it will be added here. -->
+
+    <RelativeLayout
+        android:id="@+id/title_template"
+        android:layout_width="match_parent"
+        android:layout_height="@dimen/car_card_header_height"
+        android:orientation="horizontal">
+
+        <ImageView
+            android:id="@+id/icon"
+            android:layout_width="@dimen/image_size"
+            android:layout_height="@dimen/image_size"
+            android:layout_marginStart="@dimen/image_margin_start"
+            android:layout_alignParentStart="true"
+            android:layout_centerVertical="true"
+            android:scaleType="fitCenter"
+            android:src="@null" />
+
+        <com.android.internal.widget.DialogTitle
+            android:id="@+id/alertTitle"
+            android:maxLines="1"
+            android:ellipsize="none"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:layout_toEndOf="@+id/icon"
+            android:textAlignment="viewStart"
+            android:layout_centerVertical="true"
+            android:layout_marginStart="@dimen/text_view_start_margin"
+            android:layout_marginEnd="@dimen/text_view_end_margin"
+            style="?attr/windowTitleStyle" />
+    </RelativeLayout>
+
+    <Space
+        android:id="@+id/titleDividerNoCustom"
+        android:visibility="gone"
+        android:layout_width="match_parent"
+        android:layout_height="0dp" />
+</LinearLayout>
diff --git a/core/res/res/layout/chooser_grid_preview_text.xml b/core/res/res/layout/chooser_grid_preview_text.xml
index 00291746..1d18648 100644
--- a/core/res/res/layout/chooser_grid_preview_text.xml
+++ b/core/res/res/layout/chooser_grid_preview_text.xml
@@ -44,6 +44,8 @@
         android:ellipsize="end"
         android:fontFamily="@android:string/config_headlineFontFamily"
         android:textColor="?android:attr/textColorPrimary"
+        android:textAlignment="gravity"
+        android:textDirection="locale"
         android:maxLines="2"
         android:focusable="true"/>
 
@@ -90,6 +92,8 @@
         android:layout_gravity="center_vertical"
         android:ellipsize="end"
         android:maxLines="2"
+        android:textAlignment="gravity"
+        android:textDirection="locale"
         android:textAppearance="@style/TextAppearance.DeviceDefault.WindowTitle"
         android:fontFamily="@android:string/config_headlineFontFamily"/>
   </LinearLayout>
diff --git a/core/res/res/layout/notification_template_material_conversation.xml b/core/res/res/layout/notification_template_material_conversation.xml
index 9a9d8b9..139185f 100644
--- a/core/res/res/layout/notification_template_material_conversation.xml
+++ b/core/res/res/layout/notification_template_material_conversation.xml
@@ -38,6 +38,8 @@
         <FrameLayout
             android:layout_width="wrap_content"
             android:layout_height="wrap_content"
+            android:clipChildren="false"
+            android:clipToPadding="false"
             android:layout_gravity="top|center_horizontal"
         >
 
@@ -63,13 +65,17 @@
                 android:layout_height="@dimen/conversation_icon_size_badged"
                 android:layout_marginLeft="@dimen/conversation_badge_side_margin"
                 android:layout_marginTop="@dimen/conversation_badge_side_margin"
+                android:clipChildren="false"
+                android:clipToPadding="false"
             >
                 <com.android.internal.widget.CachingIconView
                     android:id="@+id/conversation_icon_badge_bg"
                     android:layout_width="match_parent"
                     android:layout_height="match_parent"
+                    android:layout_gravity="center"
                     android:src="@drawable/conversation_badge_background"
                     android:forceHasOverlappingRendering="false"
+                    android:scaleType="center"
                 />
                 <com.android.internal.widget.CachingIconView
                     android:id="@+id/icon"
@@ -81,11 +87,14 @@
                 />
                 <com.android.internal.widget.CachingIconView
                     android:id="@+id/conversation_icon_badge_ring"
-                    android:layout_width="match_parent"
-                    android:layout_height="match_parent"
+                    android:layout_width="wrap_content"
+                    android:layout_height="wrap_content"
+                    android:layout_gravity="center"
                     android:src="@drawable/conversation_badge_ring"
                     android:visibility="gone"
                     android:forceHasOverlappingRendering="false"
+                    android:clipToPadding="false"
+                    android:scaleType="center"
                 />
             </FrameLayout>
         </FrameLayout>
@@ -132,21 +141,20 @@
                         android:id="@+id/conversation_text"
                         android:layout_width="wrap_content"
                         android:layout_height="wrap_content"
-                        android:layout_marginEnd="@dimen/notification_header_separating_margin"
+                        android:layout_marginEnd="@dimen/notification_conversation_header_separating_margin"
                         android:textAppearance="@style/TextAppearance.DeviceDefault.Notification.Title"
                         android:textSize="16sp"
                         android:singleLine="true"
                         android:layout_weight="1"
                         />
 
-
                     <TextView
                         android:id="@+id/app_name_divider"
                         android:layout_width="wrap_content"
                         android:layout_height="wrap_content"
                         android:textAppearance="?attr/notificationHeaderTextAppearance"
-                        android:layout_marginStart="@dimen/notification_header_separating_margin"
-                        android:layout_marginEnd="@dimen/notification_header_separating_margin"
+                        android:layout_marginStart="@dimen/notification_conversation_header_separating_margin"
+                        android:layout_marginEnd="@dimen/notification_conversation_header_separating_margin"
                         android:text="@string/notification_header_divider_symbol"
                         android:layout_gravity="center"
                         android:paddingTop="1sp"
@@ -161,9 +169,11 @@
                         android:layout_width="wrap_content"
                         android:layout_height="wrap_content"
                         android:layout_gravity="center"
-                        android:layout_marginStart="@dimen/notification_header_separating_margin"
+                        android:layout_marginStart="@dimen/notification_conversation_header_separating_margin"
+                        android:layout_marginEnd="@dimen/notification_conversation_header_separating_margin"
                         android:paddingTop="1sp"
                         android:singleLine="true"
+                        android:visibility="gone"
                     />
 
                     <TextView
@@ -171,8 +181,8 @@
                         android:layout_width="wrap_content"
                         android:layout_height="wrap_content"
                         android:textAppearance="?attr/notificationHeaderTextAppearance"
-                        android:layout_marginStart="@dimen/notification_header_separating_margin"
-                        android:layout_marginEnd="@dimen/notification_header_separating_margin"
+                        android:layout_marginStart="@dimen/notification_conversation_header_separating_margin"
+                        android:layout_marginEnd="@dimen/notification_conversation_header_separating_margin"
                         android:text="@string/notification_header_divider_symbol"
                         android:layout_gravity="center"
                         android:paddingTop="1sp"
@@ -182,11 +192,11 @@
 
                     <DateTimeView
                         android:id="@+id/time"
-                        android:textAppearance="@style/TextAppearance.Material.Notification.Time"
+                        android:textAppearance="@style/TextAppearance.DeviceDefault.Notification.Time"
                         android:layout_width="wrap_content"
                         android:layout_height="wrap_content"
                         android:layout_gravity="center"
-                        android:layout_marginStart="@dimen/notification_header_separating_margin"
+                        android:layout_marginStart="@dimen/notification_conversation_header_separating_margin"
                         android:paddingTop="1sp"
                         android:showRelative="true"
                         android:singleLine="true"
diff --git a/core/res/res/values-gl/strings.xml b/core/res/res/values-gl/strings.xml
index 1a8c129..8272fed 100644
--- a/core/res/res/values-gl/strings.xml
+++ b/core/res/res/values-gl/strings.xml
@@ -1786,7 +1786,7 @@
     <string name="managed_profile_label_badge" msgid="6762559569999499495">"<xliff:g id="LABEL">%1$s</xliff:g> do traballo"</string>
     <string name="managed_profile_label_badge_2" msgid="5673187309555352550">"2.º <xliff:g id="LABEL">%1$s</xliff:g> do traballo"</string>
     <string name="managed_profile_label_badge_3" msgid="6882151970556391957">"3.º <xliff:g id="LABEL">%1$s</xliff:g> do traballo"</string>
-    <string name="lock_to_app_unlock_pin" msgid="3890940811866290782">"Solicitar PIN para soltar fixación"</string>
+    <string name="lock_to_app_unlock_pin" msgid="3890940811866290782">"Solicitar PIN para deixar de fixar"</string>
     <string name="lock_to_app_unlock_pattern" msgid="2694204070499712503">"Solicitar un padrón de desbloqueo antes de deixar de fixar a pantalla"</string>
     <string name="lock_to_app_unlock_password" msgid="9126722403506560473">"Solicitar un contrasinal para deixar de fixar a pantalla"</string>
     <string name="package_installed_device_owner" msgid="7035926868974878525">"Instalado polo teu administrador"</string>
diff --git a/core/res/res/values-mn/strings.xml b/core/res/res/values-mn/strings.xml
index 2877e80..11683ae 100644
--- a/core/res/res/values-mn/strings.xml
+++ b/core/res/res/values-mn/strings.xml
@@ -1786,7 +1786,7 @@
     <string name="managed_profile_label_badge" msgid="6762559569999499495">"Ажлын <xliff:g id="LABEL">%1$s</xliff:g>"</string>
     <string name="managed_profile_label_badge_2" msgid="5673187309555352550">"2 дахь ажил <xliff:g id="LABEL">%1$s</xliff:g>"</string>
     <string name="managed_profile_label_badge_3" msgid="6882151970556391957">"3 дахь ажил <xliff:g id="LABEL">%1$s</xliff:g>"</string>
-    <string name="lock_to_app_unlock_pin" msgid="3890940811866290782">"Тогтоосныг суллахаас өмнө PIN асуух"</string>
+    <string name="lock_to_app_unlock_pin" msgid="3890940811866290782">"Бэхэлснийг болиулахаасаа өмнө PIN асуух"</string>
     <string name="lock_to_app_unlock_pattern" msgid="2694204070499712503">"Тогтоосныг суллахаас өмнө түгжээ тайлах хээ асуух"</string>
     <string name="lock_to_app_unlock_password" msgid="9126722403506560473">"Тогтоосныг суллахаас өмнө нууц үг асуух"</string>
     <string name="package_installed_device_owner" msgid="7035926868974878525">"Таны админ суулгасан"</string>
@@ -1841,7 +1841,7 @@
     <string name="zen_mode_default_weeknights_name" msgid="7902108149994062847">"Ажлын өдрийн шөнө"</string>
     <string name="zen_mode_default_weekends_name" msgid="4707200272709377930">"Амралтын өдөр"</string>
     <string name="zen_mode_default_events_name" msgid="2280682960128512257">"Үйл явдал"</string>
-    <string name="zen_mode_default_every_night_name" msgid="1467765312174275823">"Идэвхгүй"</string>
+    <string name="zen_mode_default_every_night_name" msgid="1467765312174275823">"Унтлагын цаг"</string>
     <string name="muted_by" msgid="91464083490094950">"<xliff:g id="THIRD_PARTY">%1$s</xliff:g> зарим дууны дууг хааж байна"</string>
     <string name="system_error_wipe_data" msgid="5910572292172208493">"Таны төхөөрөмжид дотоод алдаа байна.Та төхөөрөмжөө үйлдвэрээс гарсан төлөвт шилжүүлэх хүртэл таны төхөөрөмж чинь тогтворгүй байж болох юм."</string>
     <string name="system_error_manufacturer" msgid="703545241070116315">"Таны төхөөрөмжид дотоод алдаа байна. Дэлгэрэнгүй мэдээлэл авахыг хүсвэл үйлдвэрлэгчтэйгээ холбоо барина уу."</string>
diff --git a/core/res/res/values-my/strings.xml b/core/res/res/values-my/strings.xml
index 1f72b8b..d910fc0 100644
--- a/core/res/res/values-my/strings.xml
+++ b/core/res/res/values-my/strings.xml
@@ -1551,7 +1551,7 @@
     <string name="activity_resolver_use_once" msgid="948462794469672658">"တစ်ခါတည်း"</string>
     <string name="activity_resolver_work_profiles_support" msgid="4071345609235361269">"%1$s က အလုပ်ပရိုဖိုင်ကို မပံ့ပိုးပါ။"</string>
     <string name="default_audio_route_name" product="tablet" msgid="367936735632195517">"တက်ဘလက်"</string>
-    <string name="default_audio_route_name" product="tv" msgid="4908971385068087367">"တီဗွီ"</string>
+    <string name="default_audio_route_name" product="tv" msgid="4908971385068087367">"TV"</string>
     <string name="default_audio_route_name" product="default" msgid="9213546147739983977">"ဖုန်း"</string>
     <string name="default_audio_route_name_dock_speakers" msgid="1551166029093995289">"အထိုင်ရှိသော စပီကာများ"</string>
     <string name="default_audio_route_name_hdmi" msgid="5474470558160717850">"HDMI"</string>
diff --git a/core/res/res/values-nl/strings.xml b/core/res/res/values-nl/strings.xml
index 1739453..b1c4fbb 100644
--- a/core/res/res/values-nl/strings.xml
+++ b/core/res/res/values-nl/strings.xml
@@ -951,11 +951,11 @@
     <string name="autofill_area" msgid="8289022370678448983">"Gebied"</string>
     <string name="autofill_emirate" msgid="2544082046790551168">"Emiraat"</string>
     <string name="permlab_readHistoryBookmarks" msgid="9102293913842539697">"je webbladwijzers en -geschiedenis lezen"</string>
-    <string name="permdesc_readHistoryBookmarks" msgid="2323799501008967852">"Hiermee kan de app de geschiedenis lezen van alle URL\'s die in de systeemeigen browser zijn bezocht, en alle bladwijzers in de systeemeigen browser. Let op: deze toestemming kan niet worden geforceerd door andere browsers of andere apps met internetmogelijkheden."</string>
+    <string name="permdesc_readHistoryBookmarks" msgid="2323799501008967852">"Hiermee kan de app de geschiedenis lezen van alle URL\'s die in de systeemeigen browser zijn bezocht, en alle bookmarks in de systeemeigen browser. Let op: deze toestemming kan niet worden geforceerd door andere browsers of andere apps met internetmogelijkheden."</string>
     <string name="permlab_writeHistoryBookmarks" msgid="6090259925187986937">"webbladwijzers en -geschiedenis schrijven"</string>
-    <string name="permdesc_writeHistoryBookmarks" product="tablet" msgid="573341025292489065">"Hiermee kan de app de webgeschiedenis wijzigen in de systeemeigen browser en de bladwijzers die zijn opgeslagen op je tablet. Deze toestemming kan niet worden geforceerd door andere browsers of andere apps met internetmogelijkheden.."</string>
-    <string name="permdesc_writeHistoryBookmarks" product="tv" msgid="88642768580408561">"Hiermee kan de app de browsergeschiedenis of opgeslagen bladwijzers bewerken op je Android TV-apparaat. Hierdoor kan de app mogelijk browsergegevens wissen of aanpassen. Opmerking: Dit recht kan niet worden afgedwongen door andere browsers of andere apps met internetmogelijkheden."</string>
-    <string name="permdesc_writeHistoryBookmarks" product="default" msgid="2245203087160913652">"Hiermee kan de app de webgeschiedenis wijzigen in de systeemeigen browser en de bladwijzers die zijn opgeslagen op je telefoon. Deze toestemming kan niet worden geforceerd door andere browsers of andere apps met internetmogelijkheden."</string>
+    <string name="permdesc_writeHistoryBookmarks" product="tablet" msgid="573341025292489065">"Hiermee kan de app de webgeschiedenis wijzigen in de systeemeigen browser en de bookmarks die zijn opgeslagen op je tablet. Deze toestemming kan niet worden geforceerd door andere browsers of andere apps met internetmogelijkheden.."</string>
+    <string name="permdesc_writeHistoryBookmarks" product="tv" msgid="88642768580408561">"Hiermee kan de app de browsergeschiedenis of opgeslagen bookmarks bewerken op je Android TV-apparaat. Hierdoor kan de app mogelijk browsergegevens wissen of aanpassen. Opmerking: Dit recht kan niet worden afgedwongen door andere browsers of andere apps met internetmogelijkheden."</string>
+    <string name="permdesc_writeHistoryBookmarks" product="default" msgid="2245203087160913652">"Hiermee kan de app de webgeschiedenis wijzigen in de systeemeigen browser en de bookmarks die zijn opgeslagen op je telefoon. Deze toestemming kan niet worden geforceerd door andere browsers of andere apps met internetmogelijkheden."</string>
     <string name="permlab_setAlarm" msgid="1158001610254173567">"een wekker instellen"</string>
     <string name="permdesc_setAlarm" msgid="2185033720060109640">"Hiermee kan de app een wekker instellen in een geïnstalleerde wekker-app. Deze functie wordt door sommige wekker-apps niet geïmplementeerd."</string>
     <string name="permlab_addVoicemail" msgid="4770245808840814471">"voicemail toevoegen"</string>
diff --git a/core/res/res/values-or/strings.xml b/core/res/res/values-or/strings.xml
index 4224523..5986e76 100644
--- a/core/res/res/values-or/strings.xml
+++ b/core/res/res/values-or/strings.xml
@@ -787,7 +787,7 @@
     <string name="imProtocolYahoo" msgid="5373338758093392231">"Yahoo"</string>
     <string name="imProtocolSkype" msgid="1486297589164830043">"Skype"</string>
     <string name="imProtocolQq" msgid="7254708777029006592">"QQ"</string>
-    <string name="imProtocolGoogleTalk" msgid="9194016024343166782">"ହ୍ୟାଙ୍ଗଆଉଟ୍ସ"</string>
+    <string name="imProtocolGoogleTalk" msgid="9194016024343166782">"Hangouts"</string>
     <string name="imProtocolIcq" msgid="2410325380427389521">"ICQ"</string>
     <string name="imProtocolJabber" msgid="7919269388889582015">"Jabber"</string>
     <string name="imProtocolNetMeeting" msgid="4985002408136148256">"NetMeeting"</string>
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index b79c9e8..0e11d49 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -4313,10 +4313,6 @@
     notifications until they target R -->
     <string-array name="config_notificationMsgPkgsAllowedAsConvos" translatable="false"/>
 
-    <!-- Contains a blacklist of apps that should not get pre-installed carrier app permission
-         grants, even if the UICC claims that the app should be privileged. See b/138150105 -->
-    <string-array name="config_restrictedPreinstalledCarrierApps" translatable="false"/>
-
     <!-- Sharesheet: define a max number of targets per application for new shortcuts-based direct share introduced in Q -->
     <integer name="config_maxShortcutTargetsPerApp">3</integer>
 
diff --git a/core/res/res/values/dimens.xml b/core/res/res/values/dimens.xml
index 59bb052..ebaf85c 100644
--- a/core/res/res/values/dimens.xml
+++ b/core/res/res/values/dimens.xml
@@ -273,6 +273,9 @@
     <!-- The margin before and after each of the items in the notification header. -->
     <dimen name="notification_header_separating_margin">2dp</dimen>
 
+    <!-- The margin before and after each of the items in the conversation header. -->
+    <dimen name="notification_conversation_header_separating_margin">4dp</dimen>
+
     <!-- The absolute size of the notification expand icon. -2 for wrap_content. -->
     <dimen name="notification_header_expand_icon_size">-2px</dimen>
 
@@ -719,13 +722,19 @@
     <!-- The width of the protection of the face pile layout when expanded-->
     <dimen name="conversation_face_pile_protection_width_expanded">1dp</dimen>
     <!-- The padding of the expanded message container-->
-    <dimen name="expanded_group_conversation_message_padding">14dp</dimen>
+    <dimen name="expanded_group_conversation_message_padding">17dp</dimen>
+    <!-- The stroke width of the ring used to visually mark a conversation as important -->
+    <dimen name="importance_ring_stroke_width">2dp</dimen>
+    <!-- The maximum stroke width used for the animation shown when a conversation is marked as important -->
+    <dimen name="importance_ring_anim_max_stroke_width">10dp</dimen>
+    <!-- The size of the importance ring -->
+    <dimen name="importance_ring_size">20dp</dimen>
 
     <!-- The top padding of the conversation icon container in the regular state-->
-    <dimen name="conversation_icon_container_top_padding">9dp</dimen>
+    <dimen name="conversation_icon_container_top_padding">12dp</dimen>
 
     <!-- The top padding of the conversation icon container when the avatar is small-->
-    <dimen name="conversation_icon_container_top_padding_small_avatar">17.5dp</dimen>
+    <dimen name="conversation_icon_container_top_padding_small_avatar">9dp</dimen>
 
     <!-- The padding of the conversation header when expanded. This is calculated from the expand button size + notification_content_margin_end -->
     <dimen name="conversation_header_expanded_padding_end">38dp</dimen>
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index a1c2450..0c87453 100644
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -4363,9 +4363,6 @@
     <!-- The delete-widget drop target button text -->
     <string name="kg_reordering_delete_drop_target_text">Remove</string>
 
-    <!-- Toast message for background started foreground service while-in-use permission restriction feature -->
-    <string name="allow_while_in_use_permission_in_fgs">The background started foreground service from <xliff:g id="packageName" example="com.example">%1$s</xliff:g> will not have while-in-use permission in future R builds. Please see go/r-bg-fgs-restriction and file a bugreport.</string>
-
     <!-- Message shown in dialog when user is attempting to set the music volume above the
     recommended maximum level for headphones -->
     <string name="safe_media_volume_warning" product="default">
diff --git a/core/res/res/values/styles_device_defaults.xml b/core/res/res/values/styles_device_defaults.xml
index e9ac679..ef019ba 100644
--- a/core/res/res/values/styles_device_defaults.xml
+++ b/core/res/res/values/styles_device_defaults.xml
@@ -296,9 +296,12 @@
     <style name="TextAppearance.DeviceDefault.Notification.Info" parent="TextAppearance.Material.Notification.Info">
         <item name="fontFamily">@string/config_bodyFontFamily</item>
     </style>
+    <style name="TextAppearance.DeviceDefault.Notification.Time" parent="TextAppearance.Material.Notification.Time">
+        <item name="fontFamily">@string/config_bodyFontFamily</item>
+    </style>
     <style name="TextAppearance.DeviceDefault.Notification.Conversation.AppName"
-           parent="@*android:style/TextAppearance.DeviceDefault.Notification.Title">
-        <item name="android:textSize">16sp</item>
+           parent="TextAppearance.Material.Notification.Conversation.AppName">
+        <item name="fontFamily">@string/config_headlineFontFamilyMedium</item>
     </style>
     <style name="TextAppearance.DeviceDefault.Widget" parent="TextAppearance.Material.Widget">
         <item name="fontFamily">@string/config_bodyFontFamily</item>
diff --git a/core/res/res/values/styles_material.xml b/core/res/res/values/styles_material.xml
index 2415837..67536fd 100644
--- a/core/res/res/values/styles_material.xml
+++ b/core/res/res/values/styles_material.xml
@@ -491,6 +491,10 @@
         <item name="textColor">#66000000</item>
     </style>
 
+    <style name="TextAppearance.Material.Notification.Conversation.AppName" parent="TextAppearance.Material.Notification.Title">
+        <item name="android:textSize">16sp</item>
+    </style>
+
     <style name="TextAppearance.Material.ListItem" parent="TextAppearance.Material.Subhead" />
     <style name="TextAppearance.Material.ListItemSecondary" parent="TextAppearance.Material.Body1" />
 
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index ab4005b..08d1182 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -3827,10 +3827,10 @@
 
   <java-symbol type="string" name="config_defaultSupervisionProfileOwnerComponent" />
   <java-symbol type="bool" name="config_inflateSignalStrength" />
-  <java-symbol type="array" name="config_restrictedPreinstalledCarrierApps" />
 
   <java-symbol type="drawable" name="android_logotype" />
   <java-symbol type="layout" name="platlogo_layout" />
+  <java-symbol type="drawable" name="ic_number11" />
 
   <java-symbol type="integer" name="config_notificationWarnRemoteViewSizeBytes" />
   <java-symbol type="integer" name="config_notificationStripRemoteViewSizeBytes" />
@@ -3903,6 +3903,12 @@
   <java-symbol type="array" name="config_defaultImperceptibleKillingExemptionPkgs" />
   <java-symbol type="array" name="config_defaultImperceptibleKillingExemptionProcStates" />
 
+  <java-symbol type="color" name="conversation_important_highlight" />
+  <java-symbol type="dimen" name="importance_ring_stroke_width" />
+  <java-symbol type="dimen" name="importance_ring_anim_max_stroke_width" />
+  <java-symbol type="dimen" name="importance_ring_size" />
+  <java-symbol type="dimen" name="conversation_icon_size_badged" />
+
   <java-symbol type="id" name="header_icon_container" />
   <java-symbol type="attr" name="notificationHeaderTextAppearance" />
   <java-symbol type="string" name="conversation_single_line_name_display" />
@@ -3950,6 +3956,13 @@
   <java-symbol type="id" name="conversation_unread_count" />
   <java-symbol type="string" name="unread_convo_overflow" />
   <java-symbol type="style" name="TextAppearance.DeviceDefault.Notification.Conversation.AppName" />
+  <java-symbol type="drawable" name="conversation_badge_background" />
+  <java-symbol type="drawable" name="conversation_badge_ring" />
+  <java-symbol type="color" name="conversation_important_highlight" />
+  <java-symbol type="dimen" name="importance_ring_stroke_width" />
+  <java-symbol type="dimen" name="importance_ring_anim_max_stroke_width" />
+  <java-symbol type="dimen" name="importance_ring_size" />
+  <java-symbol type="dimen" name="conversation_icon_size_badged" />
 
   <!-- Intent resolver and share sheet -->
   <java-symbol type="string" name="resolver_personal_tab" />
@@ -3995,9 +4008,6 @@
   <java-symbol type="dimen" name="resolver_empty_state_container_padding_top" />
   <java-symbol type="dimen" name="resolver_empty_state_container_padding_bottom" />
 
-  <!-- Toast message for background started foreground service while-in-use permission restriction feature -->
-  <java-symbol type="string" name="allow_while_in_use_permission_in_fgs" />
-
   <java-symbol type="string" name="config_deviceSpecificDisplayAreaPolicyProvider" />
 
   <!-- Whether to expand the lock screen user switcher by default -->
diff --git a/core/res/res/xml/sms_short_codes.xml b/core/res/res/xml/sms_short_codes.xml
index 70917e7..d5733e3 100644
--- a/core/res/res/xml/sms_short_codes.xml
+++ b/core/res/res/xml/sms_short_codes.xml
@@ -39,7 +39,7 @@
     <!-- Albania: 5 digits, known short codes listed -->
     <shortcode country="al" pattern="\\d{5}" premium="15191|55[56]00" />
 
-    <!-- Argentia: 5 digits, known short codes listed -->
+    <!-- Argentina: 5 digits, known short codes listed -->
     <shortcode country="ar" pattern="\\d{5}" free="11711|28291" />
 
     <!-- Armenia: 3-4 digits, emergency numbers 10[123] -->
@@ -70,7 +70,7 @@
     <shortcode country="by" pattern="\\d{4}" premium="3336|4161|444[4689]|501[34]|7781" />
 
     <!-- Canada: 5-6 digits -->
-    <shortcode country="ca" pattern="\\d{5,6}" premium="60999|88188|43030" standard="244444" />
+    <shortcode country="ca" pattern="\\d{5,6}" premium="60999|88188|43030" standard="244444" free="455677" />
 
     <!-- Switzerland: 3-5 digits: http://www.swisscom.ch/fxres/kmu/thirdpartybusiness_code_of_conduct_en.pdf -->
     <shortcode country="ch" pattern="[2-9]\\d{2,4}" premium="543|83111|30118" free="98765|30075|30047" />
diff --git a/core/tests/coretests/src/android/view/InsetsControllerTest.java b/core/tests/coretests/src/android/view/InsetsControllerTest.java
index d4c2569..964ae21 100644
--- a/core/tests/coretests/src/android/view/InsetsControllerTest.java
+++ b/core/tests/coretests/src/android/view/InsetsControllerTest.java
@@ -678,7 +678,8 @@
             final InsetsState currentState = new InsetsState(mController.getState());
             // The caption bar source should be synced with the info in mAttachInfo.
             assertEquals(captionFrame, currentState.peekSource(ITYPE_CAPTION_BAR).getFrame());
-            assertTrue(currentState.equals(state, true /* excludingCaptionInsets*/));
+            assertTrue(currentState.equals(state, true /* excludingCaptionInsets*/,
+                    true /* excludeInvisibleIme */));
             mController.setCaptionInsetsHeight(0);
             mController.onStateChanged(state);
             // The caption bar source should not be there at all, because we don't add empty
diff --git a/core/tests/coretests/src/android/view/InsetsStateTest.java b/core/tests/coretests/src/android/view/InsetsStateTest.java
index daaf31a..7115acf 100644
--- a/core/tests/coretests/src/android/view/InsetsStateTest.java
+++ b/core/tests/coretests/src/android/view/InsetsStateTest.java
@@ -27,6 +27,8 @@
 import static android.view.InsetsState.ITYPE_STATUS_BAR;
 import static android.view.View.SYSTEM_UI_FLAG_LAYOUT_STABLE;
 import static android.view.WindowInsets.Type.ime;
+import static android.view.WindowInsets.Type.navigationBars;
+import static android.view.WindowInsets.Type.statusBars;
 import static android.view.WindowManager.LayoutParams.SOFT_INPUT_ADJUST_NOTHING;
 import static android.view.WindowManager.LayoutParams.SOFT_INPUT_ADJUST_PAN;
 import static android.view.WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE;
@@ -274,6 +276,15 @@
     }
 
     @Test
+    public void testEquals_excludeInvisibleIme() {
+        mState.getSource(ITYPE_IME).setFrame(new Rect(0, 0, 100, 100));
+        mState.getSource(ITYPE_IME).setVisible(false);
+        mState2.getSource(ITYPE_IME).setFrame(new Rect(0, 0, 100, 200));
+        mState2.getSource(ITYPE_IME).setVisible(false);
+        assertTrue(mState2.equals(mState, true, true /* excludeInvisibleIme */));
+    }
+
+    @Test
     public void testParcelUnparcel() {
         mState.getSource(ITYPE_IME).setFrame(new Rect(0, 0, 100, 100));
         mState.getSource(ITYPE_IME).setVisibleFrame(new Rect(0, 0, 50, 10));
@@ -341,6 +352,26 @@
         }
     }
 
+    @Test
+    public void testCalculateUncontrollableInsets() throws Exception {
+        try (InsetsModeSession session = new InsetsModeSession(ViewRootImpl.NEW_INSETS_MODE_FULL)) {
+            mState.getSource(ITYPE_STATUS_BAR).setFrame(new Rect(0, 0, 200, 100));
+            mState.getSource(ITYPE_STATUS_BAR).setVisible(true);
+            mState.getSource(ITYPE_IME).setFrame(new Rect(0, 200, 200, 300));
+            mState.getSource(ITYPE_IME).setVisible(true);
+            mState.getSource(ITYPE_NAVIGATION_BAR).setFrame(new Rect(100, 0, 200, 300));
+            mState.getSource(ITYPE_NAVIGATION_BAR).setVisible(true);
+
+            mState.setDisplayFrame(new Rect(0, 0, 200, 300));
+            assertEquals(0,
+                    mState.calculateUncontrollableInsetsFromFrame(new Rect(0, 0, 200, 300)));
+            assertEquals(statusBars() | ime(),
+                    mState.calculateUncontrollableInsetsFromFrame(new Rect(0, 50, 200, 250)));
+            assertEquals(navigationBars(),
+                    mState.calculateUncontrollableInsetsFromFrame(new Rect(50, 0, 150, 300)));
+        }
+    }
+
     private void assertEqualsAndHashCode() {
         assertEquals(mState, mState2);
         assertEquals(mState.hashCode(), mState2.hashCode());
diff --git a/core/tests/coretests/src/com/android/internal/app/ChooserActivityTest.java b/core/tests/coretests/src/com/android/internal/app/ChooserActivityTest.java
index 5471768..49de7c8 100644
--- a/core/tests/coretests/src/com/android/internal/app/ChooserActivityTest.java
+++ b/core/tests/coretests/src/com/android/internal/app/ChooserActivityTest.java
@@ -21,6 +21,7 @@
 import static androidx.test.espresso.action.ViewActions.swipeUp;
 import static androidx.test.espresso.assertion.ViewAssertions.doesNotExist;
 import static androidx.test.espresso.assertion.ViewAssertions.matches;
+import static androidx.test.espresso.matcher.ViewMatchers.hasSibling;
 import static androidx.test.espresso.matcher.ViewMatchers.isDisplayed;
 import static androidx.test.espresso.matcher.ViewMatchers.withId;
 import static androidx.test.espresso.matcher.ViewMatchers.withText;
@@ -299,9 +300,8 @@
     public void fourOptionsStackedIntoOneTarget() throws InterruptedException {
         Intent sendIntent = createSendTextIntent();
 
-        // create 12 unique app targets to ensure the app ranking row can be filled, otherwise
-        // targets will not stack
-        List<ResolvedComponentInfo> resolvedComponentInfos = createResolvedComponentsForTest(12);
+        // create just enough targets to ensure the a-z list should be shown
+        List<ResolvedComponentInfo> resolvedComponentInfos = createResolvedComponentsForTest(1);
 
         // next create 4 targets in a single app that should be stacked into a single target
         String packageName = "xxx.yyy";
@@ -328,8 +328,8 @@
                 .launchActivity(Intent.createChooser(sendIntent, null));
         waitForIdle();
 
-        // expect 12 unique targets + 1 group + 4 ranked app targets
-        assertThat(activity.getAdapter().getCount(), is(17));
+        // expect 1 unique targets + 1 group + 4 ranked app targets
+        assertThat(activity.getAdapter().getCount(), is(6));
 
         ResolveInfo[] chosen = new ResolveInfo[1];
         sOverrides.onSafelyStartCallback = targetInfo -> {
@@ -337,7 +337,7 @@
             return true;
         };
 
-        onView(withText(appName)).perform(click());
+        onView(allOf(withText(appName), hasSibling(withText("")))).perform(click());
         waitForIdle();
 
         // clicking will launch a dialog to choose the activity within the app
diff --git a/core/tests/coretests/src/com/android/internal/app/ChooserWrapperActivity.java b/core/tests/coretests/src/com/android/internal/app/ChooserWrapperActivity.java
index 44a5263..0f6b51f 100644
--- a/core/tests/coretests/src/com/android/internal/app/ChooserWrapperActivity.java
+++ b/core/tests/coretests/src/com/android/internal/app/ChooserWrapperActivity.java
@@ -222,6 +222,11 @@
         super.queryTargetServices(adapter);
     }
 
+    @Override
+    protected boolean isQuietModeEnabled(UserHandle userHandle) {
+        return sOverrides.isQuietModeEnabled;
+    }
+
     /**
      * We cannot directly mock the activity created since instrumentation creates it.
      * <p>
diff --git a/core/tests/overlaytests/remount/Android.bp b/core/tests/overlaytests/remount/Android.bp
index 4e79a45..939334c 100644
--- a/core/tests/overlaytests/remount/Android.bp
+++ b/core/tests/overlaytests/remount/Android.bp
@@ -19,6 +19,9 @@
         "tradefed",
         "junit",
     ],
+    static_libs: [
+        "frameworks-base-hostutils",
+    ],
     test_suites: ["general-tests"],
     java_resources: [
         ":com.android.overlaytest.overlaid",
diff --git a/core/tests/overlaytests/remount/src/com/android/overlaytest/remounted/OverlayRemountedTestBase.java b/core/tests/overlaytests/remount/src/com/android/overlaytest/remounted/OverlayRemountedTestBase.java
index 14b5bf6..1a39e20 100644
--- a/core/tests/overlaytests/remount/src/com/android/overlaytest/remounted/OverlayRemountedTestBase.java
+++ b/core/tests/overlaytests/remount/src/com/android/overlaytest/remounted/OverlayRemountedTestBase.java
@@ -18,6 +18,7 @@
 
 import static org.junit.Assert.fail;
 
+import com.android.internal.util.test.SystemPreparer;
 import com.android.tradefed.device.DeviceNotAvailableException;
 import com.android.tradefed.testtype.junit4.BaseHostJUnit4Test;
 
diff --git a/core/tests/overlaytests/remount/src/com/android/overlaytest/remounted/SystemPreparer.java b/core/tests/overlaytests/remount/src/com/android/overlaytest/remounted/SystemPreparer.java
deleted file mode 100644
index bb72d0e..0000000
--- a/core/tests/overlaytests/remount/src/com/android/overlaytest/remounted/SystemPreparer.java
+++ /dev/null
@@ -1,151 +0,0 @@
-/*
- * 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.overlaytest.remounted;
-
-import static org.junit.Assert.assertTrue;
-
-import com.android.tradefed.device.DeviceNotAvailableException;
-import com.android.tradefed.device.ITestDevice;
-
-import org.junit.Assert;
-import org.junit.rules.ExternalResource;
-import org.junit.rules.TemporaryFolder;
-
-import java.io.File;
-import java.io.FileOutputStream;
-import java.io.IOException;
-import java.io.InputStream;
-import java.util.ArrayList;
-
-class SystemPreparer extends ExternalResource {
-    private static final long OVERLAY_ENABLE_TIMEOUT_MS = 30000;
-
-    // The paths of the files pushed onto the device through this rule.
-    private ArrayList<String> mPushedFiles = new ArrayList<>();
-
-    // The package names of packages installed through this rule.
-    private ArrayList<String> mInstalledPackages = new ArrayList<>();
-
-    private final TemporaryFolder mHostTempFolder;
-    private final DeviceProvider mDeviceProvider;
-
-    SystemPreparer(TemporaryFolder hostTempFolder, DeviceProvider deviceProvider) {
-        mHostTempFolder = hostTempFolder;
-        mDeviceProvider = deviceProvider;
-    }
-
-    /** Copies a file within the host test jar to a path on device. */
-    SystemPreparer pushResourceFile(String resourcePath,
-            String outputPath) throws DeviceNotAvailableException, IOException {
-        final ITestDevice device = mDeviceProvider.getDevice();
-        remount();
-        assertTrue(device.pushFile(copyResourceToTemp(resourcePath), outputPath));
-        mPushedFiles.add(outputPath);
-        return this;
-    }
-
-    /** Installs an APK within the host test jar onto the device. */
-    SystemPreparer installResourceApk(String resourcePath, String packageName)
-            throws DeviceNotAvailableException, IOException {
-        final ITestDevice device = mDeviceProvider.getDevice();
-        final File tmpFile = copyResourceToTemp(resourcePath);
-        final String result = device.installPackage(tmpFile, true /* reinstall */);
-        Assert.assertNull(result);
-        mInstalledPackages.add(packageName);
-        return this;
-    }
-
-    /** Sets the enable state of an overlay package. */
-    SystemPreparer setOverlayEnabled(String packageName, boolean enabled)
-            throws DeviceNotAvailableException {
-        final ITestDevice device = mDeviceProvider.getDevice();
-        final String enable = enabled ? "enable" : "disable";
-
-        // Wait for the overlay to change its enabled state.
-        final long endMillis = System.currentTimeMillis() + OVERLAY_ENABLE_TIMEOUT_MS;
-        String result;
-        while (System.currentTimeMillis() <= endMillis) {
-            device.executeShellCommand(String.format("cmd overlay %s %s", enable, packageName));
-            result = device.executeShellCommand("cmd overlay dump isenabled "
-                    + packageName);
-            if (((enabled) ? "true\n" : "false\n").equals(result)) {
-                return this;
-            }
-
-            try {
-                Thread.sleep(200);
-            } catch (InterruptedException ignore) {
-            }
-        }
-
-        throw new IllegalStateException(String.format("Failed to %s overlay %s:\n%s", enable,
-                packageName, device.executeShellCommand("cmd overlay list")));
-    }
-
-    /** Restarts the device and waits until after boot is completed. */
-    SystemPreparer reboot() throws DeviceNotAvailableException {
-        final ITestDevice device = mDeviceProvider.getDevice();
-        device.reboot();
-        return this;
-    }
-
-    SystemPreparer remount() throws DeviceNotAvailableException {
-        mDeviceProvider.getDevice().executeAdbCommand("remount");
-        return this;
-    }
-
-    /** Copies a file within the host test jar to a temporary file on the host machine. */
-    private File copyResourceToTemp(String resourcePath) throws IOException {
-        final File tempFile = mHostTempFolder.newFile(resourcePath);
-        final ClassLoader classLoader = getClass().getClassLoader();
-        try (InputStream assetIs = classLoader.getResource(resourcePath).openStream();
-             FileOutputStream assetOs = new FileOutputStream(tempFile)) {
-            if (assetIs == null) {
-                throw new IllegalStateException("Failed to find resource " + resourcePath);
-            }
-
-            int b;
-            while ((b = assetIs.read()) >= 0) {
-                assetOs.write(b);
-            }
-        }
-
-        return tempFile;
-    }
-
-    /** Removes installed packages and files that were pushed to the device. */
-    @Override
-    protected void after() {
-        final ITestDevice device = mDeviceProvider.getDevice();
-        try {
-            remount();
-            for (final String file : mPushedFiles) {
-                device.deleteFile(file);
-            }
-            for (final String packageName : mInstalledPackages) {
-                device.uninstallPackage(packageName);
-            }
-            device.reboot();
-        } catch (DeviceNotAvailableException e) {
-            Assert.fail(e.toString());
-        }
-    }
-
-    interface DeviceProvider {
-        ITestDevice getDevice();
-    }
-}
diff --git a/data/etc/car/Android.bp b/data/etc/car/Android.bp
index 1b1a624..d6542de 100644
--- a/data/etc/car/Android.bp
+++ b/data/etc/car/Android.bp
@@ -122,6 +122,13 @@
 }
 
 prebuilt_etc {
+    name: "privapp_whitelist_com.android.car.bugreport",
+    sub_dir: "permissions",
+    src: "com.android.car.bugreport.xml",
+    filename_from_src: true,
+}
+
+prebuilt_etc {
     name: "privapp_whitelist_com.google.android.car.kitchensink",
     sub_dir: "permissions",
     src: "com.google.android.car.kitchensink.xml",
diff --git a/data/etc/car/com.android.car.bugreport.xml b/data/etc/car/com.android.car.bugreport.xml
new file mode 100644
index 0000000..432a838
--- /dev/null
+++ b/data/etc/car/com.android.car.bugreport.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright (C) 2020 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
+  -->
+<permissions>
+    <privapp-permissions package="com.android.car.bugreport">
+        <permission name="android.permission.DUMP"/>
+        <permission name="android.permission.INTERACT_ACROSS_USERS"/>
+        <permission name="android.permission.READ_LOGS"/>
+        <permission name="android.permission.MANAGE_USERS"/>
+    </privapp-permissions>
+  </permissions>
diff --git a/data/etc/preinstalled-packages-platform.xml b/data/etc/preinstalled-packages-platform.xml
index 17e1f2e..6255584 100644
--- a/data/etc/preinstalled-packages-platform.xml
+++ b/data/etc/preinstalled-packages-platform.xml
@@ -17,7 +17,9 @@
 <!--
 This XML file declares which system packages should be initially installed for new users based on
 their user type. All system packages on the device should ideally have an entry in an xml file
-(keyed by its manifest name).
+(keyed by its manifest name), except auto-generated rro packages. Auto-generated RRO packages 
+(package name ends with ".auto_generated_rro_product__" or ".auto_generated_rro_vendor__")
+will be installed for new users according to corresponding overlay target packages.
 
 Base user-types (every user will be at least one of these types) are:
   SYSTEM    (user 0)
@@ -51,7 +53,7 @@
 
 
 2. For a system package to be pre-installed on all human users (e.g. a web browser), i.e. to be
-installed on any user of type type FULL or PROFILE (since this covers all human users):
+installed on any user of type FULL or PROFILE (since this covers all human users):
 
    <install-in-user-type package="com.android.example">
        <install-in user-type="FULL" />
diff --git a/libs/WindowManager/Jetpack/Android.bp b/libs/WindowManager/Jetpack/Android.bp
index 308c1a5..4f4364f 100644
--- a/libs/WindowManager/Jetpack/Android.bp
+++ b/libs/WindowManager/Jetpack/Android.bp
@@ -13,26 +13,26 @@
 // limitations under the License.
 
 android_library_import {
-    name: "window-extensions",
-    aars: ["window-extensions-release.aar"],
+    name: "window-sidecar",
+    aars: ["window-sidecar-release.aar"],
     sdk_version: "current",
 }
 
 java_library {
-    name: "androidx.window.extensions",
+    name: "androidx.window.sidecar",
     srcs: ["src/**/*.java"],
-    static_libs: ["window-extensions"],
+    static_libs: ["window-sidecar"],
     installable: true,
     sdk_version: "core_platform",
     vendor: true,
     libs: ["framework", "androidx.annotation_annotation",],
-    required: ["androidx.window.extensions.xml",],
+    required: ["androidx.window.sidecar.xml",],
 }
 
 prebuilt_etc {
-    name: "androidx.window.extensions.xml",
+    name: "androidx.window.sidecar.xml",
     vendor: true,
     sub_dir: "permissions",
-    src: "androidx.window.extensions.xml",
+    src: "androidx.window.sidecar.xml",
     filename_from_src: true,
 }
diff --git a/libs/WindowManager/Jetpack/androidx.window.extensions.xml b/libs/WindowManager/Jetpack/androidx.window.extensions.xml
deleted file mode 100644
index 1f0ff66..0000000
--- a/libs/WindowManager/Jetpack/androidx.window.extensions.xml
+++ /dev/null
@@ -1,21 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-  Copyright 2020 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.
-  -->
-<permissions>
-    <library
-        name="androidx.window.extensions"
-        file="/vendor/framework/androidx.window.extensions.jar"/>
-</permissions>
diff --git a/packages/SystemUI/res/color/qs_user_detail_avatar_tint.xml b/libs/WindowManager/Jetpack/androidx.window.sidecar.xml
similarity index 64%
rename from packages/SystemUI/res/color/qs_user_detail_avatar_tint.xml
rename to libs/WindowManager/Jetpack/androidx.window.sidecar.xml
index 696e9b1..f88a5f4 100644
--- a/packages/SystemUI/res/color/qs_user_detail_avatar_tint.xml
+++ b/libs/WindowManager/Jetpack/androidx.window.sidecar.xml
@@ -1,7 +1,6 @@
 <?xml version="1.0" encoding="utf-8"?>
-
 <!--
-  ~ Copyright (C) 2016 The Android Open Source Project
+  ~ Copyright (C) 2020 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.
@@ -13,10 +12,10 @@
   ~ 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
+  ~ limitations under the License.
   -->
-
-<selector xmlns:android="http://schemas.android.com/apk/res/android">
-    <item android:state_enabled="false" android:color="?android:attr/textColorPrimary" />
-    <item android:color="@android:color/transparent" />
-</selector>
+<permissions>
+    <library
+        name="androidx.window.sidecar"
+        file="/vendor/framework/androidx.window.sidecar.jar"/>
+</permissions>
diff --git a/libs/WindowManager/Jetpack/src/androidx/window/extensions/SettingsExtensionImpl.java b/libs/WindowManager/Jetpack/src/androidx/window/sidecar/SettingsSidecarImpl.java
similarity index 79%
rename from libs/WindowManager/Jetpack/src/androidx/window/extensions/SettingsExtensionImpl.java
rename to libs/WindowManager/Jetpack/src/androidx/window/sidecar/SettingsSidecarImpl.java
index 7a3fbf3..92e5758 100644
--- a/libs/WindowManager/Jetpack/src/androidx/window/extensions/SettingsExtensionImpl.java
+++ b/libs/WindowManager/Jetpack/src/androidx/window/sidecar/SettingsSidecarImpl.java
@@ -1,5 +1,5 @@
 /*
- * Copyright 2020 The Android Open Source Project
+ * Copyright (C) 2020 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.
@@ -14,14 +14,14 @@
  * limitations under the License.
  */
 
-package androidx.window.extensions;
+package androidx.window.sidecar;
 
 import static android.view.Display.DEFAULT_DISPLAY;
 
-import static androidx.window.extensions.ExtensionHelper.getWindowDisplay;
-import static androidx.window.extensions.ExtensionHelper.isInMultiWindow;
-import static androidx.window.extensions.ExtensionHelper.rotateRectToDisplayRotation;
-import static androidx.window.extensions.ExtensionHelper.transformToWindowSpaceRect;
+import static androidx.window.sidecar.SidecarHelper.getWindowDisplay;
+import static androidx.window.sidecar.SidecarHelper.isInMultiWindow;
+import static androidx.window.sidecar.SidecarHelper.rotateRectToDisplayRotation;
+import static androidx.window.sidecar.SidecarHelper.transformToWindowSpaceRect;
 
 import android.content.ContentResolver;
 import android.content.Context;
@@ -42,8 +42,8 @@
 import java.util.regex.Matcher;
 import java.util.regex.Pattern;
 
-class SettingsExtensionImpl extends StubExtension {
-    private static final String TAG = "SettingsExtension";
+class SettingsSidecarImpl extends StubSidecar {
+    private static final String TAG = "SettingsSidecar";
 
     private static final String DEVICE_POSTURE = "device_posture";
     private static final String DISPLAY_FEATURES = "display_features";
@@ -106,7 +106,7 @@
         }
     }
 
-    SettingsExtensionImpl(Context context) {
+    SettingsSidecarImpl(Context context) {
         mContext = context;
         mSettingsObserver = new SettingsObserver();
     }
@@ -118,29 +118,33 @@
     /** Update display features with values read from settings. */
     private void updateDisplayFeatures() {
         for (IBinder windowToken : getWindowsListeningForLayoutChanges()) {
-            ExtensionWindowLayoutInfo newLayout = getWindowLayoutInfo(windowToken);
+            SidecarWindowLayoutInfo newLayout = getWindowLayoutInfo(windowToken);
             updateWindowLayout(windowToken, newLayout);
         }
     }
 
     @NonNull
     @Override
-    public ExtensionDeviceState getDeviceState() {
+    public SidecarDeviceState getDeviceState() {
         ContentResolver resolver = mContext.getContentResolver();
         int posture = Settings.Global.getInt(resolver, DEVICE_POSTURE,
-                ExtensionDeviceState.POSTURE_UNKNOWN);
-        return new ExtensionDeviceState(posture);
+                SidecarDeviceState.POSTURE_UNKNOWN);
+        SidecarDeviceState deviceState = new SidecarDeviceState();
+        deviceState.posture = posture;
+        return deviceState;
     }
 
     @NonNull
     @Override
-    public ExtensionWindowLayoutInfo getWindowLayoutInfo(@NonNull IBinder windowToken) {
-        List<ExtensionDisplayFeature> displayFeatures = readDisplayFeatures(windowToken);
-        return new ExtensionWindowLayoutInfo(displayFeatures);
+    public SidecarWindowLayoutInfo getWindowLayoutInfo(@NonNull IBinder windowToken) {
+        List<SidecarDisplayFeature> displayFeatures = readDisplayFeatures(windowToken);
+        SidecarWindowLayoutInfo windowLayoutInfo = new SidecarWindowLayoutInfo();
+        windowLayoutInfo.displayFeatures = displayFeatures;
+        return windowLayoutInfo;
     }
 
-    private List<ExtensionDisplayFeature> readDisplayFeatures(IBinder windowToken) {
-        List<ExtensionDisplayFeature> features = new ArrayList<ExtensionDisplayFeature>();
+    private List<SidecarDisplayFeature> readDisplayFeatures(IBinder windowToken) {
+        List<SidecarDisplayFeature> features = new ArrayList<SidecarDisplayFeature>();
         int displayId = getWindowDisplay(windowToken);
         if (displayId != DEFAULT_DISPLAY) {
             Log.w(TAG, "This sample doesn't support display features on secondary displays");
@@ -170,10 +174,10 @@
                 int type;
                 switch (featureType) {
                     case FEATURE_TYPE_FOLD:
-                        type = ExtensionDisplayFeature.TYPE_FOLD;
+                        type = SidecarDisplayFeature.TYPE_FOLD;
                         break;
                     case FEATURE_TYPE_HINGE:
-                        type = ExtensionDisplayFeature.TYPE_HINGE;
+                        type = SidecarDisplayFeature.TYPE_HINGE;
                         break;
                     default: {
                         Log.e(TAG, "Malformed feature type: " + featureType);
@@ -189,8 +193,9 @@
                 rotateRectToDisplayRotation(featureRect, displayId);
                 transformToWindowSpaceRect(featureRect, windowToken);
                 if (!featureRect.isEmpty()) {
-                    ExtensionDisplayFeature feature =
-                            new ExtensionDisplayFeature(featureRect, type);
+                    SidecarDisplayFeature feature = new SidecarDisplayFeature();
+                    feature.setRect(featureRect);
+                    feature.setType(type);
                     features.add(feature);
                 } else {
                     Log.w(TAG, "Failed to adjust feature to window");
diff --git a/libs/WindowManager/Jetpack/src/androidx/window/extensions/ExtensionHelper.java b/libs/WindowManager/Jetpack/src/androidx/window/sidecar/SidecarHelper.java
similarity index 92%
rename from libs/WindowManager/Jetpack/src/androidx/window/extensions/ExtensionHelper.java
rename to libs/WindowManager/Jetpack/src/androidx/window/sidecar/SidecarHelper.java
index c61f1ed..e5b6cff 100644
--- a/libs/WindowManager/Jetpack/src/androidx/window/extensions/ExtensionHelper.java
+++ b/libs/WindowManager/Jetpack/src/androidx/window/sidecar/SidecarHelper.java
@@ -1,5 +1,5 @@
 /*
- * Copyright 2020 The Android Open Source Project
+ * Copyright (C) 2020 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.
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package androidx.window.extensions;
+package androidx.window.sidecar;
 
 import static android.view.Display.INVALID_DISPLAY;
 import static android.view.Surface.ROTATION_0;
@@ -32,12 +32,7 @@
 
 import androidx.annotation.Nullable;
 
-/**
- * Toolkit class for calculation of the display feature bounds within the window.
- * NOTE: This sample implementation only works for Activity windows, because there is no public APIs
- * to obtain layout params or bounds for arbitrary windows.
- */
-class ExtensionHelper {
+class SidecarHelper {
     /**
      * Rotate the input rectangle specified in default display orientation to the current display
      * rotation.
diff --git a/libs/WindowManager/Jetpack/src/androidx/window/extensions/ExtensionProvider.java b/libs/WindowManager/Jetpack/src/androidx/window/sidecar/SidecarProvider.java
similarity index 70%
rename from libs/WindowManager/Jetpack/src/androidx/window/extensions/ExtensionProvider.java
rename to libs/WindowManager/Jetpack/src/androidx/window/sidecar/SidecarProvider.java
index 47349f1..0b4915e 100644
--- a/libs/WindowManager/Jetpack/src/androidx/window/extensions/ExtensionProvider.java
+++ b/libs/WindowManager/Jetpack/src/androidx/window/sidecar/SidecarProvider.java
@@ -1,5 +1,5 @@
 /*
- * Copyright 2020 The Android Open Source Project
+ * Copyright (C) 2020 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.
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package androidx.window.extensions;
+package androidx.window.sidecar;
 
 import android.content.Context;
 
@@ -22,14 +22,13 @@
  * Provider class that will instantiate the library implementation. It must be included in the
  * vendor library, and the vendor implementation must match the signature of this class.
  */
-public class ExtensionProvider {
-
+public class SidecarProvider {
     /**
-     * The support library will instantiate the vendor implementation using this interface.
-     * @return An implementation of {@link ExtensionInterface}.
+     * Provide a simple implementation of {@link SidecarInterface} that can be replaced by
+     * an OEM by overriding this method.
      */
-    public static ExtensionInterface getExtensionImpl(Context context) {
-        return new SettingsExtensionImpl(context);
+    public static SidecarInterface getSidecarImpl(Context context) {
+        return new SettingsSidecarImpl(context);
     }
 
     /**
@@ -37,6 +36,6 @@
      * @return API version string in MAJOR.MINOR.PATCH-description format.
      */
     public static String getApiVersion() {
-        return "1.0.0-settings_sample";
+        return "0.1.0-settings_sample";
     }
 }
diff --git a/libs/WindowManager/Jetpack/src/androidx/window/sidecar/StubSidecar.java b/libs/WindowManager/Jetpack/src/androidx/window/sidecar/StubSidecar.java
new file mode 100644
index 0000000..199c373
--- /dev/null
+++ b/libs/WindowManager/Jetpack/src/androidx/window/sidecar/StubSidecar.java
@@ -0,0 +1,85 @@
+/*
+ * Copyright (C) 2020 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 androidx.window.sidecar;
+
+import android.os.IBinder;
+
+import androidx.annotation.NonNull;
+
+import java.util.HashSet;
+import java.util.Set;
+
+/**
+ * Basic implementation of the {@link SidecarInterface}. An OEM can choose to use it as the base
+ * class for their implementation.
+ */
+abstract class StubSidecar implements SidecarInterface {
+
+    private SidecarCallback mSidecarCallback;
+    private final Set<IBinder> mWindowLayoutChangeListenerTokens = new HashSet<>();
+    private boolean mDeviceStateChangeListenerRegistered;
+
+    StubSidecar() {
+    }
+
+    @Override
+    public void setSidecarCallback(@NonNull SidecarCallback sidecarCallback) {
+        this.mSidecarCallback = sidecarCallback;
+    }
+
+    @Override
+    public void onWindowLayoutChangeListenerAdded(@NonNull IBinder iBinder) {
+        this.mWindowLayoutChangeListenerTokens.add(iBinder);
+        this.onListenersChanged();
+    }
+
+    @Override
+    public void onWindowLayoutChangeListenerRemoved(@NonNull IBinder iBinder) {
+        this.mWindowLayoutChangeListenerTokens.remove(iBinder);
+        this.onListenersChanged();
+    }
+
+    @Override
+    public void onDeviceStateListenersChanged(boolean isEmpty) {
+        this.mDeviceStateChangeListenerRegistered = !isEmpty;
+        this.onListenersChanged();
+    }
+
+    void updateDeviceState(SidecarDeviceState newState) {
+        if (this.mSidecarCallback != null) {
+            mSidecarCallback.onDeviceStateChanged(newState);
+        }
+    }
+
+    void updateWindowLayout(@NonNull IBinder windowToken,
+            @NonNull SidecarWindowLayoutInfo newLayout) {
+        if (this.mSidecarCallback != null) {
+            mSidecarCallback.onWindowLayoutChanged(windowToken, newLayout);
+        }
+    }
+
+    @NonNull
+    Set<IBinder> getWindowsListeningForLayoutChanges() {
+        return mWindowLayoutChangeListenerTokens;
+    }
+
+    protected boolean hasListeners() {
+        return !mWindowLayoutChangeListenerTokens.isEmpty() || mDeviceStateChangeListenerRegistered;
+    }
+
+    protected abstract void onListenersChanged();
+}
diff --git a/libs/WindowManager/Jetpack/window-extensions-release.aar b/libs/WindowManager/Jetpack/window-extensions-release.aar
deleted file mode 100644
index 0ebbb86..0000000
--- a/libs/WindowManager/Jetpack/window-extensions-release.aar
+++ /dev/null
Binary files differ
diff --git a/libs/WindowManager/Jetpack/window-sidecar-release.aar b/libs/WindowManager/Jetpack/window-sidecar-release.aar
new file mode 100644
index 0000000..50f101d
--- /dev/null
+++ b/libs/WindowManager/Jetpack/window-sidecar-release.aar
Binary files differ
diff --git a/libs/incident/Android.bp b/libs/incident/Android.bp
index af64110..d291ec0 100644
--- a/libs/incident/Android.bp
+++ b/libs/incident/Android.bp
@@ -95,7 +95,17 @@
     name: "libincident_test",
     test_config: "AndroidTest.xml",
     defaults: ["libincidentpriv_defaults"],
-    test_suites: ["device-tests"],
+    test_suites: ["device-tests", "mts"],
+    compile_multilib: "both",
+    multilib: {
+        lib64: {
+            suffix: "64",
+        },
+        lib32: {
+            suffix: "32",
+        },
+    },
+    require_root: true,
 
     include_dirs: [
         "frameworks/base/libs/incident/include",
diff --git a/libs/incident/AndroidTest.xml b/libs/incident/AndroidTest.xml
index 7c0b044..b6b3f85 100644
--- a/libs/incident/AndroidTest.xml
+++ b/libs/incident/AndroidTest.xml
@@ -16,13 +16,17 @@
 <configuration description="Config for libincident_test">
     <option name="test-suite-tag" value="device-tests" />
     <option name="config-descriptor:metadata" key="component" value="misc" />
-    <target_preparer class="com.android.tradefed.targetprep.PushFilePreparer">
+    <target_preparer class="com.android.compatibility.common.tradefed.targetprep.FilePusher">
         <option name="cleanup" value="true" />
         <option name="push" value="libincident_test->/data/local/tmp/libincident_test" />
+        <option name="append-bitness" value="true" />
     </target_preparer>
     <test class="com.android.tradefed.testtype.GTest" >
         <option name="native-test-device-path" value="/data/local/tmp" />
         <option name="module-name" value="libincident_test" />
     </test>
+    <object type="module_controller" class="com.android.tradefed.testtype.suite.module.MainlineTestModuleController">
+        <option name="mainline-module-package-name" value="com.google.android.os.statsd" />
+    </object>
 </configuration>
 
diff --git a/libs/incident/TEST_MAPPING b/libs/incident/TEST_MAPPING
index 59ebe76..25e0000 100644
--- a/libs/incident/TEST_MAPPING
+++ b/libs/incident/TEST_MAPPING
@@ -2,9 +2,6 @@
   "presubmit": [
     {
       "name": "libincident_test"
-    },
-    {
-      "name": "GtsLibIncidentTests"
     }
   ]
 }
diff --git a/location/java/android/location/LocationManager.java b/location/java/android/location/LocationManager.java
index a112bdd0..7d15bbd 100644
--- a/location/java/android/location/LocationManager.java
+++ b/location/java/android/location/LocationManager.java
@@ -2583,9 +2583,15 @@
         }
 
         public void cancel() {
+            remove();
+        }
+
+        private Consumer<Location> remove() {
+            Consumer<Location> consumer;
             ICancellationSignal cancellationSignal;
             synchronized (this) {
                 mExecutor = null;
+                consumer = mConsumer;
                 mConsumer = null;
 
                 if (mAlarmManager != null) {
@@ -2605,6 +2611,8 @@
                     // ignore
                 }
             }
+
+            return consumer;
         }
 
         public void fail() {
@@ -2663,16 +2671,10 @@
         }
 
         private void acceptResult(Location location) {
-            Consumer<Location> consumer;
-            synchronized (this) {
-                if (mConsumer == null) {
-                    return;
-                }
-                consumer = mConsumer;
-                cancel();
+            Consumer<Location> consumer = remove();
+            if (consumer != null) {
+                consumer.accept(location);
             }
-
-            consumer.accept(location);
         }
     }
 
diff --git a/location/java/com/android/internal/location/GpsNetInitiatedHandler.java b/location/java/com/android/internal/location/GpsNetInitiatedHandler.java
index 9846436..67a040d 100644
--- a/location/java/com/android/internal/location/GpsNetInitiatedHandler.java
+++ b/location/java/com/android/internal/location/GpsNetInitiatedHandler.java
@@ -18,7 +18,6 @@
 
 import android.app.Notification;
 import android.app.NotificationManager;
-import android.app.PendingIntent;
 import android.compat.annotation.UnsupportedAppUsage;
 import android.content.BroadcastReceiver;
 import android.content.Context;
@@ -402,13 +401,9 @@
             mNiNotificationBuilder.setDefaults(0);
         }
 
-        // if not to popup dialog immediately, pending intent will open the dialog
-        Intent intent = !mPopupImmediately ? getDlgIntent(notif) : new Intent();
-        PendingIntent pi = PendingIntent.getBroadcast(mContext, 0, intent, 0);
         mNiNotificationBuilder.setTicker(getNotifTicker(notif, mContext))
                 .setContentTitle(title)
-                .setContentText(message)
-                .setContentIntent(pi);
+                .setContentText(message);
 
         notificationManager.notifyAsUser(null, notif.notificationId, mNiNotificationBuilder.build(),
                 UserHandle.ALL);
diff --git a/location/java/com/android/internal/location/gnssmetrics/GnssMetrics.java b/location/java/com/android/internal/location/gnssmetrics/GnssMetrics.java
index 323bba3..6c40116 100644
--- a/location/java/com/android/internal/location/gnssmetrics/GnssMetrics.java
+++ b/location/java/com/android/internal/location/gnssmetrics/GnssMetrics.java
@@ -32,7 +32,7 @@
 import com.android.internal.app.IBatteryStats;
 import com.android.internal.location.nano.GnssLogsProto.GnssLog;
 import com.android.internal.location.nano.GnssLogsProto.PowerMetrics;
-import com.android.internal.os.BackgroundThread;
+import com.android.internal.util.ConcurrentUtils;
 import com.android.internal.util.FrameworkStatsLog;
 
 import java.util.ArrayList;
@@ -124,8 +124,6 @@
     private long mL5SvStatusReportsUsedInFix;
     /** Stats manager service for reporting atoms */
     private StatsManager mStatsManager;
-    /** Pull atom callback, this is called when atom pull request occurs */
-    private StatsPullAtomCallbackImpl mPullAtomCallback;
     /* Statds Logging Variables Section End */
 
     public GnssMetrics(Context context, IBatteryStats stats) {
@@ -467,8 +465,8 @@
         mConstellationTypes = new boolean[GnssStatus.CONSTELLATION_COUNT];
     }
 
-    /** Class for storing statistics */
-    private class Statistics {
+    /** Thread-safe class for storing statistics */
+    private static class Statistics {
 
         private int mCount;
         private double mSum;
@@ -476,7 +474,7 @@
         private long mLongSum;
 
         /** Resets statistics */
-        public void reset() {
+        public synchronized void reset() {
             mCount = 0;
             mSum = 0.0;
             mSumSquare = 0.0;
@@ -484,7 +482,7 @@
         }
 
         /** Adds an item */
-        public void addItem(double item) {
+        public synchronized void addItem(double item) {
             mCount++;
             mSum += item;
             mSumSquare += item * item;
@@ -492,17 +490,17 @@
         }
 
         /** Returns number of items added */
-        public int getCount() {
+        public synchronized int getCount() {
             return mCount;
         }
 
         /** Returns mean */
-        public double getMean() {
+        public synchronized double getMean() {
             return mSum / mCount;
         }
 
         /** Returns standard deviation */
-        public double getStandardDeviation() {
+        public synchronized double getStandardDeviation() {
             double m = mSum / mCount;
             m = m * m;
             double v = mSumSquare / mCount;
@@ -513,7 +511,7 @@
         }
 
         /** Returns long sum */
-        public long getLongSum() {
+        public synchronized long getLongSum() {
             return mLongSum;
         }
     }
@@ -623,11 +621,11 @@
     }
 
     private void registerGnssStats() {
-        mPullAtomCallback = new StatsPullAtomCallbackImpl();
+        StatsPullAtomCallbackImpl pullAtomCallback = new StatsPullAtomCallbackImpl();
         mStatsManager.setPullAtomCallback(
                 FrameworkStatsLog.GNSS_STATS,
                 null, // use default PullAtomMetadata values
-                BackgroundThread.getExecutor(), mPullAtomCallback);
+                ConcurrentUtils.DIRECT_EXECUTOR, pullAtomCallback);
     }
 
     /**
diff --git a/media/java/android/media/IMediaRouter2Manager.aidl b/media/java/android/media/IMediaRouter2Manager.aidl
index 5925d38..5113dc2 100644
--- a/media/java/android/media/IMediaRouter2Manager.aidl
+++ b/media/java/android/media/IMediaRouter2Manager.aidl
@@ -24,8 +24,9 @@
  * {@hide}
  */
 oneway interface IMediaRouter2Manager {
-    void notifySessionCreated(int requestId, in RoutingSessionInfo sessionInfo);
-    void notifySessionUpdated(in RoutingSessionInfo sessionInfo);
+    void notifySessionCreated(int requestId, in RoutingSessionInfo session);
+    void notifySessionUpdated(in RoutingSessionInfo session);
+    void notifySessionReleased(in RoutingSessionInfo session);
     void notifyPreferredFeaturesChanged(String packageName, in List<String> preferredFeatures);
     void notifyRoutesAdded(in List<MediaRoute2Info> routes);
     void notifyRoutesRemoved(in List<MediaRoute2Info> routes);
diff --git a/media/java/android/media/IMediaRouterClient.aidl b/media/java/android/media/IMediaRouterClient.aidl
index 240ae79..53122bb 100644
--- a/media/java/android/media/IMediaRouterClient.aidl
+++ b/media/java/android/media/IMediaRouterClient.aidl
@@ -23,4 +23,5 @@
     void onStateChanged();
     void onRestoreRoute();
     void onSelectedRouteChanged(String routeId);
+    void onGlobalA2dpChanged(boolean a2dpOn);
 }
diff --git a/media/java/android/media/MediaRoute2Info.java b/media/java/android/media/MediaRoute2Info.java
index e5ad569..54c0bc9 100644
--- a/media/java/android/media/MediaRoute2Info.java
+++ b/media/java/android/media/MediaRoute2Info.java
@@ -317,9 +317,10 @@
     @ConnectionState
     final int mConnectionState;
     final String mClientPackageName;
-    final int mVolume;
-    final int mVolumeMax;
     final int mVolumeHandling;
+    final int mVolumeMax;
+    final int mVolume;
+    final String mAddress;
     final Bundle mExtras;
     final String mProviderId;
 
@@ -336,6 +337,7 @@
         mVolumeHandling = builder.mVolumeHandling;
         mVolumeMax = builder.mVolumeMax;
         mVolume = builder.mVolume;
+        mAddress = builder.mAddress;
         mExtras = builder.mExtras;
         mProviderId = builder.mProviderId;
     }
@@ -353,6 +355,7 @@
         mVolumeHandling = in.readInt();
         mVolumeMax = in.readInt();
         mVolume = in.readInt();
+        mAddress = in.readString();
         mExtras = in.readBundle();
         mProviderId = in.readString();
     }
@@ -483,6 +486,15 @@
         return mVolume;
     }
 
+    /**
+     * Gets the hardware address of the route if available.
+     * @hide
+     */
+    @Nullable
+    public String getAddress() {
+        return mAddress;
+    }
+
     @Nullable
     public Bundle getExtras() {
         return mExtras == null ? null : new Bundle(mExtras);
@@ -564,6 +576,7 @@
                 && (mVolumeHandling == other.mVolumeHandling)
                 && (mVolumeMax == other.mVolumeMax)
                 && (mVolume == other.mVolume)
+                && Objects.equals(mAddress, other.mAddress)
                 && Objects.equals(mProviderId, other.mProviderId);
     }
 
@@ -572,7 +585,7 @@
         // Note: mExtras is not included.
         return Objects.hash(mId, mName, mFeatures, mType, mIsSystem, mIconUri, mDescription,
                 mConnectionState, mClientPackageName, mVolumeHandling, mVolumeMax, mVolume,
-                mProviderId);
+                mAddress, mProviderId);
     }
 
     @Override
@@ -614,6 +627,7 @@
         dest.writeInt(mVolumeHandling);
         dest.writeInt(mVolumeMax);
         dest.writeInt(mVolume);
+        dest.writeString(mAddress);
         dest.writeBundle(mExtras);
         dest.writeString(mProviderId);
     }
@@ -637,6 +651,7 @@
         int mVolumeHandling = PLAYBACK_VOLUME_FIXED;
         int mVolumeMax;
         int mVolume;
+        String mAddress;
         Bundle mExtras;
         String mProviderId;
 
@@ -669,24 +684,7 @@
          * @param routeInfo the existing instance to copy data from.
          */
         public Builder(@NonNull MediaRoute2Info routeInfo) {
-            Objects.requireNonNull(routeInfo, "routeInfo must not be null");
-
-            mId = routeInfo.mId;
-            mName = routeInfo.mName;
-            mFeatures = new ArrayList<>(routeInfo.mFeatures);
-            mType = routeInfo.mType;
-            mIsSystem = routeInfo.mIsSystem;
-            mIconUri = routeInfo.mIconUri;
-            mDescription = routeInfo.mDescription;
-            mConnectionState = routeInfo.mConnectionState;
-            mClientPackageName = routeInfo.mClientPackageName;
-            mVolumeHandling = routeInfo.mVolumeHandling;
-            mVolumeMax = routeInfo.mVolumeMax;
-            mVolume = routeInfo.mVolume;
-            if (routeInfo.mExtras != null) {
-                mExtras = new Bundle(routeInfo.mExtras);
-            }
-            mProviderId = routeInfo.mProviderId;
+            this(routeInfo.mId, routeInfo);
         }
 
         /**
@@ -715,6 +713,7 @@
             mVolumeHandling = routeInfo.mVolumeHandling;
             mVolumeMax = routeInfo.mVolumeMax;
             mVolume = routeInfo.mVolume;
+            mAddress = routeInfo.mAddress;
             if (routeInfo.mExtras != null) {
                 mExtras = new Bundle(routeInfo.mExtras);
             }
@@ -865,6 +864,16 @@
         }
 
         /**
+         * Sets the hardware address of the route.
+         * @hide
+         */
+        @NonNull
+        public Builder setAddress(String address) {
+            mAddress = address;
+            return this;
+        }
+
+        /**
          * Sets a bundle of extras for the route.
          * <p>
          * Note: The extras will not affect the result of {@link MediaRoute2Info#equals(Object)}.
diff --git a/media/java/android/media/MediaRoute2ProviderService.java b/media/java/android/media/MediaRoute2ProviderService.java
index 05c6e3a..e199cf4 100644
--- a/media/java/android/media/MediaRoute2ProviderService.java
+++ b/media/java/android/media/MediaRoute2ProviderService.java
@@ -40,8 +40,10 @@
 
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
+import java.util.ArrayDeque;
 import java.util.ArrayList;
 import java.util.Collection;
+import java.util.Deque;
 import java.util.List;
 import java.util.Objects;
 import java.util.concurrent.atomic.AtomicBoolean;
@@ -132,15 +134,21 @@
     @Retention(RetentionPolicy.SOURCE)
     public @interface Reason {}
 
+    private static final int MAX_REQUEST_IDS_SIZE = 500;
+
     private final Handler mHandler;
     private final Object mSessionLock = new Object();
+    private final Object mRequestIdsLock = new Object();
     private final AtomicBoolean mStatePublishScheduled = new AtomicBoolean(false);
     private MediaRoute2ProviderServiceStub mStub;
     private IMediaRoute2ProviderServiceCallback mRemoteCallback;
     private volatile MediaRoute2ProviderInfo mProviderInfo;
 
+    @GuardedBy("mRequestIdsLock")
+    private final Deque<Long> mRequestIds = new ArrayDeque<>(MAX_REQUEST_IDS_SIZE);
+
     @GuardedBy("mSessionLock")
-    private ArrayMap<String, RoutingSessionInfo> mSessionInfo = new ArrayMap<>();
+    private final ArrayMap<String, RoutingSessionInfo> mSessionInfo = new ArrayMap<>();
 
     public MediaRoute2ProviderService() {
         mHandler = new Handler(Looper.getMainLooper());
@@ -230,10 +238,15 @@
             @NonNull RoutingSessionInfo sessionInfo) {
         Objects.requireNonNull(sessionInfo, "sessionInfo must not be null");
 
+        if (requestId != REQUEST_ID_NONE && !removeRequestId(requestId)) {
+            Log.w(TAG, "notifySessionCreated: The requestId doesn't exist. requestId=" + requestId);
+            return;
+        }
+
         String sessionId = sessionInfo.getId();
         synchronized (mSessionLock) {
             if (mSessionInfo.containsKey(sessionId)) {
-                Log.w(TAG, "Ignoring duplicate session id.");
+                Log.w(TAG, "notifySessionCreated: Ignoring duplicate session id.");
                 return;
             }
             mSessionInfo.put(sessionInfo.getId(), sessionInfo);
@@ -261,7 +274,7 @@
             if (mSessionInfo.containsKey(sessionId)) {
                 mSessionInfo.put(sessionId, sessionInfo);
             } else {
-                Log.w(TAG, "Ignoring unknown session info.");
+                Log.w(TAG, "notifySessionUpdated: Ignoring unknown session info.");
                 return;
             }
 
@@ -291,7 +304,7 @@
             sessionInfo = mSessionInfo.remove(sessionId);
 
             if (sessionInfo == null) {
-                Log.w(TAG, "Ignoring unknown session info.");
+                Log.w(TAG, "notifySessionReleased: Ignoring unknown session info.");
                 return;
             }
 
@@ -301,7 +314,7 @@
             try {
                 mRemoteCallback.notifySessionReleased(sessionInfo);
             } catch (RemoteException ex) {
-                Log.w(TAG, "Failed to notify session info changed.");
+                Log.w(TAG, "Failed to notify session released.", ex);
             }
         }
     }
@@ -322,6 +335,13 @@
         if (mRemoteCallback == null) {
             return;
         }
+
+        if (!removeRequestId(requestId)) {
+            Log.w(TAG, "notifyRequestFailed: The requestId doesn't exist. requestId="
+                    + requestId);
+            return;
+        }
+
         try {
             mRemoteCallback.notifyRequestFailed(requestId, reason);
         } catch (RemoteException ex) {
@@ -465,7 +485,37 @@
         try {
             mRemoteCallback.updateState(mProviderInfo);
         } catch (RemoteException ex) {
-            Log.w(TAG, "Failed to send onProviderInfoUpdated");
+            Log.w(TAG, "Failed to publish provider state.", ex);
+        }
+    }
+
+    /**
+     * Adds a requestId in the request ID list whose max size is {@link #MAX_REQUEST_IDS_SIZE}.
+     * When the max size is reached, the first element is removed (FIFO).
+     */
+    private void addRequestId(long requestId) {
+        synchronized (mRequestIdsLock) {
+            if (mRequestIds.size() >= MAX_REQUEST_IDS_SIZE) {
+                mRequestIds.removeFirst();
+            }
+            mRequestIds.addLast(requestId);
+        }
+    }
+
+    /**
+     * Removes the given {@code requestId} from received request ID list.
+     * <p>
+     * Returns whether the list contains the {@code requestId}. These are the cases when the list
+     * doesn't contain the given {@code requestId}:
+     * <ul>
+     *     <li>This service has never received a request with the requestId. </li>
+     *     <li>{@link #notifyRequestFailed} or {@link #notifySessionCreated} already has been called
+     *         for the requestId. </li>
+     * </ul>
+     */
+    private boolean removeRequestId(long requestId) {
+        synchronized (mRequestIdsLock) {
+            return mRequestIds.removeFirstOccurrence(requestId);
         }
     }
 
@@ -529,6 +579,7 @@
             if (!checkRouteIdIsValid(routeId, "setRouteVolume")) {
                 return;
             }
+            addRequestId(requestId);
             mHandler.sendMessage(obtainMessage(MediaRoute2ProviderService::onSetRouteVolume,
                     MediaRoute2ProviderService.this, requestId, routeId, volume));
         }
@@ -542,6 +593,7 @@
             if (!checkRouteIdIsValid(routeId, "requestCreateSession")) {
                 return;
             }
+            addRequestId(requestId);
             mHandler.sendMessage(obtainMessage(MediaRoute2ProviderService::onCreateSession,
                     MediaRoute2ProviderService.this, requestId, packageName, routeId,
                     requestCreateSession));
@@ -556,6 +608,7 @@
                     || !checkRouteIdIsValid(routeId, "selectRoute")) {
                 return;
             }
+            addRequestId(requestId);
             mHandler.sendMessage(obtainMessage(MediaRoute2ProviderService::onSelectRoute,
                     MediaRoute2ProviderService.this, requestId, sessionId, routeId));
         }
@@ -569,6 +622,7 @@
                     || !checkRouteIdIsValid(routeId, "deselectRoute")) {
                 return;
             }
+            addRequestId(requestId);
             mHandler.sendMessage(obtainMessage(MediaRoute2ProviderService::onDeselectRoute,
                     MediaRoute2ProviderService.this, requestId, sessionId, routeId));
         }
@@ -582,6 +636,7 @@
                     || !checkRouteIdIsValid(routeId, "transferToRoute")) {
                 return;
             }
+            addRequestId(requestId);
             mHandler.sendMessage(obtainMessage(MediaRoute2ProviderService::onTransferToRoute,
                     MediaRoute2ProviderService.this, requestId, sessionId, routeId));
         }
@@ -594,6 +649,7 @@
             if (!checkSessionIdIsValid(sessionId, "setSessionVolume")) {
                 return;
             }
+            addRequestId(requestId);
             mHandler.sendMessage(obtainMessage(MediaRoute2ProviderService::onSetSessionVolume,
                     MediaRoute2ProviderService.this, requestId, sessionId, volume));
         }
@@ -606,6 +662,7 @@
             if (!checkSessionIdIsValid(sessionId, "releaseSession")) {
                 return;
             }
+            addRequestId(requestId);
             mHandler.sendMessage(obtainMessage(MediaRoute2ProviderService::onReleaseSession,
                     MediaRoute2ProviderService.this, requestId, sessionId));
         }
diff --git a/media/java/android/media/MediaRouter.java b/media/java/android/media/MediaRouter.java
index 12fc3a6..7ae2949e 100644
--- a/media/java/android/media/MediaRouter.java
+++ b/media/java/android/media/MediaRouter.java
@@ -621,33 +621,27 @@
         final class Client extends IMediaRouterClient.Stub {
             @Override
             public void onStateChanged() {
-                mHandler.post(new Runnable() {
-                    @Override
-                    public void run() {
-                        if (Client.this == mClient) {
-                            updateClientState();
-                        }
+                mHandler.post(() -> {
+                    if (Client.this == mClient) {
+                        updateClientState();
                     }
                 });
             }
 
             @Override
             public void onRestoreRoute() {
-                mHandler.post(new Runnable() {
-                    @Override
-                    public void run() {
-                        // Skip restoring route if the selected route is not a system audio route,
-                        // MediaRouter is initializing, or mClient was changed.
-                        if (Client.this != mClient || mSelectedRoute == null
-                                || (mSelectedRoute != mDefaultAudioVideo
-                                        && mSelectedRoute != mBluetoothA2dpRoute)) {
-                            return;
-                        }
-                        if (DEBUG) {
-                            Log.d(TAG, "onRestoreRoute() : route=" + mSelectedRoute);
-                        }
-                        mSelectedRoute.select();
+                mHandler.post(() -> {
+                    // Skip restoring route if the selected route is not a system audio route,
+                    // MediaRouter is initializing, or mClient was changed.
+                    if (Client.this != mClient || mSelectedRoute == null
+                            || (mSelectedRoute != mDefaultAudioVideo
+                                    && mSelectedRoute != mBluetoothA2dpRoute)) {
+                        return;
                     }
+                    if (DEBUG) {
+                        Log.d(TAG, "onRestoreRoute() : route=" + mSelectedRoute);
+                    }
+                    mSelectedRoute.select();
                 });
             }
 
@@ -659,6 +653,19 @@
                     }
                 });
             }
+
+            // Called when the selection of a connected device (phone speaker or BT devices)
+            // is changed.
+            @Override
+            public void onGlobalA2dpChanged(boolean a2dpOn) {
+                mHandler.post(() -> {
+                    if (mSelectedRoute == mDefaultAudioVideo && a2dpOn) {
+                        setSelectedRoute(mBluetoothA2dpRoute, false);
+                    } else if (mSelectedRoute == mBluetoothA2dpRoute && !a2dpOn) {
+                        setSelectedRoute(mDefaultAudioVideo, false);
+                    }
+                });
+            }
         }
     }
 
diff --git a/media/java/android/media/MediaRouter2.java b/media/java/android/media/MediaRouter2.java
index 20e26cd..0f538a5 100644
--- a/media/java/android/media/MediaRouter2.java
+++ b/media/java/android/media/MediaRouter2.java
@@ -196,7 +196,7 @@
                 try {
                     mMediaRouterService.setDiscoveryRequestWithRouter2(mStub, mDiscoveryPreference);
                 } catch (RemoteException ex) {
-                    Log.e(TAG, "registerRouteCallback: Unable to set discovery request.");
+                    Log.e(TAG, "registerRouteCallback: Unable to set discovery request.", ex);
                 }
             }
         }
@@ -214,7 +214,7 @@
 
         if (!mRouteCallbackRecords.remove(
                 new RouteCallbackRecord(null, routeCallback, null))) {
-            Log.w(TAG, "Ignoring unknown callback");
+            Log.w(TAG, "unregisterRouteCallback: Ignoring unknown callback");
             return;
         }
 
@@ -227,7 +227,7 @@
                     mMediaRouterService.setDiscoveryRequestWithRouter2(
                             mStub, mDiscoveryPreference);
                 } catch (RemoteException ex) {
-                    Log.e(TAG, "unregisterRouteCallback: Unable to set discovery request.");
+                    Log.e(TAG, "unregisterRouteCallback: Unable to set discovery request.", ex);
                 }
             }
             if (mRouteCallbackRecords.isEmpty() && mNonSystemRoutingControllers.isEmpty()) {
@@ -399,11 +399,16 @@
         Objects.requireNonNull(controller, "controller must not be null");
         Objects.requireNonNull(route, "route must not be null");
 
-        // TODO(b/157873496): Check thread-safety, at least check "sRouterLock" for every variable
-        if (!mRoutes.containsKey(route.getId())) {
+        boolean routeFound;
+        synchronized (sRouterLock) {
+            // TODO: Check thread-safety
+            routeFound = mRoutes.containsKey(route.getId());
+        }
+        if (!routeFound) {
             notifyTransferFailure(route);
             return;
         }
+
         if (controller.getRoutingSessionInfo().getTransferableRoutes().contains(route.getId())) {
             controller.transferToRoute(route);
             return;
@@ -495,7 +500,7 @@
             try {
                 mMediaRouterService.setRouteVolumeWithRouter2(stub, route, volume);
             } catch (RemoteException ex) {
-                Log.e(TAG, "Unable to send control request.", ex);
+                Log.e(TAG, "Unable to set route volume.", ex);
             }
         }
     }
@@ -572,10 +577,6 @@
     }
 
     void addRoutesOnHandler(List<MediaRoute2Info> routes) {
-        // TODO(b/157874065): When onRoutesAdded is first called,
-        //  1) clear mRoutes before adding the routes
-        //  2) Call onRouteSelected(system_route, reason_fallback) if previously selected route
-        //     does not exist anymore. => We may need 'boolean MediaRoute2Info#isSystemRoute()'.
         List<MediaRoute2Info> addedRoutes = new ArrayList<>();
         synchronized (sRouterLock) {
             for (MediaRoute2Info route : routes) {
@@ -787,7 +788,8 @@
                 mMediaRouterService.notifySessionHintsForCreatingSession(
                         stub, uniqueRequestId, route, controllerHints);
             } catch (RemoteException ex) {
-                Log.e(TAG, "getSessionHintsOnHandler: Unable to request.", ex);
+                Log.e(TAG, "onGetControllerHintsForCreatingSessionOnHandler: Unable to notify "
+                        + " session hints for creating session.", ex);
             }
         }
     }
@@ -1119,7 +1121,7 @@
             Objects.requireNonNull(route, "route must not be null");
             synchronized (mControllerLock) {
                 if (mIsReleased) {
-                    Log.w(TAG, "selectRoute() called on released controller. Ignoring.");
+                    Log.w(TAG, "selectRoute: Called on released controller. Ignoring.");
                     return;
                 }
             }
@@ -1168,7 +1170,7 @@
             Objects.requireNonNull(route, "route must not be null");
             synchronized (mControllerLock) {
                 if (mIsReleased) {
-                    Log.w(TAG, "deselectRoute() called on released controller. Ignoring.");
+                    Log.w(TAG, "deselectRoute: called on released controller. Ignoring.");
                     return;
                 }
             }
@@ -1215,7 +1217,7 @@
             Objects.requireNonNull(route, "route must not be null");
             synchronized (mControllerLock) {
                 if (mIsReleased) {
-                    Log.w(TAG, "transferToRoute() called on released controller. Ignoring.");
+                    Log.w(TAG, "transferToRoute: Called on released controller. Ignoring.");
                     return;
                 }
 
@@ -1253,17 +1255,17 @@
          */
         public void setVolume(int volume) {
             if (getVolumeHandling() == MediaRoute2Info.PLAYBACK_VOLUME_FIXED) {
-                Log.w(TAG, "setVolume: the routing session has fixed volume. Ignoring.");
+                Log.w(TAG, "setVolume: The routing session has fixed volume. Ignoring.");
                 return;
             }
             if (volume < 0 || volume > getVolumeMax()) {
-                Log.w(TAG, "setVolume: the target volume is out of range. Ignoring");
+                Log.w(TAG, "setVolume: The target volume is out of range. Ignoring");
                 return;
             }
 
             synchronized (mControllerLock) {
                 if (mIsReleased) {
-                    Log.w(TAG, "setVolume is called on released controller. Ignoring.");
+                    Log.w(TAG, "setVolume: Called on released controller. Ignoring.");
                     return;
                 }
             }
@@ -1297,7 +1299,7 @@
         boolean releaseInternal(boolean shouldReleaseSession, boolean shouldNotifyStop) {
             synchronized (mControllerLock) {
                 if (mIsReleased) {
-                    Log.w(TAG, "releaseInternal() called on released controller. Ignoring.");
+                    Log.w(TAG, "releaseInternal: Called on released controller. Ignoring.");
                     return false;
                 }
                 mIsReleased = true;
diff --git a/media/java/android/media/MediaRouter2Manager.java b/media/java/android/media/MediaRouter2Manager.java
index 673fffe..5a7c87e0 100644
--- a/media/java/android/media/MediaRouter2Manager.java
+++ b/media/java/android/media/MediaRouter2Manager.java
@@ -121,7 +121,7 @@
 
         CallbackRecord callbackRecord = new CallbackRecord(executor, callback);
         if (!mCallbackRecords.addIfAbsent(callbackRecord)) {
-            Log.w(TAG, "Ignoring to add the same callback twice.");
+            Log.w(TAG, "Ignoring to register the same callback twice.");
             return;
         }
     }
@@ -384,7 +384,7 @@
                 int requestId = mNextRequestId.getAndIncrement();
                 mMediaRouterService.setRouteVolumeWithManager(client, requestId, route, volume);
             } catch (RemoteException ex) {
-                Log.e(TAG, "Unable to send control request.", ex);
+                Log.e(TAG, "Unable to set route volume.", ex);
             }
         }
     }
@@ -414,7 +414,7 @@
                 mMediaRouterService.setSessionVolumeWithManager(
                         client, requestId, sessionInfo.getId(), volume);
             } catch (RemoteException ex) {
-                Log.e(TAG, "Unable to send control request.", ex);
+                Log.e(TAG, "Unable to set session volume.", ex);
             }
         }
     }
@@ -509,7 +509,7 @@
         notifyRequestFailed(reason);
     }
 
-    void handleSessionsUpdated(RoutingSessionInfo sessionInfo) {
+    void handleSessionsUpdatedOnHandler(RoutingSessionInfo sessionInfo) {
         for (TransferRequest request : mTransferRequests) {
             String sessionId = request.mOldSessionInfo.getId();
             if (!TextUtils.equals(sessionId, sessionInfo.getId())) {
@@ -551,6 +551,12 @@
         }
     }
 
+    void notifySessionReleased(RoutingSessionInfo session) {
+        for (CallbackRecord record : mCallbackRecords) {
+            record.mExecutor.execute(() -> record.mCallback.onSessionReleased(session));
+        }
+    }
+
     void notifyRequestFailed(int reason) {
         for (CallbackRecord record : mCallbackRecords) {
             record.mExecutor.execute(() -> record.mCallback.onRequestFailed(reason));
@@ -570,6 +576,10 @@
     }
 
     void updatePreferredFeatures(String packageName, List<String> preferredFeatures) {
+        if (preferredFeatures == null) {
+            mPreferredFeaturesMap.remove(packageName);
+            return;
+        }
         List<String> prevFeatures = mPreferredFeaturesMap.put(packageName, preferredFeatures);
         if ((prevFeatures == null && preferredFeatures.size() == 0)
                 || Objects.equals(preferredFeatures, prevFeatures)) {
@@ -864,9 +874,16 @@
 
         /**
          * Called when a session is changed.
-         * @param sessionInfo the updated session
+         * @param session the updated session
          */
-        public void onSessionUpdated(@NonNull RoutingSessionInfo sessionInfo) {}
+        public void onSessionUpdated(@NonNull RoutingSessionInfo session) {}
+
+        /**
+         * Called when a session is released.
+         * @param session the released session.
+         * @see #releaseSession(RoutingSessionInfo)
+         */
+        public void onSessionReleased(@NonNull RoutingSessionInfo session) {}
 
         /**
          * Called when media is transferred.
@@ -946,15 +963,21 @@
 
     class Client extends IMediaRouter2Manager.Stub {
         @Override
-        public void notifySessionCreated(int requestId, RoutingSessionInfo sessionInfo) {
+        public void notifySessionCreated(int requestId, RoutingSessionInfo session) {
             mHandler.sendMessage(obtainMessage(MediaRouter2Manager::createSessionOnHandler,
-                    MediaRouter2Manager.this, requestId, sessionInfo));
+                    MediaRouter2Manager.this, requestId, session));
         }
 
         @Override
-        public void notifySessionUpdated(RoutingSessionInfo sessionInfo) {
-            mHandler.sendMessage(obtainMessage(MediaRouter2Manager::handleSessionsUpdated,
-                    MediaRouter2Manager.this, sessionInfo));
+        public void notifySessionUpdated(RoutingSessionInfo session) {
+            mHandler.sendMessage(obtainMessage(MediaRouter2Manager::handleSessionsUpdatedOnHandler,
+                    MediaRouter2Manager.this, session));
+        }
+
+        @Override
+        public void notifySessionReleased(RoutingSessionInfo session) {
+            mHandler.sendMessage(obtainMessage(MediaRouter2Manager::notifySessionReleased,
+                    MediaRouter2Manager.this, session));
         }
 
         @Override
diff --git a/media/java/android/media/soundtrigger_middleware/RecognitionEvent.aidl b/media/java/android/media/soundtrigger_middleware/RecognitionEvent.aidl
index de4d060..a237ec1 100644
--- a/media/java/android/media/soundtrigger_middleware/RecognitionEvent.aidl
+++ b/media/java/android/media/soundtrigger_middleware/RecognitionEvent.aidl
@@ -43,9 +43,9 @@
     boolean triggerInData;
     /**
      * Audio format of either the trigger in event data or to use for capture of the rest of the
-     * utterance.
+     * utterance. May be null when no audio is available for this event type.
      */
-    AudioConfig audioConfig;
+    @nullable AudioConfig audioConfig;
     /** Additional data. */
     byte[] data;
 }
diff --git a/media/jni/android_media_MediaCodec.cpp b/media/jni/android_media_MediaCodec.cpp
index a03b24c..f970b59 100644
--- a/media/jni/android_media_MediaCodec.cpp
+++ b/media/jni/android_media_MediaCodec.cpp
@@ -233,10 +233,12 @@
 }
 
 void JMediaCodec::releaseAsync() {
-    if (mCodec != NULL) {
-        mCodec->releaseAsync();
-    }
-    mInitStatus = NO_INIT;
+    std::call_once(mAsyncReleaseFlag, [this] {
+        if (mCodec != NULL) {
+            mCodec->releaseAsync(new AMessage(kWhatAsyncReleaseComplete, this));
+        }
+        mInitStatus = NO_INIT;
+    });
 }
 
 JMediaCodec::~JMediaCodec() {
@@ -1084,6 +1086,12 @@
             handleFrameRenderedNotification(msg);
             break;
         }
+        case kWhatAsyncReleaseComplete:
+        {
+            mCodec.clear();
+            mLooper->stop();
+            break;
+        }
         default:
             TRESPASS();
     }
diff --git a/media/jni/android_media_MediaCodec.h b/media/jni/android_media_MediaCodec.h
index 5c34341..a58f9a7 100644
--- a/media/jni/android_media_MediaCodec.h
+++ b/media/jni/android_media_MediaCodec.h
@@ -173,6 +173,7 @@
     enum {
         kWhatCallbackNotify,
         kWhatFrameRendered,
+        kWhatAsyncReleaseComplete,
     };
 
     jclass mClass;
@@ -185,6 +186,7 @@
     bool mGraphicOutput{false};
     bool mHasCryptoOrDescrambler{false};
     std::once_flag mReleaseFlag;
+    std::once_flag mAsyncReleaseFlag;
 
     sp<AMessage> mCallbackNotification;
     sp<AMessage> mOnFrameRenderedNotification;
diff --git a/media/tests/MediaRouter/src/com/android/mediaroutertest/MediaRouter2ManagerTest.java b/media/tests/MediaRouter/src/com/android/mediaroutertest/MediaRouter2ManagerTest.java
index 356acdc..638a842 100644
--- a/media/tests/MediaRouter/src/com/android/mediaroutertest/MediaRouter2ManagerTest.java
+++ b/media/tests/MediaRouter/src/com/android/mediaroutertest/MediaRouter2ManagerTest.java
@@ -281,17 +281,19 @@
     }
 
     @Test
-    public void testGetRoutingControllers() throws Exception {
+    public void testGetRoutingSessions() throws Exception {
         CountDownLatch latch = new CountDownLatch(1);
 
         Map<String, MediaRoute2Info> routes = waitAndGetRoutesWithManager(FEATURES_ALL);
+        MediaRoute2Info routeToSelect = routes.get(ROUTE_ID1);
+
         addRouterCallback(new RouteCallback() {});
         addManagerCallback(new MediaRouter2Manager.Callback() {
             @Override
             public void onTransferred(RoutingSessionInfo oldSessionInfo,
                     RoutingSessionInfo newSessionInfo) {
                 if (TextUtils.equals(mPackageName, newSessionInfo.getClientPackageName())
-                        && newSessionInfo.getSelectedRoutes().contains(ROUTE_ID1)) {
+                        && newSessionInfo.getSelectedRoutes().contains(routeToSelect.getId())) {
                     latch.countDown();
                 }
             }
@@ -299,11 +301,10 @@
 
         assertEquals(1, mManager.getRoutingSessions(mPackageName).size());
 
-        mManager.selectRoute(mPackageName, routes.get(ROUTE_ID1));
-        latch.await(TIMEOUT_MS, TimeUnit.MILLISECONDS);
+        mManager.selectRoute(mPackageName, routeToSelect);
+        assertTrue(latch.await(TIMEOUT_MS, TimeUnit.MILLISECONDS));
 
         List<RoutingSessionInfo> sessions = mManager.getRoutingSessions(mPackageName);
-
         assertEquals(2, sessions.size());
 
         RoutingSessionInfo sessionInfo = sessions.get(1);
@@ -344,6 +345,47 @@
         assertTrue(onTransferFailedLatch.await(TIMEOUT_MS, TimeUnit.MILLISECONDS));
     }
 
+    @Test
+    public void testRouterRelease_managerGetRoutingSessions() throws Exception {
+        CountDownLatch transferLatch = new CountDownLatch(1);
+        CountDownLatch releaseLatch = new CountDownLatch(1);
+
+        Map<String, MediaRoute2Info> routes = waitAndGetRoutesWithManager(FEATURES_ALL);
+        MediaRoute2Info routeToSelect = routes.get(ROUTE_ID1);
+        assertNotNull(routeToSelect);
+
+        addRouterCallback(new RouteCallback() {});
+        addManagerCallback(new MediaRouter2Manager.Callback() {
+            @Override
+            public void onTransferred(RoutingSessionInfo oldSessionInfo,
+                    RoutingSessionInfo newSessionInfo) {
+                if (TextUtils.equals(mPackageName, newSessionInfo.getClientPackageName())
+                        && newSessionInfo.getSelectedRoutes().contains(routeToSelect.getId())) {
+                    transferLatch.countDown();
+                }
+            }
+            @Override
+            public void onSessionReleased(RoutingSessionInfo session) {
+                releaseLatch.countDown();
+            }
+        });
+
+        assertEquals(1, mManager.getRoutingSessions(mPackageName).size());
+        assertEquals(1, mRouter2.getControllers().size());
+
+        mManager.transfer(mManager.getRoutingSessions(mPackageName).get(0), routeToSelect);
+        assertTrue(transferLatch.await(TIMEOUT_MS, TimeUnit.MILLISECONDS));
+
+        assertEquals(2, mManager.getRoutingSessions(mPackageName).size());
+        assertEquals(2, mRouter2.getControllers().size());
+        mRouter2.getControllers().get(1).release();
+
+        assertTrue(releaseLatch.await(TIMEOUT_MS, TimeUnit.MILLISECONDS));
+
+        assertEquals(1, mRouter2.getControllers().size());
+        assertEquals(1, mManager.getRoutingSessions(mPackageName).size());
+    }
+
     /**
      * Tests select, transfer, release of routes of a provider
      */
@@ -551,11 +593,16 @@
 
         final int failureReason = REASON_REJECTED;
         final CountDownLatch onRequestFailedLatch = new CountDownLatch(1);
+        final CountDownLatch onRequestFailedSecondCallLatch = new CountDownLatch(1);
         addManagerCallback(new MediaRouter2Manager.Callback() {
             @Override
             public void onRequestFailed(int reason) {
                 if (reason == failureReason) {
-                    onRequestFailedLatch.countDown();
+                    if (onRequestFailedLatch.getCount() > 0) {
+                        onRequestFailedLatch.countDown();
+                    } else {
+                        onRequestFailedSecondCallLatch.countDown();
+                    }
                 }
             }
         });
@@ -567,6 +614,11 @@
         final long validRequestId = requestIds.get(0);
         instance.notifyRequestFailed(validRequestId, failureReason);
         assertTrue(onRequestFailedLatch.await(TIMEOUT_MS, TimeUnit.MILLISECONDS));
+
+        // Test calling notifyRequestFailed() multiple times with the same valid requestId.
+        // onRequestFailed() shouldn't be called since the requestId has been already handled.
+        instance.notifyRequestFailed(validRequestId, failureReason);
+        assertFalse(onRequestFailedSecondCallLatch.await(TIMEOUT_MS, TimeUnit.MILLISECONDS));
     }
 
     @Test
diff --git a/packages/CarSystemUI/res/values/colors.xml b/packages/CarSystemUI/res/values/colors.xml
index d20ab49..ab94265 100644
--- a/packages/CarSystemUI/res/values/colors.xml
+++ b/packages/CarSystemUI/res/values/colors.xml
@@ -15,7 +15,6 @@
   ~ limitations under the License
   -->
 <resources xmlns:android="http://schemas.android.com/apk/res/android">
-    <color name="nav_bar_ripple_background_color">#40ffffff</color>
     <!-- colors for user switcher -->
     <color name="car_user_switcher_background_color">#000000</color>
     <color name="car_user_switcher_name_text_color">@*android:color/car_body1_light</color>
diff --git a/packages/CarSystemUI/res/values/config.xml b/packages/CarSystemUI/res/values/config.xml
index 4bf0fca..cf967c0 100644
--- a/packages/CarSystemUI/res/values/config.xml
+++ b/packages/CarSystemUI/res/values/config.xml
@@ -118,4 +118,7 @@
         <item>com.android.systemui.car.window.SystemUIOverlayWindowManager</item>
         <item>com.android.systemui.car.volume.VolumeUI</item>
     </string-array>
+
+    <!-- How many milliseconds to wait before force hiding the UserSwitchTransitionView -->
+    <integer name="config_userSwitchTransitionViewShownTimeoutMs" translatable="false">5000</integer>
 </resources>
diff --git a/packages/CarSystemUI/res/values/styles.xml b/packages/CarSystemUI/res/values/styles.xml
index 7fc69e6..e76373d 100644
--- a/packages/CarSystemUI/res/values/styles.xml
+++ b/packages/CarSystemUI/res/values/styles.xml
@@ -37,13 +37,9 @@
         <item name="android:textColor">@*android:color/car_grey_50</item>
     </style>
 
-    <style name="CarNavigationBarButtonTheme">
-        <item name="android:colorControlHighlight">@color/nav_bar_ripple_background_color</item>
-    </style>
-
     <style name="NavigationBarButton">
         <item name="android:layout_height">96dp</item>
         <item name="android:layout_width">96dp</item>
-        <item name="android:background">@*android:drawable/item_background_material</item>
+        <item name="android:background">?android:attr/selectableItemBackground</item>
     </style>
 </resources>
\ No newline at end of file
diff --git a/packages/CarSystemUI/src/com/android/systemui/car/keyguard/CarKeyguardViewController.java b/packages/CarSystemUI/src/com/android/systemui/car/keyguard/CarKeyguardViewController.java
index 2dad5f8..69766cc 100644
--- a/packages/CarSystemUI/src/com/android/systemui/car/keyguard/CarKeyguardViewController.java
+++ b/packages/CarSystemUI/src/com/android/systemui/car/keyguard/CarKeyguardViewController.java
@@ -103,6 +103,7 @@
     private KeyguardBouncer mBouncer;
     private OnKeyguardCancelClickedListener mKeyguardCancelClickedListener;
     private boolean mShowing;
+    private boolean mIsOccluded;
 
     @Inject
     public CarKeyguardViewController(
@@ -220,6 +221,7 @@
 
     @Override
     public void setOccluded(boolean occluded, boolean animate) {
+        mIsOccluded = occluded;
         getOverlayViewGlobalStateController().setOccluded(occluded);
         if (!occluded) {
             reset(/* hideBouncerWhenShowing= */ false);
@@ -244,6 +246,12 @@
 
     @Override
     public void dismissAndCollapse() {
+        // If dismissing and collapsing Keyguard is requested (e.g. by a Keyguard-dismissing
+        // Activity) while Keyguard is occluded, unocclude Keyguard so the user can authenticate to
+        // dismiss Keyguard.
+        if (mIsOccluded) {
+            setOccluded(/* occluded= */ false, /* animate= */ false);
+        }
         if (!mBouncer.isSecure()) {
             hide(/* startTime= */ 0, /* fadeoutDuration= */ 0);
         }
diff --git a/packages/CarSystemUI/src/com/android/systemui/car/navigationbar/CarNavigationBar.java b/packages/CarSystemUI/src/com/android/systemui/car/navigationbar/CarNavigationBar.java
index 4c720ab..37dfce4 100644
--- a/packages/CarSystemUI/src/com/android/systemui/car/navigationbar/CarNavigationBar.java
+++ b/packages/CarSystemUI/src/com/android/systemui/car/navigationbar/CarNavigationBar.java
@@ -16,10 +16,10 @@
 
 package com.android.systemui.car.navigationbar;
 
-import static android.view.InsetsState.ITYPE_BOTTOM_GESTURES;
+import static android.view.InsetsState.ITYPE_CLIMATE_BAR;
+import static android.view.InsetsState.ITYPE_EXTRA_NAVIGATION_BAR;
 import static android.view.InsetsState.ITYPE_NAVIGATION_BAR;
 import static android.view.InsetsState.ITYPE_STATUS_BAR;
-import static android.view.InsetsState.ITYPE_TOP_GESTURES;
 import static android.view.InsetsState.containsType;
 import static android.view.WindowInsetsController.APPEARANCE_LIGHT_STATUS_BARS;
 
@@ -368,15 +368,13 @@
             WindowManager.LayoutParams lp = new WindowManager.LayoutParams(
                     ViewGroup.LayoutParams.MATCH_PARENT,
                     height,
-                    WindowManager.LayoutParams.TYPE_STATUS_BAR_ADDITIONAL,
+                    WindowManager.LayoutParams.TYPE_STATUS_BAR,
                     WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
                             | WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL
                             | WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH
                             | WindowManager.LayoutParams.FLAG_SPLIT_TOUCH,
                     PixelFormat.TRANSLUCENT);
             lp.setTitle("TopCarNavigationBar");
-            lp.providesInsetsTypes = new int[]{ITYPE_STATUS_BAR, ITYPE_TOP_GESTURES};
-            lp.setFitInsetsTypes(0);
             lp.windowAnimations = 0;
             lp.gravity = Gravity.TOP;
             mWindowManager.addView(mTopNavigationBarWindow, lp);
@@ -390,14 +388,13 @@
             WindowManager.LayoutParams lp = new WindowManager.LayoutParams(
                     ViewGroup.LayoutParams.MATCH_PARENT,
                     height,
-                    WindowManager.LayoutParams.TYPE_NAVIGATION_BAR_PANEL,
+                    WindowManager.LayoutParams.TYPE_NAVIGATION_BAR,
                     WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
                             | WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL
                             | WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH
                             | WindowManager.LayoutParams.FLAG_SPLIT_TOUCH,
                     PixelFormat.TRANSLUCENT);
             lp.setTitle("BottomCarNavigationBar");
-            lp.providesInsetsTypes = new int[]{ITYPE_NAVIGATION_BAR, ITYPE_BOTTOM_GESTURES};
             lp.windowAnimations = 0;
             lp.gravity = Gravity.BOTTOM;
             mWindowManager.addView(mBottomNavigationBarWindow, lp);
@@ -415,6 +412,8 @@
                             | WindowManager.LayoutParams.FLAG_SPLIT_TOUCH,
                     PixelFormat.TRANSLUCENT);
             leftlp.setTitle("LeftCarNavigationBar");
+            leftlp.providesInsetsTypes = new int[]{ITYPE_CLIMATE_BAR};
+            leftlp.setFitInsetsTypes(0);
             leftlp.windowAnimations = 0;
             leftlp.gravity = Gravity.LEFT;
             mWindowManager.addView(mLeftNavigationBarWindow, leftlp);
@@ -432,6 +431,8 @@
                             | WindowManager.LayoutParams.FLAG_SPLIT_TOUCH,
                     PixelFormat.TRANSLUCENT);
             rightlp.setTitle("RightCarNavigationBar");
+            rightlp.providesInsetsTypes = new int[]{ITYPE_EXTRA_NAVIGATION_BAR};
+            rightlp.setFitInsetsTypes(0);
             rightlp.windowAnimations = 0;
             rightlp.gravity = Gravity.RIGHT;
             mWindowManager.addView(mRightNavigationBarWindow, rightlp);
diff --git a/packages/CarSystemUI/src/com/android/systemui/car/navigationbar/CarNavigationBarView.java b/packages/CarSystemUI/src/com/android/systemui/car/navigationbar/CarNavigationBarView.java
index 0ced402..029d4c7 100644
--- a/packages/CarSystemUI/src/com/android/systemui/car/navigationbar/CarNavigationBarView.java
+++ b/packages/CarSystemUI/src/com/android/systemui/car/navigationbar/CarNavigationBarView.java
@@ -16,10 +16,7 @@
 
 package com.android.systemui.car.navigationbar;
 
-import static android.view.WindowInsets.Type.systemBars;
-
 import android.content.Context;
-import android.graphics.Insets;
 import android.util.AttributeSet;
 import android.view.MotionEvent;
 import android.view.View;
@@ -82,28 +79,9 @@
 
     @Override
     public WindowInsets onApplyWindowInsets(WindowInsets windowInsets) {
-        applyMargins(windowInsets.getInsets(systemBars()));
         return windowInsets;
     }
 
-    private void applyMargins(Insets insets) {
-        final int count = getChildCount();
-        for (int i = 0; i < count; i++) {
-            View child = getChildAt(i);
-            if (child.getLayoutParams() instanceof LayoutParams) {
-                LayoutParams lp = (LayoutParams) child.getLayoutParams();
-                if (lp.rightMargin != insets.right || lp.leftMargin != insets.left
-                        || lp.topMargin != insets.top || lp.bottomMargin != insets.bottom) {
-                    lp.rightMargin = insets.right;
-                    lp.leftMargin = insets.left;
-                    lp.topMargin = insets.top;
-                    lp.bottomMargin = insets.bottom;
-                    child.requestLayout();
-                }
-            }
-        }
-    }
-
     // Used to forward touch events even if the touch was initiated from a child component
     @Override
     public boolean onInterceptTouchEvent(MotionEvent ev) {
diff --git a/packages/CarSystemUI/src/com/android/systemui/car/notification/BottomNotificationPanelViewMediator.java b/packages/CarSystemUI/src/com/android/systemui/car/notification/BottomNotificationPanelViewMediator.java
index 6d140ca..7d353f5a 100644
--- a/packages/CarSystemUI/src/com/android/systemui/car/notification/BottomNotificationPanelViewMediator.java
+++ b/packages/CarSystemUI/src/com/android/systemui/car/notification/BottomNotificationPanelViewMediator.java
@@ -16,6 +16,7 @@
 
 package com.android.systemui.car.notification;
 
+import com.android.systemui.broadcast.BroadcastDispatcher;
 import com.android.systemui.car.CarDeviceProvisionedController;
 import com.android.systemui.car.navigationbar.CarNavigationBarController;
 import com.android.systemui.car.window.OverlayPanelViewController;
@@ -37,6 +38,7 @@
             NotificationPanelViewController notificationPanelViewController,
 
             PowerManagerHelper powerManagerHelper,
+            BroadcastDispatcher broadcastDispatcher,
 
             CarDeviceProvisionedController carDeviceProvisionedController,
             ConfigurationController configurationController
@@ -44,6 +46,7 @@
         super(carNavigationBarController,
                 notificationPanelViewController,
                 powerManagerHelper,
+                broadcastDispatcher,
                 carDeviceProvisionedController,
                 configurationController);
         notificationPanelViewController.setOverlayDirection(
diff --git a/packages/CarSystemUI/src/com/android/systemui/car/notification/NotificationPanelViewMediator.java b/packages/CarSystemUI/src/com/android/systemui/car/notification/NotificationPanelViewMediator.java
index 41349b2..0c185ba 100644
--- a/packages/CarSystemUI/src/com/android/systemui/car/notification/NotificationPanelViewMediator.java
+++ b/packages/CarSystemUI/src/com/android/systemui/car/notification/NotificationPanelViewMediator.java
@@ -17,10 +17,17 @@
 package com.android.systemui.car.notification;
 
 import android.car.hardware.power.CarPowerManager;
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
 import android.content.res.Configuration;
+import android.os.UserHandle;
+import android.util.Log;
 
 import androidx.annotation.CallSuper;
 
+import com.android.systemui.broadcast.BroadcastDispatcher;
 import com.android.systemui.car.CarDeviceProvisionedController;
 import com.android.systemui.car.navigationbar.CarNavigationBarController;
 import com.android.systemui.car.window.OverlayViewMediator;
@@ -37,18 +44,36 @@
 public class NotificationPanelViewMediator implements OverlayViewMediator,
         ConfigurationController.ConfigurationListener {
 
+    private static final boolean DEBUG = false;
+    private static final String TAG = "NotificationPanelVM";
+
     private final CarNavigationBarController mCarNavigationBarController;
     private final NotificationPanelViewController mNotificationPanelViewController;
     private final PowerManagerHelper mPowerManagerHelper;
+    private final BroadcastDispatcher mBroadcastDispatcher;
     private final CarDeviceProvisionedController mCarDeviceProvisionedController;
     private final ConfigurationController mConfigurationController;
 
+    private final BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {
+        @Override
+        public void onReceive(Context context, Intent intent) {
+            if (DEBUG) Log.v(TAG, "onReceive: " + intent);
+            String action = intent.getAction();
+            if (Intent.ACTION_CLOSE_SYSTEM_DIALOGS.equals(action)) {
+                if (mNotificationPanelViewController.isPanelExpanded()) {
+                    mNotificationPanelViewController.toggle();
+                }
+            }
+        }
+    };
+
     @Inject
     public NotificationPanelViewMediator(
             CarNavigationBarController carNavigationBarController,
             NotificationPanelViewController notificationPanelViewController,
 
             PowerManagerHelper powerManagerHelper,
+            BroadcastDispatcher broadcastDispatcher,
 
             CarDeviceProvisionedController carDeviceProvisionedController,
             ConfigurationController configurationController
@@ -56,6 +81,7 @@
         mCarNavigationBarController = carNavigationBarController;
         mNotificationPanelViewController = notificationPanelViewController;
         mPowerManagerHelper = powerManagerHelper;
+        mBroadcastDispatcher = broadcastDispatcher;
         mCarDeviceProvisionedController = carDeviceProvisionedController;
         mConfigurationController = configurationController;
     }
@@ -84,6 +110,9 @@
                         return mNotificationPanelViewController.isPanelExpanded();
                     }
                 });
+
+        mBroadcastDispatcher.registerReceiver(mBroadcastReceiver,
+                new IntentFilter(Intent.ACTION_CLOSE_SYSTEM_DIALOGS), null, UserHandle.ALL);
     }
 
     @Override
diff --git a/packages/CarSystemUI/src/com/android/systemui/car/notification/TopNotificationPanelViewMediator.java b/packages/CarSystemUI/src/com/android/systemui/car/notification/TopNotificationPanelViewMediator.java
index 8d3eb4c..89c9931 100644
--- a/packages/CarSystemUI/src/com/android/systemui/car/notification/TopNotificationPanelViewMediator.java
+++ b/packages/CarSystemUI/src/com/android/systemui/car/notification/TopNotificationPanelViewMediator.java
@@ -16,6 +16,7 @@
 
 package com.android.systemui.car.notification;
 
+import com.android.systemui.broadcast.BroadcastDispatcher;
 import com.android.systemui.car.CarDeviceProvisionedController;
 import com.android.systemui.car.navigationbar.CarNavigationBarController;
 import com.android.systemui.car.window.OverlayPanelViewController;
@@ -37,6 +38,7 @@
             NotificationPanelViewController notificationPanelViewController,
 
             PowerManagerHelper powerManagerHelper,
+            BroadcastDispatcher broadcastDispatcher,
 
             CarDeviceProvisionedController carDeviceProvisionedController,
             ConfigurationController configurationController
@@ -44,6 +46,7 @@
         super(carNavigationBarController,
                 notificationPanelViewController,
                 powerManagerHelper,
+                broadcastDispatcher,
                 carDeviceProvisionedController,
                 configurationController);
         notificationPanelViewController.setOverlayDirection(
diff --git a/packages/CarSystemUI/src/com/android/systemui/car/userswitcher/UserSwitchTransitionViewController.java b/packages/CarSystemUI/src/com/android/systemui/car/userswitcher/UserSwitchTransitionViewController.java
index 775ef81..45f3d34 100644
--- a/packages/CarSystemUI/src/com/android/systemui/car/userswitcher/UserSwitchTransitionViewController.java
+++ b/packages/CarSystemUI/src/com/android/systemui/car/userswitcher/UserSwitchTransitionViewController.java
@@ -23,13 +23,17 @@
 import android.content.res.Resources;
 import android.graphics.Bitmap;
 import android.os.Handler;
+import android.os.RemoteException;
 import android.os.UserHandle;
 import android.os.UserManager;
 import android.provider.Settings;
+import android.util.Log;
+import android.view.IWindowManager;
 import android.widget.ImageView;
 import android.widget.TextView;
 
 import com.android.internal.annotations.GuardedBy;
+import com.android.internal.annotations.VisibleForTesting;
 import com.android.settingslib.drawable.CircleFramedDrawable;
 import com.android.systemui.R;
 import com.android.systemui.car.window.OverlayViewController;
@@ -44,13 +48,24 @@
  */
 @Singleton
 public class UserSwitchTransitionViewController extends OverlayViewController {
-    private static final String TAG = "UserSwitchTransitionViewController";
+    private static final String TAG = "UserSwitchTransition";
     private static final String ENABLE_DEVELOPER_MESSAGE_TRUE = "true";
+    private static final boolean DEBUG = false;
 
     private final Context mContext;
     private final Handler mHandler;
     private final Resources mResources;
     private final UserManager mUserManager;
+    private final IWindowManager mWindowManagerService;
+    private final int mWindowShownTimeoutMs;
+    private final Runnable mWindowShownTimeoutCallback = () -> {
+        if (DEBUG) {
+            Log.w(TAG, "Window was not hidden within " + getWindowShownTimeoutMs() + " ms, so it"
+                    + "was hidden by mWindowShownTimeoutCallback.");
+        }
+
+        handleHide();
+    };
 
     @GuardedBy("this")
     private boolean mShowing;
@@ -62,6 +77,7 @@
             @Main Handler handler,
             @Main Resources resources,
             UserManager userManager,
+            IWindowManager windowManagerService,
             OverlayViewGlobalStateController overlayViewGlobalStateController) {
 
         super(R.id.user_switching_dialog_stub, overlayViewGlobalStateController);
@@ -70,6 +86,9 @@
         mHandler = handler;
         mResources = resources;
         mUserManager = userManager;
+        mWindowManagerService = windowManagerService;
+        mWindowShownTimeoutMs = mResources.getInteger(
+                R.integer.config_userSwitchTransitionViewShownTimeoutMs);
     }
 
     /**
@@ -81,10 +100,20 @@
         if (mPreviousUserId == newUserId || mShowing) return;
         mShowing = true;
         mHandler.post(() -> {
+            try {
+                mWindowManagerService.setSwitchingUser(true);
+                mWindowManagerService.lockNow(null);
+            } catch (RemoteException e) {
+                Log.e(TAG, "unable to notify window manager service regarding user switch");
+            }
+
             start();
             populateDialog(mPreviousUserId, newUserId);
             // next time a new user is selected, this current new user will be the previous user.
             mPreviousUserId = newUserId;
+            // In case the window is still showing after WINDOW_SHOWN_TIMEOUT_MS, then hide the
+            // window and log a warning message.
+            mHandler.postDelayed(mWindowShownTimeoutCallback, mWindowShownTimeoutMs);
         });
     }
 
@@ -92,6 +121,12 @@
         if (!mShowing) return;
         mShowing = false;
         mHandler.post(this::stop);
+        mHandler.removeCallbacks(mWindowShownTimeoutCallback);
+    }
+
+    @VisibleForTesting
+    int getWindowShownTimeoutMs() {
+        return mWindowShownTimeoutMs;
     }
 
     private void populateDialog(@UserIdInt int previousUserId, @UserIdInt int newUserId) {
diff --git a/packages/CarSystemUI/tests/src/com/android/systemui/car/userswitcher/UserSwitchTransitionViewControllerTest.java b/packages/CarSystemUI/tests/src/com/android/systemui/car/userswitcher/UserSwitchTransitionViewControllerTest.java
index eab381c..797dbf5 100644
--- a/packages/CarSystemUI/tests/src/com/android/systemui/car/userswitcher/UserSwitchTransitionViewControllerTest.java
+++ b/packages/CarSystemUI/tests/src/com/android/systemui/car/userswitcher/UserSwitchTransitionViewControllerTest.java
@@ -18,6 +18,8 @@
 
 import static org.mockito.ArgumentMatchers.any;
 import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.reset;
 import static org.mockito.Mockito.verify;
 
 import android.content.Context;
@@ -28,6 +30,7 @@
 import android.testing.AndroidTestingRunner;
 import android.testing.TestableLooper;
 import android.testing.TestableResources;
+import android.view.IWindowManager;
 import android.view.LayoutInflater;
 import android.view.ViewGroup;
 
@@ -52,6 +55,8 @@
     private TestableResources mTestableResources;
     @Mock
     private OverlayViewGlobalStateController mOverlayViewGlobalStateController;
+    @Mock
+    private IWindowManager mWindowManagerService;
 
     @Before
     public void setUp() {
@@ -62,6 +67,7 @@
                 Handler.getMain(),
                 mTestableResources.getResources(),
                 (UserManager) mContext.getSystemService(Context.USER_SERVICE),
+                mWindowManagerService,
                 mOverlayViewGlobalStateController
         );
 
@@ -118,6 +124,29 @@
                 any());
     }
 
+    @Test
+    public void onWindowShownTimeoutPassed_viewNotHidden_hidesUserSwitchTransitionView() {
+        mCarUserSwitchingDialogController.handleShow(/* currentUserId= */ TEST_USER_1);
+        reset(mOverlayViewGlobalStateController);
+
+        getContext().getMainThreadHandler().postDelayed(() -> {
+            verify(mOverlayViewGlobalStateController).hideView(
+                    eq(mCarUserSwitchingDialogController), any());
+        }, mCarUserSwitchingDialogController.getWindowShownTimeoutMs() + 10);
+    }
+
+    @Test
+    public void onWindowShownTimeoutPassed_viewHidden_doesNotHideUserSwitchTransitionViewAgain() {
+        mCarUserSwitchingDialogController.handleShow(/* currentUserId= */ TEST_USER_1);
+        mCarUserSwitchingDialogController.handleHide();
+        reset(mOverlayViewGlobalStateController);
+
+        getContext().getMainThreadHandler().postDelayed(() -> {
+            verify(mOverlayViewGlobalStateController, never()).hideView(
+                    eq(mCarUserSwitchingDialogController), any());
+        }, mCarUserSwitchingDialogController.getWindowShownTimeoutMs() + 10);
+    }
+
     private final class TestableUserSwitchTransitionViewController extends
             UserSwitchTransitionViewController {
 
@@ -125,8 +154,10 @@
 
         TestableUserSwitchTransitionViewController(Context context, Handler handler,
                 Resources resources, UserManager userManager,
+                IWindowManager windowManagerService,
                 OverlayViewGlobalStateController overlayViewGlobalStateController) {
-            super(context, handler, resources, userManager, overlayViewGlobalStateController);
+            super(context, handler, resources, userManager, windowManagerService,
+                    overlayViewGlobalStateController);
             mHandler = handler;
         }
 
diff --git a/packages/ExternalStorageProvider/src/com/android/externalstorage/ExternalStorageProvider.java b/packages/ExternalStorageProvider/src/com/android/externalstorage/ExternalStorageProvider.java
index 8f919c3..f42bf19 100644
--- a/packages/ExternalStorageProvider/src/com/android/externalstorage/ExternalStorageProvider.java
+++ b/packages/ExternalStorageProvider/src/com/android/externalstorage/ExternalStorageProvider.java
@@ -95,7 +95,8 @@
         public String docId;
         public File visiblePath;
         public File path;
-        public boolean reportAvailableBytes = true;
+        // TODO (b/157033915): Make getFreeBytes() faster
+        public boolean reportAvailableBytes = false;
     }
 
     private static final String ROOT_ID_PRIMARY_EMULATED =
@@ -520,9 +521,11 @@
         final RootInfo root = resolvedDocId.first;
         File child = resolvedDocId.second;
 
+        final File rootFile = root.visiblePath != null ? root.visiblePath
+                : root.path;
         final File parent = TextUtils.isEmpty(parentDocId)
-                        ? root.path
-                        : getFileForDocId(parentDocId);
+                ? rootFile
+                : getFileForDocId(parentDocId);
 
         return new Path(parentDocId == null ? root.rootId : null, findDocumentPath(parent, child));
     }
diff --git a/packages/OsuLogin/Android.bp b/packages/OsuLogin/Android.bp
index d7e36b1..445c81b 100644
--- a/packages/OsuLogin/Android.bp
+++ b/packages/OsuLogin/Android.bp
@@ -1,5 +1,6 @@
 android_app {
     name: "OsuLogin",
+    defaults: ["wifi-module-sdk-version-defaults"],
     static_libs: ["androidx.legacy_legacy-support-v4"],
     resource_dirs: ["res"],
     srcs: ["src/**/*.java"],
diff --git a/packages/PackageInstaller/res/values-ne/strings.xml b/packages/PackageInstaller/res/values-ne/strings.xml
index 60934b1..495a05b 100644
--- a/packages/PackageInstaller/res/values-ne/strings.xml
+++ b/packages/PackageInstaller/res/values-ne/strings.xml
@@ -30,11 +30,11 @@
     <string name="install_failed_blocked" msgid="8512284352994752094">"यो प्याकेज स्थापना गर्ने क्रममा अवरोध गरियो।"</string>
     <string name="install_failed_conflict" msgid="3493184212162521426">"प्याकेजका रूपमा स्थापना नगरिएको एप विद्यमान प्याकेजसँग मेल खाँदैन।"</string>
     <string name="install_failed_incompatible" product="tablet" msgid="6019021440094927928">"एपका रूपमा स्थापना नगरिएको एप तपाईंको ट्याब्लेटसँग मिल्दो छैन।"</string>
-    <string name="install_failed_incompatible" product="tv" msgid="2890001324362291683">"यो एप तपाईंको TV सँग मिल्दो छैन।"</string>
+    <string name="install_failed_incompatible" product="tv" msgid="2890001324362291683">"यो एप तपाईंको टिभी सँग मिल्दो छैन।"</string>
     <string name="install_failed_incompatible" product="default" msgid="7254630419511645826">"एपका रूपमा स्थापना नगरिएको एप तपाईंको फोनसँग मिल्दो छैन।"</string>
     <string name="install_failed_invalid_apk" msgid="8581007676422623930">"प्याकेजका रूपमा स्थापना नगरिएको एप अमान्य जस्तो देखिन्छ।"</string>
     <string name="install_failed_msg" product="tablet" msgid="6298387264270562442">"तपाईंको ट्याब्लेटमा <xliff:g id="APP_NAME">%1$s</xliff:g> स्थापना गर्न सकिएन।"</string>
-    <string name="install_failed_msg" product="tv" msgid="1920009940048975221">"तपाईंको TV मा <xliff:g id="APP_NAME">%1$s</xliff:g> स्थापना गर्न सकिएन।"</string>
+    <string name="install_failed_msg" product="tv" msgid="1920009940048975221">"तपाईंको टिभी मा <xliff:g id="APP_NAME">%1$s</xliff:g> स्थापना गर्न सकिएन।"</string>
     <string name="install_failed_msg" product="default" msgid="6484461562647915707">"तपाईंको फोनमा <xliff:g id="APP_NAME">%1$s</xliff:g> स्थापना गर्न सकिएन।"</string>
     <string name="launch" msgid="3952550563999890101">"खोल्नुहोस्"</string>
     <string name="unknown_apps_admin_dlg_text" msgid="4456572224020176095">"तपाईंका प्रशासकले अज्ञात स्रोतहरूबाट प्राप्त अनुप्रयोगहरूलाई स्थापना गर्ने अनुमति दिनुहुन्न"</string>
@@ -81,11 +81,11 @@
     <string name="message_staging" msgid="8032722385658438567">"एप स्थापना गर्न तयारी गर्दै…"</string>
     <string name="app_name_unknown" msgid="6881210203354323926">"अज्ञात"</string>
     <string name="untrusted_external_source_warning" product="tablet" msgid="6539403649459942547">"तपाईंको सुरक्षाका लागि, तपाईंको ट्याब्लेटलाई यो स्रोतबाट प्राप्त हुने अज्ञात एपहरू स्थापना गर्ने अनुमति छैन।"</string>
-    <string name="untrusted_external_source_warning" product="tv" msgid="1206648674551321364">"तपाईंको सुरक्षाका लागि, तपाईंको TV लाई यस स्रोतबाट प्राप्त हुने अज्ञात एपहरू स्थापना गर्ने अनुमति छैन।"</string>
+    <string name="untrusted_external_source_warning" product="tv" msgid="1206648674551321364">"तपाईंको सुरक्षाका लागि, तपाईंको टिभी लाई यस स्रोतबाट प्राप्त हुने अज्ञात एपहरू स्थापना गर्ने अनुमति छैन।"</string>
     <string name="untrusted_external_source_warning" product="default" msgid="7279739265754475165">"तपाईंको सुरक्षाका लागि, तपाईंको फोनलाई यो स्रोतबाट प्राप्त हुने अज्ञात एपहरू स्थापना गर्ने अनुमति छैन।"</string>
     <string name="anonymous_source_warning" product="default" msgid="2784902545920822500">"तपाईंको फोन तथा व्यक्तिगत डेटा अज्ञात एपहरूबाट हुने आक्रमणको चपेटामा पर्ने बढी जोखिममा हुन्छन्। यो एप स्थापना गरेर तपाईं यसको प्रयोगबाट तपाईंको फोनमा हुन सक्ने क्षति वा डेटाको नोक्सानीका लागि स्वयं जिम्मेवार हुने कुरामा सहमत हुनुहुन्छ।"</string>
     <string name="anonymous_source_warning" product="tablet" msgid="3939101621438855516">"तपाईंको ट्याब्लेट तथा व्यक्तिगत डेटा अज्ञात एपहरूबाट हुने आक्रमणको चपेटामा पर्ने बढी जोखिममा हुन्छन्। यो एप स्थापना गरेर तपाईं यसको प्रयोगबाट तपाईंको ट्याब्लेटमा हुन सक्ने क्षति वा डेटाको नोक्सानीका लागि स्वयं जिम्मेवार हुने कुरामा सहमत हुनुहुन्छ।"</string>
-    <string name="anonymous_source_warning" product="tv" msgid="5599483539528168566">"तपाईंको TV तथा व्यक्तिगत डेटा अज्ञात एपहरूबाट हुने आक्रमणको चपेटामा पर्ने बढी जोखिममा हुन्छन्। यो एप स्थापना गरेर तपाईं यसको प्रयोगबाट तपाईंको TV मा हुन सक्ने क्षति वा डेटाको नोक्सानीका लागि स्वयं जिम्मेवार हुने कुरामा सहमत हुनुहुन्छ।"</string>
+    <string name="anonymous_source_warning" product="tv" msgid="5599483539528168566">"तपाईंको टिभी तथा व्यक्तिगत डेटा अज्ञात एपहरूबाट हुने आक्रमणको चपेटामा पर्ने बढी जोखिममा हुन्छन्। यो एप स्थापना गरेर तपाईं यसको प्रयोगबाट तपाईंको टिभी मा हुन सक्ने क्षति वा डेटाको नोक्सानीका लागि स्वयं जिम्मेवार हुने कुरामा सहमत हुनुहुन्छ।"</string>
     <string name="anonymous_source_continue" msgid="4375745439457209366">"जारी राख्नुहोस्"</string>
     <string name="external_sources_settings" msgid="4046964413071713807">"सेटिङहरू"</string>
     <string name="wear_app_channel" msgid="1960809674709107850">"वेयर एपहरूको स्थापना/स्थापना रद्द गर्दै"</string>
diff --git a/packages/SettingsLib/AdaptiveIcon/src/com/android/settingslib/widget/AdaptiveOutlineDrawable.java b/packages/SettingsLib/AdaptiveIcon/src/com/android/settingslib/widget/AdaptiveOutlineDrawable.java
index 4438893..3565b0e 100644
--- a/packages/SettingsLib/AdaptiveIcon/src/com/android/settingslib/widget/AdaptiveOutlineDrawable.java
+++ b/packages/SettingsLib/AdaptiveIcon/src/com/android/settingslib/widget/AdaptiveOutlineDrawable.java
@@ -29,7 +29,10 @@
 import android.graphics.Rect;
 import android.graphics.drawable.AdaptiveIconDrawable;
 import android.graphics.drawable.DrawableWrapper;
+import android.os.RemoteException;
 import android.util.PathParser;
+import android.view.IWindowManager;
+import android.view.WindowManagerGlobal;
 
 import androidx.annotation.IntDef;
 import androidx.annotation.VisibleForTesting;
@@ -42,6 +45,9 @@
  */
 public class AdaptiveOutlineDrawable extends DrawableWrapper {
 
+    private static final float ADVANCED_ICON_CENTER = 50f;
+    private static final float ADVANCED_ICON_RADIUS = 48f;
+
     @Retention(RetentionPolicy.SOURCE)
     @IntDef({TYPE_DEFAULT, TYPE_ADVANCED})
     public @interface AdaptiveOutlineIconType {
@@ -130,7 +136,7 @@
         if (mType == TYPE_DEFAULT) {
             canvas.drawPath(mPath, mOutlinePaint);
         } else {
-            canvas.drawCircle(2 * mInsetPx, 2 * mInsetPx, 2 * mInsetPx - mStrokeWidth,
+            canvas.drawCircle(ADVANCED_ICON_CENTER, ADVANCED_ICON_CENTER, ADVANCED_ICON_RADIUS,
                     mOutlinePaint);
         }
         canvas.restoreToCount(count);
@@ -139,6 +145,15 @@
         canvas.drawBitmap(mBitmap, bounds.left + mInsetPx, bounds.top + mInsetPx, null);
     }
 
+    private static int getDefaultDisplayDensity(int displayId) {
+        try {
+            final IWindowManager wm = WindowManagerGlobal.getWindowManagerService();
+            return wm.getInitialDisplayDensity(displayId);
+        } catch (RemoteException exc) {
+            return -1;
+        }
+    }
+
     @Override
     public int getIntrinsicHeight() {
         return mBitmap.getHeight() + 2 * mInsetPx;
diff --git a/packages/SettingsLib/OWNERS b/packages/SettingsLib/OWNERS
index a28ba85..d7bd6a4 100644
--- a/packages/SettingsLib/OWNERS
+++ b/packages/SettingsLib/OWNERS
@@ -3,6 +3,7 @@
 edgarwang@google.com
 emilychuang@google.com
 evanlaird@google.com
+juliacr@google.com
 leifhendrik@google.com
 rafftsai@google.com
 tmfang@google.com
diff --git a/packages/SettingsLib/SearchWidget/res/values-el/strings.xml b/packages/SettingsLib/SearchWidget/res/values-el/strings.xml
index 6f5ab78..d50436a 100644
--- a/packages/SettingsLib/SearchWidget/res/values-el/strings.xml
+++ b/packages/SettingsLib/SearchWidget/res/values-el/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="search_menu" msgid="1914043873178389845">"Ρυθμίσεις αναζήτησης"</string>
+    <string name="search_menu" msgid="1914043873178389845">"Αναζήτηση στις ρυθμίσεις"</string>
 </resources>
diff --git a/packages/SettingsLib/SearchWidget/res/values-hy/strings.xml b/packages/SettingsLib/SearchWidget/res/values-hy/strings.xml
index 8fa5a84..b68b792 100644
--- a/packages/SettingsLib/SearchWidget/res/values-hy/strings.xml
+++ b/packages/SettingsLib/SearchWidget/res/values-hy/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="search_menu" msgid="1914043873178389845">"Որոնման կարգավորումներ"</string>
+    <string name="search_menu" msgid="1914043873178389845">"Որոնեք կարգավորումներ"</string>
 </resources>
diff --git a/packages/SettingsLib/SearchWidget/res/values-pt-rPT/strings.xml b/packages/SettingsLib/SearchWidget/res/values-pt-rPT/strings.xml
index 85a8d73..5fe116e 100644
--- a/packages/SettingsLib/SearchWidget/res/values-pt-rPT/strings.xml
+++ b/packages/SettingsLib/SearchWidget/res/values-pt-rPT/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="search_menu" msgid="1914043873178389845">"Pesquisa de definições"</string>
+    <string name="search_menu" msgid="1914043873178389845">"Pesquisar nas definições"</string>
 </resources>
diff --git a/packages/SettingsLib/SearchWidget/res/values-sq/strings.xml b/packages/SettingsLib/SearchWidget/res/values-sq/strings.xml
index a531321..354941d 100644
--- a/packages/SettingsLib/SearchWidget/res/values-sq/strings.xml
+++ b/packages/SettingsLib/SearchWidget/res/values-sq/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="search_menu" msgid="1914043873178389845">"Cilësimet e kërkimit"</string>
+    <string name="search_menu" msgid="1914043873178389845">"Kërko te cilësimet"</string>
 </resources>
diff --git a/packages/SettingsLib/SearchWidget/res/values-uk/strings.xml b/packages/SettingsLib/SearchWidget/res/values-uk/strings.xml
index dfd66b2..560ac13 100644
--- a/packages/SettingsLib/SearchWidget/res/values-uk/strings.xml
+++ b/packages/SettingsLib/SearchWidget/res/values-uk/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="search_menu" msgid="1914043873178389845">"Налаштування пошуку"</string>
+    <string name="search_menu" msgid="1914043873178389845">"Пошук налаштувань"</string>
 </resources>
diff --git a/packages/SettingsLib/SearchWidget/res/values-vi/strings.xml b/packages/SettingsLib/SearchWidget/res/values-vi/strings.xml
index cb1a75a..90daf11 100644
--- a/packages/SettingsLib/SearchWidget/res/values-vi/strings.xml
+++ b/packages/SettingsLib/SearchWidget/res/values-vi/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="search_menu" msgid="1914043873178389845">"Tìm kiếm trong các mục cài đặt"</string>
+    <string name="search_menu" msgid="1914043873178389845">"Tìm trong thông tin cài đặt"</string>
 </resources>
diff --git a/packages/SettingsLib/res/values-ar/strings.xml b/packages/SettingsLib/res/values-ar/strings.xml
index 2b51b54..e17c0f0 100644
--- a/packages/SettingsLib/res/values-ar/strings.xml
+++ b/packages/SettingsLib/res/values-ar/strings.xml
@@ -57,7 +57,7 @@
     <string name="osu_sign_up_complete" msgid="7640183358878916847">"اكتمل الاشتراك. جارٍ الاتصال…"</string>
     <string name="speed_label_very_slow" msgid="8526005255731597666">"بطيئة جدًا"</string>
     <string name="speed_label_slow" msgid="6069917670665664161">"بطيئة"</string>
-    <string name="speed_label_okay" msgid="1253594383880810424">"حسنًا"</string>
+    <string name="speed_label_okay" msgid="1253594383880810424">"جيدة"</string>
     <string name="speed_label_medium" msgid="9078405312828606976">"متوسطة"</string>
     <string name="speed_label_fast" msgid="2677719134596044051">"سريعة"</string>
     <string name="speed_label_very_fast" msgid="8215718029533182439">"سريعة جدًا"</string>
@@ -557,5 +557,5 @@
     <string name="cached_apps_freezer_disabled" msgid="4816382260660472042">"غير مفعّل"</string>
     <string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"مفعّل"</string>
     <string name="cached_apps_freezer_reboot_dialog_text" msgid="695330563489230096">"يجب إعادة تشغيل جهازك ليتم تطبيق هذا التغيير. يمكنك إعادة التشغيل الآن أو إلغاء التغيير."</string>
-    <string name="media_transfer_wired_usb_device_name" msgid="7699141088423210903">"سمّاعة رأس سلكية"</string>
+    <string name="media_transfer_wired_usb_device_name" msgid="7699141088423210903">"سمّاعة سلكية"</string>
 </resources>
diff --git a/packages/SettingsLib/res/values-de/strings.xml b/packages/SettingsLib/res/values-de/strings.xml
index fe2a775..6b0ae2e2 100644
--- a/packages/SettingsLib/res/values-de/strings.xml
+++ b/packages/SettingsLib/res/values-de/strings.xml
@@ -57,7 +57,7 @@
     <string name="osu_sign_up_complete" msgid="7640183358878916847">"Anmeldung abgeschlossen. Verbindung wird hergestellt…"</string>
     <string name="speed_label_very_slow" msgid="8526005255731597666">"Sehr langsam"</string>
     <string name="speed_label_slow" msgid="6069917670665664161">"Langsam"</string>
-    <string name="speed_label_okay" msgid="1253594383880810424">"Ok"</string>
+    <string name="speed_label_okay" msgid="1253594383880810424">"Mittel"</string>
     <string name="speed_label_medium" msgid="9078405312828606976">"Mittel"</string>
     <string name="speed_label_fast" msgid="2677719134596044051">"Schnell"</string>
     <string name="speed_label_very_fast" msgid="8215718029533182439">"Sehr schnell"</string>
diff --git a/packages/SettingsLib/res/values-el/strings.xml b/packages/SettingsLib/res/values-el/strings.xml
index 2644cb9..4d7c882 100644
--- a/packages/SettingsLib/res/values-el/strings.xml
+++ b/packages/SettingsLib/res/values-el/strings.xml
@@ -465,7 +465,7 @@
     <item msgid="8894873528875953317">"50%"</item>
     <item msgid="7529124349186240216">"100%"</item>
   </string-array>
-    <string name="charge_length_format" msgid="6941645744588690932">"Πριν από <xliff:g id="ID_1">%1$s</xliff:g>"</string>
+    <string name="charge_length_format" msgid="6941645744588690932">"Πριν <xliff:g id="ID_1">%1$s</xliff:g>"</string>
     <string name="remaining_length_format" msgid="4310625772926171089">"Απομένουν <xliff:g id="ID_1">%1$s</xliff:g>"</string>
     <string name="screen_zoom_summary_small" msgid="6050633151263074260">"Μικρά"</string>
     <string name="screen_zoom_summary_default" msgid="1888865694033865408">"Προεπιλογή"</string>
diff --git a/packages/SettingsLib/res/values-en-rAU/strings.xml b/packages/SettingsLib/res/values-en-rAU/strings.xml
index 0ef8e06..0def17e 100644
--- a/packages/SettingsLib/res/values-en-rAU/strings.xml
+++ b/packages/SettingsLib/res/values-en-rAU/strings.xml
@@ -553,5 +553,5 @@
     <string name="cached_apps_freezer_disabled" msgid="4816382260660472042">"Disabled"</string>
     <string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"Enabled"</string>
     <string name="cached_apps_freezer_reboot_dialog_text" msgid="695330563489230096">"Your device must be rebooted for this change to apply. Reboot now or cancel."</string>
-    <string name="media_transfer_wired_usb_device_name" msgid="7699141088423210903">"Wired headphone"</string>
+    <string name="media_transfer_wired_usb_device_name" msgid="7699141088423210903">"Wired headphones"</string>
 </resources>
diff --git a/packages/SettingsLib/res/values-en-rCA/strings.xml b/packages/SettingsLib/res/values-en-rCA/strings.xml
index 0ef8e06..0def17e 100644
--- a/packages/SettingsLib/res/values-en-rCA/strings.xml
+++ b/packages/SettingsLib/res/values-en-rCA/strings.xml
@@ -553,5 +553,5 @@
     <string name="cached_apps_freezer_disabled" msgid="4816382260660472042">"Disabled"</string>
     <string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"Enabled"</string>
     <string name="cached_apps_freezer_reboot_dialog_text" msgid="695330563489230096">"Your device must be rebooted for this change to apply. Reboot now or cancel."</string>
-    <string name="media_transfer_wired_usb_device_name" msgid="7699141088423210903">"Wired headphone"</string>
+    <string name="media_transfer_wired_usb_device_name" msgid="7699141088423210903">"Wired headphones"</string>
 </resources>
diff --git a/packages/SettingsLib/res/values-en-rGB/strings.xml b/packages/SettingsLib/res/values-en-rGB/strings.xml
index 0ef8e06..0def17e 100644
--- a/packages/SettingsLib/res/values-en-rGB/strings.xml
+++ b/packages/SettingsLib/res/values-en-rGB/strings.xml
@@ -553,5 +553,5 @@
     <string name="cached_apps_freezer_disabled" msgid="4816382260660472042">"Disabled"</string>
     <string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"Enabled"</string>
     <string name="cached_apps_freezer_reboot_dialog_text" msgid="695330563489230096">"Your device must be rebooted for this change to apply. Reboot now or cancel."</string>
-    <string name="media_transfer_wired_usb_device_name" msgid="7699141088423210903">"Wired headphone"</string>
+    <string name="media_transfer_wired_usb_device_name" msgid="7699141088423210903">"Wired headphones"</string>
 </resources>
diff --git a/packages/SettingsLib/res/values-en-rIN/strings.xml b/packages/SettingsLib/res/values-en-rIN/strings.xml
index 0ef8e06..0def17e 100644
--- a/packages/SettingsLib/res/values-en-rIN/strings.xml
+++ b/packages/SettingsLib/res/values-en-rIN/strings.xml
@@ -553,5 +553,5 @@
     <string name="cached_apps_freezer_disabled" msgid="4816382260660472042">"Disabled"</string>
     <string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"Enabled"</string>
     <string name="cached_apps_freezer_reboot_dialog_text" msgid="695330563489230096">"Your device must be rebooted for this change to apply. Reboot now or cancel."</string>
-    <string name="media_transfer_wired_usb_device_name" msgid="7699141088423210903">"Wired headphone"</string>
+    <string name="media_transfer_wired_usb_device_name" msgid="7699141088423210903">"Wired headphones"</string>
 </resources>
diff --git a/packages/SettingsLib/res/values-eu/strings.xml b/packages/SettingsLib/res/values-eu/strings.xml
index 137116f..376c2e7 100644
--- a/packages/SettingsLib/res/values-eu/strings.xml
+++ b/packages/SettingsLib/res/values-eu/strings.xml
@@ -239,7 +239,7 @@
     <string name="keep_screen_on" msgid="1187161672348797558">"Mantendu aktibo"</string>
     <string name="keep_screen_on_summary" msgid="1510731514101925829">"Pantaila ez da ezarriko inoiz inaktibo kargatu bitartean"</string>
     <string name="bt_hci_snoop_log" msgid="7291287955649081448">"Gaitu Bluetooth HCI miatze-erregistroa"</string>
-    <string name="bt_hci_snoop_log_summary" msgid="6808538971394092284">"Hauteman Bluetooth paketeak (aktibatu edo desaktibatu Bluetooth konexioa ezarpena aldatu ostean)."</string>
+    <string name="bt_hci_snoop_log_summary" msgid="6808538971394092284">"Hauteman Bluetooth paketeak (aktibatu edo desaktibatu Bluetooth-a ezarpena aldatu ostean)."</string>
     <string name="oem_unlock_enable" msgid="5334869171871566731">"OEM desblokeoa"</string>
     <string name="oem_unlock_enable_summary" msgid="5857388174390953829">"Onartu abiarazlea desblokeatzea"</string>
     <string name="confirm_enable_oem_unlock_title" msgid="8249318129774367535">"OEM desblokeoa onartu nahi duzu?"</string>
diff --git a/packages/SettingsLib/res/values-in/strings.xml b/packages/SettingsLib/res/values-in/strings.xml
index 9735c16..42ccd53 100644
--- a/packages/SettingsLib/res/values-in/strings.xml
+++ b/packages/SettingsLib/res/values-in/strings.xml
@@ -347,8 +347,8 @@
     <string name="disable_overlays_summary" msgid="1954852414363338166">"Selalu gunakan GPU untuk pengomposisian layar"</string>
     <string name="simulate_color_space" msgid="1206503300335835151">"Simulasikan ruang warna"</string>
     <string name="enable_opengl_traces_title" msgid="4638773318659125196">"Aktifkan jejak OpenGL"</string>
-    <string name="usb_audio_disable_routing" msgid="3367656923544254975">"Perutean audio USB nonaktif"</string>
-    <string name="usb_audio_disable_routing_summary" msgid="8768242894849534699">"Perutean otomatis ke periferal audio USB nonaktif"</string>
+    <string name="usb_audio_disable_routing" msgid="3367656923544254975">"Pemilihan rute audio USB nonaktif"</string>
+    <string name="usb_audio_disable_routing_summary" msgid="8768242894849534699">"Pemilihan rute otomatis ke periferal audio USB nonaktif"</string>
     <string name="debug_layout" msgid="1659216803043339741">"Tampilkan batas tata letak"</string>
     <string name="debug_layout_summary" msgid="8825829038287321978">"Tampilkan batas klip, margin, dll."</string>
     <string name="force_rtl_layout_all_locales" msgid="8690762598501599796">"Paksa arah tata letak RTL"</string>
diff --git a/packages/SettingsLib/res/values-it/arrays.xml b/packages/SettingsLib/res/values-it/arrays.xml
index de38625..3018683 100644
--- a/packages/SettingsLib/res/values-it/arrays.xml
+++ b/packages/SettingsLib/res/values-it/arrays.xml
@@ -22,13 +22,13 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
   <string-array name="wifi_status">
     <item msgid="1596683495752107015"></item>
-    <item msgid="3288373008277313483">"Scansione in corso..."</item>
-    <item msgid="6050951078202663628">"Connessione..."</item>
-    <item msgid="8356618438494652335">"Autenticazione..."</item>
-    <item msgid="2837871868181677206">"Acquisizione indirizzo IP..."</item>
+    <item msgid="3288373008277313483">"Scansione in corso…"</item>
+    <item msgid="6050951078202663628">"Connessione…"</item>
+    <item msgid="8356618438494652335">"Autenticazione…"</item>
+    <item msgid="2837871868181677206">"Acquisizione indirizzo IP…"</item>
     <item msgid="4613015005934755724">"Connessa"</item>
     <item msgid="3763530049995655072">"Sospesa"</item>
-    <item msgid="7852381437933824454">"Disconnessione..."</item>
+    <item msgid="7852381437933824454">"Disconnessione…"</item>
     <item msgid="5046795712175415059">"Disconnessa"</item>
     <item msgid="2473654476624070462">"Operazione non riuscita"</item>
     <item msgid="9146847076036105115">"Bloccato"</item>
@@ -36,13 +36,13 @@
   </string-array>
   <string-array name="wifi_status_with_ssid">
     <item msgid="5969842512724979061"></item>
-    <item msgid="1818677602615822316">"Scansione in corso..."</item>
-    <item msgid="8339720953594087771">"Connessione a <xliff:g id="NETWORK_NAME">%1$s</xliff:g>..."</item>
-    <item msgid="3028983857109369308">"Autenticazione con <xliff:g id="NETWORK_NAME">%1$s</xliff:g>..."</item>
-    <item msgid="4287401332778341890">"Acquisizione indirizzo IP da <xliff:g id="NETWORK_NAME">%1$s</xliff:g>..."</item>
+    <item msgid="1818677602615822316">"Scansione in corso…"</item>
+    <item msgid="8339720953594087771">"Connessione a <xliff:g id="NETWORK_NAME">%1$s</xliff:g>…"</item>
+    <item msgid="3028983857109369308">"Autenticazione con <xliff:g id="NETWORK_NAME">%1$s</xliff:g>…"</item>
+    <item msgid="4287401332778341890">"Acquisizione indirizzo IP da <xliff:g id="NETWORK_NAME">%1$s</xliff:g>…"</item>
     <item msgid="1043944043827424501">"Connessa a <xliff:g id="NETWORK_NAME">%1$s</xliff:g>"</item>
     <item msgid="7445993821842009653">"Sospesa"</item>
-    <item msgid="1175040558087735707">"Disconnessione da <xliff:g id="NETWORK_NAME">%1$s</xliff:g>..."</item>
+    <item msgid="1175040558087735707">"Disconnessione da <xliff:g id="NETWORK_NAME">%1$s</xliff:g>…"</item>
     <item msgid="699832486578171722">"Disconnessa"</item>
     <item msgid="522383512264986901">"Operazione non riuscita"</item>
     <item msgid="3602596701217484364">"Bloccato"</item>
diff --git a/packages/SettingsLib/res/values-it/strings.xml b/packages/SettingsLib/res/values-it/strings.xml
index efc186a..24711ff 100644
--- a/packages/SettingsLib/res/values-it/strings.xml
+++ b/packages/SettingsLib/res/values-it/strings.xml
@@ -64,10 +64,10 @@
     <string name="wifi_passpoint_expired" msgid="6540867261754427561">"Scaduta"</string>
     <string name="preference_summary_default_combination" msgid="2644094566845577901">"<xliff:g id="STATE">%1$s</xliff:g>/<xliff:g id="DESCRIPTION">%2$s</xliff:g>"</string>
     <string name="bluetooth_disconnected" msgid="7739366554710388701">"Disconnesso"</string>
-    <string name="bluetooth_disconnecting" msgid="7638892134401574338">"Disconnessione..."</string>
-    <string name="bluetooth_connecting" msgid="5871702668260192755">"Connessione..."</string>
+    <string name="bluetooth_disconnecting" msgid="7638892134401574338">"Disconnessione…"</string>
+    <string name="bluetooth_connecting" msgid="5871702668260192755">"Connessione…"</string>
     <string name="bluetooth_connected" msgid="8065345572198502293">"<xliff:g id="ACTIVE_DEVICE">%1$s</xliff:g> connesso"</string>
-    <string name="bluetooth_pairing" msgid="4269046942588193600">"Accoppiamento..."</string>
+    <string name="bluetooth_pairing" msgid="4269046942588193600">"Accoppiamento…"</string>
     <string name="bluetooth_connected_no_headset" msgid="2224101138659967604">"<xliff:g id="ACTIVE_DEVICE">%1$s</xliff:g> connesso (telefono escluso)"</string>
     <string name="bluetooth_connected_no_a2dp" msgid="8566874395813947092">"<xliff:g id="ACTIVE_DEVICE">%1$s</xliff:g> connesso (contenuti multimediali esclusi)"</string>
     <string name="bluetooth_connected_no_map" msgid="3381860077002724689">"<xliff:g id="ACTIVE_DEVICE">%1$s</xliff:g> connesso (nessun accesso ai messaggi)"</string>
@@ -406,11 +406,11 @@
     <string name="select_webview_provider_dialog_title" msgid="2444261109877277714">"Imposta l\'implementazione di WebView"</string>
     <string name="select_webview_provider_toast_text" msgid="8512254949169359848">"La selezione non è più valida. Riprova."</string>
     <string name="convert_to_file_encryption" msgid="2828976934129751818">"Converti in crittografia basata su file"</string>
-    <string name="convert_to_file_encryption_enabled" msgid="840757431284311754">"Converti..."</string>
+    <string name="convert_to_file_encryption_enabled" msgid="840757431284311754">"Converti…"</string>
     <string name="convert_to_file_encryption_done" msgid="8965831011811180627">"Crittografia su base file già eseguita"</string>
     <string name="title_convert_fbe" msgid="5780013350366495149">"Conversione in crittografia basata su file"</string>
-    <string name="convert_to_fbe_warning" msgid="34294381569282109">"Converti la partizione di dati in crittografia basata su file.\n Attenzione. Questa operazione eliminerà tutti i tuoi dati.\n Questa funzione è in versione alpha, pertanto potrebbe non funzionare correttamente.\n Premi \"Cancella e converti...\" per continuare."</string>
-    <string name="button_convert_fbe" msgid="1159861795137727671">"Cancella e converti..."</string>
+    <string name="convert_to_fbe_warning" msgid="34294381569282109">"Converti la partizione di dati in crittografia basata su file.\n Attenzione. Questa operazione eliminerà tutti i tuoi dati.\n Questa funzione è in versione alpha, pertanto potrebbe non funzionare correttamente.\n Premi \"Cancella e converti…\" per continuare."</string>
+    <string name="button_convert_fbe" msgid="1159861795137727671">"Cancella e converti…"</string>
     <string name="picture_color_mode" msgid="1013807330552931903">"Modalità colori immagini"</string>
     <string name="picture_color_mode_desc" msgid="151780973768136200">"Use sRGB"</string>
     <string name="daltonizer_mode_disabled" msgid="403424372812399228">"Disattivato"</string>
diff --git a/packages/SettingsLib/res/values-pl/strings.xml b/packages/SettingsLib/res/values-pl/strings.xml
index fd5dfa5..1120c50 100644
--- a/packages/SettingsLib/res/values-pl/strings.xml
+++ b/packages/SettingsLib/res/values-pl/strings.xml
@@ -514,7 +514,7 @@
     <string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"Problem z połączeniem. Wyłącz i ponownie włącz urządzenie"</string>
     <string name="media_transfer_wired_device_name" msgid="4447880899964056007">"Przewodowe urządzenie audio"</string>
     <string name="help_label" msgid="3528360748637781274">"Pomoc i opinie"</string>
-    <string name="storage_category" msgid="2287342585424631813">"Pamięć"</string>
+    <string name="storage_category" msgid="2287342585424631813">"Pamięć wewnętrzna"</string>
     <string name="shared_data_title" msgid="1017034836800864953">"Udostępniane dane"</string>
     <string name="shared_data_summary" msgid="5516326713822885652">"Wyświetl i zmień udostępniane dane"</string>
     <string name="shared_data_no_blobs_text" msgid="3108114670341737434">"Brak udostępnionych danych w przypadku tego użytkownika."</string>
diff --git a/packages/SettingsLib/res/values-vi/strings.xml b/packages/SettingsLib/res/values-vi/strings.xml
index b501c65..7e1b476 100644
--- a/packages/SettingsLib/res/values-vi/strings.xml
+++ b/packages/SettingsLib/res/values-vi/strings.xml
@@ -195,7 +195,7 @@
   </string-array>
     <string name="choose_profile" msgid="343803890897657450">"Chọn hồ sơ"</string>
     <string name="category_personal" msgid="6236798763159385225">"Cá nhân"</string>
-    <string name="category_work" msgid="4014193632325996115">"Cơ quan"</string>
+    <string name="category_work" msgid="4014193632325996115">"Công việc"</string>
     <string name="development_settings_title" msgid="140296922921597393">"Tùy chọn cho nhà phát triển"</string>
     <string name="development_settings_enable" msgid="4285094651288242183">"Bật tùy chọn nhà phát triển"</string>
     <string name="development_settings_summary" msgid="8718917813868735095">"Đặt tùy chọn cho phát triển ứng dụng"</string>
diff --git a/packages/SettingsLib/src/com/android/settingslib/applications/AppUtils.java b/packages/SettingsLib/src/com/android/settingslib/applications/AppUtils.java
index 38eeda2..8987968 100644
--- a/packages/SettingsLib/src/com/android/settingslib/applications/AppUtils.java
+++ b/packages/SettingsLib/src/com/android/settingslib/applications/AppUtils.java
@@ -22,10 +22,12 @@
 import android.content.Intent;
 import android.content.IntentFilter;
 import android.content.pm.ApplicationInfo;
+import android.content.pm.PackageInfo;
 import android.content.pm.PackageManager;
 import android.content.pm.ResolveInfo;
 import android.hardware.usb.IUsbManager;
 import android.net.Uri;
+import android.os.Environment;
 import android.os.RemoteException;
 import android.os.SystemProperties;
 import android.os.UserHandle;
@@ -146,10 +148,23 @@
     /**
      * Returns a boolean indicating whether a given package is a mainline module.
      */
-    public static boolean isMainlineModule(Context context, String packageName) {
-        final PackageManager pm = context.getPackageManager();
+    public static boolean isMainlineModule(PackageManager pm, String packageName) {
+        // Check if the package is listed among the system modules.
         try {
-            return pm.getModuleInfo(packageName, 0 /* flags */) != null;
+            pm.getModuleInfo(packageName, 0 /* flags */);
+            return true;
+        } catch (PackageManager.NameNotFoundException e) {
+            //pass
+        }
+
+        try {
+            final PackageInfo pkg = pm.getPackageInfo(packageName, 0 /* flags */);
+            // Check if the package is contained in an APEX. There is no public API to properly
+            // check whether a given APK package comes from an APEX registered as module.
+            // Therefore we conservatively assume that any package scanned from an /apex path is
+            // a system package.
+            return pkg.applicationInfo.sourceDir.startsWith(
+                    Environment.getApexDirectory().getAbsolutePath());
         } catch (PackageManager.NameNotFoundException e) {
             return false;
         }
diff --git a/packages/SettingsLib/src/com/android/settingslib/applications/ApplicationsState.java b/packages/SettingsLib/src/com/android/settingslib/applications/ApplicationsState.java
index 1d4cfdc..a89cf37 100644
--- a/packages/SettingsLib/src/com/android/settingslib/applications/ApplicationsState.java
+++ b/packages/SettingsLib/src/com/android/settingslib/applications/ApplicationsState.java
@@ -60,6 +60,7 @@
 import com.android.internal.R;
 import com.android.internal.util.ArrayUtils;
 import com.android.settingslib.Utils;
+import com.android.settingslib.utils.ThreadUtils;
 
 import java.io.File;
 import java.io.IOException;
@@ -1588,6 +1589,15 @@
             this.size = SIZE_UNKNOWN;
             this.sizeStale = true;
             ensureLabel(context);
+            // Speed up the cache of the icon and label description if they haven't been created.
+            ThreadUtils.postOnBackgroundThread(() -> {
+                if (this.icon == null) {
+                    this.ensureIconLocked(context);
+                }
+                if (this.labelDescription == null) {
+                    this.ensureLabelDescriptionLocked(context);
+                }
+            });
         }
 
         public void ensureLabel(Context context) {
diff --git a/packages/SettingsLib/src/com/android/settingslib/media/InfoMediaManager.java b/packages/SettingsLib/src/com/android/settingslib/media/InfoMediaManager.java
index b83a9c4..6c7e03f 100644
--- a/packages/SettingsLib/src/com/android/settingslib/media/InfoMediaManager.java
+++ b/packages/SettingsLib/src/com/android/settingslib/media/InfoMediaManager.java
@@ -56,7 +56,7 @@
 public class InfoMediaManager extends MediaManager {
 
     private static final String TAG = "InfoMediaManager";
-    private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);;
+    private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
     @VisibleForTesting
     final RouterManagerCallback mMediaRouterCallback = new RouterManagerCallback();
     @VisibleForTesting
@@ -430,7 +430,7 @@
             case TYPE_HEARING_AID:
             case TYPE_BLUETOOTH_A2DP:
                 final BluetoothDevice device =
-                        BluetoothAdapter.getDefaultAdapter().getRemoteDevice(route.getOriginalId());
+                        BluetoothAdapter.getDefaultAdapter().getRemoteDevice(route.getAddress());
                 final CachedBluetoothDevice cachedDevice =
                         mBluetoothManager.getCachedDeviceManager().findDevice(device);
                 if (cachedDevice != null) {
diff --git a/packages/SettingsLib/src/com/android/settingslib/media/LocalMediaManager.java b/packages/SettingsLib/src/com/android/settingslib/media/LocalMediaManager.java
index f381cde..9d06c84 100644
--- a/packages/SettingsLib/src/com/android/settingslib/media/LocalMediaManager.java
+++ b/packages/SettingsLib/src/com/android/settingslib/media/LocalMediaManager.java
@@ -20,7 +20,6 @@
 import android.app.Notification;
 import android.bluetooth.BluetoothAdapter;
 import android.bluetooth.BluetoothDevice;
-import android.bluetooth.BluetoothProfile;
 import android.content.Context;
 import android.media.RoutingSessionInfo;
 import android.text.TextUtils;
@@ -409,7 +408,8 @@
         synchronized (mMediaDevicesLock) {
             for (MediaDevice device : mMediaDevices) {
                 if (device instanceof BluetoothMediaDevice) {
-                    if (isActiveDevice(((BluetoothMediaDevice) device).getCachedDevice())) {
+                    if (isActiveDevice(((BluetoothMediaDevice) device).getCachedDevice())
+                            && device.isConnected()) {
                         return device;
                     }
                 } else if (device instanceof PhoneMediaDevice) {
@@ -422,8 +422,22 @@
     }
 
     private boolean isActiveDevice(CachedBluetoothDevice device) {
-        return device.isActiveDevice(BluetoothProfile.A2DP)
-                || device.isActiveDevice(BluetoothProfile.HEARING_AID);
+        boolean isActiveDeviceA2dp = false;
+        boolean isActiveDeviceHearingAid = false;
+        final A2dpProfile a2dpProfile = mLocalBluetoothManager.getProfileManager().getA2dpProfile();
+        if (a2dpProfile != null) {
+            isActiveDeviceA2dp = device.getDevice().equals(a2dpProfile.getActiveDevice());
+        }
+        if (!isActiveDeviceA2dp) {
+            final HearingAidProfile hearingAidProfile = mLocalBluetoothManager.getProfileManager()
+                    .getHearingAidProfile();
+            if (hearingAidProfile != null) {
+                isActiveDeviceHearingAid =
+                        hearingAidProfile.getActiveDevices().contains(device.getDevice());
+            }
+        }
+
+        return isActiveDeviceA2dp || isActiveDeviceHearingAid;
     }
 
     private Collection<DeviceCallback> getCallbacks() {
diff --git a/packages/SettingsLib/src/com/android/settingslib/notification/ConversationIconFactory.java b/packages/SettingsLib/src/com/android/settingslib/notification/ConversationIconFactory.java
index d5f1ece..549bc8a 100644
--- a/packages/SettingsLib/src/com/android/settingslib/notification/ConversationIconFactory.java
+++ b/packages/SettingsLib/src/com/android/settingslib/notification/ConversationIconFactory.java
@@ -86,7 +86,7 @@
     /**
      * Returns the conversation info drawable
      */
-    private Drawable getBaseIconDrawable(ShortcutInfo shortcutInfo) {
+    public Drawable getBaseIconDrawable(ShortcutInfo shortcutInfo) {
         return mLauncherApps.getShortcutIconDrawable(shortcutInfo, mFillResIconDpi);
     }
 
@@ -94,7 +94,7 @@
      * Get the {@link Drawable} that represents the app icon, badged with the work profile icon
      * if appropriate.
      */
-    private Drawable getAppBadge(String packageName, int userId) {
+    public Drawable getAppBadge(String packageName, int userId) {
         Drawable badge = null;
         try {
             final ApplicationInfo appInfo = mPackageManager.getApplicationInfoAsUser(
diff --git a/packages/SettingsLib/src/com/android/settingslib/wifi/WifiTracker.java b/packages/SettingsLib/src/com/android/settingslib/wifi/WifiTracker.java
index d1cd043..3015397 100644
--- a/packages/SettingsLib/src/com/android/settingslib/wifi/WifiTracker.java
+++ b/packages/SettingsLib/src/com/android/settingslib/wifi/WifiTracker.java
@@ -900,9 +900,7 @@
                 updateNetworkInfo(info);
                 fetchScansAndConfigsAndUpdateAccessPoints();
             } else if (WifiManager.RSSI_CHANGED_ACTION.equals(action)) {
-                NetworkInfo info =
-                        mConnectivityManager.getNetworkInfo(mWifiManager.getCurrentNetwork());
-                updateNetworkInfo(info);
+                updateNetworkInfo(/* networkInfo= */ null);
             }
         }
     };
@@ -948,7 +946,7 @@
                 // We don't send a NetworkInfo object along with this message, because even if we
                 // fetch one from ConnectivityManager, it might be older than the most recent
                 // NetworkInfo message we got via a WIFI_STATE_CHANGED broadcast.
-                updateNetworkInfo(null);
+                updateNetworkInfo(/* networkInfo= */ null);
             }
         }
     }
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/media/InfoMediaManagerTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/media/InfoMediaManagerTest.java
index 248eb5b..94d95f06 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/media/InfoMediaManagerTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/media/InfoMediaManagerTest.java
@@ -681,7 +681,7 @@
         assertThat(mInfoMediaManager.mMediaDevices.get(0) instanceof PhoneMediaDevice).isTrue();
 
         when(route2Info.getType()).thenReturn(TYPE_BLUETOOTH_A2DP);
-        when(route2Info.getOriginalId()).thenReturn("00:00:00:00:00:00");
+        when(route2Info.getAddress()).thenReturn("00:00:00:00:00:00");
         when(mLocalBluetoothManager.getCachedDeviceManager())
                 .thenReturn(cachedBluetoothDeviceManager);
         when(cachedBluetoothDeviceManager.findDevice(any(BluetoothDevice.class)))
@@ -703,7 +703,7 @@
                 mock(CachedBluetoothDeviceManager.class);
 
         when(route2Info.getType()).thenReturn(TYPE_BLUETOOTH_A2DP);
-        when(route2Info.getOriginalId()).thenReturn("00:00:00:00:00:00");
+        when(route2Info.getAddress()).thenReturn("00:00:00:00:00:00");
         when(mLocalBluetoothManager.getCachedDeviceManager())
                 .thenReturn(cachedBluetoothDeviceManager);
         when(cachedBluetoothDeviceManager.findDevice(any(BluetoothDevice.class)))
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/media/LocalMediaManagerTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/media/LocalMediaManagerTest.java
index 368245f..a654fd4 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/media/LocalMediaManagerTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/media/LocalMediaManagerTest.java
@@ -578,6 +578,9 @@
         when(cachedDevice.getBondState()).thenReturn(BluetoothDevice.BOND_BONDED);
         when(cachedDevice.isConnected()).thenReturn(false);
         when(cachedDevice.getConnectableProfiles()).thenReturn(profiles);
+        when(cachedDevice.getDevice()).thenReturn(bluetoothDevice);
+        when(mA2dpProfile.getActiveDevice()).thenReturn(bluetoothDevice);
+        when(mHapProfile.getActiveDevices()).thenReturn(new ArrayList<>());
 
         when(device1.getId()).thenReturn(TEST_DEVICE_ID_1);
         when(device2.getId()).thenReturn(TEST_DEVICE_ID_2);
@@ -734,11 +737,19 @@
         final PhoneMediaDevice phoneDevice = mock(PhoneMediaDevice.class);
         final CachedBluetoothDevice cachedDevice1 = mock(CachedBluetoothDevice.class);
         final CachedBluetoothDevice cachedDevice2 = mock(CachedBluetoothDevice.class);
+        final BluetoothDevice bluetoothDevice1 = mock(BluetoothDevice.class);
+        final BluetoothDevice bluetoothDevice2 = mock(BluetoothDevice.class);
 
+        when(mA2dpProfile.getActiveDevice()).thenReturn(bluetoothDevice2);
+        when(mHapProfile.getActiveDevices()).thenReturn(new ArrayList<>());
         when(device1.getCachedDevice()).thenReturn(cachedDevice1);
         when(device2.getCachedDevice()).thenReturn(cachedDevice2);
+        when(cachedDevice1.getDevice()).thenReturn(bluetoothDevice1);
+        when(cachedDevice2.getDevice()).thenReturn(bluetoothDevice2);
         when(cachedDevice1.isActiveDevice(BluetoothProfile.A2DP)).thenReturn(false);
         when(cachedDevice2.isActiveDevice(BluetoothProfile.A2DP)).thenReturn(true);
+        when(device1.isConnected()).thenReturn(true);
+        when(device2.isConnected()).thenReturn(true);
 
         mLocalMediaManager.mMediaDevices.add(device1);
         mLocalMediaManager.mMediaDevices.add(phoneDevice);
@@ -754,11 +765,19 @@
         final PhoneMediaDevice phoneDevice = mock(PhoneMediaDevice.class);
         final CachedBluetoothDevice cachedDevice1 = mock(CachedBluetoothDevice.class);
         final CachedBluetoothDevice cachedDevice2 = mock(CachedBluetoothDevice.class);
+        final BluetoothDevice bluetoothDevice1 = mock(BluetoothDevice.class);
+        final BluetoothDevice bluetoothDevice2 = mock(BluetoothDevice.class);
 
+        when(mA2dpProfile.getActiveDevice()).thenReturn(null);
+        when(mHapProfile.getActiveDevices()).thenReturn(new ArrayList<>());
         when(device1.getCachedDevice()).thenReturn(cachedDevice1);
         when(device2.getCachedDevice()).thenReturn(cachedDevice2);
+        when(cachedDevice1.getDevice()).thenReturn(bluetoothDevice1);
+        when(cachedDevice2.getDevice()).thenReturn(bluetoothDevice2);
         when(cachedDevice1.isActiveDevice(BluetoothProfile.A2DP)).thenReturn(false);
         when(cachedDevice2.isActiveDevice(BluetoothProfile.A2DP)).thenReturn(false);
+        when(device1.isConnected()).thenReturn(true);
+        when(device2.isConnected()).thenReturn(true);
 
         mLocalMediaManager.mMediaDevices.add(device1);
         mLocalMediaManager.mMediaDevices.add(phoneDevice);
diff --git a/packages/SettingsProvider/res/values/defaults.xml b/packages/SettingsProvider/res/values/defaults.xml
index c9e1944b..51f69a9 100644
--- a/packages/SettingsProvider/res/values/defaults.xml
+++ b/packages/SettingsProvider/res/values/defaults.xml
@@ -237,4 +237,7 @@
 
     <!-- Default for Settings.Secure.AWARE_LOCK_ENABLED -->
     <bool name="def_aware_lock_enabled">false</bool>
+
+    <!-- Default for setting for Settings.Global.HDMI_CONTROL_AUTO_DEVICE_OFF_ENABLED -->
+    <bool name="def_hdmiControlAutoDeviceOff">false</bool>
 </resources>
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
index 94509dd..b95d34f 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
@@ -3513,7 +3513,7 @@
         }
 
         private final class UpgradeController {
-            private static final int SETTINGS_VERSION = 190;
+            private static final int SETTINGS_VERSION = 191;
 
             private final int mUserId;
 
@@ -4867,6 +4867,21 @@
                     currentVersion = 190;
                 }
 
+                if (currentVersion == 190) {
+                    // Version 190: get HDMI auto device off from overlay
+                    final SettingsState globalSettings = getGlobalSettingsLocked();
+                    final Setting currentSetting = globalSettings.getSettingLocked(
+                            Global.HDMI_CONTROL_AUTO_DEVICE_OFF_ENABLED);
+                    if (currentSetting.isNull()) {
+                        globalSettings.insertSettingLocked(
+                                Global.HDMI_CONTROL_AUTO_DEVICE_OFF_ENABLED,
+                                getContext().getResources().getBoolean(
+                                        R.bool.def_hdmiControlAutoDeviceOff) ? "1" : "0",
+                                null, true, SettingsState.SYSTEM_PACKAGE_NAME);
+                    }
+                    currentVersion = 191;
+                }
+
                 // vXXX: Add new settings above this point.
 
                 if (currentVersion != newVersion) {
diff --git a/packages/Shell/res/values-it/strings.xml b/packages/Shell/res/values-it/strings.xml
index 18ab908..02531f2 100644
--- a/packages/Shell/res/values-it/strings.xml
+++ b/packages/Shell/res/values-it/strings.xml
@@ -21,7 +21,7 @@
     <string name="bugreport_in_progress_title" msgid="4311705936714972757">"Generazione segnalazione di bug <xliff:g id="ID">#%d</xliff:g> in corso"</string>
     <string name="bugreport_finished_title" msgid="4429132808670114081">"Segnalazione di bug <xliff:g id="ID">#%d</xliff:g> acquisita"</string>
     <string name="bugreport_updating_title" msgid="4423539949559634214">"Aggiunta di dettagli alla segnalazione di bug"</string>
-    <string name="bugreport_updating_wait" msgid="3322151947853929470">"Attendi..."</string>
+    <string name="bugreport_updating_wait" msgid="3322151947853929470">"Attendi…"</string>
     <string name="bugreport_finished_text" product="watch" msgid="1223616207145252689">"La segnalazione di bug comparirà a breve sul telefono"</string>
     <string name="bugreport_finished_text" product="tv" msgid="5758325479058638893">"Seleziona per condividere la segnalazione di bug"</string>
     <string name="bugreport_finished_text" product="default" msgid="8353769438382138847">"Tocca per condividere la segnalazione di bug"</string>
diff --git a/packages/Shell/res/values-ky/strings.xml b/packages/Shell/res/values-ky/strings.xml
index 969e9ed..3567ac2 100644
--- a/packages/Shell/res/values-ky/strings.xml
+++ b/packages/Shell/res/values-ky/strings.xml
@@ -29,7 +29,7 @@
     <string name="bugreport_finished_pending_screenshot_text" product="watch" msgid="1474435374470177193">"Мүчүлүштүк тууралуу билдирүүңүздү скриншотсуз бөлүшүү үчүн таптап коюңуз же скриншот даяр болгуча күтө туруңуз"</string>
     <string name="bugreport_finished_pending_screenshot_text" product="default" msgid="1474435374470177193">"Мүчүлүштүк тууралуу билдирүүңүздү скриншотсуз бөлүшүү үчүн таптап коюңуз же скриншот даяр болгуча күтө туруңуз"</string>
     <string name="bugreport_confirm" msgid="5917407234515812495">"Мүчүлүштүктөр тууралуу билдирүүлөрдө тутумдун ар кандай таржымалдарынан алынган дайындар, ошондой эле купуя маалымат камтылышы мүмкүн (мисалы, жайгашкан жер сыяктуу). Мындай билдирүүлөрдү бир гана ишеничтүү адамдар жана колдонмолор менен бөлүшүңүз."</string>
-    <string name="bugreport_confirm_dont_repeat" msgid="6179945398364357318">"Экинчи көрсөтүлбөсүн"</string>
+    <string name="bugreport_confirm_dont_repeat" msgid="6179945398364357318">"Экинчи көрүнбөсүн"</string>
     <string name="bugreport_storage_title" msgid="5332488144740527109">"Мүчүлүштүктөрдү кабарлоо"</string>
     <string name="bugreport_unreadable_text" msgid="586517851044535486">"Мүчүлүштүк тууралуу кабарлаган файл окулбай койду"</string>
     <string name="bugreport_add_details_to_zip_failed" msgid="1302931926486712371">"Мүчүлүштүктөр жөнүндө кабардын чоо-жайы zip файлына кошулбай койду"</string>
diff --git a/packages/SystemUI/docs/broadcasts.md b/packages/SystemUI/docs/broadcasts.md
index 6c8488b..8ec20f5 100644
--- a/packages/SystemUI/docs/broadcasts.md
+++ b/packages/SystemUI/docs/broadcasts.md
@@ -62,7 +62,7 @@
  * @param executor An executor to dispatch [BroadcastReceiver.onReceive]. Pass null to use an
  *                 executor in the main thread (default).
  * @param user A user handle to determine which broadcast should be dispatched to this receiver.
- *             By default, it is the current user.
+ *             By default, it is the user of the context (system user in SystemUI).
  * @throws IllegalArgumentException if the filter has other constraints that are not actions or
  *                                  categories or the filter has no actions.
  */
diff --git a/packages/SystemUI/plugin/src/com/android/systemui/plugins/qs/QS.java b/packages/SystemUI/plugin/src/com/android/systemui/plugins/qs/QS.java
index 85a9fec..fffcafb 100644
--- a/packages/SystemUI/plugin/src/com/android/systemui/plugins/qs/QS.java
+++ b/packages/SystemUI/plugin/src/com/android/systemui/plugins/qs/QS.java
@@ -34,7 +34,7 @@
 
     String ACTION = "com.android.systemui.action.PLUGIN_QS";
 
-    int VERSION = 7;
+    int VERSION = 8;
 
     String TAG = "QS";
 
@@ -67,15 +67,12 @@
     }
 
     /**
-     * We need this to handle nested scrolling for QS..
-     * Normally we would do this with requestDisallowInterceptTouchEvent, but when both the
-     * scroll containers are using the same touch slop, they try to start scrolling at the
-     * same time and NotificationPanelView wins, this lets QS win.
-     *
-     * TODO: Do this using NestedScroll capabilities.
+     * Should touches from the notification panel be disallowed?
+     * The notification panel might grab any touches rom QS at any time to collapse the shade.
+     * We should disallow that in case we are showing the detail panel.
      */
-    default boolean onInterceptTouchEvent(MotionEvent event) {
-        return isCustomizing();
+    default boolean disallowPanelTouches() {
+        return isShowingDetail();
     }
 
     @ProvidesInterface(version = HeightListener.VERSION)
diff --git a/packages/SystemUI/res-keyguard/values-it/strings.xml b/packages/SystemUI/res-keyguard/values-it/strings.xml
index 80deb34..fe460e3 100644
--- a/packages/SystemUI/res-keyguard/values-it/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-it/strings.xml
@@ -48,7 +48,7 @@
     <string name="keyguard_permanent_disabled_sim_instructions" msgid="2490584154727897806">"La scheda SIM è stata disattivata definitivamente.\n Contatta il fornitore del tuo servizio wireless per ricevere un\'altra scheda SIM."</string>
     <string name="keyguard_sim_locked_message" msgid="4343544458476911044">"La SIM è bloccata."</string>
     <string name="keyguard_sim_puk_locked_message" msgid="6253830777745450550">"La SIM è bloccata tramite PUK."</string>
-    <string name="keyguard_sim_unlock_progress_dialog_message" msgid="2394023844117630429">"Sblocco SIM..."</string>
+    <string name="keyguard_sim_unlock_progress_dialog_message" msgid="2394023844117630429">"Sblocco SIM…"</string>
     <string name="keyguard_accessibility_pin_area" msgid="7403009340414014734">"Area PIN"</string>
     <string name="keyguard_accessibility_password" msgid="3524161948484801450">"Password del dispositivo"</string>
     <string name="keyguard_accessibility_sim_pin_area" msgid="6272116591533888062">"Area PIN SIM"</string>
@@ -77,7 +77,7 @@
     <string name="kg_puk_enter_puk_hint_multi" msgid="4876780689904862943">"La SIM \"<xliff:g id="CARRIER">%1$s</xliff:g>\" non è attiva al momento. Inserisci il codice PUK per continuare. Contatta l\'operatore per avere informazioni dettagliate."</string>
     <string name="kg_puk_enter_pin_hint" msgid="6028432138916150399">"Inserisci il codice PIN desiderato"</string>
     <string name="kg_enter_confirm_pin_hint" msgid="4261064020391799132">"Conferma il codice PIN desiderato"</string>
-    <string name="kg_sim_unlock_progress_dialog_message" msgid="4251352015304070326">"Sblocco SIM..."</string>
+    <string name="kg_sim_unlock_progress_dialog_message" msgid="4251352015304070326">"Sblocco SIM…"</string>
     <string name="kg_invalid_sim_pin_hint" msgid="2762202646949552978">"Il PIN deve essere di 4-8 numeri."</string>
     <string name="kg_invalid_sim_puk_hint" msgid="5319756880543857694">"Il codice PUK dovrebbe avere almeno otto numeri."</string>
     <string name="kg_invalid_puk" msgid="1774337070084931186">"Inserisci di nuovo il codice PUK corretto. Ripetuti tentativi comportano la disattivazione definitiva della scheda SIM."</string>
diff --git a/packages/SystemUI/res-product/values-ne/strings.xml b/packages/SystemUI/res-product/values-ne/strings.xml
index 81a063c..148cb51 100644
--- a/packages/SystemUI/res-product/values-ne/strings.xml
+++ b/packages/SystemUI/res-product/values-ne/strings.xml
@@ -21,7 +21,7 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="dock_alignment_slow_charging" product="default" msgid="6997633396534416792">"अझ छिटो चार्ज गर्न फोनलाई फेरि मिलाउनुहोस्"</string>
     <string name="dock_alignment_not_charging" product="default" msgid="3980752926226749808">"तारविनै चार्ज गर्न फोनलाई फेरि मिलाउनुहोस्"</string>
-    <string name="inattentive_sleep_warning_message" product="tv" msgid="6844464574089665063">"Android TV यन्त्र चाँडै निष्क्रिय हुने छ; सक्रिय राख्न कुनै बटन थिच्नुहोस्।"</string>
+    <string name="inattentive_sleep_warning_message" product="tv" msgid="6844464574089665063">"Android टिभी यन्त्र चाँडै निष्क्रिय हुने छ; सक्रिय राख्न कुनै बटन थिच्नुहोस्।"</string>
     <string name="inattentive_sleep_warning_message" product="default" msgid="5693904520452332224">"यो यन्त्र चाँडै निष्क्रिय हुने छ; सक्रिय राख्न थिच्नुहोस्।"</string>
     <string name="keyguard_missing_sim_message" product="tablet" msgid="5018086454277963787">"ट्याब्लेटमा SIM कार्ड छैन।"</string>
     <string name="keyguard_missing_sim_message" product="default" msgid="7053347843877341391">"फोनमा SIM कार्ड छैन।"</string>
diff --git a/packages/SystemUI/res/drawable/ic_error_outline.xml b/packages/SystemUI/res/drawable/ic_error_outline.xml
new file mode 100644
index 0000000..140180a
--- /dev/null
+++ b/packages/SystemUI/res/drawable/ic_error_outline.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright (C) 2020 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
+  -->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="24dp"
+    android:height="24dp"
+    android:viewportWidth="24"
+    android:viewportHeight="24">
+  <path
+      android:fillColor="#FF000000"
+      android:pathData="M11,15h2v2h-2v-2zM11,7h2v6h-2L11,7zM11.99,2C6.47,2 2,6.48 2,12s4.47,10 9.99,10C17.52,22 22,17.52 22,12S17.52,2 11.99,2zM12,20c-4.42,0 -8,-3.58 -8,-8s3.58,-8 8,-8 8,3.58 8,8 -3.58,8 -8,8z"/>
+</vector>
diff --git a/packages/SystemUI/res/drawable/ic_settings_power.xml b/packages/SystemUI/res/drawable/ic_settings_power.xml
new file mode 100644
index 0000000..137c289
--- /dev/null
+++ b/packages/SystemUI/res/drawable/ic_settings_power.xml
@@ -0,0 +1,25 @@
+<!--
+  ~ Copyright (C) 2020 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.
+  -->
+
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+        android:width="24dp"
+        android:height="24dp"
+        android:viewportWidth="24"
+        android:viewportHeight="24">
+    <path
+        android:pathData="M8,24c0.55,0 1,-0.45 1,-1s-0.45,-1 -1,-1 -1,0.45 -1,1 0.45,1 1,1zM12,24c0.55,0 1,-0.45 1,-1s-0.45,-1 -1,-1 -1,0.45 -1,1 0.45,1 1,1zM13,2h-2v10h2L13,2zM16.56,4.44l-1.45,1.45C16.84,6.94 18,8.83 18,11c0,3.31 -2.69,6 -6,6s-6,-2.69 -6,-6c0,-2.17 1.16,-4.06 2.88,-5.12L7.44,4.44C5.36,5.88 4,8.28 4,11c0,4.42 3.58,8 8,8s8,-3.58 8,-8c0,-2.72 -1.36,-5.12 -3.44,-6.56zM16,24c0.55,0 1,-0.45 1,-1s-0.45,-1 -1,-1 -1,0.45 -1,1 0.45,1 1,1z"
+        android:fillColor="#000000"/>
+</vector>
\ No newline at end of file
diff --git a/packages/SystemUI/res/layout-sw600dp/keyguard_user_switcher_item.xml b/packages/SystemUI/res/layout-sw600dp/keyguard_user_switcher_item.xml
index 4413b1e..9ce030e 100644
--- a/packages/SystemUI/res/layout-sw600dp/keyguard_user_switcher_item.xml
+++ b/packages/SystemUI/res/layout-sw600dp/keyguard_user_switcher_item.xml
@@ -27,13 +27,13 @@
         android:gravity="end|center_vertical"
         android:clickable="true"
         android:background="@drawable/kg_user_switcher_rounded_bg"
+        sysui:activatedTextAppearance="@style/TextAppearance.StatusBar.Expanded.UserSwitcher"
         sysui:regularTextAppearance="@style/TextAppearance.StatusBar.Expanded.UserSwitcher">
     <TextView android:id="@+id/user_name"
             android:layout_width="wrap_content"
             android:layout_height="wrap_content"
             android:layout_marginStart="25dp"
             android:layout_marginEnd="12dp"
-            android:textAppearance="@style/TextAppearance.StatusBar.Expanded.UserSwitcher"
             />
     <com.android.systemui.statusbar.phone.UserAvatarView android:id="@+id/user_picture"
             android:layout_width="@dimen/kg_framed_avatar_size"
diff --git a/packages/SystemUI/res/layout/bubbles_manage_button_education.xml b/packages/SystemUI/res/layout/bubbles_manage_button_education.xml
index 0cabc32..7313d54 100644
--- a/packages/SystemUI/res/layout/bubbles_manage_button_education.xml
+++ b/packages/SystemUI/res/layout/bubbles_manage_button_education.xml
@@ -17,30 +17,72 @@
 <com.android.systemui.bubbles.BubbleManageEducationView
     xmlns:android="http://schemas.android.com/apk/res/android"
     android:layout_width="match_parent"
-    android:layout_height="match_parent">
-
+    android:layout_height="match_parent"
+    >
     <LinearLayout
-        android:id="@+id/manage_education_view"
-        android:orientation="vertical"
+        android:layout_width="wrap_content"
         android:layout_height="wrap_content"
-        android:layout_width="@dimen/bubbles_manage_education_width">
+        android:id="@+id/manage_education_view"
+        android:clickable="true"
+        android:paddingTop="28dp"
+        android:paddingBottom="16dp"
+        android:paddingStart="@dimen/bubble_expanded_view_padding"
+        android:paddingEnd="48dp"
+        android:layout_marginEnd="24dp"
+        android:orientation="vertical"
+        android:background="@drawable/bubble_stack_user_education_bg"
+        android:alpha="0.9"
+        >
+
+        <TextView
+            android:id="@+id/user_education_title"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:paddingStart="16dp"
+            android:paddingBottom="16dp"
+            android:fontFamily="@*android:string/config_bodyFontFamilyMedium"
+            android:maxLines="1"
+            android:text="@string/bubbles_user_education_manage_title"
+            android:textAppearance="@*android:style/TextAppearance.DeviceDefault.Headline"/>
 
         <TextView
             android:id="@+id/user_education_description"
             android:layout_width="wrap_content"
             android:layout_height="wrap_content"
-            android:padding="8dp"
+            android:paddingStart="16dp"
+            android:paddingBottom="24dp"
             android:text="@string/bubbles_user_education_manage"
             android:fontFamily="@*android:string/config_bodyFontFamily"
-            android:textAppearance="@*android:style/TextAppearance.DeviceDefault.Body2"
-            android:background="@drawable/bubble_manage_user_education_bg"
-        />
+            android:textAppearance="@*android:style/TextAppearance.DeviceDefault.Body2"/>
 
-        <View
-            android:id="@+id/user_education_pointer"
-            android:layout_width="@dimen/bubble_pointer_width"
-            android:layout_height="@dimen/bubble_pointer_height"
-        />
+        <LinearLayout
+            android:layout_height="wrap_content"
+            android:layout_width="wrap_content"
+            android:orientation="horizontal" >
 
+            <com.android.systemui.statusbar.AlphaOptimizedButton
+                style="@android:style/Widget.Material.Button.Borderless"
+                android:id="@+id/manage"
+                android:layout_gravity="start"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:focusable="true"
+                android:clickable="false"
+                android:text="@string/manage_bubbles_text"
+                android:textColor="?attr/wallpaperTextColor"
+                android:alpha="0.89"
+                />
+
+            <com.android.systemui.statusbar.AlphaOptimizedButton
+                style="@android:style/Widget.Material.Button.Borderless"
+                android:id="@+id/got_it"
+                android:layout_gravity="start"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:focusable="true"
+                android:text="@string/bubbles_user_education_got_it"
+                android:textColor="?attr/wallpaperTextColor"
+                />
+        </LinearLayout>
     </LinearLayout>
 </com.android.systemui.bubbles.BubbleManageEducationView>
\ No newline at end of file
diff --git a/packages/SystemUI/res/layout/controls_base_item.xml b/packages/SystemUI/res/layout/controls_base_item.xml
index 477a70f..5f83f45 100644
--- a/packages/SystemUI/res/layout/controls_base_item.xml
+++ b/packages/SystemUI/res/layout/controls_base_item.xml
@@ -52,6 +52,7 @@
         android:singleLine="true"
         android:ellipsize="marquee"
         android:marqueeRepeatLimit = "marquee_forever"
+        android:textDirection="locale"
         app:layout_constraintEnd_toEndOf="parent"
         app:layout_constraintBottom_toBottomOf="@+id/icon"
         app:layout_constraintStart_toEndOf="@+id/icon" />
@@ -67,6 +68,7 @@
         android:focusable="false"
         android:maxLines="1"
         android:ellipsize="end"
+        android:textDirection="locale"
         app:layout_constraintStart_toStartOf="parent"
         app:layout_constraintEnd_toEndOf="parent"
         app:layout_constraintBottom_toTopOf="@id/barrier"/>
@@ -90,6 +92,7 @@
         android:focusable="false"
         android:maxLines="1"
         android:ellipsize="end"
+        android:textDirection="locale"
         app:layout_constraintStart_toStartOf="parent"
         app:layout_constraintEnd_toStartOf="@id/favorite"
         app:layout_constraintTop_toTopOf="@id/favorite"
diff --git a/packages/SystemUI/res/layout/controls_more_item.xml b/packages/SystemUI/res/layout/controls_more_item.xml
index df03787..da9c43c 100644
--- a/packages/SystemUI/res/layout/controls_more_item.xml
+++ b/packages/SystemUI/res/layout/controls_more_item.xml
@@ -20,5 +20,6 @@
     android:layout_height="wrap_content"
     android:layout_gravity="start"
     android:paddingStart="@dimen/control_menu_horizontal_padding"
-    android:paddingEnd="@dimen/control_menu_horizontal_padding"/>
+    android:paddingEnd="@dimen/control_menu_horizontal_padding"
+    android:textDirection="locale"/>
 
diff --git a/packages/SystemUI/res/layout/global_screenshot.xml b/packages/SystemUI/res/layout/global_screenshot.xml
index fce4610..ef7325e 100644
--- a/packages/SystemUI/res/layout/global_screenshot.xml
+++ b/packages/SystemUI/res/layout/global_screenshot.xml
@@ -30,11 +30,10 @@
         android:id="@+id/global_screenshot_animated_view"
         android:layout_width="wrap_content"
         android:layout_height="wrap_content"
-        android:layout_gravity="center"
+        android:layout_gravity="top|start"
         android:visibility="gone"
         android:elevation="@dimen/screenshot_preview_elevation"
-        android:background="@drawable/screenshot_rounded_corners"
-        android:adjustViewBounds="true"/>
+        android:background="@drawable/screenshot_rounded_corners" />
     <ImageView
         android:id="@+id/global_screenshot_flash"
         android:layout_width="match_parent"
@@ -49,4 +48,18 @@
         android:visibility="gone"
         android:pointerIcon="crosshair"/>
     <include layout="@layout/global_screenshot_static"/>
+    <FrameLayout
+        android:id="@+id/global_screenshot_dismiss_button"
+        android:layout_width="@dimen/screenshot_dismiss_button_tappable_size"
+        android:layout_height="@dimen/screenshot_dismiss_button_tappable_size"
+        android:elevation="7dp"
+        android:visibility="gone"
+        android:contentDescription="@string/screenshot_dismiss_ui_description">
+        <ImageView
+            android:id="@+id/global_screenshot_dismiss_image"
+            android:layout_width="match_parent"
+            android:layout_height="match_parent"
+            android:layout_margin="@dimen/screenshot_dismiss_button_margin"
+            android:src="@drawable/screenshot_cancel"/>
+    </FrameLayout>
 </FrameLayout>
diff --git a/packages/SystemUI/res/layout/global_screenshot_static.xml b/packages/SystemUI/res/layout/global_screenshot_static.xml
index a46823d..9ec2f20 100644
--- a/packages/SystemUI/res/layout/global_screenshot_static.xml
+++ b/packages/SystemUI/res/layout/global_screenshot_static.xml
@@ -53,32 +53,5 @@
             android:layout_width="wrap_content"
             android:layout_height="wrap_content"/>
     </HorizontalScrollView>
-    <ImageView
-        android:id="@+id/global_screenshot_animated_view"
-        android:layout_width="match_parent"
-        android:layout_height="match_parent"
-        android:layout_gravity="center"
-        android:visibility="gone"
-        android:elevation="@dimen/screenshot_preview_elevation"
-        android:background="@drawable/screenshot_rounded_corners"
-        android:adjustViewBounds="true"/>
     <include layout="@layout/global_screenshot_preview"/>
-    <FrameLayout
-        android:id="@+id/global_screenshot_dismiss_button"
-        android:layout_width="@dimen/screenshot_dismiss_button_tappable_size"
-        android:layout_height="@dimen/screenshot_dismiss_button_tappable_size"
-        android:elevation="7dp"
-        android:visibility="gone"
-        android:contentDescription="@string/screenshot_dismiss_ui_description"
-        app:layout_constraintStart_toEndOf="@+id/global_screenshot_preview"
-        app:layout_constraintEnd_toEndOf="@+id/global_screenshot_preview"
-        app:layout_constraintTop_toTopOf="@+id/global_screenshot_preview"
-        app:layout_constraintBottom_toTopOf="@+id/global_screenshot_preview">
-        <ImageView
-            android:id="@+id/global_screenshot_dismiss_image"
-            android:layout_width="match_parent"
-            android:layout_height="match_parent"
-            android:layout_margin="@dimen/screenshot_dismiss_button_margin"
-            android:src="@drawable/screenshot_cancel"/>
-    </FrameLayout>
 </androidx.constraintlayout.widget.ConstraintLayout>
diff --git a/packages/SystemUI/res/layout/hybrid_conversation_notification.xml b/packages/SystemUI/res/layout/hybrid_conversation_notification.xml
index 21a671c..214c44a 100644
--- a/packages/SystemUI/res/layout/hybrid_conversation_notification.xml
+++ b/packages/SystemUI/res/layout/hybrid_conversation_notification.xml
@@ -20,24 +20,26 @@
     android:layout_width="match_parent"
     android:layout_height="wrap_content"
     android:gravity="center_vertical|start"
+    android:paddingTop="1dp"
+    android:paddingBottom="1dp"
     android:paddingEnd="12dp">
 
     <FrameLayout
         android:layout_width="@*android:dimen/conversation_content_start"
-        android:layout_height="36dp"
+        android:layout_height="25dp"
     >
         <ImageView
             android:id="@*android:id/conversation_icon"
-            android:layout_width="24dp"
-            android:layout_height="24dp"
+            android:layout_width="20dp"
+            android:layout_height="20dp"
             android:layout_gravity="center"
         />
 
         <ViewStub
             android:id="@*android:id/conversation_face_pile"
             android:layout="@*android:layout/conversation_face_pile_layout"
-            android:layout_width="36dp"
-            android:layout_height="36dp"
+            android:layout_width="25dp"
+            android:layout_height="25dp"
             android:layout_gravity="center"
         />
     </FrameLayout>
diff --git a/packages/SystemUI/res/layout/keyguard_user_switcher_item.xml b/packages/SystemUI/res/layout/keyguard_user_switcher_item.xml
index 626951c..1cd1a04 100644
--- a/packages/SystemUI/res/layout/keyguard_user_switcher_item.xml
+++ b/packages/SystemUI/res/layout/keyguard_user_switcher_item.xml
@@ -39,8 +39,6 @@
             android:layout_width="@dimen/kg_framed_avatar_size"
             android:layout_height="@dimen/kg_framed_avatar_size"
             android:contentDescription="@null"
-            android:backgroundTint="@color/qs_user_detail_avatar_tint"
-            android:backgroundTintMode="src_atop"
             sysui:frameWidth="@dimen/keyguard_user_switcher_border_thickness"
             sysui:framePadding="2.5dp"
             sysui:badgeDiameter="18dp"
diff --git a/packages/SystemUI/res/layout/media_view.xml b/packages/SystemUI/res/layout/media_view.xml
index d721818..a722fbf 100644
--- a/packages/SystemUI/res/layout/media_view.xml
+++ b/packages/SystemUI/res/layout/media_view.xml
@@ -39,7 +39,7 @@
             android:layout_alignParentLeft="true"
             android:fontFamily="@*android:string/config_bodyFontFamily"
             android:textColor="@color/media_primary_text"
-            android:gravity="left"
+            android:gravity="start"
             android:textSize="14sp" />
 
         <TextView
@@ -49,7 +49,7 @@
             android:layout_alignParentRight="true"
             android:fontFamily="@*android:string/config_bodyFontFamily"
             android:textColor="@color/media_primary_text"
-            android:gravity="right"
+            android:gravity="end"
             android:textSize="14sp" />
     </FrameLayout>
 
diff --git a/packages/SystemUI/res/layout/notification_conversation_info.xml b/packages/SystemUI/res/layout/notification_conversation_info.xml
index 49d525f..2c4b937 100644
--- a/packages/SystemUI/res/layout/notification_conversation_info.xml
+++ b/packages/SystemUI/res/layout/notification_conversation_info.xml
@@ -34,7 +34,7 @@
         android:layout_height="wrap_content"
         android:gravity="center_vertical"
         android:clipChildren="false"
-        android:paddingTop="8dp"
+        android:paddingTop="11dp"
         android:clipToPadding="true">
         <ImageView
             android:id="@+id/conversation_icon"
@@ -85,14 +85,6 @@
                     style="@style/TextAppearance.NotificationImportanceChannel"/>
             </LinearLayout>
             <TextView
-                android:id="@+id/pkg_name"
-                android:layout_width="match_parent"
-                android:layout_height="wrap_content"
-                style="@style/TextAppearance.NotificationImportanceChannelGroup"
-                android:ellipsize="end"
-                android:textDirection="locale"
-                android:maxLines="1"/>
-            <TextView
                 android:id="@+id/group_name"
                 android:layout_width="match_parent"
                 android:layout_height="wrap_content"
@@ -100,6 +92,14 @@
                 android:textDirection="locale"
                 style="@style/TextAppearance.NotificationImportanceChannelGroup"/>
             <TextView
+                android:id="@+id/pkg_name"
+                android:layout_width="match_parent"
+                android:layout_height="wrap_content"
+                style="@style/TextAppearance.NotificationImportanceApp"
+                android:ellipsize="end"
+                android:textDirection="locale"
+                android:maxLines="1"/>
+            <TextView
                 android:id="@+id/delegate_name"
                 android:layout_width="match_parent"
                 android:layout_height="wrap_content"
diff --git a/packages/SystemUI/res/layout/notification_info.xml b/packages/SystemUI/res/layout/notification_info.xml
index 870deac..1c7c226 100644
--- a/packages/SystemUI/res/layout/notification_info.xml
+++ b/packages/SystemUI/res/layout/notification_info.xml
@@ -59,14 +59,6 @@
                 android:textDirection="locale"
                 style="@style/TextAppearance.NotificationImportanceChannel"/>
             <TextView
-                android:id="@+id/pkg_name"
-                android:layout_width="match_parent"
-                android:layout_height="wrap_content"
-                style="@style/TextAppearance.NotificationImportanceChannelGroup"
-                android:ellipsize="end"
-                android:textDirection="locale"
-                android:maxLines="1"/>
-            <TextView
                 android:id="@+id/group_name"
                 android:layout_width="match_parent"
                 android:layout_height="wrap_content"
@@ -74,6 +66,14 @@
                 android:ellipsize="end"
                 style="@style/TextAppearance.NotificationImportanceChannelGroup"/>
             <TextView
+                android:id="@+id/pkg_name"
+                android:layout_width="match_parent"
+                android:layout_height="wrap_content"
+                style="@style/TextAppearance.NotificationImportanceApp"
+                android:ellipsize="end"
+                android:textDirection="locale"
+                android:maxLines="1"/>
+            <TextView
                 android:id="@+id/delegate_name"
                 android:layout_width="match_parent"
                 android:layout_height="wrap_content"
diff --git a/packages/SystemUI/res/layout/partial_conversation_info.xml b/packages/SystemUI/res/layout/partial_conversation_info.xml
index 803b0c6..0795170 100644
--- a/packages/SystemUI/res/layout/partial_conversation_info.xml
+++ b/packages/SystemUI/res/layout/partial_conversation_info.xml
@@ -35,7 +35,7 @@
         android:clipChildren="false"
         android:clipToPadding="false">
         <ImageView
-            android:id="@+id/conversation_icon"
+            android:id="@+id/icon"
             android:layout_width="@dimen/notification_guts_conversation_icon_size"
             android:layout_height="@dimen/notification_guts_conversation_icon_size"
             android:layout_centerVertical="true"
@@ -60,20 +60,6 @@
                 android:textDirection="locale"
                 style="@style/TextAppearance.NotificationImportanceChannel"/>
             <TextView
-                android:id="@+id/parent_channel_name"
-                android:layout_width="match_parent"
-                android:layout_height="wrap_content"
-                android:ellipsize="end"
-                android:textDirection="locale"
-                style="@style/TextAppearance.NotificationImportanceChannel"/>
-            <TextView
-                android:id="@+id/group_name"
-                android:layout_width="match_parent"
-                android:layout_height="wrap_content"
-                android:ellipsize="end"
-                android:textDirection="locale"
-                style="@style/TextAppearance.NotificationImportanceChannelGroup"/>
-            <TextView
                 android:id="@+id/delegate_name"
                 android:layout_width="match_parent"
                 android:layout_height="wrap_content"
@@ -127,18 +113,21 @@
                 android:layout_height="wrap_content"
                 android:clipChildren="false"
                 android:clipToPadding="false"
+                android:layout_centerVertical="true"
                 android:orientation="horizontal">
                 <ImageView
-                    android:layout_height="wrap_content"
+                    android:layout_height="match_parent"
                     android:layout_width="wrap_content"
                     android:contentDescription="@null"
                     android:src="@drawable/ic_info"
+                    android:layout_centerVertical="true"
                     android:tint="?android:attr/textColorPrimary"
                     android:layout_marginEnd="8dp"/>
                 <TextView
                     android:id="@+id/non_configurable_text"
                     android:layout_width="match_parent"
                     android:layout_height="wrap_content"
+                    android:layout_centerVertical="true"
                     style="@style/TextAppearance.NotificationImportanceChannelGroup" />
             </LinearLayout>
         </com.android.systemui.statusbar.notification.row.ButtonLinearLayout>
diff --git a/packages/SystemUI/res/layout/priority_onboarding_half_shell.xml b/packages/SystemUI/res/layout/priority_onboarding_half_shell.xml
index bf2eac3..3f0e514 100644
--- a/packages/SystemUI/res/layout/priority_onboarding_half_shell.xml
+++ b/packages/SystemUI/res/layout/priority_onboarding_half_shell.xml
@@ -38,11 +38,61 @@
         android:background="@drawable/rounded_bg_full"
         >
 
+    <FrameLayout
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:clipChildren="false"
+        android:clipToPadding="false"
+        android:padding="12dp"
+        android:layout_gravity="center_horizontal"
+    >
+
+        <!-- Big icon: 52x52, 12dp padding left + top, 16dp padding right -->
         <ImageView
             android:id="@+id/conversation_icon"
-            android:layout_width="@dimen/notification_guts_conversation_icon_size"
-            android:layout_height="@dimen/notification_guts_conversation_icon_size"
-            android:layout_gravity="center_horizontal" />
+            android:layout_width="@*android:dimen/conversation_avatar_size"
+            android:layout_height="@*android:dimen/conversation_avatar_size"
+            android:scaleType="centerCrop"
+            android:importantForAccessibility="no"
+        />
+
+        <FrameLayout
+            android:id="@+id/conversation_icon_badge"
+            android:layout_width="@*android:dimen/conversation_icon_size_badged"
+            android:layout_height="@*android:dimen/conversation_icon_size_badged"
+            android:layout_marginLeft="@*android:dimen/conversation_badge_side_margin"
+            android:layout_marginTop="@*android:dimen/conversation_badge_side_margin"
+            android:clipChildren="false"
+            android:clipToPadding="false"
+        >
+            <ImageView
+                android:id="@+id/conversation_icon_badge_bg"
+                android:layout_width="match_parent"
+                android:layout_height="match_parent"
+                android:layout_gravity="center"
+                android:src="@*android:drawable/conversation_badge_background"
+                android:forceHasOverlappingRendering="false"
+            />
+            <ImageView
+                android:id="@+id/icon"
+                android:layout_width="match_parent"
+                android:layout_height="match_parent"
+                android:layout_margin="4dp"
+                android:layout_gravity="center"
+                android:forceHasOverlappingRendering="false"
+            />
+            <ImageView
+                android:id="@+id/conversation_icon_badge_ring"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:layout_gravity="center"
+                android:src="@*android:drawable/conversation_badge_ring"
+                android:forceHasOverlappingRendering="false"
+                android:clipToPadding="false"
+                android:scaleType="center"
+            />
+        </FrameLayout>
+    </FrameLayout>
 
         <TextView
             android:id="@+id/title"
diff --git a/packages/SystemUI/res/layout/qs_detail.xml b/packages/SystemUI/res/layout/qs_detail.xml
index 294bd50..59e1a75 100644
--- a/packages/SystemUI/res/layout/qs_detail.xml
+++ b/packages/SystemUI/res/layout/qs_detail.xml
@@ -22,6 +22,7 @@
     android:background="@drawable/qs_detail_background"
     android:clickable="true"
     android:orientation="vertical"
+    android:layout_marginTop="@*android:dimen/quick_qs_offset_height"
     android:paddingBottom="8dp"
     android:visibility="invisible"
     android:elevation="4dp"
@@ -44,7 +45,7 @@
         android:scaleType="fitXY"
         />
 
-    <com.android.systemui.qs.NonInterceptingScrollView
+    <ScrollView
         android:layout_width="match_parent"
         android:layout_height="0dp"
         android:layout_weight="1"
@@ -54,7 +55,7 @@
             android:id="@android:id/content"
             android:layout_width="match_parent"
             android:layout_height="match_parent"/>
-    </com.android.systemui.qs.NonInterceptingScrollView>
+    </ScrollView>
 
     <include layout="@layout/qs_detail_buttons" />
 
diff --git a/packages/SystemUI/res/layout/qs_divider.xml b/packages/SystemUI/res/layout/qs_divider.xml
deleted file mode 100644
index 39d48ea..0000000
--- a/packages/SystemUI/res/layout/qs_divider.xml
+++ /dev/null
@@ -1,20 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2017 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.
--->
-<View xmlns:android="http://schemas.android.com/apk/res/android"
-    android:layout_width="match_parent"
-    android:layout_height="1dp"
-    android:alpha=".12"
-    android:background="?android:attr/colorForeground" />
diff --git a/packages/SystemUI/res/layout/qs_footer_impl.xml b/packages/SystemUI/res/layout/qs_footer_impl.xml
index ebfd0a0..5c00af5 100644
--- a/packages/SystemUI/res/layout/qs_footer_impl.xml
+++ b/packages/SystemUI/res/layout/qs_footer_impl.xml
@@ -61,7 +61,10 @@
                 android:clickable="true"
                 android:gravity="center_vertical"
                 android:focusable="true"
+                android:singleLine="true"
+                android:ellipsize="end"
                 android:textAppearance="@style/TextAppearance.QS.Status"
+                android:layout_marginEnd="4dp"
                 android:visibility="gone"/>
          </com.android.keyguard.AlphaOptimizedLinearLayout>
 
diff --git a/packages/SystemUI/res/layout/qs_paged_page.xml b/packages/SystemUI/res/layout/qs_paged_page.xml
index a8960d9..5c8b2b0 100644
--- a/packages/SystemUI/res/layout/qs_paged_page.xml
+++ b/packages/SystemUI/res/layout/qs_paged_page.xml
@@ -20,7 +20,5 @@
     android:id="@+id/tile_page"
     android:layout_width="match_parent"
     android:layout_height="match_parent"
-    android:paddingStart="@dimen/notification_side_paddings"
-    android:paddingEnd="@dimen/notification_side_paddings"
     android:clipChildren="false"
     android:clipToPadding="false" />
diff --git a/packages/SystemUI/res/layout/qs_panel.xml b/packages/SystemUI/res/layout/qs_panel.xml
index cdf8426..761ab03 100644
--- a/packages/SystemUI/res/layout/qs_panel.xml
+++ b/packages/SystemUI/res/layout/qs_panel.xml
@@ -48,18 +48,22 @@
         android:clipChildren="false"
         android:background="@drawable/qs_bg_gradient" />
 
-
-    <com.android.systemui.qs.QSPanel
-        android:id="@+id/quick_settings_panel"
-        android:layout_marginTop="@*android:dimen/quick_qs_offset_height"
+    <com.android.systemui.qs.NonInterceptingScrollView
+        android:id="@+id/expanded_qs_scroll_view"
         android:layout_width="match_parent"
         android:layout_height="wrap_content"
         android:elevation="4dp"
-        android:background="@android:color/transparent"
-        android:focusable="true"
-        android:accessibilityTraversalBefore="@android:id/edit">
-        <include layout="@layout/qs_footer_impl" />
-    </com.android.systemui.qs.QSPanel>
+        android:layout_weight="1">
+        <com.android.systemui.qs.QSPanel
+            android:id="@+id/quick_settings_panel"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:background="@android:color/transparent"
+            android:focusable="true"
+            android:accessibilityTraversalBefore="@android:id/edit">
+            <include layout="@layout/qs_footer_impl" />
+        </com.android.systemui.qs.QSPanel>
+    </com.android.systemui.qs.NonInterceptingScrollView>
 
     <include layout="@layout/quick_status_bar_expanded_header" />
 
diff --git a/packages/SystemUI/res/layout/qs_user_detail_item.xml b/packages/SystemUI/res/layout/qs_user_detail_item.xml
index 0608685..cc6c5d3 100644
--- a/packages/SystemUI/res/layout/qs_user_detail_item.xml
+++ b/packages/SystemUI/res/layout/qs_user_detail_item.xml
@@ -30,6 +30,7 @@
         android:clipToPadding="false"
         android:focusable="true"
         android:background="@drawable/ripple_drawable"
+        systemui:activatedTextAppearance="@style/TextAppearance.QS.UserSwitcher"
         systemui:regularTextAppearance="@style/TextAppearance.QS.UserSwitcher">
 
     <com.android.systemui.statusbar.phone.UserAvatarView
@@ -37,8 +38,6 @@
             android:layout_width="@dimen/qs_framed_avatar_size"
             android:layout_height="@dimen/qs_framed_avatar_size"
             android:layout_marginBottom="7dp"
-            android:backgroundTint="@color/qs_user_detail_avatar_tint"
-            android:backgroundTintMode="src_atop"
             systemui:frameWidth="6dp"
             systemui:badgeDiameter="18dp"
             systemui:badgeMargin="1dp"
diff --git a/packages/SystemUI/res/layout/quick_settings_footer.xml b/packages/SystemUI/res/layout/quick_settings_footer.xml
index 15f398a..e7c7b5f 100644
--- a/packages/SystemUI/res/layout/quick_settings_footer.xml
+++ b/packages/SystemUI/res/layout/quick_settings_footer.xml
@@ -14,8 +14,8 @@
      See the License for the specific language governing permissions and
      limitations under the License.
 -->
-<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
-    android:layout_width="match_parent"
+<com.android.systemui.util.NeverExactlyLinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="wrap_content"
     android:layout_height="wrap_content"
     android:clickable="true"
     android:paddingBottom="@dimen/qs_tile_padding_top"
@@ -23,23 +23,28 @@
     android:paddingStart="@dimen/qs_footer_padding_start"
     android:paddingEnd="@dimen/qs_footer_padding_end"
     android:gravity="center_vertical"
+    android:layout_gravity="center_vertical|center_horizontal"
     android:background="@android:color/transparent">
 
-    <TextView
+    <com.android.systemui.util.AutoMarqueeTextView
         android:id="@+id/footer_text"
         android:layout_width="wrap_content"
         android:layout_height="wrap_content"
         android:gravity="start"
         android:layout_weight="1"
+        android:singleLine="true"
+        android:ellipsize="marquee"
+        android:marqueeRepeatLimit="marquee_forever"
         android:textAppearance="@style/TextAppearance.QS.TileLabel"
-        style="@style/qs_security_footer"/>
+        android:textColor="?android:attr/textColorPrimary"/>
 
     <ImageView
         android:id="@+id/footer_icon"
         android:layout_width="@dimen/qs_footer_icon_size"
         android:layout_height="@dimen/qs_footer_icon_size"
+        android:layout_marginStart="8dp"
         android:contentDescription="@null"
         android:src="@drawable/ic_info_outline"
-        style="@style/qs_security_footer"/>
+        android:tint="?android:attr/textColorPrimary" />
 
-</LinearLayout>
+</com.android.systemui.util.NeverExactlyLinearLayout>
diff --git a/packages/SystemUI/res/layout/quick_settings_header_info.xml b/packages/SystemUI/res/layout/quick_settings_header_info.xml
index e6ef9b4..fb82304 100644
--- a/packages/SystemUI/res/layout/quick_settings_header_info.xml
+++ b/packages/SystemUI/res/layout/quick_settings_header_info.xml
@@ -20,11 +20,12 @@
     android:layout_height="@dimen/qs_header_tooltip_height"
     android:layout_below="@id/quick_status_bar_system_icons"
     android:visibility="invisible"
-    android:theme="@style/QSHeaderTheme">
+    android:theme="@style/QSHeaderTheme"
+    android:forceHasOverlappingRendering="false">
 
         <com.android.systemui.qs.QSHeaderInfoLayout
             android:id="@+id/status_container"
-            android:layout_width="match_parent"
+            android:layout_width="0dp"
             android:layout_weight="1"
             android:layout_height="match_parent">
 
diff --git a/packages/SystemUI/res/layout/quick_status_bar_expanded_header.xml b/packages/SystemUI/res/layout/quick_status_bar_expanded_header.xml
index abeb331..dc341274 100644
--- a/packages/SystemUI/res/layout/quick_status_bar_expanded_header.xml
+++ b/packages/SystemUI/res/layout/quick_status_bar_expanded_header.xml
@@ -29,7 +29,6 @@
     android:clipToPadding="false"
     android:paddingTop="0dp"
     android:paddingEnd="0dp"
-    android:paddingBottom="10dp"
     android:paddingStart="0dp"
     android:elevation="4dp" >
 
@@ -52,6 +51,7 @@
         android:clipChildren="false"
         android:clipToPadding="false"
         android:focusable="true"
+        android:paddingBottom="10dp"
         android:importantForAccessibility="yes" />
 
     <TextView
diff --git a/packages/SystemUI/res/values-af/strings.xml b/packages/SystemUI/res/values-af/strings.xml
index 45d4cb4..48b25b0 100644
--- a/packages/SystemUI/res/values-af/strings.xml
+++ b/packages/SystemUI/res/values-af/strings.xml
@@ -510,7 +510,7 @@
     <string name="clear_all_notifications_text" msgid="348312370303046130">"Vee alles uit"</string>
     <string name="manage_notifications_text" msgid="6885645344647733116">"Bestuur"</string>
     <string name="manage_notifications_history_text" msgid="57055985396576230">"Geskiedenis"</string>
-    <string name="notification_section_header_incoming" msgid="5295312809341711367">"Inkomend"</string>
+    <string name="notification_section_header_incoming" msgid="850925217908095197">"Nuut"</string>
     <string name="notification_section_header_gentle" msgid="6804099527336337197">"Stil"</string>
     <string name="notification_section_header_alerting" msgid="5581175033680477651">"Kennisgewings"</string>
     <string name="notification_section_header_conversations" msgid="821834744538345661">"Gesprekke"</string>
@@ -1002,7 +1002,7 @@
     <string name="bubble_accessibility_action_move_top_right" msgid="6916868852433483569">"Beweeg na regs bo"</string>
     <string name="bubble_accessibility_action_move_bottom_left" msgid="6339015902495504715">"Beweeg na links onder"</string>
     <string name="bubble_accessibility_action_move_bottom_right" msgid="7471571700628346212">"Beweeg na regs onder"</string>
-    <string name="bubble_dismiss_text" msgid="7071770411580452911">"Maak toe"</string>
+    <string name="bubble_dismiss_text" msgid="1314082410868930066">"Maak borrel toe"</string>
     <string name="bubbles_dont_bubble_conversation" msgid="1033040343437428822">"Moenie dat gesprek \'n borrel word nie"</string>
     <string name="bubbles_user_education_title" msgid="5547017089271445797">"Klets met borrels"</string>
     <string name="bubbles_user_education_description" msgid="1160281719576715211">"Nuwe gesprekke verskyn as swerwende ikone, of borrels Tik op borrel om dit oop te maak. Sleep om dit te skuif."</string>
@@ -1062,9 +1062,13 @@
     <string name="controls_structure_tooltip" msgid="4355922222944447867">"Swiep om meer te sien"</string>
     <string name="controls_seeding_in_progress" msgid="3033855341410264148">"Laai tans aanbevelings"</string>
     <string name="controls_media_close_session" msgid="9023534788828414585">"Maak hierdie mediasessie toe"</string>
+    <string name="controls_media_resume" msgid="1933520684481586053">"Hervat"</string>
     <string name="controls_error_timeout" msgid="794197289772728958">"Onaktief, gaan program na"</string>
     <string name="controls_error_retryable" msgid="864025882878378470">"Fout, probeer tans weer …"</string>
-    <string name="controls_error_removed" msgid="6299213591234723805">"Toestel is verwyder"</string>
+    <string name="controls_error_removed" msgid="6675638069846014366">"Nie gekry nie"</string>
+    <string name="controls_error_removed_title" msgid="1207794911208047818">"Kontrole is nie beskikbaar nie"</string>
+    <string name="controls_error_removed_message" msgid="2885911717034750542">"Kon nie by <xliff:g id="DEVICE">%1$s</xliff:g> ingaan nie. Gaan die <xliff:g id="APPLICATION">%2$s</xliff:g>-program na om seker te maak dat die kontrole steeds beskikbaar is en dat die programinstellings nie verander het nie."</string>
+    <string name="controls_open_app" msgid="483650971094300141">"Maak program oop"</string>
     <string name="controls_error_generic" msgid="352500456918362905">"Kan nie status laai nie"</string>
     <string name="controls_error_failed" msgid="960228639198558525">"Fout, probeer weer"</string>
     <string name="controls_in_progress" msgid="4421080500238215939">"Besig"</string>
diff --git a/packages/SystemUI/res/values-am/strings.xml b/packages/SystemUI/res/values-am/strings.xml
index a88be36..9a75c1c 100644
--- a/packages/SystemUI/res/values-am/strings.xml
+++ b/packages/SystemUI/res/values-am/strings.xml
@@ -510,7 +510,7 @@
     <string name="clear_all_notifications_text" msgid="348312370303046130">"ሁሉንም አጽዳ"</string>
     <string name="manage_notifications_text" msgid="6885645344647733116">"ያቀናብሩ"</string>
     <string name="manage_notifications_history_text" msgid="57055985396576230">"ታሪክ"</string>
-    <string name="notification_section_header_incoming" msgid="5295312809341711367">"ገቢ"</string>
+    <string name="notification_section_header_incoming" msgid="850925217908095197">"አዲስ"</string>
     <string name="notification_section_header_gentle" msgid="6804099527336337197">"ጸጥ ያለ"</string>
     <string name="notification_section_header_alerting" msgid="5581175033680477651">"ማሳወቂያዎች"</string>
     <string name="notification_section_header_conversations" msgid="821834744538345661">"ውይይቶች"</string>
@@ -1002,7 +1002,7 @@
     <string name="bubble_accessibility_action_move_top_right" msgid="6916868852433483569">"ወደ ላይኛው ቀኝ አንቀሳቅስ"</string>
     <string name="bubble_accessibility_action_move_bottom_left" msgid="6339015902495504715">"የግርጌውን ግራ አንቀሳቅስ"</string>
     <string name="bubble_accessibility_action_move_bottom_right" msgid="7471571700628346212">"ታችኛውን ቀኝ ያንቀሳቅሱ"</string>
-    <string name="bubble_dismiss_text" msgid="7071770411580452911">"አሰናብት"</string>
+    <string name="bubble_dismiss_text" msgid="1314082410868930066">"አረፋን አሰናብት"</string>
     <string name="bubbles_dont_bubble_conversation" msgid="1033040343437428822">"ውይይቶችን በአረፋ አታሳይ"</string>
     <string name="bubbles_user_education_title" msgid="5547017089271445797">"አረፋዎችን በመጠቀም ይወያዩ"</string>
     <string name="bubbles_user_education_description" msgid="1160281719576715211">"አዲስ ውይይቶች እንደ ተንሳፋፊ አዶዎች ወይም አረፋዎች ሆነው ይታያሉ። አረፋን ለመክፈት መታ ያድርጉ። ለመውሰድ ይጎትቱት።"</string>
@@ -1062,9 +1062,13 @@
     <string name="controls_structure_tooltip" msgid="4355922222944447867">"ተጨማሪ ለማየት ያንሸራትቱ"</string>
     <string name="controls_seeding_in_progress" msgid="3033855341410264148">"ምክሮችን በመጫን ላይ"</string>
     <string name="controls_media_close_session" msgid="9023534788828414585">"ይህን የሚዲያ ክፍለ-ጊዜ ዝጋ"</string>
+    <string name="controls_media_resume" msgid="1933520684481586053">"ከቆመበት ቀጥል"</string>
     <string name="controls_error_timeout" msgid="794197289772728958">"ንቁ ያልኾነ፣ መተግበሪያን ይፈትሹ"</string>
     <string name="controls_error_retryable" msgid="864025882878378470">"ስህተት፣ እንደገና በመሞከር ላይ…"</string>
-    <string name="controls_error_removed" msgid="6299213591234723805">"መሣሪያ ተወግዷል"</string>
+    <string name="controls_error_removed" msgid="6675638069846014366">"አልተገኘም"</string>
+    <string name="controls_error_removed_title" msgid="1207794911208047818">"መቆጣጠሪያ አይገኝም"</string>
+    <string name="controls_error_removed_message" msgid="2885911717034750542">"<xliff:g id="DEVICE">%1$s</xliff:g>ን መድረስ አልተቻለም። አሁንም ድረስ መቆጣጠሪያው ሊገኝ እንደሚችል እና የመተግበሪያ ቅንብሮቹ እንዳልተለወጡ ለማረጋገጥ <xliff:g id="APPLICATION">%2$s</xliff:g> መተግበሪያን ይፈትሹ።"</string>
+    <string name="controls_open_app" msgid="483650971094300141">"መተግበሪያ ክፈት"</string>
     <string name="controls_error_generic" msgid="352500456918362905">"ሁኔታን መጫን አልተቻልም"</string>
     <string name="controls_error_failed" msgid="960228639198558525">"ስህተት፣ እንደገና ይሞክሩ"</string>
     <string name="controls_in_progress" msgid="4421080500238215939">"በሂደት ላይ"</string>
diff --git a/packages/SystemUI/res/values-ar/strings.xml b/packages/SystemUI/res/values-ar/strings.xml
index 2a0af5d..bfa2107 100644
--- a/packages/SystemUI/res/values-ar/strings.xml
+++ b/packages/SystemUI/res/values-ar/strings.xml
@@ -522,7 +522,7 @@
     <string name="clear_all_notifications_text" msgid="348312370303046130">"محو الكل"</string>
     <string name="manage_notifications_text" msgid="6885645344647733116">"إدارة"</string>
     <string name="manage_notifications_history_text" msgid="57055985396576230">"السجلّ"</string>
-    <string name="notification_section_header_incoming" msgid="5295312809341711367">"الإشعارات الواردة"</string>
+    <string name="notification_section_header_incoming" msgid="850925217908095197">"الإشعارات الجديدة"</string>
     <string name="notification_section_header_gentle" msgid="6804099527336337197">"صامت"</string>
     <string name="notification_section_header_alerting" msgid="5581175033680477651">"الإشعارات"</string>
     <string name="notification_section_header_conversations" msgid="821834744538345661">"المحادثات"</string>
@@ -607,7 +607,7 @@
     <string name="screen_pinning_title" msgid="9058007390337841305">"تم تثبيت الشاشة على التطبيق"</string>
     <string name="screen_pinning_description" msgid="8699395373875667743">"يؤدي هذا إلى استمرار عرض الشاشة المُختارة إلى أن تتم إزالة تثبيتها. المس مع الاستمرار الزرين \"رجوع\" و\"نظرة عامة\" لإزالة التثبيت."</string>
     <string name="screen_pinning_description_recents_invisible" msgid="4564466648700390037">"يؤدي هذا إلى استمرار عرض الشاشة المُختارة إلى أن تتم إزالة تثبيتها. المس مع الاستمرار الزرين \"رجوع\" و\"الشاشة الرئيسية\" لإزالة التثبيت."</string>
-    <string name="screen_pinning_description_gestural" msgid="7246323931831232068">"يؤدي هذا إلى استمرار عرض الشاشة المُختارة إلى أن تتم إزالة تثبيتها. مرّر الشاشة بسرعة للأعلى مع الاستمرار لإزالة تثبيت الشاشة."</string>
+    <string name="screen_pinning_description_gestural" msgid="7246323931831232068">"يؤدي هذا الإجراء إلى استمرار عرض الشاشة المُختارة إلى أن تتم إزالة تثبيتها. لإلغاء تثبيت الشاشة على هذا التطبيق، اسحب بسرعة للأعلى مع إبقاء الإصبع على الشاشة."</string>
     <string name="screen_pinning_description_accessible" msgid="7386449191953535332">"يؤدي هذا إلى استمرار عرض الشاشة المُختارة إلى أن تتم إزالة تثبيتها. المس مع الاستمرار زر \"نظرة عامة\" لإزالة التثبيت."</string>
     <string name="screen_pinning_description_recents_invisible_accessible" msgid="2857071808674481986">"يؤدي هذا إلى استمرار عرض الشاشة المُختارة إلى أن تتم إزالة تثبيتها. المس مع الاستمرار زر \"الشاشة الرئيسية\" لإزالة التثبيت."</string>
     <string name="screen_pinning_exposes_personal_data" msgid="8189852022981524789">"يمكن الوصول إلى البيانات الشخصية (مثلاً جهات الاتصال ومحتوى الرسائل الإلكترونية)"</string>
@@ -1022,7 +1022,7 @@
     <string name="bubble_accessibility_action_move_top_right" msgid="6916868852433483569">"الانتقال إلى أعلى اليسار"</string>
     <string name="bubble_accessibility_action_move_bottom_left" msgid="6339015902495504715">"نقل إلى أسفل يمين الشاشة"</string>
     <string name="bubble_accessibility_action_move_bottom_right" msgid="7471571700628346212">"نقل إلى أسفل اليسار"</string>
-    <string name="bubble_dismiss_text" msgid="7071770411580452911">"تجاهل"</string>
+    <string name="bubble_dismiss_text" msgid="1314082410868930066">"إغلاق فقاعة المحادثة"</string>
     <string name="bubbles_dont_bubble_conversation" msgid="1033040343437428822">"عدم عرض المحادثة كفقاعة محادثة"</string>
     <string name="bubbles_user_education_title" msgid="5547017089271445797">"الدردشة باستخدام فقاعات المحادثات"</string>
     <string name="bubbles_user_education_description" msgid="1160281719576715211">"تظهر المحادثات الجديدة كرموز عائمة أو كفقاعات. انقر لفتح فقاعة المحادثة، واسحبها لتحريكها."</string>
@@ -1086,9 +1086,13 @@
     <string name="controls_structure_tooltip" msgid="4355922222944447867">"مرّر سريعًا لرؤية المزيد."</string>
     <string name="controls_seeding_in_progress" msgid="3033855341410264148">"جارٍ تحميل الاقتراحات"</string>
     <string name="controls_media_close_session" msgid="9023534788828414585">"إغلاق جلسة تشغيل الوسائط هذه"</string>
+    <string name="controls_media_resume" msgid="1933520684481586053">"استئناف التشغيل"</string>
     <string name="controls_error_timeout" msgid="794197289772728958">"غير نشط، تحقّق من التطبيق."</string>
     <string name="controls_error_retryable" msgid="864025882878378470">"حدث خطأ، جارٍ إعادة المحاولة…"</string>
-    <string name="controls_error_removed" msgid="6299213591234723805">"تمت إزالة الجهاز."</string>
+    <string name="controls_error_removed" msgid="6675638069846014366">"لم يتم العثور عليه."</string>
+    <string name="controls_error_removed_title" msgid="1207794911208047818">"عنصر التحكّم غير متوفّر"</string>
+    <string name="controls_error_removed_message" msgid="2885911717034750542">"تعذّر الوصول إلى <xliff:g id="DEVICE">%1$s</xliff:g>. تحقّق من تطبيق <xliff:g id="APPLICATION">%2$s</xliff:g> للتأكّد من أن عنصر التحكّم لا يزال متوفّرًا وأنه لم يتم تغيير إعدادات التطبيق."</string>
+    <string name="controls_open_app" msgid="483650971094300141">"فتح التطبيق"</string>
     <string name="controls_error_generic" msgid="352500456918362905">"يتعذّر تحميل الحالة."</string>
     <string name="controls_error_failed" msgid="960228639198558525">"حدث خطأ، يُرجى إعادة المحاولة."</string>
     <string name="controls_in_progress" msgid="4421080500238215939">"قيد التقدم"</string>
diff --git a/packages/SystemUI/res/values-as/strings.xml b/packages/SystemUI/res/values-as/strings.xml
index e3fd2cb..ca21ff6 100644
--- a/packages/SystemUI/res/values-as/strings.xml
+++ b/packages/SystemUI/res/values-as/strings.xml
@@ -510,7 +510,7 @@
     <string name="clear_all_notifications_text" msgid="348312370303046130">"সকলো মচক"</string>
     <string name="manage_notifications_text" msgid="6885645344647733116">"পৰিচালনা"</string>
     <string name="manage_notifications_history_text" msgid="57055985396576230">"ইতিহাস"</string>
-    <string name="notification_section_header_incoming" msgid="5295312809341711367">"অন্তৰ্গামী"</string>
+    <string name="notification_section_header_incoming" msgid="850925217908095197">"নতুন"</string>
     <string name="notification_section_header_gentle" msgid="6804099527336337197">"নীৰৱ"</string>
     <string name="notification_section_header_alerting" msgid="5581175033680477651">"জাননীসমূহ"</string>
     <string name="notification_section_header_conversations" msgid="821834744538345661">"বাৰ্তালাপ"</string>
@@ -1002,7 +1002,7 @@
     <string name="bubble_accessibility_action_move_top_right" msgid="6916868852433483569">"শীৰ্ষৰ সোঁফালে নিয়ক"</string>
     <string name="bubble_accessibility_action_move_bottom_left" msgid="6339015902495504715">"বুটামটো বাওঁফালে নিয়ক"</string>
     <string name="bubble_accessibility_action_move_bottom_right" msgid="7471571700628346212">"তলৰ সোঁফালে নিয়ক"</string>
-    <string name="bubble_dismiss_text" msgid="7071770411580452911">"অগ্ৰাহ্য কৰক"</string>
+    <string name="bubble_dismiss_text" msgid="1314082410868930066">"বাবল অগ্ৰাহ্য কৰক"</string>
     <string name="bubbles_dont_bubble_conversation" msgid="1033040343437428822">"বাৰ্তালাপ বাবল নকৰিব"</string>
     <string name="bubbles_user_education_title" msgid="5547017089271445797">"Bubbles ব্যৱহাৰ কৰি চাট কৰক"</string>
     <string name="bubbles_user_education_description" msgid="1160281719576715211">"নতুন বাৰ্তালাপ উপঙি থকা চিহ্নসমূহ অথবা bubbles হিচাপে প্ৰদর্শিত হয়। Bubbles খুলিবলৈ টিপক। এইটো স্থানান্তৰ কৰিবলৈ টানি নিয়ক।"</string>
@@ -1062,9 +1062,13 @@
     <string name="controls_structure_tooltip" msgid="4355922222944447867">"অধিক চাবলৈ ছোৱাইপ কৰক"</string>
     <string name="controls_seeding_in_progress" msgid="3033855341410264148">"চুপাৰিছসমূহ ল’ড কৰি থকা হৈছে"</string>
     <string name="controls_media_close_session" msgid="9023534788828414585">"এই মিডিয়া ছেশ্বনটো বন্ধ কৰক"</string>
+    <string name="controls_media_resume" msgid="1933520684481586053">"পুনৰ আৰম্ভ কৰক"</string>
     <string name="controls_error_timeout" msgid="794197289772728958">"সক্ৰিয় নহয়, এপ্‌টো পৰীক্ষা কৰক"</string>
     <string name="controls_error_retryable" msgid="864025882878378470">"আসোঁৱাহ, পুনৰ চেষ্টা কৰি আছে…"</string>
-    <string name="controls_error_removed" msgid="6299213591234723805">"ডিভাইচটো আঁতৰোৱা হৈছে"</string>
+    <string name="controls_error_removed" msgid="6675638069846014366">"বিচাৰি পোৱা নগ’ল"</string>
+    <string name="controls_error_removed_title" msgid="1207794911208047818">"নিয়ন্ত্ৰণটো উপলব্ধ নহয়"</string>
+    <string name="controls_error_removed_message" msgid="2885911717034750542">"<xliff:g id="DEVICE">%1$s</xliff:g> এক্সেছ কৰিব পৰা নগ’ল। নিয়ন্ত্ৰণটো এতিয়াও উপলব্ধ আৰু এপ্‌টোৰ ছেটিংসমূহ সলনি কৰা হোৱা নাই বুলি নিশ্চিত কৰিবলৈ <xliff:g id="APPLICATION">%2$s</xliff:g> এপ্‌টো পৰীক্ষা কৰক।"</string>
+    <string name="controls_open_app" msgid="483650971094300141">"এপ্‌টো খোলক"</string>
     <string name="controls_error_generic" msgid="352500456918362905">"স্থিতি ল’ড কৰিব নোৱাৰি"</string>
     <string name="controls_error_failed" msgid="960228639198558525">"আসোঁৱাহ হৈছে, আকৌ চেষ্টা কৰক"</string>
     <string name="controls_in_progress" msgid="4421080500238215939">"চলি আছে"</string>
diff --git a/packages/SystemUI/res/values-az/strings.xml b/packages/SystemUI/res/values-az/strings.xml
index 0adee8c..3a7c98c 100644
--- a/packages/SystemUI/res/values-az/strings.xml
+++ b/packages/SystemUI/res/values-az/strings.xml
@@ -510,7 +510,7 @@
     <string name="clear_all_notifications_text" msgid="348312370303046130">"Hamısını silin"</string>
     <string name="manage_notifications_text" msgid="6885645344647733116">"İdarə edin"</string>
     <string name="manage_notifications_history_text" msgid="57055985396576230">"Tarixçə"</string>
-    <string name="notification_section_header_incoming" msgid="5295312809341711367">"Gələn"</string>
+    <string name="notification_section_header_incoming" msgid="850925217908095197">"Yeni"</string>
     <string name="notification_section_header_gentle" msgid="6804099527336337197">"Səssiz"</string>
     <string name="notification_section_header_alerting" msgid="5581175033680477651">"Bildirişlər"</string>
     <string name="notification_section_header_conversations" msgid="821834744538345661">"Söhbətlər"</string>
@@ -1002,7 +1002,7 @@
     <string name="bubble_accessibility_action_move_top_right" msgid="6916868852433483569">"Yuxarıya sağa köçürün"</string>
     <string name="bubble_accessibility_action_move_bottom_left" msgid="6339015902495504715">"Aşağıya sola köçürün"</string>
     <string name="bubble_accessibility_action_move_bottom_right" msgid="7471571700628346212">"Aşağıya sağa köçürün"</string>
-    <string name="bubble_dismiss_text" msgid="7071770411580452911">"Kənarlaşdırın"</string>
+    <string name="bubble_dismiss_text" msgid="1314082410868930066">"Qabarcığı ləğv edin"</string>
     <string name="bubbles_dont_bubble_conversation" msgid="1033040343437428822">"Söhbətdən gələn bildirişi göstərməyin"</string>
     <string name="bubbles_user_education_title" msgid="5547017089271445797">"Yumrucuqlardan istifadə edərək söhbət edin"</string>
     <string name="bubbles_user_education_description" msgid="1160281719576715211">"Yeni söhbətlər üzən nişanlar və ya yumrucuqlar kimi görünür. Yumrucuğu açmaq üçün toxunun. Hərəkət etdirmək üçün sürüşdürün."</string>
@@ -1062,9 +1062,13 @@
     <string name="controls_structure_tooltip" msgid="4355922222944447867">"Digərlərini görmək üçün sürüşdürün"</string>
     <string name="controls_seeding_in_progress" msgid="3033855341410264148">"Tövsiyələr yüklənir"</string>
     <string name="controls_media_close_session" msgid="9023534788828414585">"Bu media sessiyasını bağlayın"</string>
+    <string name="controls_media_resume" msgid="1933520684481586053">"Davam edin"</string>
     <string name="controls_error_timeout" msgid="794197289772728958">"Aktiv deyil, tətbiqi yoxlayın"</string>
     <string name="controls_error_retryable" msgid="864025882878378470">"Xəta, yenidən cəhd edilir…"</string>
-    <string name="controls_error_removed" msgid="6299213591234723805">"Cihaz silindi"</string>
+    <string name="controls_error_removed" msgid="6675638069846014366">"Tapılmadı"</string>
+    <string name="controls_error_removed_title" msgid="1207794911208047818">"Nəzarət əlçatan deyil"</string>
+    <string name="controls_error_removed_message" msgid="2885911717034750542">"<xliff:g id="DEVICE">%1$s</xliff:g> cihazına giriş mümkün olmadı. <xliff:g id="APPLICATION">%2$s</xliff:g> tətbiqini yoxlayaraq nəzarətin hələ də əlçatan olduğuna və tətbiq ayarlarının dəyişmədiyinə əmin olun."</string>
+    <string name="controls_open_app" msgid="483650971094300141">"Tətbiqi açın"</string>
     <string name="controls_error_generic" msgid="352500456918362905">"Statusu yükləmək alınmadı"</string>
     <string name="controls_error_failed" msgid="960228639198558525">"Xəta, yenidən cəhd edin"</string>
     <string name="controls_in_progress" msgid="4421080500238215939">"Davam edir"</string>
diff --git a/packages/SystemUI/res/values-b+sr+Latn/strings.xml b/packages/SystemUI/res/values-b+sr+Latn/strings.xml
index 868d1cb..cdface9 100644
--- a/packages/SystemUI/res/values-b+sr+Latn/strings.xml
+++ b/packages/SystemUI/res/values-b+sr+Latn/strings.xml
@@ -513,7 +513,7 @@
     <string name="clear_all_notifications_text" msgid="348312370303046130">"Obriši sve"</string>
     <string name="manage_notifications_text" msgid="6885645344647733116">"Upravljajte"</string>
     <string name="manage_notifications_history_text" msgid="57055985396576230">"Istorija"</string>
-    <string name="notification_section_header_incoming" msgid="5295312809341711367">"Dolazno"</string>
+    <string name="notification_section_header_incoming" msgid="850925217908095197">"Novo"</string>
     <string name="notification_section_header_gentle" msgid="6804099527336337197">"Nečujno"</string>
     <string name="notification_section_header_alerting" msgid="5581175033680477651">"Obaveštenja"</string>
     <string name="notification_section_header_conversations" msgid="821834744538345661">"Konverzacije"</string>
@@ -598,7 +598,7 @@
     <string name="screen_pinning_title" msgid="9058007390337841305">"Aplikacija je zakačena"</string>
     <string name="screen_pinning_description" msgid="8699395373875667743">"Na ovaj način se ovo stalno prikazuje dok ga ne otkačite. Dodirnite i zadržite Nazad i Pregled da biste ga otkačili."</string>
     <string name="screen_pinning_description_recents_invisible" msgid="4564466648700390037">"Na ovaj način se ovo stalno prikazuje dok ga ne otkačite. Dodirnite i zadržite Nazad i Početna da biste ga otkačili."</string>
-    <string name="screen_pinning_description_gestural" msgid="7246323931831232068">"Na ovaj način se stalno prikazuje dok ga ne otkačite. Prevucite nagore i zadržite da biste ga otkačili."</string>
+    <string name="screen_pinning_description_gestural" msgid="7246323931831232068">"Stalno će se prikazivati dok je ne otkačite. Prevucite nagore i zadržite da biste je otkačili."</string>
     <string name="screen_pinning_description_accessible" msgid="7386449191953535332">"Na ovaj način se ovo stalno prikazuje dok ga ne otkačite. Dodirnite i zadržite Pregled da biste ga otkačili."</string>
     <string name="screen_pinning_description_recents_invisible_accessible" msgid="2857071808674481986">"Na ovaj način se ovo stalno prikazuje dok ga ne otkačite. Dodirnite i zadržite Početna da biste ga otkačili."</string>
     <string name="screen_pinning_exposes_personal_data" msgid="8189852022981524789">"Mogu da budu dostupni lični podaci (kao što su kontakti i sadržaj imejlova)."</string>
@@ -1007,9 +1007,9 @@
     <string name="bubble_accessibility_action_move_top_right" msgid="6916868852433483569">"Premesti gore desno"</string>
     <string name="bubble_accessibility_action_move_bottom_left" msgid="6339015902495504715">"Premesti dole levo"</string>
     <string name="bubble_accessibility_action_move_bottom_right" msgid="7471571700628346212">"Premesti dole desno"</string>
-    <string name="bubble_dismiss_text" msgid="7071770411580452911">"Odbaci"</string>
+    <string name="bubble_dismiss_text" msgid="1314082410868930066">"Odbacivanje oblačića"</string>
     <string name="bubbles_dont_bubble_conversation" msgid="1033040343437428822">"Ne koristi oblačiće za konverzaciju"</string>
-    <string name="bubbles_user_education_title" msgid="5547017089271445797">"Ćaskajte pomoću oblačića"</string>
+    <string name="bubbles_user_education_title" msgid="5547017089271445797">"Ćaskajte u oblačićima"</string>
     <string name="bubbles_user_education_description" msgid="1160281719576715211">"Nove konverzacije se prikazuju kao plutajuće ikone ili oblačići. Dodirnite da biste otvorili oblačić. Prevucite da biste ga premestili."</string>
     <string name="bubbles_user_education_manage_title" msgid="2848511858160342320">"Kontrolišite oblačiće u bilo kom trenutku"</string>
     <string name="bubbles_user_education_manage" msgid="1391639189507036423">"Dodirnite Upravljajte da biste isključili oblačiće iz ove aplikacije"</string>
@@ -1068,9 +1068,13 @@
     <string name="controls_structure_tooltip" msgid="4355922222944447867">"Prevucite da biste videli još"</string>
     <string name="controls_seeding_in_progress" msgid="3033855341410264148">"Učitavaju se preporuke"</string>
     <string name="controls_media_close_session" msgid="9023534788828414585">"Zatvorite ovu sesiju medija"</string>
+    <string name="controls_media_resume" msgid="1933520684481586053">"Nastavi"</string>
     <string name="controls_error_timeout" msgid="794197289772728958">"Neaktivno. Vidite aplikaciju"</string>
     <string name="controls_error_retryable" msgid="864025882878378470">"Greška, pokušava se ponovo…"</string>
-    <string name="controls_error_removed" msgid="6299213591234723805">"Uređaj je uklonjen"</string>
+    <string name="controls_error_removed" msgid="6675638069846014366">"Nije pronađeno"</string>
+    <string name="controls_error_removed_title" msgid="1207794911208047818">"Kontrola nije dostupna"</string>
+    <string name="controls_error_removed_message" msgid="2885911717034750542">"Pristupanje uređaju <xliff:g id="DEVICE">%1$s</xliff:g> nije uspelo. Pogledajte aplikaciju <xliff:g id="APPLICATION">%2$s</xliff:g> da biste se uverili da je kontrola još uvek dostupna i da se podešavanja aplikacije nisu promenila."</string>
+    <string name="controls_open_app" msgid="483650971094300141">"Otvori aplikaciju"</string>
     <string name="controls_error_generic" msgid="352500456918362905">"Učitavanje statusa nije uspelo"</string>
     <string name="controls_error_failed" msgid="960228639198558525">"Greška. Probajte ponovo"</string>
     <string name="controls_in_progress" msgid="4421080500238215939">"U toku"</string>
diff --git a/packages/SystemUI/res/values-be/strings.xml b/packages/SystemUI/res/values-be/strings.xml
index 04cd56a..32ec184 100644
--- a/packages/SystemUI/res/values-be/strings.xml
+++ b/packages/SystemUI/res/values-be/strings.xml
@@ -516,7 +516,7 @@
     <string name="clear_all_notifications_text" msgid="348312370303046130">"Ачысціць усё"</string>
     <string name="manage_notifications_text" msgid="6885645344647733116">"Кіраваць"</string>
     <string name="manage_notifications_history_text" msgid="57055985396576230">"Гісторыя"</string>
-    <string name="notification_section_header_incoming" msgid="5295312809341711367">"Уваходныя"</string>
+    <string name="notification_section_header_incoming" msgid="850925217908095197">"Новае"</string>
     <string name="notification_section_header_gentle" msgid="6804099527336337197">"Без гуку"</string>
     <string name="notification_section_header_alerting" msgid="5581175033680477651">"Апавяшчэнні"</string>
     <string name="notification_section_header_conversations" msgid="821834744538345661">"Размовы"</string>
@@ -601,7 +601,7 @@
     <string name="screen_pinning_title" msgid="9058007390337841305">"Праграма замацавана"</string>
     <string name="screen_pinning_description" msgid="8699395373875667743">"Будзе паказвацца, пакуль не адмацуеце. Каб адмацаваць, краніце і ўтрымлівайце кнопкі \"Назад\" і \"Агляд\"."</string>
     <string name="screen_pinning_description_recents_invisible" msgid="4564466648700390037">"Будзе паказвацца, пакуль не адмацуеце. Каб адмацаваць, націсніце і ўтрымлівайце кнопкі \"Назад\" і \"Галоўны экран\"."</string>
-    <string name="screen_pinning_description_gestural" msgid="7246323931831232068">"Будзе паказвацца, пакуль не адмацуеце Каб адмацаваць, прагартайце ўверх, утрымліваючы палец на экране"</string>
+    <string name="screen_pinning_description_gestural" msgid="7246323931831232068">"Будзе паказвацца, пакуль не адмацуеце. Каб адмацаваць, прагартайце ўверх, утрымліваючы палец на экране."</string>
     <string name="screen_pinning_description_accessible" msgid="7386449191953535332">"Будзе паказвацца, пакуль не адмацуеце. Каб адмацаваць, краніце і ўтрымлівайце кнопку \"Агляд\"."</string>
     <string name="screen_pinning_description_recents_invisible_accessible" msgid="2857071808674481986">"Будзе паказвацца, пакуль не адмацуеце. Каб адмацаваць, націсніце і ўтрымлівайце кнопку \"Галоўны экран\"."</string>
     <string name="screen_pinning_exposes_personal_data" msgid="8189852022981524789">"Могуць быць даступныя асабістыя даныя (напрыклад, кантакты і змесціва электроннай пошты)."</string>
@@ -1012,9 +1012,9 @@
     <string name="bubble_accessibility_action_move_top_right" msgid="6916868852433483569">"Перамясціце правей і вышэй"</string>
     <string name="bubble_accessibility_action_move_bottom_left" msgid="6339015902495504715">"Перамясціць лявей і ніжэй"</string>
     <string name="bubble_accessibility_action_move_bottom_right" msgid="7471571700628346212">"Перамясціць правей і ніжэй"</string>
-    <string name="bubble_dismiss_text" msgid="7071770411580452911">"Адхіліць"</string>
+    <string name="bubble_dismiss_text" msgid="1314082410868930066">"Адхіліць апавяшчэнне"</string>
     <string name="bubbles_dont_bubble_conversation" msgid="1033040343437428822">"Не паказваць размову ў выглядзе ўсплывальных апавяшчэнняў"</string>
-    <string name="bubbles_user_education_title" msgid="5547017089271445797">"Размаўляйце ў чаце, які паказвае ўсплывальныя апавяшчэнні"</string>
+    <string name="bubbles_user_education_title" msgid="5547017089271445797">"Усплывальныя апавяшчэнні"</string>
     <string name="bubbles_user_education_description" msgid="1160281719576715211">"Новыя размовы будуць паказвацца як рухомыя значкі ці ўсплывальныя апавяшчэнні. Націсніце, каб адкрыць усплывальнае апавяшчэнне. Перацягніце яго, каб перамясціць."</string>
     <string name="bubbles_user_education_manage_title" msgid="2848511858160342320">"Кіруйце ўсплывальнымі апавяшчэннямі ў любы час"</string>
     <string name="bubbles_user_education_manage" msgid="1391639189507036423">"Каб выключыць усплывальныя апавяшчэнні з гэтай праграмы, націсніце \"Кіраваць\""</string>
@@ -1074,9 +1074,13 @@
     <string name="controls_structure_tooltip" msgid="4355922222944447867">"Правядзіце пальцам, каб убачыць больш інфармацыі"</string>
     <string name="controls_seeding_in_progress" msgid="3033855341410264148">"Загружаюцца рэкамендацыі"</string>
     <string name="controls_media_close_session" msgid="9023534788828414585">"Закрыць гэты сеанс мультымедыя"</string>
+    <string name="controls_media_resume" msgid="1933520684481586053">"Узнавіць"</string>
     <string name="controls_error_timeout" msgid="794197289772728958">"Неактыўна, праверце праграму"</string>
     <string name="controls_error_retryable" msgid="864025882878378470">"Памылка, паўторная спроба…"</string>
-    <string name="controls_error_removed" msgid="6299213591234723805">"Прылада выдалена"</string>
+    <string name="controls_error_removed" msgid="6675638069846014366">"Не знойдзена"</string>
+    <string name="controls_error_removed_title" msgid="1207794911208047818">"Кіраванне недаступнае"</string>
+    <string name="controls_error_removed_message" msgid="2885911717034750542">"Не ўдалося атрымаць доступ да прылады \"<xliff:g id="DEVICE">%1$s</xliff:g>\". Праверце, ці не змяніліся налады праграмы \"<xliff:g id="APPLICATION">%2$s</xliff:g>\" і ці даступная ў ёй функцыя кіравання."</string>
+    <string name="controls_open_app" msgid="483650971094300141">"Адкрыць праграму"</string>
     <string name="controls_error_generic" msgid="352500456918362905">"Не ўдалося загрузіць стан"</string>
     <string name="controls_error_failed" msgid="960228639198558525">"Памылка, паўтарыце спробу"</string>
     <string name="controls_in_progress" msgid="4421080500238215939">"Выконваецца"</string>
diff --git a/packages/SystemUI/res/values-bg/strings.xml b/packages/SystemUI/res/values-bg/strings.xml
index 034217c..a2a2671 100644
--- a/packages/SystemUI/res/values-bg/strings.xml
+++ b/packages/SystemUI/res/values-bg/strings.xml
@@ -92,7 +92,7 @@
     <string name="screenrecord_background_processing_label" msgid="7244617554884238898">"Записът на екрана се обработва"</string>
     <string name="screenrecord_channel_description" msgid="4147077128486138351">"Текущо известие за сесия за записване на екрана"</string>
     <string name="screenrecord_start_label" msgid="1750350278888217473">"Да се стартира ли записът?"</string>
-    <string name="screenrecord_description" msgid="1123231719680353736">"По време на записване системата Android може да прихване поверителна информация, която е показана на екрана или възпроизвеждана на устройството ви. Това включва пароли, данни за плащане, снимки, съобщения и аудио."</string>
+    <string name="screenrecord_description" msgid="1123231719680353736">"По време на записване системата Android може да запише и поверителна информация, която е показана на екрана или възпроизвеждана на устройството ви. Това включва пароли, данни за плащане, снимки, съобщения и аудио."</string>
     <string name="screenrecord_audio_label" msgid="6183558856175159629">"Записване на звук"</string>
     <string name="screenrecord_device_audio_label" msgid="9016927171280567791">"Аудио от устройството"</string>
     <string name="screenrecord_device_audio_description" msgid="4922694220572186193">"Звук от устройството ви, като например музика, обаждания и мелодии"</string>
@@ -510,7 +510,7 @@
     <string name="clear_all_notifications_text" msgid="348312370303046130">"Изчистване на всички"</string>
     <string name="manage_notifications_text" msgid="6885645344647733116">"Управление"</string>
     <string name="manage_notifications_history_text" msgid="57055985396576230">"История"</string>
-    <string name="notification_section_header_incoming" msgid="5295312809341711367">"Входящи"</string>
+    <string name="notification_section_header_incoming" msgid="850925217908095197">"Нови"</string>
     <string name="notification_section_header_gentle" msgid="6804099527336337197">"Беззвучни"</string>
     <string name="notification_section_header_alerting" msgid="5581175033680477651">"Известия"</string>
     <string name="notification_section_header_conversations" msgid="821834744538345661">"Разговори"</string>
@@ -1002,9 +1002,9 @@
     <string name="bubble_accessibility_action_move_top_right" msgid="6916868852433483569">"Преместване горе вдясно"</string>
     <string name="bubble_accessibility_action_move_bottom_left" msgid="6339015902495504715">"Преместване долу вляво"</string>
     <string name="bubble_accessibility_action_move_bottom_right" msgid="7471571700628346212">"Преместване долу вдясно"</string>
-    <string name="bubble_dismiss_text" msgid="7071770411580452911">"Отхвърляне"</string>
+    <string name="bubble_dismiss_text" msgid="1314082410868930066">"Балонче: Отхвърляне"</string>
     <string name="bubbles_dont_bubble_conversation" msgid="1033040343437428822">"Без балончета за разговора"</string>
-    <string name="bubbles_user_education_title" msgid="5547017089271445797">"Разговаряне чрез балончета"</string>
+    <string name="bubbles_user_education_title" msgid="5547017089271445797">"Чат с балончета"</string>
     <string name="bubbles_user_education_description" msgid="1160281719576715211">"Новите разговори се показват като плаващи икони, или балончета. Докоснете балонче, за да го отворите, или го плъзнете, за да го преместите."</string>
     <string name="bubbles_user_education_manage_title" msgid="2848511858160342320">"Управление на балончетата по всяко време"</string>
     <string name="bubbles_user_education_manage" msgid="1391639189507036423">"Докоснете „Управление“, за да изключите балончетата от това приложение"</string>
@@ -1062,9 +1062,13 @@
     <string name="controls_structure_tooltip" msgid="4355922222944447867">"Прекарайте пръст, за да видите повече"</string>
     <string name="controls_seeding_in_progress" msgid="3033855341410264148">"Препоръките се зареждат"</string>
     <string name="controls_media_close_session" msgid="9023534788828414585">"Затваряне на тази сесия за мултимедия"</string>
+    <string name="controls_media_resume" msgid="1933520684481586053">"Възобновяване"</string>
     <string name="controls_error_timeout" msgid="794197289772728958">"Неактивно, проверете прилож."</string>
     <string name="controls_error_retryable" msgid="864025882878378470">"Грешка. Извършва се нов опит…"</string>
-    <string name="controls_error_removed" msgid="6299213591234723805">"Устройството бе премахнато"</string>
+    <string name="controls_error_removed" msgid="6675638069846014366">"Не е намерено"</string>
+    <string name="controls_error_removed_title" msgid="1207794911208047818">"Контролата не е налице"</string>
+    <string name="controls_error_removed_message" msgid="2885911717034750542">"Няма достъп до <xliff:g id="DEVICE">%1$s</xliff:g>. Отворете приложението <xliff:g id="APPLICATION">%2$s</xliff:g> и проверете дали контролата още е налице и дали настройките му не са променени."</string>
+    <string name="controls_open_app" msgid="483650971094300141">"Към приложението"</string>
     <string name="controls_error_generic" msgid="352500456918362905">"Състоян. не може да се зареди"</string>
     <string name="controls_error_failed" msgid="960228639198558525">"Грешка. Опитайте отново"</string>
     <string name="controls_in_progress" msgid="4421080500238215939">"В ход"</string>
diff --git a/packages/SystemUI/res/values-bn/strings.xml b/packages/SystemUI/res/values-bn/strings.xml
index 7482dfe..7a9feca 100644
--- a/packages/SystemUI/res/values-bn/strings.xml
+++ b/packages/SystemUI/res/values-bn/strings.xml
@@ -510,7 +510,7 @@
     <string name="clear_all_notifications_text" msgid="348312370303046130">"সবকিছু সাফ করুন"</string>
     <string name="manage_notifications_text" msgid="6885645344647733116">"পরিচালনা করুন"</string>
     <string name="manage_notifications_history_text" msgid="57055985396576230">"ইতিহাস"</string>
-    <string name="notification_section_header_incoming" msgid="5295312809341711367">"ইনকামিং"</string>
+    <string name="notification_section_header_incoming" msgid="850925217908095197">"নতুন"</string>
     <string name="notification_section_header_gentle" msgid="6804099527336337197">"আওয়াজ করবে না"</string>
     <string name="notification_section_header_alerting" msgid="5581175033680477651">"বিজ্ঞপ্তি"</string>
     <string name="notification_section_header_conversations" msgid="821834744538345661">"কথোপকথন"</string>
@@ -595,7 +595,7 @@
     <string name="screen_pinning_title" msgid="9058007390337841305">"অ্যাপ পিন করা হয়েছে"</string>
     <string name="screen_pinning_description" msgid="8699395373875667743">"এটি আপনি আনপিন না করা পর্যন্ত এটিকে প্রদর্শিত করবে৷ আনপিন করতে ফিরুন এবং ওভারভিউ স্পর্শ করে ধরে থাকুন।"</string>
     <string name="screen_pinning_description_recents_invisible" msgid="4564466648700390037">"এর ফলে আপনি এটি আনপিন না করা পর্যন্ত এটি দেখানো হতে থাকবে। আনপিন করতে \"ফিরে যান\" এবং \"হোম\" বোতামদুটি ট্যাপ করে ধরে রাখুন।"</string>
-    <string name="screen_pinning_description_gestural" msgid="7246323931831232068">"এর ফলে আপনি আনপিন না করা পর্যন্ত এটি দেখানো হতে থাকবে। আনপিন করার জন্য উপরের দিকে সোয়াইপ করে ধরে থাকুন"</string>
+    <string name="screen_pinning_description_gestural" msgid="7246323931831232068">"এর ফলে আপনি আনপিন না করা পর্যন্ত এটি দেখানো হবে। আনপিন করার জন্য উপরের দিকে সোয়াইপ করে ধরে থাকুন।"</string>
     <string name="screen_pinning_description_accessible" msgid="7386449191953535332">"এটি আপনি আনপিন না করা পর্যন্ত এটিকে প্রদর্শিত করবে৷ আনপিন করতে ওভারভিউ স্পর্শ করে ধরে থাকুন৷"</string>
     <string name="screen_pinning_description_recents_invisible_accessible" msgid="2857071808674481986">"এর ফলে আপনি এটি আনপিন না করা পর্যন্ত এটি দেখানো হতে থাকবে। আনপিন করতে \"হোম\" বোতামটি ট্যাপ করে ধরে রাখুন।"</string>
     <string name="screen_pinning_exposes_personal_data" msgid="8189852022981524789">"ব্যক্তিগত তথ্য অ্যাক্সেস করা যেতে পারে (যেমন, পরিচিতি ও ইমেল কন্টেন্ট)।"</string>
@@ -1002,7 +1002,7 @@
     <string name="bubble_accessibility_action_move_top_right" msgid="6916868852433483569">"উপরে ডানদিকে সরান"</string>
     <string name="bubble_accessibility_action_move_bottom_left" msgid="6339015902495504715">"নিচে বাঁদিকে সরান"</string>
     <string name="bubble_accessibility_action_move_bottom_right" msgid="7471571700628346212">"নিচে ডান দিকে সরান"</string>
-    <string name="bubble_dismiss_text" msgid="7071770411580452911">"খারিজ করুন"</string>
+    <string name="bubble_dismiss_text" msgid="1314082410868930066">"বাবল খারিজ করুন"</string>
     <string name="bubbles_dont_bubble_conversation" msgid="1033040343437428822">"কথোপকথন বাবল হিসেবে দেখাবে না"</string>
     <string name="bubbles_user_education_title" msgid="5547017089271445797">"বাবল ব্যবহার করে চ্যাট করুন"</string>
     <string name="bubbles_user_education_description" msgid="1160281719576715211">"নতুন কথোপকথন ভেসে থাকা আইকন বা বাবল হিসেবে দেখানো হয়। বাবল খুলতে ট্যাপ করুন। সেটি সরাতে ধরে টেনে আনুন।"</string>
@@ -1013,17 +1013,14 @@
     <string name="notification_content_system_nav_changed" msgid="5077913144844684544">"সিস্টেম নেভিগেশন আপডেট হয়েছে। পরিবর্তন করার জন্য সেটিংসে যান।"</string>
     <string name="notification_content_gesture_nav_available" msgid="4431460803004659888">"সিস্টেম নেভিগেশন আপডেট করতে সেটিংসে যান"</string>
     <string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"স্ট্যান্ডবাই"</string>
-    <!-- no translation found for priority_onboarding_title (2893070698479227616) -->
-    <skip />
-    <!-- no translation found for priority_onboarding_behavior (5342816047020432929) -->
-    <skip />
+    <string name="priority_onboarding_title" msgid="2893070698479227616">"কথোপকথনকে \'গুরুত্বপূর্ণ\' হিসেবে সেট করা হয়েছে"</string>
+    <string name="priority_onboarding_behavior" msgid="5342816047020432929">"গুরুত্বপূর্ণ কথোপকথন:"</string>
     <string name="priority_onboarding_show_at_top_text" msgid="1678400241025513541">"কথোপকথনের বিভাগের উপরে দেখান"</string>
     <string name="priority_onboarding_show_avatar_text" msgid="5756291381124091508">"লক স্ক্রিনে প্রোফাইল ছবি দেখান"</string>
     <string name="priority_onboarding_appear_as_bubble_text" msgid="4227039772250263122">"অ্যাপের উপরে একটি ভাসমান বুদবুদ হিসেবে দেখা যাবে"</string>
     <string name="priority_onboarding_ignores_dnd_text" msgid="2918952762719600529">"বিরক্ত করবে না মোডে ব্যাঘাত ঘটাতে পারে"</string>
     <string name="priority_onboarding_done_button_title" msgid="4569550984286506007">"বুঝেছি"</string>
-    <!-- no translation found for priority_onboarding_settings_button_title (6663601574303585927) -->
-    <skip />
+    <string name="priority_onboarding_settings_button_title" msgid="6663601574303585927">"সেটিংস"</string>
     <string name="magnification_overlay_title" msgid="6584179429612427958">"ওভারলে উইন্ডো বড় করে দেখা"</string>
     <string name="magnification_window_title" msgid="4863914360847258333">"উইন্ডো বড় করে দেখা"</string>
     <string name="magnification_controls_title" msgid="8421106606708891519">"উইন্ডো কন্ট্রোল বড় করে দেখা"</string>
@@ -1065,9 +1062,13 @@
     <string name="controls_structure_tooltip" msgid="4355922222944447867">"আরও দেখতে সোয়াইপ করুন"</string>
     <string name="controls_seeding_in_progress" msgid="3033855341410264148">"সাজেশন লোড করা হচ্ছে"</string>
     <string name="controls_media_close_session" msgid="9023534788828414585">"এই মিডিয়া সেশন বেছে নিন"</string>
+    <string name="controls_media_resume" msgid="1933520684481586053">"আবার চালু করুন"</string>
     <string name="controls_error_timeout" msgid="794197289772728958">"বন্ধ আছে, অ্যাপ চেক করুন"</string>
     <string name="controls_error_retryable" msgid="864025882878378470">"সমস্যা, আবার চেষ্টা করা হচ্ছে…"</string>
-    <string name="controls_error_removed" msgid="6299213591234723805">"ডিভাইস সরিয়ে দেওয়া হয়েছে"</string>
+    <string name="controls_error_removed" msgid="6675638069846014366">"খুঁজে পাওয়া যায়নি"</string>
+    <string name="controls_error_removed_title" msgid="1207794911208047818">"কন্ট্রোল উপলভ্য নেই"</string>
+    <string name="controls_error_removed_message" msgid="2885911717034750542">"<xliff:g id="DEVICE">%1$s</xliff:g> ডিভাইস অ্যাক্সেস করা যায়নি। কন্ট্রোল এখনও উপলভ্য আছে কিনা ও অ্যাপ সেটিংসে কোনও পরিবর্তন করা হয়েছে কিনা তা ভাল করে দেখে নিতে <xliff:g id="APPLICATION">%2$s</xliff:g> অ্যাপ চেক করুন।"</string>
+    <string name="controls_open_app" msgid="483650971094300141">"অ্যাপ খুলুন"</string>
     <string name="controls_error_generic" msgid="352500456918362905">"স্ট্যাটাস লোড করা যাচ্ছে না"</string>
     <string name="controls_error_failed" msgid="960228639198558525">"সমস্যা হয়েছে, আবার চেষ্টা করুন"</string>
     <string name="controls_in_progress" msgid="4421080500238215939">"চলছে"</string>
diff --git a/packages/SystemUI/res/values-bs/strings.xml b/packages/SystemUI/res/values-bs/strings.xml
index c049c5f..49fae62 100644
--- a/packages/SystemUI/res/values-bs/strings.xml
+++ b/packages/SystemUI/res/values-bs/strings.xml
@@ -92,13 +92,13 @@
     <string name="screenrecord_background_processing_label" msgid="7244617554884238898">"Obrađivanje snimka ekrana"</string>
     <string name="screenrecord_channel_description" msgid="4147077128486138351">"Obavještenje za sesiju snimanja ekrana je u toku"</string>
     <string name="screenrecord_start_label" msgid="1750350278888217473">"Započeti snimanje?"</string>
-    <string name="screenrecord_description" msgid="1123231719680353736">"Prilikom snimanja, sistem Android može snimiti sve osjetljive informacije koje su vidljive na vašem ekranu ili koje reproducirate na uređaju. To uključuje lozinke, informacije za plaćanje, fotografije, poruke i zvuk."</string>
+    <string name="screenrecord_description" msgid="1123231719680353736">"Prilikom snimanja, Android sistem može snimiti sve osjetljive informacije koje su vidljive na vašem ekranu ili koje reproducirate na uređaju. To uključuje lozinke, informacije za plaćanje, fotografije, poruke i zvuk."</string>
     <string name="screenrecord_audio_label" msgid="6183558856175159629">"Snimi zvučni zapis"</string>
     <string name="screenrecord_device_audio_label" msgid="9016927171280567791">"Zvuk uređaja"</string>
     <string name="screenrecord_device_audio_description" msgid="4922694220572186193">"Zvuk s vašeg uređaja, naprimjer muzika, pozivi i melodije zvona"</string>
     <string name="screenrecord_mic_label" msgid="2111264835791332350">"Mikrofon"</string>
     <string name="screenrecord_device_audio_and_mic_label" msgid="1831323771978646841">"Zvuk i mikrofon uređaja"</string>
-    <string name="screenrecord_start" msgid="330991441575775004">"Počni"</string>
+    <string name="screenrecord_start" msgid="330991441575775004">"Započni"</string>
     <string name="screenrecord_ongoing_screen_only" msgid="4459670242451527727">"Snimanje ekrana"</string>
     <string name="screenrecord_ongoing_screen_and_audio" msgid="5351133763125180920">"Snimanje ekrana i zvuka"</string>
     <string name="screenrecord_taps_label" msgid="1595690528298857649">"Prikaži dodire na ekranu"</string>
@@ -513,7 +513,7 @@
     <string name="clear_all_notifications_text" msgid="348312370303046130">"Očisti sve"</string>
     <string name="manage_notifications_text" msgid="6885645344647733116">"Upravljajte"</string>
     <string name="manage_notifications_history_text" msgid="57055985396576230">"Historija"</string>
-    <string name="notification_section_header_incoming" msgid="5295312809341711367">"Dolazno"</string>
+    <string name="notification_section_header_incoming" msgid="850925217908095197">"Novo"</string>
     <string name="notification_section_header_gentle" msgid="6804099527336337197">"Nečujno"</string>
     <string name="notification_section_header_alerting" msgid="5581175033680477651">"Obavještenja"</string>
     <string name="notification_section_header_conversations" msgid="821834744538345661">"Razgovori"</string>
@@ -601,7 +601,7 @@
     <string name="screen_pinning_description_gestural" msgid="7246323931831232068">"Na ovaj način ekran ostaje prikazan dok ga ne otkačite. Prevucite prema gore i držite da otkačite."</string>
     <string name="screen_pinning_description_accessible" msgid="7386449191953535332">"Ekran ostaje prikazan ovako dok ga ne otkačite. Da ga otkačite, dodirnite i držite dugme Pregled."</string>
     <string name="screen_pinning_description_recents_invisible_accessible" msgid="2857071808674481986">"Na ovaj način ekran ostaje prikazan dok ga ne otkačite. Da okačite ekran, dodirnite ili držite dugme Početna."</string>
-    <string name="screen_pinning_exposes_personal_data" msgid="8189852022981524789">"Lični podaci mogu biti dostupni (kao što su kontakti i sadržaj e-pošte)."</string>
+    <string name="screen_pinning_exposes_personal_data" msgid="8189852022981524789">"Lični podaci mogu biti dostupni (naprimjer kontakti i sadržaj e-pošte)."</string>
     <string name="screen_pinning_can_open_other_apps" msgid="7529756813231421455">"Zakačena aplikacija može otvoriti druge aplikacije."</string>
     <string name="screen_pinning_toast" msgid="8177286912533744328">"Dodirnite i držite dugmad Nazad i Pregled da otkačite ovu aplikaciju"</string>
     <string name="screen_pinning_toast_recents_invisible" msgid="6850978077443052594">"Dodirnite i držite dugmad Nazad i Početni ekran da otkačite ovu aplikaciju"</string>
@@ -1009,7 +1009,7 @@
     <string name="bubble_accessibility_action_move_top_right" msgid="6916868852433483569">"Pomjerite gore desno"</string>
     <string name="bubble_accessibility_action_move_bottom_left" msgid="6339015902495504715">"Pomjeri dolje lijevo"</string>
     <string name="bubble_accessibility_action_move_bottom_right" msgid="7471571700628346212">"Pomjerite dolje desno"</string>
-    <string name="bubble_dismiss_text" msgid="7071770411580452911">"Odbaci"</string>
+    <string name="bubble_dismiss_text" msgid="1314082410868930066">"Odbaci oblačić"</string>
     <string name="bubbles_dont_bubble_conversation" msgid="1033040343437428822">"Nemoj prikazivati razgovor u oblačićima"</string>
     <string name="bubbles_user_education_title" msgid="5547017089271445797">"Chatajte koristeći oblačiće"</string>
     <string name="bubbles_user_education_description" msgid="1160281719576715211">"Novi razgovori se prikazuju kao plutajuće ikone ili oblačići. Dodirnite da otvorite oblačić. Prevucite da ga premjestite."</string>
@@ -1070,9 +1070,13 @@
     <string name="controls_structure_tooltip" msgid="4355922222944447867">"Prevucite da vidite više"</string>
     <string name="controls_seeding_in_progress" msgid="3033855341410264148">"Učitavanje preporuka"</string>
     <string name="controls_media_close_session" msgid="9023534788828414585">"Zatvori ovu medijsku sesiju"</string>
+    <string name="controls_media_resume" msgid="1933520684481586053">"Nastavi"</string>
     <string name="controls_error_timeout" msgid="794197289772728958">"Neaktivno, vidite aplikaciju"</string>
     <string name="controls_error_retryable" msgid="864025882878378470">"Greška, ponovni pokušaj…"</string>
-    <string name="controls_error_removed" msgid="6299213591234723805">"Uređaj je uklonjen"</string>
+    <string name="controls_error_removed" msgid="6675638069846014366">"Nije pronađeno"</string>
+    <string name="controls_error_removed_title" msgid="1207794911208047818">"Kontrola nije dostupna"</string>
+    <string name="controls_error_removed_message" msgid="2885911717034750542">"Pristup uređaju <xliff:g id="DEVICE">%1$s</xliff:g> nije uspio. Provjerite aplikaciju <xliff:g id="APPLICATION">%2$s</xliff:g> da se uvjerite da je kontrola i dalje dostupna i da se postavke aplikacije nisu promijenile."</string>
+    <string name="controls_open_app" msgid="483650971094300141">"Otvori aplikaciju"</string>
     <string name="controls_error_generic" msgid="352500456918362905">"Nije moguće učitati status"</string>
     <string name="controls_error_failed" msgid="960228639198558525">"Greška, pokušajte ponovo"</string>
     <string name="controls_in_progress" msgid="4421080500238215939">"U toku"</string>
diff --git a/packages/SystemUI/res/values-ca/strings.xml b/packages/SystemUI/res/values-ca/strings.xml
index 506429c..5cc0853 100644
--- a/packages/SystemUI/res/values-ca/strings.xml
+++ b/packages/SystemUI/res/values-ca/strings.xml
@@ -510,7 +510,7 @@
     <string name="clear_all_notifications_text" msgid="348312370303046130">"Esborra-ho tot"</string>
     <string name="manage_notifications_text" msgid="6885645344647733116">"Gestiona"</string>
     <string name="manage_notifications_history_text" msgid="57055985396576230">"Historial"</string>
-    <string name="notification_section_header_incoming" msgid="5295312809341711367">"Entrants"</string>
+    <string name="notification_section_header_incoming" msgid="850925217908095197">"Novetats"</string>
     <string name="notification_section_header_gentle" msgid="6804099527336337197">"Silenci"</string>
     <string name="notification_section_header_alerting" msgid="5581175033680477651">"Notificacions"</string>
     <string name="notification_section_header_conversations" msgid="821834744538345661">"Converses"</string>
@@ -1002,9 +1002,9 @@
     <string name="bubble_accessibility_action_move_top_right" msgid="6916868852433483569">"Mou a dalt a la dreta"</string>
     <string name="bubble_accessibility_action_move_bottom_left" msgid="6339015902495504715">"Mou a baix a l\'esquerra"</string>
     <string name="bubble_accessibility_action_move_bottom_right" msgid="7471571700628346212">"Mou a baix a la dreta"</string>
-    <string name="bubble_dismiss_text" msgid="7071770411580452911">"Omet"</string>
+    <string name="bubble_dismiss_text" msgid="1314082410868930066">"Ignora la bombolla"</string>
     <string name="bubbles_dont_bubble_conversation" msgid="1033040343437428822">"No mostris la conversa com a bombolla"</string>
-    <string name="bubbles_user_education_title" msgid="5547017089271445797">"Xateja utilitzant les bombolles"</string>
+    <string name="bubbles_user_education_title" msgid="5547017089271445797">"Xateja amb bombolles"</string>
     <string name="bubbles_user_education_description" msgid="1160281719576715211">"Les converses noves es mostren com a icones flotants o bombolles. Toca per obrir una bombolla. Arrossega-la per moure-la."</string>
     <string name="bubbles_user_education_manage_title" msgid="2848511858160342320">"Controla les bombolles en qualsevol moment"</string>
     <string name="bubbles_user_education_manage" msgid="1391639189507036423">"Toca Gestiona per desactivar les bombolles d\'aquesta aplicació"</string>
@@ -1062,9 +1062,13 @@
     <string name="controls_structure_tooltip" msgid="4355922222944447867">"Llisca per veure\'n més"</string>
     <string name="controls_seeding_in_progress" msgid="3033855341410264148">"Carregant les recomanacions"</string>
     <string name="controls_media_close_session" msgid="9023534788828414585">"Tanca aquesta sessió multimèdia"</string>
+    <string name="controls_media_resume" msgid="1933520684481586053">"Reprèn"</string>
     <string name="controls_error_timeout" msgid="794197289772728958">"Inactiu; comprova l\'aplicació"</string>
     <string name="controls_error_retryable" msgid="864025882878378470">"Error. S\'està tornant a provar…"</string>
-    <string name="controls_error_removed" msgid="6299213591234723805">"El dispositiu s\'ha suprimit"</string>
+    <string name="controls_error_removed" msgid="6675638069846014366">"No s\'ha trobat"</string>
+    <string name="controls_error_removed_title" msgid="1207794911208047818">"El control no està disponible"</string>
+    <string name="controls_error_removed_message" msgid="2885911717034750542">"No s\'ha pogut accedir a <xliff:g id="DEVICE">%1$s</xliff:g>. Consulta l\'aplicació <xliff:g id="APPLICATION">%2$s</xliff:g> per assegurar-te que el control encara estigui disponible i que la configuració de l\'aplicació no hagi canviat."</string>
+    <string name="controls_open_app" msgid="483650971094300141">"Obre l\'aplicació"</string>
     <string name="controls_error_generic" msgid="352500456918362905">"No es pot carregar l\'estat"</string>
     <string name="controls_error_failed" msgid="960228639198558525">"Error; torna-ho a provar"</string>
     <string name="controls_in_progress" msgid="4421080500238215939">"En curs"</string>
diff --git a/packages/SystemUI/res/values-cs/strings.xml b/packages/SystemUI/res/values-cs/strings.xml
index 48ab79e..a071793 100644
--- a/packages/SystemUI/res/values-cs/strings.xml
+++ b/packages/SystemUI/res/values-cs/strings.xml
@@ -516,7 +516,7 @@
     <string name="clear_all_notifications_text" msgid="348312370303046130">"Smazat vše"</string>
     <string name="manage_notifications_text" msgid="6885645344647733116">"Spravovat"</string>
     <string name="manage_notifications_history_text" msgid="57055985396576230">"Historie"</string>
-    <string name="notification_section_header_incoming" msgid="5295312809341711367">"Příchozí"</string>
+    <string name="notification_section_header_incoming" msgid="850925217908095197">"Nové"</string>
     <string name="notification_section_header_gentle" msgid="6804099527336337197">"Tiché"</string>
     <string name="notification_section_header_alerting" msgid="5581175033680477651">"Oznámení"</string>
     <string name="notification_section_header_conversations" msgid="821834744538345661">"Konverzace"</string>
@@ -601,7 +601,7 @@
     <string name="screen_pinning_title" msgid="9058007390337841305">"Aplikace je připnuta"</string>
     <string name="screen_pinning_description" msgid="8699395373875667743">"Obsah bude připnut v zobrazení, dokud jej neuvolníte. Uvolníte jej stisknutím a podržením tlačítek Zpět a Přehled."</string>
     <string name="screen_pinning_description_recents_invisible" msgid="4564466648700390037">"Obsah bude připnut v zobrazení, dokud ho neuvolníte. Uvolníte ho podržením tlačítek Zpět a Plocha."</string>
-    <string name="screen_pinning_description_gestural" msgid="7246323931831232068">"Obsah bude připnut v zobrazení, dokud ho neuvolníte. Uvolnit ho můžete přejetím nahoru a podržením."</string>
+    <string name="screen_pinning_description_gestural" msgid="7246323931831232068">"Díky připnutí bude vidět, dokud ji neodepnete. Odepnout ji můžete přejetím nahoru a podržením."</string>
     <string name="screen_pinning_description_accessible" msgid="7386449191953535332">"Obsah bude připnut v zobrazení, dokud jej neuvolníte. Uvolníte jej stisknutím a podržením tlačítka Přehled."</string>
     <string name="screen_pinning_description_recents_invisible_accessible" msgid="2857071808674481986">"Obsah bude připnut v zobrazení, dokud ho neuvolníte. Uvolníte ho podržením tlačítka Plocha."</string>
     <string name="screen_pinning_exposes_personal_data" msgid="8189852022981524789">"Může mít přístup k soukromým datům (například kontaktům a obsahu e-mailů)"</string>
@@ -1012,7 +1012,7 @@
     <string name="bubble_accessibility_action_move_top_right" msgid="6916868852433483569">"Přesunout vpravo nahoru"</string>
     <string name="bubble_accessibility_action_move_bottom_left" msgid="6339015902495504715">"Přesunout vlevo dolů"</string>
     <string name="bubble_accessibility_action_move_bottom_right" msgid="7471571700628346212">"Přesunout vpravo dolů"</string>
-    <string name="bubble_dismiss_text" msgid="7071770411580452911">"Zavřít"</string>
+    <string name="bubble_dismiss_text" msgid="1314082410868930066">"Zavřít bublinu"</string>
     <string name="bubbles_dont_bubble_conversation" msgid="1033040343437428822">"Nezobrazovat konverzaci v bublinách"</string>
     <string name="bubbles_user_education_title" msgid="5547017089271445797">"Chatujte pomocí bublin"</string>
     <string name="bubbles_user_education_description" msgid="1160281719576715211">"Nové konverzace se zobrazují jako plovoucí ikony, neboli bubliny. Klepnutím bublinu otevřete. Přetažením ji posunete."</string>
@@ -1074,9 +1074,13 @@
     <string name="controls_structure_tooltip" msgid="4355922222944447867">"Přejetím prstem zobrazíte další položky"</string>
     <string name="controls_seeding_in_progress" msgid="3033855341410264148">"Načítání doporučení"</string>
     <string name="controls_media_close_session" msgid="9023534788828414585">"Zavřít tuto mediální relaci"</string>
+    <string name="controls_media_resume" msgid="1933520684481586053">"Pokračovat"</string>
     <string name="controls_error_timeout" msgid="794197289772728958">"Neaktivní, zkontrolujte aplikaci"</string>
     <string name="controls_error_retryable" msgid="864025882878378470">"Chyba. Nový pokus…"</string>
-    <string name="controls_error_removed" msgid="6299213591234723805">"Zařízení bylo odebráno"</string>
+    <string name="controls_error_removed" msgid="6675638069846014366">"Nenalezeno"</string>
+    <string name="controls_error_removed_title" msgid="1207794911208047818">"Ovládání není k dispozici"</string>
+    <string name="controls_error_removed_message" msgid="2885911717034750542">"Zařízení <xliff:g id="DEVICE">%1$s</xliff:g> nelze použít. V aplikaci <xliff:g id="APPLICATION">%2$s</xliff:g> zkontrolujte, zda je ovládání stále k dispozici a zda se nezměnilo nastavení."</string>
+    <string name="controls_open_app" msgid="483650971094300141">"Otevřít aplikaci"</string>
     <string name="controls_error_generic" msgid="352500456918362905">"Stav nelze načíst"</string>
     <string name="controls_error_failed" msgid="960228639198558525">"Chyba, zkuste to znovu"</string>
     <string name="controls_in_progress" msgid="4421080500238215939">"Probíhá"</string>
diff --git a/packages/SystemUI/res/values-da/strings.xml b/packages/SystemUI/res/values-da/strings.xml
index 8d2d5c5..f1bbbff 100644
--- a/packages/SystemUI/res/values-da/strings.xml
+++ b/packages/SystemUI/res/values-da/strings.xml
@@ -510,7 +510,7 @@
     <string name="clear_all_notifications_text" msgid="348312370303046130">"Ryd alle"</string>
     <string name="manage_notifications_text" msgid="6885645344647733116">"Administrer"</string>
     <string name="manage_notifications_history_text" msgid="57055985396576230">"Historik"</string>
-    <string name="notification_section_header_incoming" msgid="5295312809341711367">"Indgående"</string>
+    <string name="notification_section_header_incoming" msgid="850925217908095197">"Nye"</string>
     <string name="notification_section_header_gentle" msgid="6804099527336337197">"Lydløs"</string>
     <string name="notification_section_header_alerting" msgid="5581175033680477651">"Notifikationer"</string>
     <string name="notification_section_header_conversations" msgid="821834744538345661">"Samtaler"</string>
@@ -595,10 +595,10 @@
     <string name="screen_pinning_title" msgid="9058007390337841305">"Appen er fastgjort"</string>
     <string name="screen_pinning_description" msgid="8699395373875667743">"Dette fastholder skærmen i visningen, indtil du frigør den. Tryk på Tilbage og Overblik, og hold fingeren nede for at frigøre skærmen."</string>
     <string name="screen_pinning_description_recents_invisible" msgid="4564466648700390037">"Dette fastholder skærmen i visningen, indtil du frigør den. Hold Tilbage og Startskærm nede for at frigøre skærmen."</string>
-    <string name="screen_pinning_description_gestural" msgid="7246323931831232068">"Dette fastholder skærmen i visningen, indtil du frigør den. Stryg opad, og hold fingeren nede for at frigøre den."</string>
+    <string name="screen_pinning_description_gestural" msgid="7246323931831232068">"Dette fastholder appen på skærmen, indtil du frigør den. Stryg opad, og hold fingeren nede for at frigøre den."</string>
     <string name="screen_pinning_description_accessible" msgid="7386449191953535332">"Dette fastholder skærmen i visningen, indtil du frigør den. Tryk på Tilbage, og hold fingeren nede for at frigøre skærmen."</string>
     <string name="screen_pinning_description_recents_invisible_accessible" msgid="2857071808674481986">"Dette fastholder skærmen i visningen, indtil du frigør den. Hold Startskærm nede for at frigøre skærmen."</string>
-    <string name="screen_pinning_exposes_personal_data" msgid="8189852022981524789">"Personoplysninger er muligvis tilgængelige (f.eks. kontakter og mailindhold)."</string>
+    <string name="screen_pinning_exposes_personal_data" msgid="8189852022981524789">"Der kan stadig være adgang til personoplysninger (f.eks. kontakter og mailindhold)."</string>
     <string name="screen_pinning_can_open_other_apps" msgid="7529756813231421455">"En fastgjort app kan åbne andre apps."</string>
     <string name="screen_pinning_toast" msgid="8177286912533744328">"Du kan frigøre denne app ved at holde knapperne Tilbage og Oversigt nede"</string>
     <string name="screen_pinning_toast_recents_invisible" msgid="6850978077443052594">"Du kan frigøre denne app ved at holde knapperne Tilbage og Hjem nede"</string>
@@ -1002,7 +1002,7 @@
     <string name="bubble_accessibility_action_move_top_right" msgid="6916868852433483569">"Flyt op til højre"</string>
     <string name="bubble_accessibility_action_move_bottom_left" msgid="6339015902495504715">"Flyt ned til venstre"</string>
     <string name="bubble_accessibility_action_move_bottom_right" msgid="7471571700628346212">"Flyt ned til højre"</string>
-    <string name="bubble_dismiss_text" msgid="7071770411580452911">"Afvis"</string>
+    <string name="bubble_dismiss_text" msgid="1314082410868930066">"Afvis bobbel"</string>
     <string name="bubbles_dont_bubble_conversation" msgid="1033040343437428822">"Vis ikke samtaler i bobler"</string>
     <string name="bubbles_user_education_title" msgid="5547017089271445797">"Chat ved hjælp af bobler"</string>
     <string name="bubbles_user_education_description" msgid="1160281719576715211">"Nye samtaler vises som svævende ikoner eller bobler. Tryk for at åbne boblen. Træk for at flytte den."</string>
@@ -1062,9 +1062,13 @@
     <string name="controls_structure_tooltip" msgid="4355922222944447867">"Stryg for at se mere"</string>
     <string name="controls_seeding_in_progress" msgid="3033855341410264148">"Indlæser anbefalinger"</string>
     <string name="controls_media_close_session" msgid="9023534788828414585">"Luk denne mediesession"</string>
+    <string name="controls_media_resume" msgid="1933520684481586053">"Genoptag"</string>
     <string name="controls_error_timeout" msgid="794197289772728958">"Inaktiv. Tjek appen"</string>
     <string name="controls_error_retryable" msgid="864025882878378470">"Fejl. Prøver igen…"</string>
-    <string name="controls_error_removed" msgid="6299213591234723805">"Enheden er fjernet"</string>
+    <string name="controls_error_removed" msgid="6675638069846014366">"Ikke fundet"</string>
+    <string name="controls_error_removed_title" msgid="1207794911208047818">"Styringselement ikke tilgængeligt"</string>
+    <string name="controls_error_removed_message" msgid="2885911717034750542">"Der kunne ikke skaffes adgang til <xliff:g id="DEVICE">%1$s</xliff:g>. Tjek <xliff:g id="APPLICATION">%2$s</xliff:g>-appen for at sikre at styringselementet stadig er tilgængeligt, og at appens indstillinger ikke er blevet ændret."</string>
+    <string name="controls_open_app" msgid="483650971094300141">"Åbn app"</string>
     <string name="controls_error_generic" msgid="352500456918362905">"Statussen kan ikke indlæses"</string>
     <string name="controls_error_failed" msgid="960228639198558525">"Der opstod en fejl. Prøv igen"</string>
     <string name="controls_in_progress" msgid="4421080500238215939">"I gang"</string>
diff --git a/packages/SystemUI/res/values-de/strings.xml b/packages/SystemUI/res/values-de/strings.xml
index 50cb3f3..3397cd6 100644
--- a/packages/SystemUI/res/values-de/strings.xml
+++ b/packages/SystemUI/res/values-de/strings.xml
@@ -510,7 +510,8 @@
     <string name="clear_all_notifications_text" msgid="348312370303046130">"Alle löschen"</string>
     <string name="manage_notifications_text" msgid="6885645344647733116">"Verwalten"</string>
     <string name="manage_notifications_history_text" msgid="57055985396576230">"Verlauf"</string>
-    <string name="notification_section_header_incoming" msgid="5295312809341711367">"Neue Benachrichtigungen"</string>
+    <!-- no translation found for notification_section_header_incoming (850925217908095197) -->
+    <skip />
     <string name="notification_section_header_gentle" msgid="6804099527336337197">"Lautlos"</string>
     <string name="notification_section_header_alerting" msgid="5581175033680477651">"Benachrichtigungen"</string>
     <string name="notification_section_header_conversations" msgid="821834744538345661">"Unterhaltungen"</string>
@@ -1002,7 +1003,7 @@
     <string name="bubble_accessibility_action_move_top_right" msgid="6916868852433483569">"Nach rechts oben verschieben"</string>
     <string name="bubble_accessibility_action_move_bottom_left" msgid="6339015902495504715">"Nach unten links verschieben"</string>
     <string name="bubble_accessibility_action_move_bottom_right" msgid="7471571700628346212">"Nach unten rechts verschieben"</string>
-    <string name="bubble_dismiss_text" msgid="7071770411580452911">"Schließen"</string>
+    <string name="bubble_dismiss_text" msgid="1314082410868930066">"Bubble schließen"</string>
     <string name="bubbles_dont_bubble_conversation" msgid="1033040343437428822">"Unterhaltung nicht als Bubble anzeigen"</string>
     <string name="bubbles_user_education_title" msgid="5547017089271445797">"Bubbles zum Chatten verwenden"</string>
     <string name="bubbles_user_education_description" msgid="1160281719576715211">"Neue Unterhaltungen erscheinen als unverankerte Symbole, \"Bubbles\" genannt. Wenn du die Bubble öffnen möchtest, tippe sie an. Wenn du sie verschieben möchtest, zieh an ihr."</string>
@@ -1062,9 +1063,13 @@
     <string name="controls_structure_tooltip" msgid="4355922222944447867">"Wischen, um weitere zu sehen"</string>
     <string name="controls_seeding_in_progress" msgid="3033855341410264148">"Empfehlungen werden geladen"</string>
     <string name="controls_media_close_session" msgid="9023534788828414585">"Diese Mediensitzung schließen"</string>
+    <string name="controls_media_resume" msgid="1933520684481586053">"Fortsetzen"</string>
     <string name="controls_error_timeout" msgid="794197289772728958">"Inaktiv – sieh in der App nach"</string>
     <string name="controls_error_retryable" msgid="864025882878378470">"Fehler. Neuer Versuch…"</string>
-    <string name="controls_error_removed" msgid="6299213591234723805">"Gerät entfernt"</string>
+    <string name="controls_error_removed" msgid="6675638069846014366">"Nicht gefunden"</string>
+    <string name="controls_error_removed_title" msgid="1207794911208047818">"Steuerelement nicht verfügbar"</string>
+    <string name="controls_error_removed_message" msgid="2885911717034750542">"Zugriff auf <xliff:g id="DEVICE">%1$s</xliff:g> nicht möglich. Prüfe, ob das Steuerelement in der App \"<xliff:g id="APPLICATION">%2$s</xliff:g>\" noch verfügbar ist und die App-Einstellungen nicht geändert wurden."</string>
+    <string name="controls_open_app" msgid="483650971094300141">"App öffnen"</string>
     <string name="controls_error_generic" msgid="352500456918362905">"Status kann nicht geladen werden"</string>
     <string name="controls_error_failed" msgid="960228639198558525">"Fehler – versuch es noch mal"</string>
     <string name="controls_in_progress" msgid="4421080500238215939">"Läuft"</string>
diff --git a/packages/SystemUI/res/values-el/strings.xml b/packages/SystemUI/res/values-el/strings.xml
index 6a32d57..f24f745 100644
--- a/packages/SystemUI/res/values-el/strings.xml
+++ b/packages/SystemUI/res/values-el/strings.xml
@@ -256,7 +256,7 @@
     <!-- no translation found for accessibility_work_mode (1280025758672376313) -->
     <skip />
     <string name="accessibility_notification_dismissed" msgid="4411652015138892952">"Η ειδοποίηση έχει απορριφθεί."</string>
-    <string name="accessibility_bubble_dismissed" msgid="270358867566720729">"Η φούσκα παραβλέφθηκε."</string>
+    <string name="accessibility_bubble_dismissed" msgid="270358867566720729">"Το συννεφάκι παραβλέφθηκε."</string>
     <string name="accessibility_desc_notification_shade" msgid="5355229129428759989">"Πλαίσιο σκίασης ειδοποιήσεων."</string>
     <string name="accessibility_desc_quick_settings" msgid="4374766941484719179">"Γρήγορες ρυθμίσεις."</string>
     <string name="accessibility_desc_lock_screen" msgid="5983125095181194887">"Οθόνη κλειδώματος"</string>
@@ -510,7 +510,7 @@
     <string name="clear_all_notifications_text" msgid="348312370303046130">"Διαγραφή όλων"</string>
     <string name="manage_notifications_text" msgid="6885645344647733116">"Διαχείριση"</string>
     <string name="manage_notifications_history_text" msgid="57055985396576230">"Ιστορικό"</string>
-    <string name="notification_section_header_incoming" msgid="5295312809341711367">"Εισερχόμενες"</string>
+    <string name="notification_section_header_incoming" msgid="850925217908095197">"Νέα"</string>
     <string name="notification_section_header_gentle" msgid="6804099527336337197">"Σίγαση"</string>
     <string name="notification_section_header_alerting" msgid="5581175033680477651">"Ειδοποιήσεις"</string>
     <string name="notification_section_header_conversations" msgid="821834744538345661">"Συζητήσεις"</string>
@@ -710,7 +710,7 @@
     <string name="inline_keep_showing_app" msgid="4393429060390649757">"Να συνεχίσουν να εμφανίζονται ειδοποιήσεις από αυτήν την εφαρμογή;"</string>
     <string name="notification_silence_title" msgid="8608090968400832335">"Σίγαση"</string>
     <string name="notification_alert_title" msgid="3656229781017543655">"Προεπιλογή"</string>
-    <string name="notification_bubble_title" msgid="8330481035191903164">"Φούσκα"</string>
+    <string name="notification_bubble_title" msgid="8330481035191903164">"Συννεφάκι"</string>
     <string name="notification_channel_summary_low" msgid="4860617986908931158">"Χωρίς ήχο ή δόνηση"</string>
     <string name="notification_conversation_summary_low" msgid="1734433426085468009">"Χωρίς ήχο ή δόνηση και εμφανίζεται χαμηλά στην ενότητα συζητήσεων"</string>
     <string name="notification_channel_summary_default" msgid="3282930979307248890">"Ενδέχεται να κουδουνίζει ή να δονείται βάσει των ρυθμίσεων του τηλεφώνου"</string>
@@ -1002,10 +1002,10 @@
     <string name="bubble_accessibility_action_move_top_right" msgid="6916868852433483569">"Μετακίνηση επάνω δεξιά"</string>
     <string name="bubble_accessibility_action_move_bottom_left" msgid="6339015902495504715">"Μετακίνηση κάτω αριστερά"</string>
     <string name="bubble_accessibility_action_move_bottom_right" msgid="7471571700628346212">"Μετακίνηση κάτω δεξιά"</string>
-    <string name="bubble_dismiss_text" msgid="7071770411580452911">"Παράβλεψη"</string>
+    <string name="bubble_dismiss_text" msgid="1314082410868930066">"Παράβλ. για συννεφ."</string>
     <string name="bubbles_dont_bubble_conversation" msgid="1033040343437428822">"Να μην γίνει προβολή της συζήτησης σε συννεφάκια."</string>
     <string name="bubbles_user_education_title" msgid="5547017089271445797">"Συζητήστε χρησιμοποιώντας συννεφάκια."</string>
-    <string name="bubbles_user_education_description" msgid="1160281719576715211">"Οι νέες συζητήσεις εμφανίζονται ως κινούμενα εικονίδια ή φούσκες. Πατήστε για να ανοίξετε τη φούσκα. Σύρετε για να το μετακινήσετε."</string>
+    <string name="bubbles_user_education_description" msgid="1160281719576715211">"Οι νέες συζητήσεις εμφανίζονται ως κινούμενα εικονίδια ή συννεφάκια. Πατήστε για να ανοίξετε το συννεφάκι. Σύρετε για να το μετακινήσετε."</string>
     <string name="bubbles_user_education_manage_title" msgid="2848511858160342320">"Ελέγξτε τα συννεφάκια ανά πάσα στιγμή."</string>
     <string name="bubbles_user_education_manage" msgid="1391639189507036423">"Πατήστε Διαχείριση για να απενεργοποιήσετε τα συννεφάκια από αυτήν την εφαρμογή."</string>
     <string name="bubbles_user_education_got_it" msgid="8282812431953161143">"Το κατάλαβα."</string>
@@ -1062,9 +1062,13 @@
     <string name="controls_structure_tooltip" msgid="4355922222944447867">"Σύρετε για να δείτε περισσότερα."</string>
     <string name="controls_seeding_in_progress" msgid="3033855341410264148">"Φόρτωση προτάσεων"</string>
     <string name="controls_media_close_session" msgid="9023534788828414585">"Κλείσιμο αυτής της περιόδου λειτουργίας μέσων."</string>
+    <string name="controls_media_resume" msgid="1933520684481586053">"Συνέχιση"</string>
     <string name="controls_error_timeout" msgid="794197289772728958">"Ανενεργό, έλεγχος εφαρμογής"</string>
     <string name="controls_error_retryable" msgid="864025882878378470">"Προέκυψε σφάλμα. Επανάληψη…"</string>
-    <string name="controls_error_removed" msgid="6299213591234723805">"Η συσκευή καταργήθηκε"</string>
+    <string name="controls_error_removed" msgid="6675638069846014366">"Δεν βρέθηκε."</string>
+    <string name="controls_error_removed_title" msgid="1207794911208047818">"Μη διαθέσιμο στοιχείο ελέγχου"</string>
+    <string name="controls_error_removed_message" msgid="2885911717034750542">"Δεν ήταν δυνατή η πρόσβαση στη συσκευή <xliff:g id="DEVICE">%1$s</xliff:g>. Ελέγξτε την εφαρμογή <xliff:g id="APPLICATION">%2$s</xliff:g> για να βεβαιωθείτε ότι το στοιχείο ελέγχου εξακολουθεί να είναι διαθέσιμο και ότι οι ρυθμίσεις της εφαρμογής δεν έχουν αλλάξει."</string>
+    <string name="controls_open_app" msgid="483650971094300141">"Άνοιγμα εφαρμογής"</string>
     <string name="controls_error_generic" msgid="352500456918362905">"Αδυναμία φόρτωσης κατάστασης"</string>
     <string name="controls_error_failed" msgid="960228639198558525">"Σφάλμα, προσπαθήστε ξανά."</string>
     <string name="controls_in_progress" msgid="4421080500238215939">"Σε εξέλιξη"</string>
diff --git a/packages/SystemUI/res/values-en-rAU/strings.xml b/packages/SystemUI/res/values-en-rAU/strings.xml
index 35f09af..ac20c84 100644
--- a/packages/SystemUI/res/values-en-rAU/strings.xml
+++ b/packages/SystemUI/res/values-en-rAU/strings.xml
@@ -92,7 +92,7 @@
     <string name="screenrecord_background_processing_label" msgid="7244617554884238898">"Processing screen recording"</string>
     <string name="screenrecord_channel_description" msgid="4147077128486138351">"Ongoing notification for a screen record session"</string>
     <string name="screenrecord_start_label" msgid="1750350278888217473">"Start recording?"</string>
-    <string name="screenrecord_description" msgid="1123231719680353736">"While recording, Android system can capture any sensitive information that’s visible on your screen or played on your device. This includes passwords, payment info, photos, messages and audio."</string>
+    <string name="screenrecord_description" msgid="1123231719680353736">"While recording, Android System can capture any sensitive information that’s visible on your screen or played on your device. This includes passwords, payment info, photos, messages and audio."</string>
     <string name="screenrecord_audio_label" msgid="6183558856175159629">"Record audio"</string>
     <string name="screenrecord_device_audio_label" msgid="9016927171280567791">"Device audio"</string>
     <string name="screenrecord_device_audio_description" msgid="4922694220572186193">"Sound from your device, like music, calls and ringtones"</string>
@@ -510,7 +510,7 @@
     <string name="clear_all_notifications_text" msgid="348312370303046130">"Clear all"</string>
     <string name="manage_notifications_text" msgid="6885645344647733116">"Manage"</string>
     <string name="manage_notifications_history_text" msgid="57055985396576230">"History"</string>
-    <string name="notification_section_header_incoming" msgid="5295312809341711367">"Incoming"</string>
+    <string name="notification_section_header_incoming" msgid="850925217908095197">"New"</string>
     <string name="notification_section_header_gentle" msgid="6804099527336337197">"Silent"</string>
     <string name="notification_section_header_alerting" msgid="5581175033680477651">"Notifications"</string>
     <string name="notification_section_header_conversations" msgid="821834744538345661">"Conversations"</string>
@@ -595,7 +595,7 @@
     <string name="screen_pinning_title" msgid="9058007390337841305">"App is pinned"</string>
     <string name="screen_pinning_description" msgid="8699395373875667743">"This keeps it in view until you unpin. Touch &amp; hold Back and Overview to unpin."</string>
     <string name="screen_pinning_description_recents_invisible" msgid="4564466648700390037">"This keeps it in view until you unpin. Touch &amp; hold Back and Home to unpin."</string>
-    <string name="screen_pinning_description_gestural" msgid="7246323931831232068">"This keeps it in view until you unpin. Swipe up &amp; hold to unpin."</string>
+    <string name="screen_pinning_description_gestural" msgid="7246323931831232068">"This keeps it in view until you unpin. Swipe up and hold to unpin."</string>
     <string name="screen_pinning_description_accessible" msgid="7386449191953535332">"This keeps it in view until you unpin. Touch &amp; hold Overview to unpin."</string>
     <string name="screen_pinning_description_recents_invisible_accessible" msgid="2857071808674481986">"This keeps it in view until you unpin. Touch &amp; hold Home to unpin."</string>
     <string name="screen_pinning_exposes_personal_data" msgid="8189852022981524789">"Personal data may be accessible (such as contacts and email content)."</string>
@@ -1002,7 +1002,7 @@
     <string name="bubble_accessibility_action_move_top_right" msgid="6916868852433483569">"Move top right"</string>
     <string name="bubble_accessibility_action_move_bottom_left" msgid="6339015902495504715">"Move bottom left"</string>
     <string name="bubble_accessibility_action_move_bottom_right" msgid="7471571700628346212">"Move bottom right"</string>
-    <string name="bubble_dismiss_text" msgid="7071770411580452911">"Dismiss"</string>
+    <string name="bubble_dismiss_text" msgid="1314082410868930066">"Dismiss bubble"</string>
     <string name="bubbles_dont_bubble_conversation" msgid="1033040343437428822">"Don’t bubble conversation"</string>
     <string name="bubbles_user_education_title" msgid="5547017089271445797">"Chat using bubbles"</string>
     <string name="bubbles_user_education_description" msgid="1160281719576715211">"New conversations appear as floating icons, or bubbles. Tap to open bubble. Drag to move it."</string>
@@ -1062,9 +1062,13 @@
     <string name="controls_structure_tooltip" msgid="4355922222944447867">"Swipe to see more"</string>
     <string name="controls_seeding_in_progress" msgid="3033855341410264148">"Loading recommendations"</string>
     <string name="controls_media_close_session" msgid="9023534788828414585">"Close this media session"</string>
+    <string name="controls_media_resume" msgid="1933520684481586053">"Resume"</string>
     <string name="controls_error_timeout" msgid="794197289772728958">"Inactive, check app"</string>
     <string name="controls_error_retryable" msgid="864025882878378470">"Error, retrying…"</string>
-    <string name="controls_error_removed" msgid="6299213591234723805">"Device removed"</string>
+    <string name="controls_error_removed" msgid="6675638069846014366">"Not found"</string>
+    <string name="controls_error_removed_title" msgid="1207794911208047818">"Control is unavailable"</string>
+    <string name="controls_error_removed_message" msgid="2885911717034750542">"Couldn’t access <xliff:g id="DEVICE">%1$s</xliff:g>. Check the <xliff:g id="APPLICATION">%2$s</xliff:g> app to make sure that the control is still available and that the app settings haven’t changed."</string>
+    <string name="controls_open_app" msgid="483650971094300141">"Open app"</string>
     <string name="controls_error_generic" msgid="352500456918362905">"Can’t load status"</string>
     <string name="controls_error_failed" msgid="960228639198558525">"Error, try again"</string>
     <string name="controls_in_progress" msgid="4421080500238215939">"In progress"</string>
diff --git a/packages/SystemUI/res/values-en-rCA/strings.xml b/packages/SystemUI/res/values-en-rCA/strings.xml
index 8c8db6a..233664e 100644
--- a/packages/SystemUI/res/values-en-rCA/strings.xml
+++ b/packages/SystemUI/res/values-en-rCA/strings.xml
@@ -92,7 +92,7 @@
     <string name="screenrecord_background_processing_label" msgid="7244617554884238898">"Processing screen recording"</string>
     <string name="screenrecord_channel_description" msgid="4147077128486138351">"Ongoing notification for a screen record session"</string>
     <string name="screenrecord_start_label" msgid="1750350278888217473">"Start recording?"</string>
-    <string name="screenrecord_description" msgid="1123231719680353736">"While recording, Android system can capture any sensitive information that’s visible on your screen or played on your device. This includes passwords, payment info, photos, messages and audio."</string>
+    <string name="screenrecord_description" msgid="1123231719680353736">"While recording, Android System can capture any sensitive information that’s visible on your screen or played on your device. This includes passwords, payment info, photos, messages and audio."</string>
     <string name="screenrecord_audio_label" msgid="6183558856175159629">"Record audio"</string>
     <string name="screenrecord_device_audio_label" msgid="9016927171280567791">"Device audio"</string>
     <string name="screenrecord_device_audio_description" msgid="4922694220572186193">"Sound from your device, like music, calls and ringtones"</string>
@@ -510,7 +510,7 @@
     <string name="clear_all_notifications_text" msgid="348312370303046130">"Clear all"</string>
     <string name="manage_notifications_text" msgid="6885645344647733116">"Manage"</string>
     <string name="manage_notifications_history_text" msgid="57055985396576230">"History"</string>
-    <string name="notification_section_header_incoming" msgid="5295312809341711367">"Incoming"</string>
+    <string name="notification_section_header_incoming" msgid="850925217908095197">"New"</string>
     <string name="notification_section_header_gentle" msgid="6804099527336337197">"Silent"</string>
     <string name="notification_section_header_alerting" msgid="5581175033680477651">"Notifications"</string>
     <string name="notification_section_header_conversations" msgid="821834744538345661">"Conversations"</string>
@@ -595,7 +595,7 @@
     <string name="screen_pinning_title" msgid="9058007390337841305">"App is pinned"</string>
     <string name="screen_pinning_description" msgid="8699395373875667743">"This keeps it in view until you unpin. Touch &amp; hold Back and Overview to unpin."</string>
     <string name="screen_pinning_description_recents_invisible" msgid="4564466648700390037">"This keeps it in view until you unpin. Touch &amp; hold Back and Home to unpin."</string>
-    <string name="screen_pinning_description_gestural" msgid="7246323931831232068">"This keeps it in view until you unpin. Swipe up &amp; hold to unpin."</string>
+    <string name="screen_pinning_description_gestural" msgid="7246323931831232068">"This keeps it in view until you unpin. Swipe up and hold to unpin."</string>
     <string name="screen_pinning_description_accessible" msgid="7386449191953535332">"This keeps it in view until you unpin. Touch &amp; hold Overview to unpin."</string>
     <string name="screen_pinning_description_recents_invisible_accessible" msgid="2857071808674481986">"This keeps it in view until you unpin. Touch &amp; hold Home to unpin."</string>
     <string name="screen_pinning_exposes_personal_data" msgid="8189852022981524789">"Personal data may be accessible (such as contacts and email content)."</string>
@@ -1002,7 +1002,7 @@
     <string name="bubble_accessibility_action_move_top_right" msgid="6916868852433483569">"Move top right"</string>
     <string name="bubble_accessibility_action_move_bottom_left" msgid="6339015902495504715">"Move bottom left"</string>
     <string name="bubble_accessibility_action_move_bottom_right" msgid="7471571700628346212">"Move bottom right"</string>
-    <string name="bubble_dismiss_text" msgid="7071770411580452911">"Dismiss"</string>
+    <string name="bubble_dismiss_text" msgid="1314082410868930066">"Dismiss bubble"</string>
     <string name="bubbles_dont_bubble_conversation" msgid="1033040343437428822">"Don’t bubble conversation"</string>
     <string name="bubbles_user_education_title" msgid="5547017089271445797">"Chat using bubbles"</string>
     <string name="bubbles_user_education_description" msgid="1160281719576715211">"New conversations appear as floating icons, or bubbles. Tap to open bubble. Drag to move it."</string>
@@ -1062,9 +1062,13 @@
     <string name="controls_structure_tooltip" msgid="4355922222944447867">"Swipe to see more"</string>
     <string name="controls_seeding_in_progress" msgid="3033855341410264148">"Loading recommendations"</string>
     <string name="controls_media_close_session" msgid="9023534788828414585">"Close this media session"</string>
+    <string name="controls_media_resume" msgid="1933520684481586053">"Resume"</string>
     <string name="controls_error_timeout" msgid="794197289772728958">"Inactive, check app"</string>
     <string name="controls_error_retryable" msgid="864025882878378470">"Error, retrying…"</string>
-    <string name="controls_error_removed" msgid="6299213591234723805">"Device removed"</string>
+    <string name="controls_error_removed" msgid="6675638069846014366">"Not found"</string>
+    <string name="controls_error_removed_title" msgid="1207794911208047818">"Control is unavailable"</string>
+    <string name="controls_error_removed_message" msgid="2885911717034750542">"Couldn’t access <xliff:g id="DEVICE">%1$s</xliff:g>. Check the <xliff:g id="APPLICATION">%2$s</xliff:g> app to make sure that the control is still available and that the app settings haven’t changed."</string>
+    <string name="controls_open_app" msgid="483650971094300141">"Open app"</string>
     <string name="controls_error_generic" msgid="352500456918362905">"Can’t load status"</string>
     <string name="controls_error_failed" msgid="960228639198558525">"Error, try again"</string>
     <string name="controls_in_progress" msgid="4421080500238215939">"In progress"</string>
diff --git a/packages/SystemUI/res/values-en-rGB/strings.xml b/packages/SystemUI/res/values-en-rGB/strings.xml
index 35f09af..ac20c84 100644
--- a/packages/SystemUI/res/values-en-rGB/strings.xml
+++ b/packages/SystemUI/res/values-en-rGB/strings.xml
@@ -92,7 +92,7 @@
     <string name="screenrecord_background_processing_label" msgid="7244617554884238898">"Processing screen recording"</string>
     <string name="screenrecord_channel_description" msgid="4147077128486138351">"Ongoing notification for a screen record session"</string>
     <string name="screenrecord_start_label" msgid="1750350278888217473">"Start recording?"</string>
-    <string name="screenrecord_description" msgid="1123231719680353736">"While recording, Android system can capture any sensitive information that’s visible on your screen or played on your device. This includes passwords, payment info, photos, messages and audio."</string>
+    <string name="screenrecord_description" msgid="1123231719680353736">"While recording, Android System can capture any sensitive information that’s visible on your screen or played on your device. This includes passwords, payment info, photos, messages and audio."</string>
     <string name="screenrecord_audio_label" msgid="6183558856175159629">"Record audio"</string>
     <string name="screenrecord_device_audio_label" msgid="9016927171280567791">"Device audio"</string>
     <string name="screenrecord_device_audio_description" msgid="4922694220572186193">"Sound from your device, like music, calls and ringtones"</string>
@@ -510,7 +510,7 @@
     <string name="clear_all_notifications_text" msgid="348312370303046130">"Clear all"</string>
     <string name="manage_notifications_text" msgid="6885645344647733116">"Manage"</string>
     <string name="manage_notifications_history_text" msgid="57055985396576230">"History"</string>
-    <string name="notification_section_header_incoming" msgid="5295312809341711367">"Incoming"</string>
+    <string name="notification_section_header_incoming" msgid="850925217908095197">"New"</string>
     <string name="notification_section_header_gentle" msgid="6804099527336337197">"Silent"</string>
     <string name="notification_section_header_alerting" msgid="5581175033680477651">"Notifications"</string>
     <string name="notification_section_header_conversations" msgid="821834744538345661">"Conversations"</string>
@@ -595,7 +595,7 @@
     <string name="screen_pinning_title" msgid="9058007390337841305">"App is pinned"</string>
     <string name="screen_pinning_description" msgid="8699395373875667743">"This keeps it in view until you unpin. Touch &amp; hold Back and Overview to unpin."</string>
     <string name="screen_pinning_description_recents_invisible" msgid="4564466648700390037">"This keeps it in view until you unpin. Touch &amp; hold Back and Home to unpin."</string>
-    <string name="screen_pinning_description_gestural" msgid="7246323931831232068">"This keeps it in view until you unpin. Swipe up &amp; hold to unpin."</string>
+    <string name="screen_pinning_description_gestural" msgid="7246323931831232068">"This keeps it in view until you unpin. Swipe up and hold to unpin."</string>
     <string name="screen_pinning_description_accessible" msgid="7386449191953535332">"This keeps it in view until you unpin. Touch &amp; hold Overview to unpin."</string>
     <string name="screen_pinning_description_recents_invisible_accessible" msgid="2857071808674481986">"This keeps it in view until you unpin. Touch &amp; hold Home to unpin."</string>
     <string name="screen_pinning_exposes_personal_data" msgid="8189852022981524789">"Personal data may be accessible (such as contacts and email content)."</string>
@@ -1002,7 +1002,7 @@
     <string name="bubble_accessibility_action_move_top_right" msgid="6916868852433483569">"Move top right"</string>
     <string name="bubble_accessibility_action_move_bottom_left" msgid="6339015902495504715">"Move bottom left"</string>
     <string name="bubble_accessibility_action_move_bottom_right" msgid="7471571700628346212">"Move bottom right"</string>
-    <string name="bubble_dismiss_text" msgid="7071770411580452911">"Dismiss"</string>
+    <string name="bubble_dismiss_text" msgid="1314082410868930066">"Dismiss bubble"</string>
     <string name="bubbles_dont_bubble_conversation" msgid="1033040343437428822">"Don’t bubble conversation"</string>
     <string name="bubbles_user_education_title" msgid="5547017089271445797">"Chat using bubbles"</string>
     <string name="bubbles_user_education_description" msgid="1160281719576715211">"New conversations appear as floating icons, or bubbles. Tap to open bubble. Drag to move it."</string>
@@ -1062,9 +1062,13 @@
     <string name="controls_structure_tooltip" msgid="4355922222944447867">"Swipe to see more"</string>
     <string name="controls_seeding_in_progress" msgid="3033855341410264148">"Loading recommendations"</string>
     <string name="controls_media_close_session" msgid="9023534788828414585">"Close this media session"</string>
+    <string name="controls_media_resume" msgid="1933520684481586053">"Resume"</string>
     <string name="controls_error_timeout" msgid="794197289772728958">"Inactive, check app"</string>
     <string name="controls_error_retryable" msgid="864025882878378470">"Error, retrying…"</string>
-    <string name="controls_error_removed" msgid="6299213591234723805">"Device removed"</string>
+    <string name="controls_error_removed" msgid="6675638069846014366">"Not found"</string>
+    <string name="controls_error_removed_title" msgid="1207794911208047818">"Control is unavailable"</string>
+    <string name="controls_error_removed_message" msgid="2885911717034750542">"Couldn’t access <xliff:g id="DEVICE">%1$s</xliff:g>. Check the <xliff:g id="APPLICATION">%2$s</xliff:g> app to make sure that the control is still available and that the app settings haven’t changed."</string>
+    <string name="controls_open_app" msgid="483650971094300141">"Open app"</string>
     <string name="controls_error_generic" msgid="352500456918362905">"Can’t load status"</string>
     <string name="controls_error_failed" msgid="960228639198558525">"Error, try again"</string>
     <string name="controls_in_progress" msgid="4421080500238215939">"In progress"</string>
diff --git a/packages/SystemUI/res/values-en-rIN/strings.xml b/packages/SystemUI/res/values-en-rIN/strings.xml
index 35f09af..ac20c84 100644
--- a/packages/SystemUI/res/values-en-rIN/strings.xml
+++ b/packages/SystemUI/res/values-en-rIN/strings.xml
@@ -92,7 +92,7 @@
     <string name="screenrecord_background_processing_label" msgid="7244617554884238898">"Processing screen recording"</string>
     <string name="screenrecord_channel_description" msgid="4147077128486138351">"Ongoing notification for a screen record session"</string>
     <string name="screenrecord_start_label" msgid="1750350278888217473">"Start recording?"</string>
-    <string name="screenrecord_description" msgid="1123231719680353736">"While recording, Android system can capture any sensitive information that’s visible on your screen or played on your device. This includes passwords, payment info, photos, messages and audio."</string>
+    <string name="screenrecord_description" msgid="1123231719680353736">"While recording, Android System can capture any sensitive information that’s visible on your screen or played on your device. This includes passwords, payment info, photos, messages and audio."</string>
     <string name="screenrecord_audio_label" msgid="6183558856175159629">"Record audio"</string>
     <string name="screenrecord_device_audio_label" msgid="9016927171280567791">"Device audio"</string>
     <string name="screenrecord_device_audio_description" msgid="4922694220572186193">"Sound from your device, like music, calls and ringtones"</string>
@@ -510,7 +510,7 @@
     <string name="clear_all_notifications_text" msgid="348312370303046130">"Clear all"</string>
     <string name="manage_notifications_text" msgid="6885645344647733116">"Manage"</string>
     <string name="manage_notifications_history_text" msgid="57055985396576230">"History"</string>
-    <string name="notification_section_header_incoming" msgid="5295312809341711367">"Incoming"</string>
+    <string name="notification_section_header_incoming" msgid="850925217908095197">"New"</string>
     <string name="notification_section_header_gentle" msgid="6804099527336337197">"Silent"</string>
     <string name="notification_section_header_alerting" msgid="5581175033680477651">"Notifications"</string>
     <string name="notification_section_header_conversations" msgid="821834744538345661">"Conversations"</string>
@@ -595,7 +595,7 @@
     <string name="screen_pinning_title" msgid="9058007390337841305">"App is pinned"</string>
     <string name="screen_pinning_description" msgid="8699395373875667743">"This keeps it in view until you unpin. Touch &amp; hold Back and Overview to unpin."</string>
     <string name="screen_pinning_description_recents_invisible" msgid="4564466648700390037">"This keeps it in view until you unpin. Touch &amp; hold Back and Home to unpin."</string>
-    <string name="screen_pinning_description_gestural" msgid="7246323931831232068">"This keeps it in view until you unpin. Swipe up &amp; hold to unpin."</string>
+    <string name="screen_pinning_description_gestural" msgid="7246323931831232068">"This keeps it in view until you unpin. Swipe up and hold to unpin."</string>
     <string name="screen_pinning_description_accessible" msgid="7386449191953535332">"This keeps it in view until you unpin. Touch &amp; hold Overview to unpin."</string>
     <string name="screen_pinning_description_recents_invisible_accessible" msgid="2857071808674481986">"This keeps it in view until you unpin. Touch &amp; hold Home to unpin."</string>
     <string name="screen_pinning_exposes_personal_data" msgid="8189852022981524789">"Personal data may be accessible (such as contacts and email content)."</string>
@@ -1002,7 +1002,7 @@
     <string name="bubble_accessibility_action_move_top_right" msgid="6916868852433483569">"Move top right"</string>
     <string name="bubble_accessibility_action_move_bottom_left" msgid="6339015902495504715">"Move bottom left"</string>
     <string name="bubble_accessibility_action_move_bottom_right" msgid="7471571700628346212">"Move bottom right"</string>
-    <string name="bubble_dismiss_text" msgid="7071770411580452911">"Dismiss"</string>
+    <string name="bubble_dismiss_text" msgid="1314082410868930066">"Dismiss bubble"</string>
     <string name="bubbles_dont_bubble_conversation" msgid="1033040343437428822">"Don’t bubble conversation"</string>
     <string name="bubbles_user_education_title" msgid="5547017089271445797">"Chat using bubbles"</string>
     <string name="bubbles_user_education_description" msgid="1160281719576715211">"New conversations appear as floating icons, or bubbles. Tap to open bubble. Drag to move it."</string>
@@ -1062,9 +1062,13 @@
     <string name="controls_structure_tooltip" msgid="4355922222944447867">"Swipe to see more"</string>
     <string name="controls_seeding_in_progress" msgid="3033855341410264148">"Loading recommendations"</string>
     <string name="controls_media_close_session" msgid="9023534788828414585">"Close this media session"</string>
+    <string name="controls_media_resume" msgid="1933520684481586053">"Resume"</string>
     <string name="controls_error_timeout" msgid="794197289772728958">"Inactive, check app"</string>
     <string name="controls_error_retryable" msgid="864025882878378470">"Error, retrying…"</string>
-    <string name="controls_error_removed" msgid="6299213591234723805">"Device removed"</string>
+    <string name="controls_error_removed" msgid="6675638069846014366">"Not found"</string>
+    <string name="controls_error_removed_title" msgid="1207794911208047818">"Control is unavailable"</string>
+    <string name="controls_error_removed_message" msgid="2885911717034750542">"Couldn’t access <xliff:g id="DEVICE">%1$s</xliff:g>. Check the <xliff:g id="APPLICATION">%2$s</xliff:g> app to make sure that the control is still available and that the app settings haven’t changed."</string>
+    <string name="controls_open_app" msgid="483650971094300141">"Open app"</string>
     <string name="controls_error_generic" msgid="352500456918362905">"Can’t load status"</string>
     <string name="controls_error_failed" msgid="960228639198558525">"Error, try again"</string>
     <string name="controls_in_progress" msgid="4421080500238215939">"In progress"</string>
diff --git a/packages/SystemUI/res/values-en-rXC/strings.xml b/packages/SystemUI/res/values-en-rXC/strings.xml
index e514ccb..f37742d 100644
--- a/packages/SystemUI/res/values-en-rXC/strings.xml
+++ b/packages/SystemUI/res/values-en-rXC/strings.xml
@@ -510,7 +510,7 @@
     <string name="clear_all_notifications_text" msgid="348312370303046130">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‎‏‏‏‎‎‏‏‎‏‎‏‎‏‎‏‏‏‎‏‎‎‎‏‎‎‎‎‎‏‎‏‎‏‏‏‏‎‏‏‎‎‏‎‎‏‏‎‎‏‎‎‎‏‏‏‏‏‎‎‏‎‎Clear all‎‏‎‎‏‎"</string>
     <string name="manage_notifications_text" msgid="6885645344647733116">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‏‏‏‏‏‏‎‎‎‏‏‏‎‏‎‏‏‏‎‎‏‏‏‏‏‎‏‎‏‏‎‎‏‎‎‎‏‎‎‎‎‏‏‎‎‏‏‎‏‏‏‏‏‎‏‏‏‏‏‎‎‎Manage‎‏‎‎‏‎"</string>
     <string name="manage_notifications_history_text" msgid="57055985396576230">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‎‎‎‏‏‎‎‏‎‏‎‏‎‏‏‎‏‎‎‎‎‎‏‏‏‎‏‏‏‎‎‏‏‎‏‏‏‎‏‏‏‏‏‎‏‏‎‏‏‏‏‏‏‏‎‎‏‏‎‎History‎‏‎‎‏‎"</string>
-    <string name="notification_section_header_incoming" msgid="5295312809341711367">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‎‏‎‎‏‎‏‏‏‏‏‎‎‏‎‏‏‏‎‏‎‏‏‏‏‎‎‎‏‏‎‏‏‏‏‏‏‎‏‏‎‎‎‏‏‎‏‏‏‎‏‎‎‎‎‎‎‎‏‏‏‎Incoming‎‏‎‎‏‎"</string>
+    <string name="notification_section_header_incoming" msgid="850925217908095197">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‎‏‎‏‏‏‏‎‎‏‏‏‏‎‎‎‏‎‏‏‏‏‏‏‏‏‎‏‎‎‎‏‎‏‏‏‏‏‏‎‏‎‏‎‏‎‏‏‏‏‎‎‎‏‏‎‏‏‏‎‏‎New‎‏‎‎‏‎"</string>
     <string name="notification_section_header_gentle" msgid="6804099527336337197">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‏‏‏‏‎‎‏‏‎‏‏‎‏‎‎‎‎‎‏‎‎‎‏‏‏‏‎‎‎‎‏‏‎‏‏‏‏‎‏‎‎‏‎‎‏‎‎‎‏‏‏‏‏‎‎‏‎‏‏‎‏‎Silent‎‏‎‎‏‎"</string>
     <string name="notification_section_header_alerting" msgid="5581175033680477651">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‎‏‏‎‏‎‏‏‏‎‏‎‎‎‏‎‏‎‎‎‏‎‎‎‏‏‏‏‏‎‏‏‎‏‏‏‏‏‏‎‎‏‏‎‏‏‎‏‏‏‏‎‏‏‏‎‏‎‎‏‏‎Notifications‎‏‎‎‏‎"</string>
     <string name="notification_section_header_conversations" msgid="821834744538345661">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‎‏‎‏‏‎‏‏‎‎‏‏‏‏‎‏‏‏‏‏‎‎‏‎‏‏‎‎‎‏‎‎‎‏‏‎‎‎‏‎‎‏‎‎‎‎‎‏‏‎‎‎‎‏‎‏‏‏‏‎‏‎Conversations‎‏‎‎‏‎"</string>
@@ -1002,7 +1002,7 @@
     <string name="bubble_accessibility_action_move_top_right" msgid="6916868852433483569">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‏‏‏‏‏‏‏‏‏‏‏‎‏‏‎‏‎‎‏‏‏‏‎‎‏‎‎‏‎‏‏‏‏‏‎‏‏‎‏‎‎‎‎‏‎‏‏‏‏‎‏‏‏‎‎‏‏‎‎‎‏‎Move top right‎‏‎‎‏‎"</string>
     <string name="bubble_accessibility_action_move_bottom_left" msgid="6339015902495504715">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‏‎‏‏‏‏‏‏‏‏‎‎‎‏‎‏‏‎‏‎‏‎‏‏‎‎‎‎‎‏‎‏‏‎‏‎‏‏‏‎‎‏‎‏‏‏‏‏‏‏‎‎‏‎‏‎‎‏‎‏‏‎Move bottom left‎‏‎‎‏‎"</string>
     <string name="bubble_accessibility_action_move_bottom_right" msgid="7471571700628346212">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‎‎‏‏‏‏‎‏‏‎‎‎‎‎‏‎‏‏‎‏‎‏‏‏‎‎‎‎‎‎‎‏‎‏‎‎‏‏‏‎‏‎‎‎‎‎‏‎‏‎‏‎‏‎‏‏‎‎‏‎‎‎Move bottom right‎‏‎‎‏‎"</string>
-    <string name="bubble_dismiss_text" msgid="7071770411580452911">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‎‎‎‏‎‎‎‏‎‎‎‏‏‏‏‏‏‏‎‎‏‏‎‏‏‏‎‎‎‏‎‏‏‎‎‏‏‎‏‎‏‏‏‏‎‏‏‏‏‎‎‎‎‎‎‏‎‏‏‏‏‎Dismiss‎‏‎‎‏‎"</string>
+    <string name="bubble_dismiss_text" msgid="1314082410868930066">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‏‏‎‎‏‎‎‎‏‏‏‏‎‎‏‎‎‎‏‏‏‎‏‏‏‏‏‏‎‏‏‎‎‎‏‎‎‏‎‏‏‎‏‏‏‎‎‏‏‏‎‏‏‎‎‎‎‏‎‎‏‎‎Dismiss bubble‎‏‎‎‏‎"</string>
     <string name="bubbles_dont_bubble_conversation" msgid="1033040343437428822">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‎‏‏‏‎‎‏‎‏‎‏‏‎‎‎‎‏‏‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‏‎‏‎‎‏‏‏‏‎‎‎‏‎‎‏‎‎‎‎‏‎‏‎‏‏‎‎Don’t bubble conversation‎‏‎‎‏‎"</string>
     <string name="bubbles_user_education_title" msgid="5547017089271445797">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‎‏‏‎‎‏‏‏‏‏‎‏‎‏‏‏‏‎‏‏‎‏‎‏‎‎‏‏‏‎‏‎‎‎‎‎‏‎‎‎‎‏‎‏‏‏‎‏‏‏‎‎‏‎‎‏‎‎‏‎‏‎Chat using bubbles‎‏‎‎‏‎"</string>
     <string name="bubbles_user_education_description" msgid="1160281719576715211">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‏‏‎‎‎‎‎‎‎‏‏‎‏‎‎‎‏‎‎‏‏‎‎‎‎‏‎‎‏‏‏‎‎‏‎‏‏‎‏‎‏‏‏‏‏‏‏‏‎‏‏‏‏‏‏‏‎‎‏‎‏‏‎New conversations appear as floating icons, or bubbles. Tap to open bubble. Drag to move it.‎‏‎‎‏‎"</string>
@@ -1062,10 +1062,13 @@
     <string name="controls_structure_tooltip" msgid="4355922222944447867">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‏‏‏‎‎‎‏‏‏‎‎‏‏‎‏‎‏‏‎‎‎‎‎‏‎‏‏‏‎‏‏‎‏‏‏‏‏‏‏‎‏‎‏‎‏‎‏‏‎‏‏‎‏‎‏‏‏‏‎‏‏‎Swipe to see more‎‏‎‎‏‎"</string>
     <string name="controls_seeding_in_progress" msgid="3033855341410264148">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‎‏‎‏‎‎‎‎‏‏‎‏‎‎‏‏‎‏‎‏‏‎‏‎‏‏‎‏‏‏‏‏‎‎‏‎‎‏‎‏‎‏‏‏‎‎‎‏‎‎‏‎‎‎‏‎‏‎‏‎‎‎Loading recommendations‎‏‎‎‏‎"</string>
     <string name="controls_media_close_session" msgid="9023534788828414585">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‏‏‎‏‎‎‏‏‏‎‏‎‎‎‎‎‏‎‎‏‎‎‎‏‎‏‎‎‏‏‏‎‏‎‏‎‎‏‏‏‏‏‏‏‎‏‎‎‎‎‏‎‎‏‏‏‏‎‎‏‎Close this media session‎‏‎‎‏‎"</string>
+    <string name="controls_media_resume" msgid="1933520684481586053">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‏‏‏‎‏‎‏‏‎‏‎‏‎‏‎‎‏‏‏‏‏‎‏‏‎‏‎‎‎‏‎‏‏‏‏‏‎‎‎‏‏‎‎‏‎‏‎‎‏‎‎‎‏‏‏‎‎‎‎‏‎‏‎Resume‎‏‎‎‏‎"</string>
     <string name="controls_error_timeout" msgid="794197289772728958">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‎‏‎‏‏‎‎‎‎‎‏‎‏‏‎‎‎‏‏‏‎‎‎‏‏‏‎‏‎‎‎‏‎‏‎‏‎‎‏‏‏‏‎‏‏‎‏‎‎‎‎‏‎‎‏‏‏‏‏‏‎‎Inactive, check app‎‏‎‎‏‎"</string>
     <string name="controls_error_retryable" msgid="864025882878378470">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‎‏‎‏‏‏‏‏‏‏‏‎‏‏‎‏‎‎‎‏‎‏‏‏‏‎‏‏‎‎‏‏‏‎‎‎‏‏‎‏‏‎‏‎‏‏‎‎‎‎‎‎‏‏‏‏‎‎‏‏‎‎Error, retrying…‎‏‎‎‏‎"</string>
-    <!-- no translation found for controls_error_removed (6299213591234723805) -->
-    <skip />
+    <string name="controls_error_removed" msgid="6675638069846014366">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‏‏‏‎‎‏‎‏‎‎‏‎‎‏‎‏‎‎‎‎‏‎‏‏‏‎‏‎‎‏‎‎‏‏‎‏‎‎‎‏‏‏‏‏‎‏‏‏‏‏‎‎‏‏‎‎‏‏‏‏‎‎Not found‎‏‎‎‏‎"</string>
+    <string name="controls_error_removed_title" msgid="1207794911208047818">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‏‏‎‎‎‎‏‏‎‎‎‎‏‎‏‏‏‏‎‎‏‏‎‎‎‏‎‎‏‎‏‎‎‏‎‏‎‎‎‎‎‏‎‏‎‎‏‎‎‎‎‏‎‎‏‏‎‎‏‎‏‎‎Control is unavailable‎‏‎‎‏‎"</string>
+    <string name="controls_error_removed_message" msgid="2885911717034750542">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‎‏‎‎‎‎‎‎‎‏‏‎‎‏‏‎‏‎‎‎‏‎‏‏‎‏‎‏‎‏‎‎‏‏‎‏‎‏‏‏‏‏‏‏‎‎‏‏‏‎‎‏‎‎‏‎‎‏‏‏‎‎Couldn’t access ‎‏‎‎‏‏‎<xliff:g id="DEVICE">%1$s</xliff:g>‎‏‎‎‏‏‏‎. Check the ‎‏‎‎‏‏‎<xliff:g id="APPLICATION">%2$s</xliff:g>‎‏‎‎‏‏‏‎ app to make sure the control is still available and that the app settings haven’t changed.‎‏‎‎‏‎"</string>
+    <string name="controls_open_app" msgid="483650971094300141">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‎‏‏‏‏‎‏‎‏‏‎‏‏‎‎‏‎‎‎‏‎‏‏‏‏‏‏‏‏‎‏‏‏‎‎‏‏‏‎‏‎‏‏‎‎‏‎‎‏‏‎‏‎‏‏‏‏‎‏‏‎‏‎Open app‎‏‎‎‏‎"</string>
     <string name="controls_error_generic" msgid="352500456918362905">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‎‏‏‏‎‎‏‏‏‎‎‏‎‎‎‏‎‏‎‏‎‏‎‏‎‎‏‏‎‎‎‏‎‎‎‏‎‏‏‏‎‎‏‎‎‎‎‎‏‎‏‎‏‏‎‎‎‏‏‎‎‏‎Can’t load status‎‏‎‎‏‎"</string>
     <string name="controls_error_failed" msgid="960228639198558525">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‎‏‏‎‏‎‏‎‏‎‎‏‏‎‏‏‎‏‎‏‎‏‏‎‏‏‏‎‎‎‎‎‏‏‏‏‎‏‎‎‏‎‏‏‎‎‎‏‏‏‎‎‏‎‎‏‏‏‏‎‏‎Error, try again‎‏‎‎‏‎"</string>
     <string name="controls_in_progress" msgid="4421080500238215939">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‏‏‏‎‏‎‏‎‏‏‎‏‎‏‏‎‏‎‏‎‏‎‏‎‎‏‎‏‎‏‎‎‎‎‏‎‎‎‎‎‏‏‎‏‎‏‏‏‎‏‎‏‏‎‎‎‎‎‎‏‏‎In progress‎‏‎‎‏‎"</string>
diff --git a/packages/SystemUI/res/values-es-rUS/strings.xml b/packages/SystemUI/res/values-es-rUS/strings.xml
index b1a7427..b4bba8f 100644
--- a/packages/SystemUI/res/values-es-rUS/strings.xml
+++ b/packages/SystemUI/res/values-es-rUS/strings.xml
@@ -146,7 +146,7 @@
     <string name="biometric_dialog_face_icon_description_authenticating" msgid="3401633342366146535">"Buscando tu rostro"</string>
     <string name="biometric_dialog_face_icon_description_authenticated" msgid="2242167416140740920">"Se autenticó el rostro"</string>
     <string name="biometric_dialog_face_icon_description_confirmed" msgid="7918067993953940778">"Confirmado"</string>
-    <string name="biometric_dialog_tap_confirm" msgid="9166350738859143358">"Presiona Confirmar para completarla"</string>
+    <string name="biometric_dialog_tap_confirm" msgid="9166350738859143358">"Presiona Confirmar para completar"</string>
     <string name="biometric_dialog_authenticated" msgid="7337147327545272484">"Autenticado"</string>
     <string name="biometric_dialog_use_pin" msgid="8385294115283000709">"Usar PIN"</string>
     <string name="biometric_dialog_use_pattern" msgid="2315593393167211194">"Usar patrón"</string>
@@ -510,7 +510,7 @@
     <string name="clear_all_notifications_text" msgid="348312370303046130">"Borrar todo"</string>
     <string name="manage_notifications_text" msgid="6885645344647733116">"Administrar"</string>
     <string name="manage_notifications_history_text" msgid="57055985396576230">"Historial"</string>
-    <string name="notification_section_header_incoming" msgid="5295312809341711367">"Entrante"</string>
+    <string name="notification_section_header_incoming" msgid="850925217908095197">"Nuevo"</string>
     <string name="notification_section_header_gentle" msgid="6804099527336337197">"Silenciadas"</string>
     <string name="notification_section_header_alerting" msgid="5581175033680477651">"Notificaciones"</string>
     <string name="notification_section_header_conversations" msgid="821834744538345661">"Conversaciones"</string>
@@ -1002,7 +1002,7 @@
     <string name="bubble_accessibility_action_move_top_right" msgid="6916868852433483569">"Ubicar arriba a la derecha"</string>
     <string name="bubble_accessibility_action_move_bottom_left" msgid="6339015902495504715">"Ubicar abajo a la izquierda"</string>
     <string name="bubble_accessibility_action_move_bottom_right" msgid="7471571700628346212">"Ubicar abajo a la derecha"</string>
-    <string name="bubble_dismiss_text" msgid="7071770411580452911">"Ignorar"</string>
+    <string name="bubble_dismiss_text" msgid="1314082410868930066">"Descartar burbuja"</string>
     <string name="bubbles_dont_bubble_conversation" msgid="1033040343437428822">"No mostrar la conversación en burbujas"</string>
     <string name="bubbles_user_education_title" msgid="5547017089271445797">"Chat con burbujas"</string>
     <string name="bubbles_user_education_description" msgid="1160281719576715211">"Las conversaciones nuevas aparecen como elementos flotantes o burbujas. Presiona para abrir la burbuja. Arrástrala para moverla."</string>
@@ -1013,17 +1013,14 @@
     <string name="notification_content_system_nav_changed" msgid="5077913144844684544">"Se actualizó el sistema de navegación. Para hacer cambios, ve a Configuración."</string>
     <string name="notification_content_gesture_nav_available" msgid="4431460803004659888">"Ve a Configuración para actualizar la navegación del sistema"</string>
     <string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"En espera"</string>
-    <!-- no translation found for priority_onboarding_title (2893070698479227616) -->
-    <skip />
-    <!-- no translation found for priority_onboarding_behavior (5342816047020432929) -->
-    <skip />
+    <string name="priority_onboarding_title" msgid="2893070698479227616">"Se estableció la conversación como prioritaria"</string>
+    <string name="priority_onboarding_behavior" msgid="5342816047020432929">"Las conversaciones prioritarias harán lo siguiente:"</string>
     <string name="priority_onboarding_show_at_top_text" msgid="1678400241025513541">"Se muestran en la parte superior de conversaciones"</string>
     <string name="priority_onboarding_show_avatar_text" msgid="5756291381124091508">"Muestran una foto de perfil en pantalla de bloqueo"</string>
     <string name="priority_onboarding_appear_as_bubble_text" msgid="4227039772250263122">"Aparecen como burbujas flotantes encima de apps"</string>
     <string name="priority_onboarding_ignores_dnd_text" msgid="2918952762719600529">"Suspender No interrumpir"</string>
     <string name="priority_onboarding_done_button_title" msgid="4569550984286506007">"Entendido"</string>
-    <!-- no translation found for priority_onboarding_settings_button_title (6663601574303585927) -->
-    <skip />
+    <string name="priority_onboarding_settings_button_title" msgid="6663601574303585927">"Configuración"</string>
     <string name="magnification_overlay_title" msgid="6584179429612427958">"Ventana superpuesta de ampliación"</string>
     <string name="magnification_window_title" msgid="4863914360847258333">"Ventana de ampliación"</string>
     <string name="magnification_controls_title" msgid="8421106606708891519">"Controles de ampliación de la ventana"</string>
@@ -1065,9 +1062,13 @@
     <string name="controls_structure_tooltip" msgid="4355922222944447867">"Desliza el dedo para ver más elementos"</string>
     <string name="controls_seeding_in_progress" msgid="3033855341410264148">"Cargando recomendaciones"</string>
     <string name="controls_media_close_session" msgid="9023534788828414585">"Cerrar esta sesión multimedia"</string>
+    <string name="controls_media_resume" msgid="1933520684481586053">"Reanudar"</string>
     <string name="controls_error_timeout" msgid="794197289772728958">"Inactivo. Verifica la app"</string>
     <string name="controls_error_retryable" msgid="864025882878378470">"Hubo un error. Reintentando…"</string>
-    <string name="controls_error_removed" msgid="6299213591234723805">"Se quitó el dispositivo"</string>
+    <string name="controls_error_removed" msgid="6675638069846014366">"No se encontró"</string>
+    <string name="controls_error_removed_title" msgid="1207794911208047818">"El control no está disponible."</string>
+    <string name="controls_error_removed_message" msgid="2885911717034750542">"No se pudo acceder a <xliff:g id="DEVICE">%1$s</xliff:g>. Revisa la app de <xliff:g id="APPLICATION">%2$s</xliff:g> para asegurarte de que el control siga estando disponible y de que no haya cambiado la configuración de la app."</string>
+    <string name="controls_open_app" msgid="483650971094300141">"Abrir app"</string>
     <string name="controls_error_generic" msgid="352500456918362905">"No se pudo cargar el estado"</string>
     <string name="controls_error_failed" msgid="960228639198558525">"Error. Vuelve a intentarlo."</string>
     <string name="controls_in_progress" msgid="4421080500238215939">"En curso"</string>
diff --git a/packages/SystemUI/res/values-es/strings.xml b/packages/SystemUI/res/values-es/strings.xml
index f210fbb..6ffed58 100644
--- a/packages/SystemUI/res/values-es/strings.xml
+++ b/packages/SystemUI/res/values-es/strings.xml
@@ -448,7 +448,7 @@
     <string name="zen_alarms_introduction" msgid="3987266042682300470">"No te molestarán los sonidos ni las vibraciones, excepto las alarmas. Seguirás escuchando el contenido que quieras reproducir, como música, vídeos y juegos."</string>
     <string name="zen_priority_customize_button" msgid="4119213187257195047">"Personalizar"</string>
     <string name="zen_silence_introduction_voice" msgid="853573681302712348">"Esta opción bloqueará TODOS los sonidos y todas las vibraciones, por ejemplo, los vídeos, los juegos, las alarmas y la música. Seguirás pudiendo hacer llamadas."</string>
-    <string name="zen_silence_introduction" msgid="6117517737057344014">"Este modo permite bloquear TODOS los sonidos y todas las vibraciones (p. ej., los de alarmas, música, vídeos y juegos)."</string>
+    <string name="zen_silence_introduction" msgid="6117517737057344014">"Este modo bloquea TODOS los sonidos y todas las vibraciones, lo que incluye alarmas, música, vídeos y juegos."</string>
     <string name="keyguard_more_overflow_text" msgid="5819512373606638727">"+<xliff:g id="NUMBER_OF_NOTIFICATIONS">%d</xliff:g>"</string>
     <string name="speed_bump_explanation" msgid="7248696377626341060">"Notificaciones menos urgente abajo"</string>
     <string name="notification_tap_again" msgid="4477318164947497249">"Toca de nuevo para abrir"</string>
@@ -510,7 +510,7 @@
     <string name="clear_all_notifications_text" msgid="348312370303046130">"Borrar todo"</string>
     <string name="manage_notifications_text" msgid="6885645344647733116">"Gestionar"</string>
     <string name="manage_notifications_history_text" msgid="57055985396576230">"Historial"</string>
-    <string name="notification_section_header_incoming" msgid="5295312809341711367">"Entrantes"</string>
+    <string name="notification_section_header_incoming" msgid="850925217908095197">"Nuevas"</string>
     <string name="notification_section_header_gentle" msgid="6804099527336337197">"Silenciadas"</string>
     <string name="notification_section_header_alerting" msgid="5581175033680477651">"Notificaciones"</string>
     <string name="notification_section_header_conversations" msgid="821834744538345661">"Conversaciones"</string>
@@ -593,16 +593,16 @@
     <string name="volume_odi_captions_hint_disable" msgid="2518846326748183407">"desactivar"</string>
     <string name="accessibility_output_chooser" msgid="7807898688967194183">"Cambiar dispositivo de salida"</string>
     <string name="screen_pinning_title" msgid="9058007390337841305">"La aplicación está fijada"</string>
-    <string name="screen_pinning_description" msgid="8699395373875667743">"La pantalla se mantiene visible hasta que dejas de fijarla. Para ello, mantén pulsados los botones Atrás y Aplicaciones recientes."</string>
-    <string name="screen_pinning_description_recents_invisible" msgid="4564466648700390037">"La pantalla se mantiene visible hasta que dejas de fijarla. Para ello, mantén pulsados los botones Atrás e Inicio."</string>
-    <string name="screen_pinning_description_gestural" msgid="7246323931831232068">"Se mantiene visible hasta que dejas de fijarla. Para ello, desliza el dedo hacia arriba y mantén pulsado."</string>
-    <string name="screen_pinning_description_accessible" msgid="7386449191953535332">"La pantalla se mantiene visible hasta que dejas de fijarla. Para ello, mantén pulsado el botón Aplicaciones recientes."</string>
-    <string name="screen_pinning_description_recents_invisible_accessible" msgid="2857071808674481986">"La pantalla se mantiene visible hasta que dejas de fijarla. Para ello, mantén pulsado el botón Inicio."</string>
-    <string name="screen_pinning_exposes_personal_data" msgid="8189852022981524789">"Es posible que se revelen datos personales, como contactos o el contenido de correos."</string>
+    <string name="screen_pinning_description" msgid="8699395373875667743">"La pantalla se mantendrá visible hasta que dejes de fijarla. Para dejar de fijarla, mantén pulsados los botones Atrás y Aplicaciones recientes."</string>
+    <string name="screen_pinning_description_recents_invisible" msgid="4564466648700390037">"La pantalla se mantendrá visible hasta que dejes de fijarla. Para dejar de fijarla, mantén pulsados los botones Atrás e Inicio."</string>
+    <string name="screen_pinning_description_gestural" msgid="7246323931831232068">"La pantalla se mantendrá visible hasta que dejes de fijarla. Para dejar de fijarla, desliza el dedo hacia arriba y mantenlo pulsado."</string>
+    <string name="screen_pinning_description_accessible" msgid="7386449191953535332">"La pantalla se mantendrá visible hasta que dejes de fijarla. Para dejar de fijarla, mantén pulsado el botón Aplicaciones recientes."</string>
+    <string name="screen_pinning_description_recents_invisible_accessible" msgid="2857071808674481986">"La pantalla se mantendrá visible hasta que dejes de fijarla. Para dejar de fijarla, mantén pulsado el botón Inicio."</string>
+    <string name="screen_pinning_exposes_personal_data" msgid="8189852022981524789">"Es posible que se pueda acceder a datos personales, como contactos o el contenido de correos."</string>
     <string name="screen_pinning_can_open_other_apps" msgid="7529756813231421455">"Se pueden abrir otras aplicaciones desde aplicaciones fijadas."</string>
     <string name="screen_pinning_toast" msgid="8177286912533744328">"Para dejar de fijar esta aplicación, mantén pulsados los botones Atrás y Aplicaciones recientes"</string>
     <string name="screen_pinning_toast_recents_invisible" msgid="6850978077443052594">"Para dejar de fijar esta aplicación, mantén pulsados los botones Atrás e Inicio"</string>
-    <string name="screen_pinning_toast_gesture_nav" msgid="170699893395336705">"Para dejar de fijar esta aplicación, desliza el dedo hacia arriba y mantenlo pulsado"</string>
+    <string name="screen_pinning_toast_gesture_nav" msgid="170699893395336705">"Para dejar de fijar esta aplicación, desliza el dedo hacia arriba y no lo separes de la pantalla."</string>
     <string name="screen_pinning_positive" msgid="3285785989665266984">"Entendido"</string>
     <string name="screen_pinning_negative" msgid="6882816864569211666">"No, gracias"</string>
     <string name="screen_pinning_start" msgid="7483998671383371313">"Aplicación fijada"</string>
@@ -1002,10 +1002,10 @@
     <string name="bubble_accessibility_action_move_top_right" msgid="6916868852433483569">"Mover arriba a la derecha"</string>
     <string name="bubble_accessibility_action_move_bottom_left" msgid="6339015902495504715">"Mover abajo a la izquierda."</string>
     <string name="bubble_accessibility_action_move_bottom_right" msgid="7471571700628346212">"Mover abajo a la derecha"</string>
-    <string name="bubble_dismiss_text" msgid="7071770411580452911">"Cerrar"</string>
+    <string name="bubble_dismiss_text" msgid="1314082410868930066">"Cerrar burbuja"</string>
     <string name="bubbles_dont_bubble_conversation" msgid="1033040343437428822">"No mostrar conversación en burbujas"</string>
-    <string name="bubbles_user_education_title" msgid="5547017089271445797">"Chatear mediante burbujas"</string>
-    <string name="bubbles_user_education_description" msgid="1160281719576715211">"Las conversaciones nuevas aparecen como iconos flotantes o burbujas. Toca para abrir la burbuja. Arrastra para moverla."</string>
+    <string name="bubbles_user_education_title" msgid="5547017089271445797">"Chatea con burbujas"</string>
+    <string name="bubbles_user_education_description" msgid="1160281719576715211">"Las conversaciones nuevas aparecen como iconos flotantes llamadas \"burbujas\". Toca para abrir la burbuja. Arrastra para moverla."</string>
     <string name="bubbles_user_education_manage_title" msgid="2848511858160342320">"Controla las burbujas en cualquier momento"</string>
     <string name="bubbles_user_education_manage" msgid="1391639189507036423">"Toca Gestionar para desactivar las burbujas de esta aplicación"</string>
     <string name="bubbles_user_education_got_it" msgid="8282812431953161143">"Entendido"</string>
@@ -1016,7 +1016,7 @@
     <string name="priority_onboarding_title" msgid="2893070698479227616">"Conversación marcada como prioritaria"</string>
     <string name="priority_onboarding_behavior" msgid="5342816047020432929">"Las conversaciones prioritarias:"</string>
     <string name="priority_onboarding_show_at_top_text" msgid="1678400241025513541">"Se muestran en la parte superior de la sección de conversaciones"</string>
-    <string name="priority_onboarding_show_avatar_text" msgid="5756291381124091508">"Muestran tu imagen de perfil en la pantalla de bloqueo"</string>
+    <string name="priority_onboarding_show_avatar_text" msgid="5756291381124091508">"Muestran la imagen de perfil en la pantalla de bloqueo"</string>
     <string name="priority_onboarding_appear_as_bubble_text" msgid="4227039772250263122">"Aparecen como burbuja sobre las aplicaciones"</string>
     <string name="priority_onboarding_ignores_dnd_text" msgid="2918952762719600529">"Interrumpen el modo No molestar"</string>
     <string name="priority_onboarding_done_button_title" msgid="4569550984286506007">"Entendido"</string>
@@ -1062,9 +1062,13 @@
     <string name="controls_structure_tooltip" msgid="4355922222944447867">"Desliza el dedo para ver más"</string>
     <string name="controls_seeding_in_progress" msgid="3033855341410264148">"Cargando recomendaciones"</string>
     <string name="controls_media_close_session" msgid="9023534788828414585">"Cerrar esta sesión multimedia"</string>
+    <string name="controls_media_resume" msgid="1933520684481586053">"Reanudar"</string>
     <string name="controls_error_timeout" msgid="794197289772728958">"Inactivo, comprobar aplicación"</string>
     <string name="controls_error_retryable" msgid="864025882878378470">"Error; reintentando…"</string>
-    <string name="controls_error_removed" msgid="6299213591234723805">"Dispositivo quitado"</string>
+    <string name="controls_error_removed" msgid="6675638069846014366">"No se ha encontrado"</string>
+    <string name="controls_error_removed_title" msgid="1207794911208047818">"El control no está disponible"</string>
+    <string name="controls_error_removed_message" msgid="2885911717034750542">"No se ha podido acceder a <xliff:g id="DEVICE">%1$s</xliff:g>. Comprueba que el control siga disponible en la aplicación <xliff:g id="APPLICATION">%2$s</xliff:g> y que no se haya modificado su configuración."</string>
+    <string name="controls_open_app" msgid="483650971094300141">"Abrir aplicación"</string>
     <string name="controls_error_generic" msgid="352500456918362905">"No se ha podido cargar el estado"</string>
     <string name="controls_error_failed" msgid="960228639198558525">"Se ha producido un error. Vuelve a intentarlo."</string>
     <string name="controls_in_progress" msgid="4421080500238215939">"En curso"</string>
diff --git a/packages/SystemUI/res/values-et/strings.xml b/packages/SystemUI/res/values-et/strings.xml
index 0d640e1..258bf5a 100644
--- a/packages/SystemUI/res/values-et/strings.xml
+++ b/packages/SystemUI/res/values-et/strings.xml
@@ -92,7 +92,7 @@
     <string name="screenrecord_background_processing_label" msgid="7244617554884238898">"Ekraanisalvestuse töötlemine"</string>
     <string name="screenrecord_channel_description" msgid="4147077128486138351">"Pooleli märguanne ekraanikuva salvestamise seansi puhul"</string>
     <string name="screenrecord_start_label" msgid="1750350278888217473">"Kas alustada salvestamist?"</string>
-    <string name="screenrecord_description" msgid="1123231719680353736">"Heli salvestamise ajal võib Androidi süsteem jäädvustada tundlikku teavet, mis on ekraanikuval nähtav või mida seadmes esitatakse. See hõlmab paroole, makseteavet, fotosid, sõnumeid ja heli."</string>
+    <string name="screenrecord_description" msgid="1123231719680353736">"Salvestamise ajal võib Androidi süsteem jäädvustada tundlikku teavet, mis on ekraanikuval nähtav või mida seadmes esitatakse. See hõlmab paroole, makseteavet, fotosid, sõnumeid ja heli."</string>
     <string name="screenrecord_audio_label" msgid="6183558856175159629">"Heli salvestamine"</string>
     <string name="screenrecord_device_audio_label" msgid="9016927171280567791">"Seadme heli"</string>
     <string name="screenrecord_device_audio_description" msgid="4922694220572186193">"Seadmest pärinev heli, nt muusika, kõned ja helinad"</string>
@@ -510,7 +510,7 @@
     <string name="clear_all_notifications_text" msgid="348312370303046130">"Tühjenda kõik"</string>
     <string name="manage_notifications_text" msgid="6885645344647733116">"Haldamine"</string>
     <string name="manage_notifications_history_text" msgid="57055985396576230">"Ajalugu"</string>
-    <string name="notification_section_header_incoming" msgid="5295312809341711367">"Sissetulevad"</string>
+    <string name="notification_section_header_incoming" msgid="850925217908095197">"Uued"</string>
     <string name="notification_section_header_gentle" msgid="6804099527336337197">"Hääletu"</string>
     <string name="notification_section_header_alerting" msgid="5581175033680477651">"Märguanded"</string>
     <string name="notification_section_header_conversations" msgid="821834744538345661">"Vestlused"</string>
@@ -1002,7 +1002,7 @@
     <string name="bubble_accessibility_action_move_top_right" msgid="6916868852433483569">"Teisalda üles paremale"</string>
     <string name="bubble_accessibility_action_move_bottom_left" msgid="6339015902495504715">"Teisalda alla vasakule"</string>
     <string name="bubble_accessibility_action_move_bottom_right" msgid="7471571700628346212">"Teisalda alla paremale"</string>
-    <string name="bubble_dismiss_text" msgid="7071770411580452911">"Loobu"</string>
+    <string name="bubble_dismiss_text" msgid="1314082410868930066">"Sule mull"</string>
     <string name="bubbles_dont_bubble_conversation" msgid="1033040343437428822">"Ära kuva vestlust mullina"</string>
     <string name="bubbles_user_education_title" msgid="5547017089271445797">"Vestelge mullide abil"</string>
     <string name="bubbles_user_education_description" msgid="1160281719576715211">"Uued vestlused kuvatakse hõljuvate ikoonidena ehk mullidena. Puudutage mulli avamiseks. Lohistage mulli, et seda liigutada."</string>
@@ -1062,9 +1062,13 @@
     <string name="controls_structure_tooltip" msgid="4355922222944447867">"Pühkige sõrmega, et näha rohkem"</string>
     <string name="controls_seeding_in_progress" msgid="3033855341410264148">"Soovituste laadimine"</string>
     <string name="controls_media_close_session" msgid="9023534788828414585">"Sulge see meediaseanss"</string>
+    <string name="controls_media_resume" msgid="1933520684481586053">"Jätka"</string>
     <string name="controls_error_timeout" msgid="794197289772728958">"Passiivne, vaadake rakendust"</string>
     <string name="controls_error_retryable" msgid="864025882878378470">"Viga, proovitakse uuesti …"</string>
-    <string name="controls_error_removed" msgid="6299213591234723805">"Seade on eemaldatud"</string>
+    <string name="controls_error_removed" msgid="6675638069846014366">"Ei leitud"</string>
+    <string name="controls_error_removed_title" msgid="1207794911208047818">"Juhtelement pole saadaval"</string>
+    <string name="controls_error_removed_message" msgid="2885911717034750542">"Seadmele <xliff:g id="DEVICE">%1$s</xliff:g> ei pääsenud juurde. Kontrollige rakendust <xliff:g id="APPLICATION">%2$s</xliff:g> ja veenduge, et juhtelement oleks endiselt saadaval ning rakenduse seaded poleks muutunud."</string>
+    <string name="controls_open_app" msgid="483650971094300141">"Ava rakendus"</string>
     <string name="controls_error_generic" msgid="352500456918362905">"Olekut ei saa laadida"</string>
     <string name="controls_error_failed" msgid="960228639198558525">"Ilmnes viga, proovige uuesti"</string>
     <string name="controls_in_progress" msgid="4421080500238215939">"Pooleli"</string>
diff --git a/packages/SystemUI/res/values-eu/strings.xml b/packages/SystemUI/res/values-eu/strings.xml
index 1cb3148..cb6f796 100644
--- a/packages/SystemUI/res/values-eu/strings.xml
+++ b/packages/SystemUI/res/values-eu/strings.xml
@@ -92,7 +92,7 @@
     <string name="screenrecord_background_processing_label" msgid="7244617554884238898">"Pantaila-grabaketa prozesatzen"</string>
     <string name="screenrecord_channel_description" msgid="4147077128486138351">"Pantailaren grabaketa-saioaren jakinarazpen jarraitua"</string>
     <string name="screenrecord_start_label" msgid="1750350278888217473">"Grabatzen hasi nahi duzu?"</string>
-    <string name="screenrecord_description" msgid="1123231719680353736">"Pantaila grabatzen duzun bitartean, Android sistemak detektatu egin dezake pantailan agertzen den edo gailuak erreproduzitzen duen kontuzko informazioa; besteak beste, pasahitzak, ordainketen informazioa, argazkiak, mezuak eta audioak."</string>
+    <string name="screenrecord_description" msgid="1123231719680353736">"Pantaila grabatzen duzun bitartean, Android sistemak detektatu egin dezake pantailan agertzen den edo gailuak erreproduzitzen duen kontuzko informazioa; besteak beste, pasahitzak, ordainketa-informazioa, argazkiak, mezuak eta audioa."</string>
     <string name="screenrecord_audio_label" msgid="6183558856175159629">"Grabatu audioa"</string>
     <string name="screenrecord_device_audio_label" msgid="9016927171280567791">"Gailuaren audioa"</string>
     <string name="screenrecord_device_audio_description" msgid="4922694220572186193">"Gailuko soinuak; adibidez, musika, deiak eta tonuak"</string>
@@ -279,12 +279,12 @@
     <string name="accessibility_quick_settings_dnd_changed_off" msgid="1457150026842505799">"Desaktibatu egin da ez molestatzeko modua."</string>
     <string name="accessibility_quick_settings_dnd_changed_on" msgid="186315911607486129">"Aktibatu egin da ez molestatzeko modua."</string>
     <string name="accessibility_quick_settings_bluetooth" msgid="8250942386687551283">"Bluetooth-a."</string>
-    <string name="accessibility_quick_settings_bluetooth_off" msgid="3795983516942423240">"Bluetooth konexioa desaktibatuta dago."</string>
-    <string name="accessibility_quick_settings_bluetooth_on" msgid="3819082137684078013">"Bluetooth konexioa aktibatuta dago."</string>
+    <string name="accessibility_quick_settings_bluetooth_off" msgid="3795983516942423240">"Bluetooth bidezko konexioa desaktibatuta dago."</string>
+    <string name="accessibility_quick_settings_bluetooth_on" msgid="3819082137684078013">"Bluetooth bidezko konexioa aktibatuta dago."</string>
     <string name="accessibility_quick_settings_bluetooth_connecting" msgid="7362294657419149294">"Bluetooth bidez konektatzen ari da."</string>
     <string name="accessibility_quick_settings_bluetooth_connected" msgid="5237625393869747261">"Bluetooth bidez konektatuta dago."</string>
-    <string name="accessibility_quick_settings_bluetooth_changed_off" msgid="3344226652293797283">"Bluetooth konexioa desaktibatu egin da."</string>
-    <string name="accessibility_quick_settings_bluetooth_changed_on" msgid="1263282011749437549">"Bluetooth konexioa aktibatu egin da."</string>
+    <string name="accessibility_quick_settings_bluetooth_changed_off" msgid="3344226652293797283">"Bluetooth bidezko konexioa desaktibatu egin da."</string>
+    <string name="accessibility_quick_settings_bluetooth_changed_on" msgid="1263282011749437549">"Bluetooth bidezko konexioa aktibatu egin da."</string>
     <string name="accessibility_quick_settings_location_off" msgid="6122523378294740598">"Kokapena hautemateko aukera desaktibatuta dago."</string>
     <string name="accessibility_quick_settings_location_on" msgid="6869947200325467243">"Kokapena hautemateko aukera aktibatuta dago."</string>
     <string name="accessibility_quick_settings_location_changed_off" msgid="5132776369388699133">"Kokapena hautemateko aukera desaktibatu egin da."</string>
@@ -510,7 +510,7 @@
     <string name="clear_all_notifications_text" msgid="348312370303046130">"Garbitu guztiak"</string>
     <string name="manage_notifications_text" msgid="6885645344647733116">"Kudeatu"</string>
     <string name="manage_notifications_history_text" msgid="57055985396576230">"Historia"</string>
-    <string name="notification_section_header_incoming" msgid="5295312809341711367">"Jasotako azkenak"</string>
+    <string name="notification_section_header_incoming" msgid="850925217908095197">"Berria"</string>
     <string name="notification_section_header_gentle" msgid="6804099527336337197">"Isila"</string>
     <string name="notification_section_header_alerting" msgid="5581175033680477651">"Jakinarazpenak"</string>
     <string name="notification_section_header_conversations" msgid="821834744538345661">"Elkarrizketak"</string>
@@ -595,11 +595,11 @@
     <string name="screen_pinning_title" msgid="9058007390337841305">"Aplikazioa ainguratuta dago"</string>
     <string name="screen_pinning_description" msgid="8699395373875667743">"Horrela, ikusgai egongo da aingura kendu arte. Aingura kentzeko, eduki sakatuta \"Atzera\" eta \"Ikuspegi orokorra\" botoiak."</string>
     <string name="screen_pinning_description_recents_invisible" msgid="4564466648700390037">"Horrela, ikusgai egongo da aingura kendu arte. Aingura kentzeko, eduki sakatuta Atzera eta Hasiera botoiak."</string>
-    <string name="screen_pinning_description_gestural" msgid="7246323931831232068">"Horrela, ikusgai egongo da aingura kendu arte. Aingura kentzeko, eduki sakatuta Hasiera botoia."</string>
+    <string name="screen_pinning_description_gestural" msgid="7246323931831232068">"Horrela, ikusgai egongo da aingura kendu arte. Aingura kentzeko, pasatu hatza gora eduki ezazu sakatuta."</string>
     <string name="screen_pinning_description_accessible" msgid="7386449191953535332">"Horrela, ikusgai egongo da aingura kendu arte. Aingura kentzeko, eduki sakatuta \"Ikuspegi orokorra\" botoia."</string>
     <string name="screen_pinning_description_recents_invisible_accessible" msgid="2857071808674481986">"Horrela, ikusgai egongo da aingura kendu arte. Aingura kentzeko, eduki sakatuta Hasiera botoia."</string>
     <string name="screen_pinning_exposes_personal_data" msgid="8189852022981524789">"Baliteke datu pertsonalak atzitu ahal izatea (adibidez, kontaktuak eta posta elektronikoko edukia)."</string>
-    <string name="screen_pinning_can_open_other_apps" msgid="7529756813231421455">"Baliteke ainguratutako aplikazioak beste aplikazio batzuk irekitzeko gai izatea."</string>
+    <string name="screen_pinning_can_open_other_apps" msgid="7529756813231421455">"Baliteke ainguratutako aplikazioa beste aplikazio batzuk irekitzeko gai izatea."</string>
     <string name="screen_pinning_toast" msgid="8177286912533744328">"Aplikazioari aingura kentzeko, eduki sakatuta Atzera eta Ikuspegi orokorra botoiak"</string>
     <string name="screen_pinning_toast_recents_invisible" msgid="6850978077443052594">"Aplikazioari aingura kentzeko, eduki sakatuta Atzera eta Hasiera botoiak"</string>
     <string name="screen_pinning_toast_gesture_nav" msgid="170699893395336705">"Aplikazioari aingura kentzeko, arrastatu aplikazioa gora eta eduki ezazu sakatuta"</string>
@@ -624,7 +624,7 @@
     <string name="volume_ringer_status_vibrate" msgid="6970078708957857825">"Dardara"</string>
     <string name="volume_ringer_status_silent" msgid="3691324657849880883">"Ez jo tonua"</string>
     <string name="qs_status_phone_vibrate" msgid="7055409506885541979">"Telefonoaren dardara aktibatuta dago"</string>
-    <string name="qs_status_phone_muted" msgid="3763664791309544103">"Telefonoaren tonu-jotzailea desaktibatuta dago"</string>
+    <string name="qs_status_phone_muted" msgid="3763664791309544103">"Tonu-jotzailea desaktibatuta"</string>
     <string name="volume_stream_content_description_unmute" msgid="7729576371406792977">"%1$s. Sakatu audioa aktibatzeko."</string>
     <string name="volume_stream_content_description_vibrate" msgid="4858111994183089761">"%1$s. Sakatu dardara ezartzeko. Baliteke erabilerraztasun-eginbideen audioa desaktibatzea."</string>
     <string name="volume_stream_content_description_mute" msgid="4079046784917920984">"%1$s. Sakatu audioa desaktibatzeko. Baliteke erabilerraztasun-eginbideen audioa desaktibatzea."</string>
@@ -959,7 +959,7 @@
     <string name="mobile_data_text_format" msgid="6806501540022589786">"<xliff:g id="ID_1">%1$s</xliff:g> - <xliff:g id="ID_2">%2$s</xliff:g>"</string>
     <string name="mobile_carrier_text_format" msgid="8912204177152950766">"<xliff:g id="CARRIER_NAME">%1$s</xliff:g> (<xliff:g id="MOBILE_DATA_TYPE">%2$s</xliff:g>)"</string>
     <string name="wifi_is_off" msgid="5389597396308001471">"Wi-Fi konexioa desaktibatuta dago"</string>
-    <string name="bt_is_off" msgid="7436344904889461591">"Bluetooth konexioa desaktibatuta dago"</string>
+    <string name="bt_is_off" msgid="7436344904889461591">"Bluetooth bidezko konexioa desaktibatuta dago"</string>
     <string name="dnd_is_off" msgid="3185706903793094463">"Ez molestatzeko modua desaktibatuta dago"</string>
     <string name="qs_dnd_prompt_auto_rule" msgid="3535469468310002616">"Ez molestatzeko modua aktibatu du arau automatiko batek (<xliff:g id="ID_1">%s</xliff:g>)."</string>
     <string name="qs_dnd_prompt_app" msgid="4027984447935396820">"Ez molestatzeko modua aktibatu du aplikazio batek (<xliff:g id="ID_1">%s</xliff:g>)."</string>
@@ -1002,7 +1002,7 @@
     <string name="bubble_accessibility_action_move_top_right" msgid="6916868852433483569">"Eraman goialdera, eskuinetara"</string>
     <string name="bubble_accessibility_action_move_bottom_left" msgid="6339015902495504715">"Eraman behealdera, ezkerretara"</string>
     <string name="bubble_accessibility_action_move_bottom_right" msgid="7471571700628346212">"Eraman behealdera, eskuinetara"</string>
-    <string name="bubble_dismiss_text" msgid="7071770411580452911">"Baztertu"</string>
+    <string name="bubble_dismiss_text" msgid="1314082410868930066">"Baztertu burbuila"</string>
     <string name="bubbles_dont_bubble_conversation" msgid="1033040343437428822">"Ez erakutsi elkarrizketak burbuila gisa"</string>
     <string name="bubbles_user_education_title" msgid="5547017089271445797">"Txateatu burbuilen bidez"</string>
     <string name="bubbles_user_education_description" msgid="1160281719576715211">"Elkarrizketa berriak ikono gainerakor edo burbuila gisa agertzen dira. Sakatu burbuila irekitzeko. Arrasta ezazu mugitzeko."</string>
@@ -1062,9 +1062,13 @@
     <string name="controls_structure_tooltip" msgid="4355922222944447867">"Pasatu hatza aukera gehiago ikusteko"</string>
     <string name="controls_seeding_in_progress" msgid="3033855341410264148">"Gomendioak kargatzen"</string>
     <string name="controls_media_close_session" msgid="9023534788828414585">"Itxi multimedia-saio hau"</string>
+    <string name="controls_media_resume" msgid="1933520684481586053">"Berrekin"</string>
     <string name="controls_error_timeout" msgid="794197289772728958">"Inaktibo; egiaztatu aplikazioa"</string>
     <string name="controls_error_retryable" msgid="864025882878378470">"Errorea. Berriro saiatzen…"</string>
-    <string name="controls_error_removed" msgid="6299213591234723805">"Gailua kendu da"</string>
+    <string name="controls_error_removed" msgid="6675638069846014366">"Ez da aurkitu"</string>
+    <string name="controls_error_removed_title" msgid="1207794911208047818">"Ez dago erabilgarri kontrolatzeko aukera"</string>
+    <string name="controls_error_removed_message" msgid="2885911717034750542">"Ezin izan da atzitu <xliff:g id="DEVICE">%1$s</xliff:g>. Joan <xliff:g id="APPLICATION">%2$s</xliff:g> aplikaziora, eta ziurtatu kontrolatzeko aukera oraindik ere erabilgarri dagoela eta aplikazioaren ezarpenak ez direla aldatu."</string>
+    <string name="controls_open_app" msgid="483650971094300141">"Ireki aplikazioa"</string>
     <string name="controls_error_generic" msgid="352500456918362905">"Ezin da kargatu egoera"</string>
     <string name="controls_error_failed" msgid="960228639198558525">"Errorea. Saiatu berriro."</string>
     <string name="controls_in_progress" msgid="4421080500238215939">"Abian"</string>
diff --git a/packages/SystemUI/res/values-fa/strings.xml b/packages/SystemUI/res/values-fa/strings.xml
index 986015e..ae98244c 100644
--- a/packages/SystemUI/res/values-fa/strings.xml
+++ b/packages/SystemUI/res/values-fa/strings.xml
@@ -510,7 +510,7 @@
     <string name="clear_all_notifications_text" msgid="348312370303046130">"پاک کردن همه موارد"</string>
     <string name="manage_notifications_text" msgid="6885645344647733116">"مدیریت"</string>
     <string name="manage_notifications_history_text" msgid="57055985396576230">"سابقه"</string>
-    <string name="notification_section_header_incoming" msgid="5295312809341711367">"ورودی"</string>
+    <string name="notification_section_header_incoming" msgid="850925217908095197">"جدید"</string>
     <string name="notification_section_header_gentle" msgid="6804099527336337197">"بی‌صدا"</string>
     <string name="notification_section_header_alerting" msgid="5581175033680477651">"اعلان‌ها"</string>
     <string name="notification_section_header_conversations" msgid="821834744538345661">"مکالمه‌ها"</string>
@@ -595,10 +595,10 @@
     <string name="screen_pinning_title" msgid="9058007390337841305">"برنامه پین شده است"</string>
     <string name="screen_pinning_description" msgid="8699395373875667743">"تا زمانی که پین را بردارید، در نما نگه‌داشته می‌شود. برای برداشتن پین، «برگشت» و «نمای کلی» را لمس کنید و نگه‌دارید."</string>
     <string name="screen_pinning_description_recents_invisible" msgid="4564466648700390037">"تا برداشتن پین، در نما نگه‌داشته می‌شود. برای برداشتن پین، «برگشت» و «صفحه اصلی» را لمس کنید و نگه‌دارید."</string>
-    <string name="screen_pinning_description_gestural" msgid="7246323931831232068">"تا برداشتن پین، در نما نگه‌داشته می‌شود. برای برداشتن پین، از پایین صفحه تند به‌طرف بالا بکشید و نگه‌دارید."</string>
+    <string name="screen_pinning_description_gestural" msgid="7246323931831232068">"به این ترتیب تا زمانی پین آن را برندارید قابل‌مشاهده است. برای برداشتن پین، از پایین صفحه تند به‌طرف بالا بکشید و نگه دارید."</string>
     <string name="screen_pinning_description_accessible" msgid="7386449191953535332">"تا زمانی که پین را بردارید، در نما نگه‌داشته می‌شود. برای برداشتن پین، «نمای کلی» را لمس کنید و نگه‌دارید."</string>
     <string name="screen_pinning_description_recents_invisible_accessible" msgid="2857071808674481986">"تا برداشتن پین، در نما نگه‌داشته می‌شود. برای برداشتن پین، «صفحه اصلی» را لمس کنید و نگه‌دارید."</string>
-    <string name="screen_pinning_exposes_personal_data" msgid="8189852022981524789">"ممکن است داده‌های شخصی (مانند مخاطبین و محتوای ایمیل) دردسترس باشند."</string>
+    <string name="screen_pinning_exposes_personal_data" msgid="8189852022981524789">"ممکن است داده‌های شخصی (مانند مخاطبین و محتوای ایمیل) در دسترس باشد."</string>
     <string name="screen_pinning_can_open_other_apps" msgid="7529756813231421455">"برنامه پین‌شده ممکن است برنامه‌های دیگر را باز کند."</string>
     <string name="screen_pinning_toast" msgid="8177286912533744328">"برای برداشتن پین این برنامه، دکمه‌های «برگشت» و «نمای کلی» را لمس کنید و نگه‌دارید"</string>
     <string name="screen_pinning_toast_recents_invisible" msgid="6850978077443052594">"برای برداشتن پین این برنامه، دکمه‌های «برگشت» و «صفحه اصلی» را لمس کنید و نگه دارید"</string>
@@ -1002,7 +1002,7 @@
     <string name="bubble_accessibility_action_move_top_right" msgid="6916868852433483569">"انتقال به بالا سمت چپ"</string>
     <string name="bubble_accessibility_action_move_bottom_left" msgid="6339015902495504715">"انتقال به پایین سمت راست"</string>
     <string name="bubble_accessibility_action_move_bottom_right" msgid="7471571700628346212">"انتقال به پایین سمت چپ"</string>
-    <string name="bubble_dismiss_text" msgid="7071770411580452911">"رد کردن"</string>
+    <string name="bubble_dismiss_text" msgid="1314082410868930066">"رد کردن حبابک"</string>
     <string name="bubbles_dont_bubble_conversation" msgid="1033040343437428822">"مکالمه در حباب نشان داده نشود"</string>
     <string name="bubbles_user_education_title" msgid="5547017089271445797">"گپ بااستفاده از ابزارک اعلان"</string>
     <string name="bubbles_user_education_description" msgid="1160281719576715211">"مکالمه‌های جدید به‌صورت نمادهای شناور یا ابزارک اعلان نشان داده شوند. برای باز کردن ابزارک اعلان ضربه بزنید. برای جابه‌جایی، آن را بکشید."</string>
@@ -1062,9 +1062,13 @@
     <string name="controls_structure_tooltip" msgid="4355922222944447867">"برای دیدن موارد بیشتر، تند بکشید"</string>
     <string name="controls_seeding_in_progress" msgid="3033855341410264148">"درحال بار کردن توصیه‌ها"</string>
     <string name="controls_media_close_session" msgid="9023534788828414585">"بستن این جلسه رسانه"</string>
+    <string name="controls_media_resume" msgid="1933520684481586053">"ازسرگیری"</string>
     <string name="controls_error_timeout" msgid="794197289772728958">"غیرفعال، برنامه را بررسی کنید"</string>
     <string name="controls_error_retryable" msgid="864025882878378470">"خطا، درحال تلاش مجدد…"</string>
-    <string name="controls_error_removed" msgid="6299213591234723805">"دستگاه برداشته شد"</string>
+    <string name="controls_error_removed" msgid="6675638069846014366">"پیدا نشد"</string>
+    <string name="controls_error_removed_title" msgid="1207794911208047818">"کنترل دردسترس نیست"</string>
+    <string name="controls_error_removed_message" msgid="2885911717034750542">"دسترسی به <xliff:g id="DEVICE">%1$s</xliff:g> ممکن نیست. برنامه <xliff:g id="APPLICATION">%2$s</xliff:g> را بررسی کنید تا مطمئن شوید کنترل هنوز دردسترس باشد و تنظیمات برنامه تغییر نکرده باشد."</string>
+    <string name="controls_open_app" msgid="483650971094300141">"بازکردن برنامه"</string>
     <string name="controls_error_generic" msgid="352500456918362905">"وضعیت بار نشد"</string>
     <string name="controls_error_failed" msgid="960228639198558525">"خطا، دوباره امتحان کنید"</string>
     <string name="controls_in_progress" msgid="4421080500238215939">"درحال انجام"</string>
diff --git a/packages/SystemUI/res/values-fi/strings.xml b/packages/SystemUI/res/values-fi/strings.xml
index be04730..05a88f4 100644
--- a/packages/SystemUI/res/values-fi/strings.xml
+++ b/packages/SystemUI/res/values-fi/strings.xml
@@ -510,7 +510,7 @@
     <string name="clear_all_notifications_text" msgid="348312370303046130">"Poista kaikki"</string>
     <string name="manage_notifications_text" msgid="6885645344647733116">"Muuta asetuksia"</string>
     <string name="manage_notifications_history_text" msgid="57055985396576230">"Historia"</string>
-    <string name="notification_section_header_incoming" msgid="5295312809341711367">"Saapuvat"</string>
+    <string name="notification_section_header_incoming" msgid="850925217908095197">"Uudet"</string>
     <string name="notification_section_header_gentle" msgid="6804099527336337197">"Äänetön"</string>
     <string name="notification_section_header_alerting" msgid="5581175033680477651">"Ilmoitukset"</string>
     <string name="notification_section_header_conversations" msgid="821834744538345661">"Keskustelut"</string>
@@ -1002,7 +1002,7 @@
     <string name="bubble_accessibility_action_move_top_right" msgid="6916868852433483569">"Siirrä oikeaan yläreunaan"</string>
     <string name="bubble_accessibility_action_move_bottom_left" msgid="6339015902495504715">"Siirrä vasempaan alareunaan"</string>
     <string name="bubble_accessibility_action_move_bottom_right" msgid="7471571700628346212">"Siirrä oikeaan alareunaan"</string>
-    <string name="bubble_dismiss_text" msgid="7071770411580452911">"Ohita"</string>
+    <string name="bubble_dismiss_text" msgid="1314082410868930066">"Ohita kupla"</string>
     <string name="bubbles_dont_bubble_conversation" msgid="1033040343437428822">"Älä näytä kuplia keskusteluista"</string>
     <string name="bubbles_user_education_title" msgid="5547017089271445797">"Chattaile kuplien avulla"</string>
     <string name="bubbles_user_education_description" msgid="1160281719576715211">"Uudet keskustelut näkyvät kelluvina kuvakkeina tai kuplina. Avaa kupla napauttamalla. Siirrä sitä vetämällä."</string>
@@ -1062,9 +1062,13 @@
     <string name="controls_structure_tooltip" msgid="4355922222944447867">"Pyyhkäise nähdäksesi lisää"</string>
     <string name="controls_seeding_in_progress" msgid="3033855341410264148">"Ladataan suosituksia"</string>
     <string name="controls_media_close_session" msgid="9023534788828414585">"Sulje tämä median käyttökerta"</string>
+    <string name="controls_media_resume" msgid="1933520684481586053">"Jatka"</string>
     <string name="controls_error_timeout" msgid="794197289772728958">"Epäaktiivinen, tarkista sovellus"</string>
     <string name="controls_error_retryable" msgid="864025882878378470">"Virhe, yritetään uudelleen…"</string>
-    <string name="controls_error_removed" msgid="6299213591234723805">"Laite poistettu"</string>
+    <string name="controls_error_removed" msgid="6675638069846014366">"Ei löydy"</string>
+    <string name="controls_error_removed_title" msgid="1207794911208047818">"Ohjain ei ole käytettävissä"</string>
+    <string name="controls_error_removed_message" msgid="2885911717034750542">"Ei pääsyä: <xliff:g id="DEVICE">%1$s</xliff:g>. Avaa <xliff:g id="APPLICATION">%2$s</xliff:g> ja tarkista, että ohjain on edelleen käytettävissä ja että sovelluksen asetukset eivät ole muuttuneet."</string>
+    <string name="controls_open_app" msgid="483650971094300141">"Avaa sovellus"</string>
     <string name="controls_error_generic" msgid="352500456918362905">"Tilaa ei voi ladata"</string>
     <string name="controls_error_failed" msgid="960228639198558525">"Virhe, yritä uudelleen"</string>
     <string name="controls_in_progress" msgid="4421080500238215939">"Käynnissä"</string>
diff --git a/packages/SystemUI/res/values-fr-rCA/strings.xml b/packages/SystemUI/res/values-fr-rCA/strings.xml
index a80e2d3..e7ef082 100644
--- a/packages/SystemUI/res/values-fr-rCA/strings.xml
+++ b/packages/SystemUI/res/values-fr-rCA/strings.xml
@@ -510,7 +510,7 @@
     <string name="clear_all_notifications_text" msgid="348312370303046130">"Tout effacer"</string>
     <string name="manage_notifications_text" msgid="6885645344647733116">"Gérer"</string>
     <string name="manage_notifications_history_text" msgid="57055985396576230">"Historique"</string>
-    <string name="notification_section_header_incoming" msgid="5295312809341711367">"Entrantes"</string>
+    <string name="notification_section_header_incoming" msgid="850925217908095197">"Nouvelles"</string>
     <string name="notification_section_header_gentle" msgid="6804099527336337197">"Mode silencieux"</string>
     <string name="notification_section_header_alerting" msgid="5581175033680477651">"Notifications"</string>
     <string name="notification_section_header_conversations" msgid="821834744538345661">"Conversations"</string>
@@ -1002,7 +1002,7 @@
     <string name="bubble_accessibility_action_move_top_right" msgid="6916868852433483569">"Déplacer dans coin sup. droit"</string>
     <string name="bubble_accessibility_action_move_bottom_left" msgid="6339015902495504715">"Déplacer dans coin inf. gauche"</string>
     <string name="bubble_accessibility_action_move_bottom_right" msgid="7471571700628346212">"Déplacer dans coin inf. droit"</string>
-    <string name="bubble_dismiss_text" msgid="7071770411580452911">"Fermer"</string>
+    <string name="bubble_dismiss_text" msgid="1314082410868930066">"Ignorer la bulle"</string>
     <string name="bubbles_dont_bubble_conversation" msgid="1033040343437428822">"Ne pas afficher les conversations dans des bulles"</string>
     <string name="bubbles_user_education_title" msgid="5547017089271445797">"Clavarder en utilisant des bulles"</string>
     <string name="bubbles_user_education_description" msgid="1160281719576715211">"Les nouvelles conversations s\'affichent sous forme d\'icônes flottantes (de bulles). Touchez une bulle pour l\'ouvrir. Faites-la glisser pour la déplacer."</string>
@@ -1062,9 +1062,13 @@
     <string name="controls_structure_tooltip" msgid="4355922222944447867">"Balayez l\'écran pour en afficher davantage"</string>
     <string name="controls_seeding_in_progress" msgid="3033855341410264148">"Chargement des recommandations…"</string>
     <string name="controls_media_close_session" msgid="9023534788828414585">"Fermer cette session multimédia"</string>
+    <string name="controls_media_resume" msgid="1933520684481586053">"Reprendre"</string>
     <string name="controls_error_timeout" msgid="794197289772728958">"Délai expiré, vérifiez l\'appli"</string>
     <string name="controls_error_retryable" msgid="864025882878378470">"Erreur, nouvelle tentative…"</string>
-    <string name="controls_error_removed" msgid="6299213591234723805">"Appareil supprimé"</string>
+    <string name="controls_error_removed" msgid="6675638069846014366">"Introuvable"</string>
+    <string name="controls_error_removed_title" msgid="1207794911208047818">"La commande n\'est pas accessible"</string>
+    <string name="controls_error_removed_message" msgid="2885911717034750542">"Impossible d\'accéder à <xliff:g id="DEVICE">%1$s</xliff:g>. Vérifiez l\'application <xliff:g id="APPLICATION">%2$s</xliff:g> pour vous assurer que la commande est toujours offerte et que les paramètres de l\'application n\'ont pas changé."</string>
+    <string name="controls_open_app" msgid="483650971094300141">"Ouvrir l\'application"</string>
     <string name="controls_error_generic" msgid="352500456918362905">"Impossible de charger l\'état"</string>
     <string name="controls_error_failed" msgid="960228639198558525">"Erreur. Veuillez réessayer."</string>
     <string name="controls_in_progress" msgid="4421080500238215939">"En cours"</string>
diff --git a/packages/SystemUI/res/values-fr/strings.xml b/packages/SystemUI/res/values-fr/strings.xml
index b95cf57..c7d8872 100644
--- a/packages/SystemUI/res/values-fr/strings.xml
+++ b/packages/SystemUI/res/values-fr/strings.xml
@@ -510,7 +510,7 @@
     <string name="clear_all_notifications_text" msgid="348312370303046130">"Tout effacer"</string>
     <string name="manage_notifications_text" msgid="6885645344647733116">"Gérer"</string>
     <string name="manage_notifications_history_text" msgid="57055985396576230">"Historique"</string>
-    <string name="notification_section_header_incoming" msgid="5295312809341711367">"Notifications entrantes"</string>
+    <string name="notification_section_header_incoming" msgid="850925217908095197">"Nouvelles notifications"</string>
     <string name="notification_section_header_gentle" msgid="6804099527336337197">"Silencieuses"</string>
     <string name="notification_section_header_alerting" msgid="5581175033680477651">"Notifications"</string>
     <string name="notification_section_header_conversations" msgid="821834744538345661">"Conversations"</string>
@@ -1002,7 +1002,7 @@
     <string name="bubble_accessibility_action_move_top_right" msgid="6916868852433483569">"Déplacer en haut à droite"</string>
     <string name="bubble_accessibility_action_move_bottom_left" msgid="6339015902495504715">"Déplacer en bas à gauche"</string>
     <string name="bubble_accessibility_action_move_bottom_right" msgid="7471571700628346212">"Déplacer en bas à droite"</string>
-    <string name="bubble_dismiss_text" msgid="7071770411580452911">"Ignorer"</string>
+    <string name="bubble_dismiss_text" msgid="1314082410868930066">"Fermer la bulle"</string>
     <string name="bubbles_dont_bubble_conversation" msgid="1033040343437428822">"Ne pas afficher la conversations dans des bulles"</string>
     <string name="bubbles_user_education_title" msgid="5547017089271445797">"Chatter en utilisant des bulles"</string>
     <string name="bubbles_user_education_description" msgid="1160281719576715211">"Les nouvelles conversations s\'affichent sous forme d\'icônes flottantes ou bulles. Appuyez sur la bulle pour l\'ouvrir. Faites-la glisser pour la déplacer."</string>
@@ -1062,9 +1062,13 @@
     <string name="controls_structure_tooltip" msgid="4355922222944447867">"Balayer l\'écran pour voir plus d\'annonces"</string>
     <string name="controls_seeding_in_progress" msgid="3033855341410264148">"Chargement des recommandations"</string>
     <string name="controls_media_close_session" msgid="9023534788828414585">"Fermer cette session multimédia"</string>
+    <string name="controls_media_resume" msgid="1933520684481586053">"Reprendre"</string>
     <string name="controls_error_timeout" msgid="794197289772728958">"Délai expiré, vérifier l\'appli"</string>
     <string name="controls_error_retryable" msgid="864025882878378470">"Erreur. Nouvelle tentative…"</string>
-    <string name="controls_error_removed" msgid="6299213591234723805">"Appareil supprimé"</string>
+    <string name="controls_error_removed" msgid="6675638069846014366">"Introuvable"</string>
+    <string name="controls_error_removed_title" msgid="1207794911208047818">"Commande indisponible"</string>
+    <string name="controls_error_removed_message" msgid="2885911717034750542">"Impossible d\'accéder à \"<xliff:g id="DEVICE">%1$s</xliff:g>\". Vérifiez l\'application <xliff:g id="APPLICATION">%2$s</xliff:g> pour vous assurer que la commande est toujours disponible et que les paramètres de l\'application n\'ont pas changé."</string>
+    <string name="controls_open_app" msgid="483650971094300141">"Ouvrir l\'application"</string>
     <string name="controls_error_generic" msgid="352500456918362905">"Impossible de charger l\'état"</string>
     <string name="controls_error_failed" msgid="960228639198558525">"Erreur. Veuillez réessayer."</string>
     <string name="controls_in_progress" msgid="4421080500238215939">"En cours"</string>
diff --git a/packages/SystemUI/res/values-gl/strings.xml b/packages/SystemUI/res/values-gl/strings.xml
index 960e416..93524f8 100644
--- a/packages/SystemUI/res/values-gl/strings.xml
+++ b/packages/SystemUI/res/values-gl/strings.xml
@@ -510,7 +510,7 @@
     <string name="clear_all_notifications_text" msgid="348312370303046130">"Eliminar todas"</string>
     <string name="manage_notifications_text" msgid="6885645344647733116">"Xestionar"</string>
     <string name="manage_notifications_history_text" msgid="57055985396576230">"Historial"</string>
-    <string name="notification_section_header_incoming" msgid="5295312809341711367">"Entrantes"</string>
+    <string name="notification_section_header_incoming" msgid="850925217908095197">"Notificacións novas"</string>
     <string name="notification_section_header_gentle" msgid="6804099527336337197">"Silencio"</string>
     <string name="notification_section_header_alerting" msgid="5581175033680477651">"Notificacións"</string>
     <string name="notification_section_header_conversations" msgid="821834744538345661">"Conversas"</string>
@@ -1002,7 +1002,7 @@
     <string name="bubble_accessibility_action_move_top_right" msgid="6916868852433483569">"Mover á parte superior dereita"</string>
     <string name="bubble_accessibility_action_move_bottom_left" msgid="6339015902495504715">"Mover á parte infer. esquerda"</string>
     <string name="bubble_accessibility_action_move_bottom_right" msgid="7471571700628346212">"Mover á parte inferior dereita"</string>
-    <string name="bubble_dismiss_text" msgid="7071770411580452911">"Ignorar"</string>
+    <string name="bubble_dismiss_text" msgid="1314082410868930066">"Ignorar burbulla"</string>
     <string name="bubbles_dont_bubble_conversation" msgid="1033040343437428822">"Non mostrar a conversa como burbulla"</string>
     <string name="bubbles_user_education_title" msgid="5547017089271445797">"Chatear usando burbullas"</string>
     <string name="bubbles_user_education_description" msgid="1160281719576715211">"As conversas novas aparecen como iconas flotantes ou burbullas. Toca para abrir a burbulla e arrastra para movela."</string>
@@ -1062,9 +1062,13 @@
     <string name="controls_structure_tooltip" msgid="4355922222944447867">"Pasar o dedo para ver máis"</string>
     <string name="controls_seeding_in_progress" msgid="3033855341410264148">"Cargando recomendacións"</string>
     <string name="controls_media_close_session" msgid="9023534788828414585">"Pechar esta sesión multimedia"</string>
+    <string name="controls_media_resume" msgid="1933520684481586053">"Retomar"</string>
     <string name="controls_error_timeout" msgid="794197289772728958">"Inactivo. Comproba a app"</string>
     <string name="controls_error_retryable" msgid="864025882878378470">"Erro. Tentando de novo…"</string>
-    <string name="controls_error_removed" msgid="6299213591234723805">"Quitouse o dispositivo"</string>
+    <string name="controls_error_removed" msgid="6675638069846014366">"Non se atopou"</string>
+    <string name="controls_error_removed_title" msgid="1207794911208047818">"O control non está dispoñible"</string>
+    <string name="controls_error_removed_message" msgid="2885911717034750542">"Non se puido acceder a: <xliff:g id="DEVICE">%1$s</xliff:g>. Comproba a aplicación <xliff:g id="APPLICATION">%2$s</xliff:g> para asegurarte de que o control aínda estea dispoñible e que non se modificase a configuración da aplicación."</string>
+    <string name="controls_open_app" msgid="483650971094300141">"Abrir aplicación"</string>
     <string name="controls_error_generic" msgid="352500456918362905">"Non se puido cargar o estado"</string>
     <string name="controls_error_failed" msgid="960228639198558525">"Erro. Téntao de novo"</string>
     <string name="controls_in_progress" msgid="4421080500238215939">"En curso"</string>
diff --git a/packages/SystemUI/res/values-gu/strings.xml b/packages/SystemUI/res/values-gu/strings.xml
index 4936b7b..473f6de 100644
--- a/packages/SystemUI/res/values-gu/strings.xml
+++ b/packages/SystemUI/res/values-gu/strings.xml
@@ -510,7 +510,7 @@
     <string name="clear_all_notifications_text" msgid="348312370303046130">"બધુ સાફ કરો"</string>
     <string name="manage_notifications_text" msgid="6885645344647733116">"મેનેજ કરો"</string>
     <string name="manage_notifications_history_text" msgid="57055985396576230">"ઇતિહાસ"</string>
-    <string name="notification_section_header_incoming" msgid="5295312809341711367">"ઇનકમિંગ"</string>
+    <string name="notification_section_header_incoming" msgid="850925217908095197">"નવા"</string>
     <string name="notification_section_header_gentle" msgid="6804099527336337197">"સાઇલન્ટ"</string>
     <string name="notification_section_header_alerting" msgid="5581175033680477651">"નોટિફિકેશન"</string>
     <string name="notification_section_header_conversations" msgid="821834744538345661">"વાતચીત"</string>
@@ -593,11 +593,11 @@
     <string name="volume_odi_captions_hint_disable" msgid="2518846326748183407">"બંધ કરો"</string>
     <string name="accessibility_output_chooser" msgid="7807898688967194183">"આઉટપુટ ઉપકરણ સ્વિચ કરો"</string>
     <string name="screen_pinning_title" msgid="9058007390337841305">"ઍપને પિન કરેલી છે"</string>
-    <string name="screen_pinning_description" msgid="8699395373875667743">"તમે જ્યાં સુધી અનપિન કરશો નહીં ત્યાં સુધી આ તેને દૃશ્યક્ષમ રાખે છે. અનપિન કરવા માટે પાછળ અને ઝલકને સ્પર્શ કરી રાખો."</string>
-    <string name="screen_pinning_description_recents_invisible" msgid="4564466648700390037">"તમે જ્યાં સુધી અનપિન કરશો નહીં ત્યાં સુધી આ તેને દૃશ્યક્ષમ રાખે છે. અનપિન કરવા માટે પાછળ અને હોમને સ્પર્શ કરી રાખો."</string>
-    <string name="screen_pinning_description_gestural" msgid="7246323931831232068">"તમે જ્યાં સુધી અનપિન નહીં કરો ત્યાં સુધી આ તેને દૃશ્યક્ષમ રાખે છે. ઉપરની તરફ સ્વાઇપ કરો અને અનપિન કરવા માટે દબાવી રાખો."</string>
-    <string name="screen_pinning_description_accessible" msgid="7386449191953535332">"તમે જ્યાં સુધી અનપિન કરશો નહીં ત્યાં સુધી આ તેને દૃશ્યક્ષમ રાખે છે. અનપિન કરવા માટે ઝલકને સ્પર્શ કરી રાખો."</string>
-    <string name="screen_pinning_description_recents_invisible_accessible" msgid="2857071808674481986">"તમે જ્યાં સુધી અનપિન કરશો નહીં ત્યાં સુધી આ તેને દૃશ્યક્ષમ રાખે છે. અનપિન કરવા માટે હોમને સ્પર્શ કરી રાખો."</string>
+    <string name="screen_pinning_description" msgid="8699395373875667743">"તમે જ્યાં સુધી અનપિન કરશો નહીં ત્યાં સુધી આ તેને વ્યૂમાં રાખે છે. અનપિન કરવા માટે પાછળ અને ઓવરવ્યૂને સ્પર્શ કરી રાખો."</string>
+    <string name="screen_pinning_description_recents_invisible" msgid="4564466648700390037">"તમે જ્યાં સુધી અનપિન કરશો નહીં ત્યાં સુધી આ તેને વ્યૂમાં રાખે છે. અનપિન કરવા માટે પાછળ અને હોમને સ્પર્શ કરી રાખો."</string>
+    <string name="screen_pinning_description_gestural" msgid="7246323931831232068">"તમે જ્યાં સુધી અનપિન નહીં કરો ત્યાં સુધી આ તેને વ્યૂમાં રાખે છે. ઉપરની તરફ સ્વાઇપ કરો અને અનપિન કરવા માટે દબાવી રાખો."</string>
+    <string name="screen_pinning_description_accessible" msgid="7386449191953535332">"તમે જ્યાં સુધી અનપિન કરશો નહીં ત્યાં સુધી આ તેને વ્યૂમાં રાખે છે. અનપિન કરવા માટે ઓવરવ્યૂને સ્પર્શ કરી રાખો."</string>
+    <string name="screen_pinning_description_recents_invisible_accessible" msgid="2857071808674481986">"તમે જ્યાં સુધી અનપિન કરશો નહીં ત્યાં સુધી આ તેને વ્યૂમાં રાખે છે. અનપિન કરવા માટે હોમને સ્પર્શ કરી રાખો."</string>
     <string name="screen_pinning_exposes_personal_data" msgid="8189852022981524789">"વ્યક્તિગત ડેટા ઍક્સેસ કરી શકાતો હોઈ શકે (જેમ કે સંપર્કો અને ઇમેઇલનું કન્ટેન્ટ)."</string>
     <string name="screen_pinning_can_open_other_apps" msgid="7529756813231421455">"પિન કરેલી ઍપ અન્ય ઍપને ખોલી શકે છે."</string>
     <string name="screen_pinning_toast" msgid="8177286912533744328">"આ ઍપને અનપિન કરવા માટે, પાછળ અને ઓવરવ્યૂ બટનને સ્પર્શ કરી રાખો"</string>
@@ -1002,7 +1002,7 @@
     <string name="bubble_accessibility_action_move_top_right" msgid="6916868852433483569">"ઉપર જમણે ખસેડો"</string>
     <string name="bubble_accessibility_action_move_bottom_left" msgid="6339015902495504715">"નીચે ડાબે ખસેડો"</string>
     <string name="bubble_accessibility_action_move_bottom_right" msgid="7471571700628346212">"નીચે જમણે ખસેડો"</string>
-    <string name="bubble_dismiss_text" msgid="7071770411580452911">"છોડી દો"</string>
+    <string name="bubble_dismiss_text" msgid="1314082410868930066">"બબલને છોડી દો"</string>
     <string name="bubbles_dont_bubble_conversation" msgid="1033040343437428822">"વાતચીતને બબલ કરશો નહીં"</string>
     <string name="bubbles_user_education_title" msgid="5547017089271445797">"બબલનો ઉપયોગ કરીને ચેટ કરો"</string>
     <string name="bubbles_user_education_description" msgid="1160281719576715211">"નવી વાતચીત ફ્લોટિંગ આઇકન અથવા બબલ જેવી દેખાશે. બબલને ખોલવા માટે ટૅપ કરો. તેને ખસેડવા માટે ખેંચો."</string>
@@ -1013,17 +1013,14 @@
     <string name="notification_content_system_nav_changed" msgid="5077913144844684544">"સિસ્ટમ નૅવિગેશન અપડેટ કર્યું. ફેરફારો કરવા માટે, સેટિંગ પર જાઓ."</string>
     <string name="notification_content_gesture_nav_available" msgid="4431460803004659888">"સિસ્ટમ નૅવિગેશનને અપડેટ કરવા માટે સેટિંગ પર જાઓ"</string>
     <string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"સ્ટૅન્ડબાય"</string>
-    <!-- no translation found for priority_onboarding_title (2893070698479227616) -->
-    <skip />
-    <!-- no translation found for priority_onboarding_behavior (5342816047020432929) -->
-    <skip />
+    <string name="priority_onboarding_title" msgid="2893070698479227616">"વાતચીતને પ્રાધાન્યતા ધરાવતી તરીકે સેટ કરી"</string>
+    <string name="priority_onboarding_behavior" msgid="5342816047020432929">"પ્રાધાન્યતા ધરાવતી વાતચીતો:"</string>
     <string name="priority_onboarding_show_at_top_text" msgid="1678400241025513541">"વાતચીત વિભાગની ટોચ પર બતાવો"</string>
     <string name="priority_onboarding_show_avatar_text" msgid="5756291381124091508">"લૉક સ્ક્રીન પર પ્રોફાઇલ ફોટો બતાવો"</string>
     <string name="priority_onboarding_appear_as_bubble_text" msgid="4227039772250263122">"ઍપની ટોચ પર તરતા બબલ તરીકે દેખાય છે"</string>
     <string name="priority_onboarding_ignores_dnd_text" msgid="2918952762719600529">"ખલેલ પાડશો નહીં સેટિંગમાં હસ્તક્ષેપ કરી શકે છે"</string>
     <string name="priority_onboarding_done_button_title" msgid="4569550984286506007">"સમજાઈ ગયું"</string>
-    <!-- no translation found for priority_onboarding_settings_button_title (6663601574303585927) -->
-    <skip />
+    <string name="priority_onboarding_settings_button_title" msgid="6663601574303585927">"સેટિંગ"</string>
     <string name="magnification_overlay_title" msgid="6584179429612427958">"વિસ્તૃતીકરણ ઓવરલે વિંડો"</string>
     <string name="magnification_window_title" msgid="4863914360847258333">"વિસ્તૃતીકરણ વિંડો"</string>
     <string name="magnification_controls_title" msgid="8421106606708891519">"વિસ્તૃતીકરણ વિંડોના નિયંત્રણો"</string>
@@ -1065,9 +1062,13 @@
     <string name="controls_structure_tooltip" msgid="4355922222944447867">"વધુ જોવા માટે સ્વાઇપ કરો"</string>
     <string name="controls_seeding_in_progress" msgid="3033855341410264148">"સુઝાવ લોડ કરી રહ્યાં છીએ"</string>
     <string name="controls_media_close_session" msgid="9023534788828414585">"આ મીડિયા સત્રને બંધ કરો"</string>
+    <string name="controls_media_resume" msgid="1933520684481586053">"ફરી શરૂ કરો"</string>
     <string name="controls_error_timeout" msgid="794197289772728958">"નિષ્ક્રિય, ઍપને ચેક કરો"</string>
     <string name="controls_error_retryable" msgid="864025882878378470">"ભૂલ, ફરી પ્રયાસ કરી રહ્યા છીએ…"</string>
-    <string name="controls_error_removed" msgid="6299213591234723805">"ડિવાઇસ કાઢી નાખ્યું"</string>
+    <string name="controls_error_removed" msgid="6675638069846014366">"મળ્યું નથી"</string>
+    <string name="controls_error_removed_title" msgid="1207794911208047818">"નિયંત્રણ ઉપલબ્ધ નથી"</string>
+    <string name="controls_error_removed_message" msgid="2885911717034750542">"<xliff:g id="DEVICE">%1$s</xliff:g>ને ઍક્સેસ કરી શક્યાં નહીં. નિયંત્રણ હજી પણ ઉપલબ્ધ છે અને તે કે ઍપના સેટિંગ બદલાયા નથી તેની ખાતરી કરવા માટે <xliff:g id="APPLICATION">%2$s</xliff:g> ઍપ ચેક કરો."</string>
+    <string name="controls_open_app" msgid="483650971094300141">"ઍપ ખોલો"</string>
     <string name="controls_error_generic" msgid="352500456918362905">"સ્ટેટસ લોડ કરી શકાતું નથી"</string>
     <string name="controls_error_failed" msgid="960228639198558525">"ભૂલ, ફરીથી પ્રયાસ કરો"</string>
     <string name="controls_in_progress" msgid="4421080500238215939">"પ્રક્રિયા ચાલુ છે"</string>
diff --git a/packages/SystemUI/res/values-hi/strings.xml b/packages/SystemUI/res/values-hi/strings.xml
index 1fcfcc4..0038907 100644
--- a/packages/SystemUI/res/values-hi/strings.xml
+++ b/packages/SystemUI/res/values-hi/strings.xml
@@ -512,7 +512,7 @@
     <string name="clear_all_notifications_text" msgid="348312370303046130">"सभी को हटाएं"</string>
     <string name="manage_notifications_text" msgid="6885645344647733116">"प्रबंधित करें"</string>
     <string name="manage_notifications_history_text" msgid="57055985396576230">"इतिहास"</string>
-    <string name="notification_section_header_incoming" msgid="5295312809341711367">"हाल ही में मिली सूचनाएं"</string>
+    <string name="notification_section_header_incoming" msgid="850925217908095197">"नई सूचनाएं"</string>
     <string name="notification_section_header_gentle" msgid="6804099527336337197">"बिना आवाज़ किए मिलने वाली सूचनाएं"</string>
     <string name="notification_section_header_alerting" msgid="5581175033680477651">"वाइब्रेशन या आवाज़ के साथ मिलने वाली सूचनाएं"</string>
     <string name="notification_section_header_conversations" msgid="821834744538345661">"बातचीत"</string>
@@ -595,12 +595,12 @@
     <string name="volume_odi_captions_hint_disable" msgid="2518846326748183407">"बंद करें"</string>
     <string name="accessibility_output_chooser" msgid="7807898688967194183">"आउटपुट डिवाइस बदलें"</string>
     <string name="screen_pinning_title" msgid="9058007390337841305">"ऐप्लिकेशन पिन किया गया है"</string>
-    <string name="screen_pinning_description" msgid="8699395373875667743">"इससे वह तब तक दिखता रहता है जब तक कि आप उसे अनपिन नहीं कर देते. अनपिन करने के लिए, \'वापस जाएं\' और \'खास जानकारी\' को दबाकर रखें."</string>
+    <string name="screen_pinning_description" msgid="8699395373875667743">"इससे वह तब तक दिखता रहता है, जब तक कि आप उसे अनपिन नहीं कर देते. अनपिन करने के लिए, \'वापस जाएं\' और \'खास जानकारी\' को दबाकर रखें."</string>
     <string name="screen_pinning_description_recents_invisible" msgid="4564466648700390037">"इससे वह तब तक दिखाई देती है जब तक आप उसे अनपिन नहीं कर देते. अनपिन करने के लिए, होम और वापस जाएं वाले बटन को दबाकर रखें."</string>
-    <string name="screen_pinning_description_gestural" msgid="7246323931831232068">"इससे ऐप्लिकेशन की स्क्रीन तब तक दिखाई देती है जब तक आप उसे अनपिन नहीं करते. अनपिन करने के लिए ऊपर स्वाइप करें और स्क्रीन दबाकर रखें."</string>
+    <string name="screen_pinning_description_gestural" msgid="7246323931831232068">"इससे ऐप्लिकेशन की स्क्रीन तब तक दिखाई देती है, जब तक आप उसे अनपिन नहीं करते. अनपिन करने के लिए ऊपर स्वाइप करें और स्क्रीन दबाकर रखें."</string>
     <string name="screen_pinning_description_accessible" msgid="7386449191953535332">"इससे वह तब तक दिखता रहता है जब तक कि आप उसे अनपिन नहीं कर देते. अनपिन करने के लिए, \'खास जानकारी\' को दबाकर रखें."</string>
     <string name="screen_pinning_description_recents_invisible_accessible" msgid="2857071808674481986">"इससे वह तब तक दिखाई देती है जब तक आप उसे अनपिन नहीं कर देते. अनपिन करने के लिए, होम बटन को दबाकर रखें."</string>
-    <string name="screen_pinning_exposes_personal_data" msgid="8189852022981524789">"निजी डेटा ऐक्सेस किया जा सकता है. जैसे कि संपर्क और ईमेल का कॉन्टेंट."</string>
+    <string name="screen_pinning_exposes_personal_data" msgid="8189852022981524789">"निजी डेटा ऐक्सेस किया जा सकता है, जैसे कि संपर्क और ईमेल का कॉन्टेंट."</string>
     <string name="screen_pinning_can_open_other_apps" msgid="7529756813231421455">"पिन किए गए ऐप्लिकेशन से दूसरे ऐप्लिकेशन भी खोले जा सकते हैं."</string>
     <string name="screen_pinning_toast" msgid="8177286912533744328">"इस ऐप्लिकेशन को अनपिन करने के लिए, \'वापस जाएं\' और \'खास जानकारी\' बटन को साथ-साथ दबाकर रखें"</string>
     <string name="screen_pinning_toast_recents_invisible" msgid="6850978077443052594">"इस ऐप्लिकेशन को अनपिन करने के लिए, \'होम\' और \'वापस जाएं\' बटन को साथ-साथ दबाकर रखें"</string>
@@ -1004,7 +1004,7 @@
     <string name="bubble_accessibility_action_move_top_right" msgid="6916868852433483569">"सबसे ऊपर दाईं ओर ले जाएं"</string>
     <string name="bubble_accessibility_action_move_bottom_left" msgid="6339015902495504715">"बाईं ओर सबसे नीचे ले जाएं"</string>
     <string name="bubble_accessibility_action_move_bottom_right" msgid="7471571700628346212">"सबसे नीचे दाईं ओर ले जाएं"</string>
-    <string name="bubble_dismiss_text" msgid="7071770411580452911">"खारिज करें"</string>
+    <string name="bubble_dismiss_text" msgid="1314082410868930066">"बबल खारिज करें"</string>
     <string name="bubbles_dont_bubble_conversation" msgid="1033040343437428822">"बातचीत को बबल न करें"</string>
     <string name="bubbles_user_education_title" msgid="5547017089271445797">"बबल्स का इस्तेमाल करके चैट करें"</string>
     <string name="bubbles_user_education_description" msgid="1160281719576715211">"नई बातचीत फ़्लोटिंग आइकॉन या बबल्स की तरह दिखेंगी. बबल को खोलने के लिए टैप करें. इसे एक जगह से दूसरी जगह ले जाने के लिए खींचें और छोड़ें."</string>
@@ -1016,7 +1016,7 @@
     <string name="notification_content_gesture_nav_available" msgid="4431460803004659888">"सिस्टम नेविगेशन अपडेट करने के लिए \'सेटिंग\' में जाएं"</string>
     <string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"स्टैंडबाई"</string>
     <string name="priority_onboarding_title" msgid="2893070698479227616">"बातचीत को अहम बातचीत के तौर पर सेट किया गया है"</string>
-    <string name="priority_onboarding_behavior" msgid="5342816047020432929">"अहम बातचीत:"</string>
+    <string name="priority_onboarding_behavior" msgid="5342816047020432929">"अहम बातचीत यहां दिखेगी:"</string>
     <string name="priority_onboarding_show_at_top_text" msgid="1678400241025513541">"बातचीत सेक्शन में सबसे ऊपर दिखाएं"</string>
     <string name="priority_onboarding_show_avatar_text" msgid="5756291381124091508">"लॉक स्क्रीन पर प्रोफ़ाइल फ़ोटो दिखाएं"</string>
     <string name="priority_onboarding_appear_as_bubble_text" msgid="4227039772250263122">"खास बातचीत फ़्लोटिंग बबल की तरह ऐप्लिकेशन के ऊपर दिखेंगी"</string>
@@ -1064,9 +1064,13 @@
     <string name="controls_structure_tooltip" msgid="4355922222944447867">"ज़्यादा देखने के लिए स्वाइप करें"</string>
     <string name="controls_seeding_in_progress" msgid="3033855341410264148">"सुझाव लोड हो रहे हैं"</string>
     <string name="controls_media_close_session" msgid="9023534788828414585">"इस मीडिया सेशन को बंद करें"</string>
+    <string name="controls_media_resume" msgid="1933520684481586053">"फिर से शुरू करें"</string>
     <string name="controls_error_timeout" msgid="794197289772728958">"काम नहीं कर रहा, ऐप जांचें"</string>
     <string name="controls_error_retryable" msgid="864025882878378470">"कोई गड़बड़ी हुई, फिर से कोशिश की जा रही है…"</string>
-    <string name="controls_error_removed" msgid="6299213591234723805">"डिवाइस हटाया गया"</string>
+    <string name="controls_error_removed" msgid="6675638069846014366">"कंट्रोल मौजूद नहीं है"</string>
+    <string name="controls_error_removed_title" msgid="1207794911208047818">"कंट्रोल मौजूद नहीं है"</string>
+    <string name="controls_error_removed_message" msgid="2885911717034750542">"<xliff:g id="DEVICE">%1$s</xliff:g> को ऐक्सेस नहीं किया जा सका. <xliff:g id="APPLICATION">%2$s</xliff:g> ऐप्लिकेशन देखें, ताकि यह पक्का किया जा सके कि कंट्रोल अब भी मौजूद है और सेटिंग में कोई बदलाव नहीं हुआ है."</string>
+    <string name="controls_open_app" msgid="483650971094300141">"ऐप्लिकेशन खोलें"</string>
     <string name="controls_error_generic" msgid="352500456918362905">"स्थिति लोड नहीं की जा सकती"</string>
     <string name="controls_error_failed" msgid="960228639198558525">"गड़बड़ी हुई, फिर से कोशिश करें"</string>
     <string name="controls_in_progress" msgid="4421080500238215939">"जारी है"</string>
diff --git a/packages/SystemUI/res/values-hr/strings.xml b/packages/SystemUI/res/values-hr/strings.xml
index c918dca..b0e6b51 100644
--- a/packages/SystemUI/res/values-hr/strings.xml
+++ b/packages/SystemUI/res/values-hr/strings.xml
@@ -513,7 +513,7 @@
     <string name="clear_all_notifications_text" msgid="348312370303046130">"Izbriši sve"</string>
     <string name="manage_notifications_text" msgid="6885645344647733116">"Upravljajte"</string>
     <string name="manage_notifications_history_text" msgid="57055985396576230">"Povijest"</string>
-    <string name="notification_section_header_incoming" msgid="5295312809341711367">"Dolazno"</string>
+    <string name="notification_section_header_incoming" msgid="850925217908095197">"Novo"</string>
     <string name="notification_section_header_gentle" msgid="6804099527336337197">"Bešumno"</string>
     <string name="notification_section_header_alerting" msgid="5581175033680477651">"Obavijesti"</string>
     <string name="notification_section_header_conversations" msgid="821834744538345661">"Razgovori"</string>
@@ -1007,9 +1007,9 @@
     <string name="bubble_accessibility_action_move_top_right" msgid="6916868852433483569">"Premjesti u gornji desni kut"</string>
     <string name="bubble_accessibility_action_move_bottom_left" msgid="6339015902495504715">"Premjesti u donji lijevi kut"</string>
     <string name="bubble_accessibility_action_move_bottom_right" msgid="7471571700628346212">"Premjestite u donji desni kut"</string>
-    <string name="bubble_dismiss_text" msgid="7071770411580452911">"Odbaci"</string>
+    <string name="bubble_dismiss_text" msgid="1314082410868930066">"Odbaci oblačić"</string>
     <string name="bubbles_dont_bubble_conversation" msgid="1033040343437428822">"Zaustavi razgovor u oblačićima"</string>
-    <string name="bubbles_user_education_title" msgid="5547017089271445797">"Chatanje pomoću oblačića"</string>
+    <string name="bubbles_user_education_title" msgid="5547017089271445797">"Oblačići u chatu"</string>
     <string name="bubbles_user_education_description" msgid="1160281719576715211">"Novi razgovori pojavljuju se kao pomične ikone ili oblačići. Dodirnite za otvaranje oblačića. Povucite da biste ga premjestili."</string>
     <string name="bubbles_user_education_manage_title" msgid="2848511858160342320">"Upravljanje oblačićima u svakom trenutku"</string>
     <string name="bubbles_user_education_manage" msgid="1391639189507036423">"Dodirnite Upravljanje da biste isključili oblačiće iz ove aplikacije"</string>
@@ -1068,9 +1068,13 @@
     <string name="controls_structure_tooltip" msgid="4355922222944447867">"Prijeđite prstom da vidite više"</string>
     <string name="controls_seeding_in_progress" msgid="3033855341410264148">"Učitavanje preporuka"</string>
     <string name="controls_media_close_session" msgid="9023534788828414585">"Zatvorite ovu medijsku sesiju"</string>
+    <string name="controls_media_resume" msgid="1933520684481586053">"Nastavi"</string>
     <string name="controls_error_timeout" msgid="794197289772728958">"Neaktivno, provjerite aplik."</string>
     <string name="controls_error_retryable" msgid="864025882878378470">"Pogreška, pokušavamo ponovo…"</string>
-    <string name="controls_error_removed" msgid="6299213591234723805">"Uređaj je uklonjen"</string>
+    <string name="controls_error_removed" msgid="6675638069846014366">"Nije pronađeno"</string>
+    <string name="controls_error_removed_title" msgid="1207794911208047818">"Kontrola nije dostupna"</string>
+    <string name="controls_error_removed_message" msgid="2885911717034750542">"Nije moguće pristupiti uređaju: <xliff:g id="DEVICE">%1$s</xliff:g>. U aplikaciji <xliff:g id="APPLICATION">%2$s</xliff:g> provjerite je li kontrola i dalje dostupna te potvrdite da se postavke aplikacije nisu promijenile."</string>
+    <string name="controls_open_app" msgid="483650971094300141">"Otvori apl."</string>
     <string name="controls_error_generic" msgid="352500456918362905">"Status se ne može učitati"</string>
     <string name="controls_error_failed" msgid="960228639198558525">"Pogreška, pokušajte ponovo"</string>
     <string name="controls_in_progress" msgid="4421080500238215939">"U tijeku"</string>
diff --git a/packages/SystemUI/res/values-hu/strings.xml b/packages/SystemUI/res/values-hu/strings.xml
index 2a991f1..64e7011 100644
--- a/packages/SystemUI/res/values-hu/strings.xml
+++ b/packages/SystemUI/res/values-hu/strings.xml
@@ -510,7 +510,7 @@
     <string name="clear_all_notifications_text" msgid="348312370303046130">"Az összes törlése"</string>
     <string name="manage_notifications_text" msgid="6885645344647733116">"Kezelés"</string>
     <string name="manage_notifications_history_text" msgid="57055985396576230">"Előzmények"</string>
-    <string name="notification_section_header_incoming" msgid="5295312809341711367">"Bejövő"</string>
+    <string name="notification_section_header_incoming" msgid="850925217908095197">"Új"</string>
     <string name="notification_section_header_gentle" msgid="6804099527336337197">"Néma"</string>
     <string name="notification_section_header_alerting" msgid="5581175033680477651">"Értesítések"</string>
     <string name="notification_section_header_conversations" msgid="821834744538345661">"Beszélgetések"</string>
@@ -595,7 +595,7 @@
     <string name="screen_pinning_title" msgid="9058007390337841305">"Az alkalmazás ki van tűzve"</string>
     <string name="screen_pinning_description" msgid="8699395373875667743">"Megjelenítve tartja addig, amíg Ön fel nem oldja a rögzítést. A feloldáshoz tartsa lenyomva a Vissza és az Áttekintés lehetőséget."</string>
     <string name="screen_pinning_description_recents_invisible" msgid="4564466648700390037">"Megjelenítve tartja addig, amíg Ön fel nem oldja a rögzítést. A feloldáshoz tartsa lenyomva a Vissza és a Kezdőképernyő elemet."</string>
-    <string name="screen_pinning_description_gestural" msgid="7246323931831232068">"Megjelenítve tartja addig, amíg Ön fel nem oldja a rögzítést. A feloldáshoz csúsztasson fel, és tartsa ujját a képernyőn."</string>
+    <string name="screen_pinning_description_gestural" msgid="7246323931831232068">"Megjelenítve tartja addig, amíg Ön fel nem oldja a rögzítést. A feloldáshoz csúsztassa fel és tartsa ujját a képernyőn."</string>
     <string name="screen_pinning_description_accessible" msgid="7386449191953535332">"Megjelenítve tartja addig, amíg Ön fel nem oldja a rögzítést. A feloldáshoz tartsa lenyomva az Áttekintés lehetőséget."</string>
     <string name="screen_pinning_description_recents_invisible_accessible" msgid="2857071808674481986">"Megjelenítve tartja addig, amíg Ön fel nem oldja a rögzítést. A feloldáshoz tartsa lenyomva a Kezdőképernyő elemet."</string>
     <string name="screen_pinning_exposes_personal_data" msgid="8189852022981524789">"Bizonyos személyes adatok (például a névjegyek és az e-mailek tartalma) hozzáférhetők lehetnek."</string>
@@ -1002,7 +1002,7 @@
     <string name="bubble_accessibility_action_move_top_right" msgid="6916868852433483569">"Áthelyezés fel és jobbra"</string>
     <string name="bubble_accessibility_action_move_bottom_left" msgid="6339015902495504715">"Áthelyezés le és balra"</string>
     <string name="bubble_accessibility_action_move_bottom_right" msgid="7471571700628346212">"Áthelyezés le és jobbra"</string>
-    <string name="bubble_dismiss_text" msgid="7071770411580452911">"Elvetés"</string>
+    <string name="bubble_dismiss_text" msgid="1314082410868930066">"Buborék elvetése"</string>
     <string name="bubbles_dont_bubble_conversation" msgid="1033040343437428822">"Ne jelenjen meg a beszélgetés buborékban"</string>
     <string name="bubbles_user_education_title" msgid="5547017089271445797">"Buborékokat használó csevegés"</string>
     <string name="bubbles_user_education_description" msgid="1160281719576715211">"Az új beszélgetések lebegő ikonként, vagyis buborékként jelennek meg. A buborék megnyitásához koppintson rá. Áthelyezéshez húzza a kívánt helyre."</string>
@@ -1062,9 +1062,13 @@
     <string name="controls_structure_tooltip" msgid="4355922222944447867">"Továbbiak megtekintéséhez csúsztasson"</string>
     <string name="controls_seeding_in_progress" msgid="3033855341410264148">"Javaslatok betöltése…"</string>
     <string name="controls_media_close_session" msgid="9023534788828414585">"Médiamunkamenet bezárása"</string>
+    <string name="controls_media_resume" msgid="1933520684481586053">"Folytatás"</string>
     <string name="controls_error_timeout" msgid="794197289772728958">"Inaktív, ellenőrizze az appot"</string>
     <string name="controls_error_retryable" msgid="864025882878378470">"Hiba, újrapróbálkozás…"</string>
-    <string name="controls_error_removed" msgid="6299213591234723805">"Eszköz eltávolítva"</string>
+    <string name="controls_error_removed" msgid="6675638069846014366">"Nem található"</string>
+    <string name="controls_error_removed_title" msgid="1207794911208047818">"Nem hozzáférhető vezérlő"</string>
+    <string name="controls_error_removed_message" msgid="2885911717034750542">"Nem lehet hozzáférni a következőhöz: <xliff:g id="DEVICE">%1$s</xliff:g>. Ellenőrizze a(z) <xliff:g id="APPLICATION">%2$s</xliff:g> alkalmazást, és győződjön meg arról, hogy a vezérlő továbbra is rendelkezésre áll, illetve nem változtak az alkalmazás beállításai."</string>
+    <string name="controls_open_app" msgid="483650971094300141">"App megnyitása"</string>
     <string name="controls_error_generic" msgid="352500456918362905">"Állapot betöltése sikertelen"</string>
     <string name="controls_error_failed" msgid="960228639198558525">"Hiba történt. Próbálja újra."</string>
     <string name="controls_in_progress" msgid="4421080500238215939">"Folyamatban"</string>
diff --git a/packages/SystemUI/res/values-hy/strings.xml b/packages/SystemUI/res/values-hy/strings.xml
index 908231a..a337cc2 100644
--- a/packages/SystemUI/res/values-hy/strings.xml
+++ b/packages/SystemUI/res/values-hy/strings.xml
@@ -92,7 +92,7 @@
     <string name="screenrecord_background_processing_label" msgid="7244617554884238898">"Էկրանի տեսագրության մշակում"</string>
     <string name="screenrecord_channel_description" msgid="4147077128486138351">"Էկրանի տեսագրման աշխատաշրջանի ընթացիկ ծանուցում"</string>
     <string name="screenrecord_start_label" msgid="1750350278888217473">"Սկսե՞լ տեսագրումը"</string>
-    <string name="screenrecord_description" msgid="1123231719680353736">"Տեսագրման ընթացքում Android-ի համակարգը կարող է գրանցել անձնական տեղեկություններ, որոնք տեսանելի են էկրանին կամ նվագարկվում են ձեր սարքում։ Սա ներառում է այնպիսի տեղեկություններ, ինչպիսիք են, օրինակ, գաղտնաբառերը, վճարային տվյալները, լուսանկարները, հաղորդագրությունները և նվագարկվող աուդիո ֆայլերը։"</string>
+    <string name="screenrecord_description" msgid="1123231719680353736">"Տեսագրման ընթացքում Android համակարգը կարող է գրանցել անձնական տեղեկություններ, որոնք տեսանելի են էկրանին կամ նվագարկվում են ձեր սարքում։ Սա ներառում է այնպիսի տեղեկություններ, ինչպիսիք են, օրինակ, գաղտնաբառերը, վճարային տվյալները, լուսանկարները, հաղորդագրությունները և նվագարկվող աուդիո ֆայլերը։"</string>
     <string name="screenrecord_audio_label" msgid="6183558856175159629">"Ձայնագրել"</string>
     <string name="screenrecord_device_audio_label" msgid="9016927171280567791">"Սարքի ձայները"</string>
     <string name="screenrecord_device_audio_description" msgid="4922694220572186193">"Ձեր սարքի ձայները, օրինակ՝ երաժշտությունը, զանգերն ու զանգերանգները"</string>
@@ -510,7 +510,7 @@
     <string name="clear_all_notifications_text" msgid="348312370303046130">"Մաքրել բոլորը"</string>
     <string name="manage_notifications_text" msgid="6885645344647733116">"Կառավարել"</string>
     <string name="manage_notifications_history_text" msgid="57055985396576230">"Պատմություն"</string>
-    <string name="notification_section_header_incoming" msgid="5295312809341711367">"Մուտքային"</string>
+    <string name="notification_section_header_incoming" msgid="850925217908095197">"Նոր"</string>
     <string name="notification_section_header_gentle" msgid="6804099527336337197">"Անձայն"</string>
     <string name="notification_section_header_alerting" msgid="5581175033680477651">"Ծանուցումներ"</string>
     <string name="notification_section_header_conversations" msgid="821834744538345661">"Խոսակցություններ"</string>
@@ -720,7 +720,7 @@
     <string name="notification_conversation_channel_settings" msgid="2409977688430606835">"Կարգավորումներ"</string>
     <string name="notification_priority_title" msgid="2079708866333537093">"Կարևոր"</string>
     <string name="no_shortcut" msgid="8257177117568230126">"<xliff:g id="APP_NAME">%1$s</xliff:g> հավելվածը զրույցի գործառույթներ չի աջակցում"</string>
-    <string name="bubble_overflow_empty_title" msgid="3120029421991510842">"Վերջին ամպիկներ չկան"</string>
+    <string name="bubble_overflow_empty_title" msgid="3120029421991510842">"Ամպիկներ չկան"</string>
     <string name="bubble_overflow_empty_subtitle" msgid="2030874469510497397">"Այստեղ կցուցադրվեն վերջերս օգտագործված և փակված ամպիկները, որոնք կկարողանաք հեշտությամբ վերաբացել"</string>
     <string name="notification_unblockable_desc" msgid="2073030886006190804">"Այս ծանուցումները չեն կարող փոփոխվել:"</string>
     <string name="notification_multichannel_desc" msgid="7414593090056236179">"Ծանուցումների տվյալ խումբը հնարավոր չէ կարգավորել այստեղ"</string>
@@ -1002,10 +1002,10 @@
     <string name="bubble_accessibility_action_move_top_right" msgid="6916868852433483569">"Տեղափոխել վերև՝ աջ"</string>
     <string name="bubble_accessibility_action_move_bottom_left" msgid="6339015902495504715">"Տեղափոխել ներքև՝ ձախ"</string>
     <string name="bubble_accessibility_action_move_bottom_right" msgid="7471571700628346212">"Տեղափոխել ներքև՝ աջ"</string>
-    <string name="bubble_dismiss_text" msgid="7071770411580452911">"Փակել"</string>
+    <string name="bubble_dismiss_text" msgid="1314082410868930066">"Փակել ամպիկը"</string>
     <string name="bubbles_dont_bubble_conversation" msgid="1033040343437428822">"Զրույցը չցուցադրել ամպիկի տեսքով"</string>
-    <string name="bubbles_user_education_title" msgid="5547017089271445797">"Զրուցել ամպիկների միջոցով"</string>
-    <string name="bubbles_user_education_description" msgid="1160281719576715211">"Նոր խոսակցությունները կհայտնվեն լողացող պատկերակների կամ ամպիկների տեսքով։ Հպեք՝ ամպիկը բացելու համար։ Քաշեք՝ այն տեղափոխելու համար։"</string>
+    <string name="bubbles_user_education_title" msgid="5547017089271445797">"Զրույցի ամպիկներ"</string>
+    <string name="bubbles_user_education_description" msgid="1160281719576715211">"Նոր զրույցները կհայտնվեն լողացող պատկերակների կամ ամպիկների տեսքով։ Հպեք՝ ամպիկը բացելու համար։ Քաշեք՝ այն տեղափոխելու համար։"</string>
     <string name="bubbles_user_education_manage_title" msgid="2848511858160342320">"Ամպիկների կարգավորումներ"</string>
     <string name="bubbles_user_education_manage" msgid="1391639189507036423">"Հպեք «Կառավարել» կոճակին՝ այս հավելվածի ամպիկներն անջատելու համար։"</string>
     <string name="bubbles_user_education_got_it" msgid="8282812431953161143">"Եղավ"</string>
@@ -1062,9 +1062,13 @@
     <string name="controls_structure_tooltip" msgid="4355922222944447867">"Սահեցրեք մատը՝ ավելին իմանալու համար"</string>
     <string name="controls_seeding_in_progress" msgid="3033855341410264148">"Բեռնման խորհուրդներ"</string>
     <string name="controls_media_close_session" msgid="9023534788828414585">"Փակել աշխատաշրջանը"</string>
+    <string name="controls_media_resume" msgid="1933520684481586053">"Շարունակել"</string>
     <string name="controls_error_timeout" msgid="794197289772728958">"Ակտիվ չէ, ստուգեք հավելվածը"</string>
     <string name="controls_error_retryable" msgid="864025882878378470">"Սխալ. նորից ենք փորձում…"</string>
-    <string name="controls_error_removed" msgid="6299213591234723805">"Սարքը հեռացված է"</string>
+    <string name="controls_error_removed" msgid="6675638069846014366">"Չի գտնվել"</string>
+    <string name="controls_error_removed_title" msgid="1207794911208047818">"Կառավարման տարրը հասանելի չէ"</string>
+    <string name="controls_error_removed_message" msgid="2885911717034750542">"<xliff:g id="DEVICE">%1$s</xliff:g> սարքն անհասանելի է։ Ստուգեք <xliff:g id="APPLICATION">%2$s</xliff:g> հավելվածը՝ համոզվելու, որ կառավարման տարրը դեռ հասանելի է և հավելվածի կարգավորումները չեն փոխվել։"</string>
+    <string name="controls_open_app" msgid="483650971094300141">"Բացել հավելվածը"</string>
     <string name="controls_error_generic" msgid="352500456918362905">"Չհաջողվեց բեռնել կարգավիճակը"</string>
     <string name="controls_error_failed" msgid="960228639198558525">"Սխալ առաջացավ։ Նորից փորձեք։"</string>
     <string name="controls_in_progress" msgid="4421080500238215939">"Ընթացքի մեջ է"</string>
diff --git a/packages/SystemUI/res/values-in/strings.xml b/packages/SystemUI/res/values-in/strings.xml
index 2e11e42..72fac71 100644
--- a/packages/SystemUI/res/values-in/strings.xml
+++ b/packages/SystemUI/res/values-in/strings.xml
@@ -510,7 +510,7 @@
     <string name="clear_all_notifications_text" msgid="348312370303046130">"Hapus semua"</string>
     <string name="manage_notifications_text" msgid="6885645344647733116">"Kelola"</string>
     <string name="manage_notifications_history_text" msgid="57055985396576230">"Histori"</string>
-    <string name="notification_section_header_incoming" msgid="5295312809341711367">"Masuk"</string>
+    <string name="notification_section_header_incoming" msgid="850925217908095197">"Baru"</string>
     <string name="notification_section_header_gentle" msgid="6804099527336337197">"Senyap"</string>
     <string name="notification_section_header_alerting" msgid="5581175033680477651">"Notifikasi"</string>
     <string name="notification_section_header_conversations" msgid="821834744538345661">"Percakapan"</string>
@@ -595,7 +595,7 @@
     <string name="screen_pinning_title" msgid="9058007390337841305">"Aplikasi dipasangi pin"</string>
     <string name="screen_pinning_description" msgid="8699395373875667743">"Ini akan terus ditampilkan sampai Anda melepas pin. Sentuh lama tombol Kembali dan Ringkasan untuk melepas pin."</string>
     <string name="screen_pinning_description_recents_invisible" msgid="4564466648700390037">"Ini akan terus ditampilkan sampai Anda melepas pin. Sentuh lama tombol Kembali dan Beranda untuk melepas pin."</string>
-    <string name="screen_pinning_description_gestural" msgid="7246323931831232068">"Ini akan terus ditampilkan sampai Anda melepas pin. Geser ke atas &amp; tahan untuk melepas pin."</string>
+    <string name="screen_pinning_description_gestural" msgid="7246323931831232068">"Aplikasi akan terus ditampilkan sampai pin dilepas. Geser ke atas dan tahan untuk lepas pin."</string>
     <string name="screen_pinning_description_accessible" msgid="7386449191953535332">"Ini akan terus ditampilkan sampai Anda melepas pin. Sentuh lama tombol Ringkasan untuk melepas pin."</string>
     <string name="screen_pinning_description_recents_invisible_accessible" msgid="2857071808674481986">"Ini akan terus ditampilkan sampai Anda melepas pin. Sentuh lama tombol Beranda untuk melepas pin."</string>
     <string name="screen_pinning_exposes_personal_data" msgid="8189852022981524789">"Data pribadi dapat diakses (seperti kontak dan konten email)."</string>
@@ -1002,7 +1002,7 @@
     <string name="bubble_accessibility_action_move_top_right" msgid="6916868852433483569">"Pindahkan ke kanan atas"</string>
     <string name="bubble_accessibility_action_move_bottom_left" msgid="6339015902495504715">"Pindahkan ke kiri bawah"</string>
     <string name="bubble_accessibility_action_move_bottom_right" msgid="7471571700628346212">"Pindahkan ke kanan bawah"</string>
-    <string name="bubble_dismiss_text" msgid="7071770411580452911">"Tutup"</string>
+    <string name="bubble_dismiss_text" msgid="1314082410868930066">"Tutup balon"</string>
     <string name="bubbles_dont_bubble_conversation" msgid="1033040343437428822">"Jangan gunakan percakapan balon"</string>
     <string name="bubbles_user_education_title" msgid="5547017089271445797">"Chat dalam tampilan balon"</string>
     <string name="bubbles_user_education_description" msgid="1160281719576715211">"Percakapan baru muncul sebagai ikon mengambang, atau balon. Ketuk untuk membuka balon. Tarik untuk memindahkannya."</string>
@@ -1062,9 +1062,13 @@
     <string name="controls_structure_tooltip" msgid="4355922222944447867">"Geser untuk melihat selengkapnya"</string>
     <string name="controls_seeding_in_progress" msgid="3033855341410264148">"Memuat rekomendasi"</string>
     <string name="controls_media_close_session" msgid="9023534788828414585">"Tutup sesi media ini"</string>
+    <string name="controls_media_resume" msgid="1933520684481586053">"Lanjutkan"</string>
     <string name="controls_error_timeout" msgid="794197289772728958">"Nonaktif, periksa aplikasi"</string>
     <string name="controls_error_retryable" msgid="864025882878378470">"Error, mencoba lagi..."</string>
-    <string name="controls_error_removed" msgid="6299213591234723805">"Perangkat dihapus"</string>
+    <string name="controls_error_removed" msgid="6675638069846014366">"Tidak ditemukan"</string>
+    <string name="controls_error_removed_title" msgid="1207794911208047818">"Kontrol tidak tersedia"</string>
+    <string name="controls_error_removed_message" msgid="2885911717034750542">"Tidak dapat mengakses <xliff:g id="DEVICE">%1$s</xliff:g>. Periksa aplikasi <xliff:g id="APPLICATION">%2$s</xliff:g> untuk memastikan kontrol masih tersedia dan bahwa setelan aplikasi tidak berubah."</string>
+    <string name="controls_open_app" msgid="483650971094300141">"Buka aplikasi"</string>
     <string name="controls_error_generic" msgid="352500456918362905">"Tidak dapat memuat status"</string>
     <string name="controls_error_failed" msgid="960228639198558525">"Error, coba lagi"</string>
     <string name="controls_in_progress" msgid="4421080500238215939">"Dalam proses"</string>
diff --git a/packages/SystemUI/res/values-is/strings.xml b/packages/SystemUI/res/values-is/strings.xml
index 773bda7..a3119ce 100644
--- a/packages/SystemUI/res/values-is/strings.xml
+++ b/packages/SystemUI/res/values-is/strings.xml
@@ -510,7 +510,7 @@
     <string name="clear_all_notifications_text" msgid="348312370303046130">"Hreinsa allt"</string>
     <string name="manage_notifications_text" msgid="6885645344647733116">"Stjórna"</string>
     <string name="manage_notifications_history_text" msgid="57055985396576230">"Ferill"</string>
-    <string name="notification_section_header_incoming" msgid="5295312809341711367">"Mótteknar"</string>
+    <string name="notification_section_header_incoming" msgid="850925217908095197">"Nýtt"</string>
     <string name="notification_section_header_gentle" msgid="6804099527336337197">"Hljóðlaust"</string>
     <string name="notification_section_header_alerting" msgid="5581175033680477651">"Tilkynningar"</string>
     <string name="notification_section_header_conversations" msgid="821834744538345661">"Samtöl"</string>
@@ -1002,7 +1002,7 @@
     <string name="bubble_accessibility_action_move_top_right" msgid="6916868852433483569">"Færa efst til hægri"</string>
     <string name="bubble_accessibility_action_move_bottom_left" msgid="6339015902495504715">"Færa neðst til vinstri"</string>
     <string name="bubble_accessibility_action_move_bottom_right" msgid="7471571700628346212">"Færðu neðst til hægri"</string>
-    <string name="bubble_dismiss_text" msgid="7071770411580452911">"Hunsa"</string>
+    <string name="bubble_dismiss_text" msgid="1314082410868930066">"Loka blöðru"</string>
     <string name="bubbles_dont_bubble_conversation" msgid="1033040343437428822">"Ekki setja samtal í blöðru"</string>
     <string name="bubbles_user_education_title" msgid="5547017089271445797">"Spjalla með blöðrum"</string>
     <string name="bubbles_user_education_description" msgid="1160281719576715211">"Ný samtöl birtast sem fljótandi tákn eða blöðrur. Ýttu til að opna blöðru. Dragðu hana til að færa."</string>
@@ -1062,9 +1062,13 @@
     <string name="controls_structure_tooltip" msgid="4355922222944447867">"Strjúktu til að sjá meira"</string>
     <string name="controls_seeding_in_progress" msgid="3033855341410264148">"Hleður tillögum"</string>
     <string name="controls_media_close_session" msgid="9023534788828414585">"Loka þessari efnislotu"</string>
+    <string name="controls_media_resume" msgid="1933520684481586053">"Halda áfram"</string>
     <string name="controls_error_timeout" msgid="794197289772728958">"Óvirkt, athugaðu forrit"</string>
     <string name="controls_error_retryable" msgid="864025882878378470">"Villa, reynir aftur…"</string>
-    <string name="controls_error_removed" msgid="6299213591234723805">"Tæki fjarlægt"</string>
+    <string name="controls_error_removed" msgid="6675638069846014366">"Fannst ekki"</string>
+    <string name="controls_error_removed_title" msgid="1207794911208047818">"Stýring er ekki tiltæk"</string>
+    <string name="controls_error_removed_message" msgid="2885911717034750542">"Ekki tókst að tengjast <xliff:g id="DEVICE">%1$s</xliff:g>. Athugaðu <xliff:g id="APPLICATION">%2$s</xliff:g> forritið til að ganga úr skugga um að stýringin sé enn í boði og að stillingum forritsins hafi ekki verið breytt."</string>
+    <string name="controls_open_app" msgid="483650971094300141">"Opna forrit"</string>
     <string name="controls_error_generic" msgid="352500456918362905">"Ekki er hægt að hlaða stöðu"</string>
     <string name="controls_error_failed" msgid="960228639198558525">"Villa, reyndu aftur"</string>
     <string name="controls_in_progress" msgid="4421080500238215939">"Í gangi"</string>
diff --git a/packages/SystemUI/res/values-it/strings.xml b/packages/SystemUI/res/values-it/strings.xml
index 0844284..b90ae3e 100644
--- a/packages/SystemUI/res/values-it/strings.xml
+++ b/packages/SystemUI/res/values-it/strings.xml
@@ -78,8 +78,8 @@
     <string name="compat_mode_off" msgid="7682459748279487945">"Estendi per riemp. schermo"</string>
     <string name="global_action_screenshot" msgid="2760267567509131654">"Screenshot"</string>
     <string name="remote_input_image_insertion_text" msgid="4850791636452521123">"è stata inviata un\'immagine"</string>
-    <string name="screenshot_saving_ticker" msgid="6519186952674544916">"Salvataggio screenshot..."</string>
-    <string name="screenshot_saving_title" msgid="2298349784913287333">"Salvataggio screenshot..."</string>
+    <string name="screenshot_saving_ticker" msgid="6519186952674544916">"Salvataggio screenshot…"</string>
+    <string name="screenshot_saving_title" msgid="2298349784913287333">"Salvataggio screenshot…"</string>
     <string name="screenshot_saved_title" msgid="8893267638659083153">"Screenshot salvato"</string>
     <string name="screenshot_saved_text" msgid="7778833104901642442">"Tocca per visualizzare lo screenshot"</string>
     <string name="screenshot_failed_title" msgid="3259148215671936891">"Impossibile salvare lo screenshot"</string>
@@ -510,7 +510,7 @@
     <string name="clear_all_notifications_text" msgid="348312370303046130">"Cancella tutto"</string>
     <string name="manage_notifications_text" msgid="6885645344647733116">"Gestisci"</string>
     <string name="manage_notifications_history_text" msgid="57055985396576230">"Cronologia"</string>
-    <string name="notification_section_header_incoming" msgid="5295312809341711367">"In arrivo"</string>
+    <string name="notification_section_header_incoming" msgid="850925217908095197">"Nuove"</string>
     <string name="notification_section_header_gentle" msgid="6804099527336337197">"Silenziose"</string>
     <string name="notification_section_header_alerting" msgid="5581175033680477651">"Notifiche"</string>
     <string name="notification_section_header_conversations" msgid="821834744538345661">"Conversazioni"</string>
@@ -592,14 +592,14 @@
     <string name="volume_odi_captions_hint_enable" msgid="2073091194012843195">"attiva"</string>
     <string name="volume_odi_captions_hint_disable" msgid="2518846326748183407">"disattiva"</string>
     <string name="accessibility_output_chooser" msgid="7807898688967194183">"Cambia dispositivo di uscita"</string>
-    <string name="screen_pinning_title" msgid="9058007390337841305">"L\'app è bloccata"</string>
+    <string name="screen_pinning_title" msgid="9058007390337841305">"L\'app è bloccata su schermo"</string>
     <string name="screen_pinning_description" msgid="8699395373875667743">"La schermata rimane visibile finché non viene sganciata. Per sganciarla, tieni premuto Indietro e Panoramica."</string>
     <string name="screen_pinning_description_recents_invisible" msgid="4564466648700390037">"La schermata rimane visibile finché non viene disattivato il blocco su schermo. Per disattivarlo, tocca e tieni premuto Indietro e Home."</string>
-    <string name="screen_pinning_description_gestural" msgid="7246323931831232068">"Mantiene la visualizzazione fino allo sblocco. Scorri verso l\'alto e tieni premuto per sbloccare."</string>
+    <string name="screen_pinning_description_gestural" msgid="7246323931831232068">"Rimarrà visibile finché non viene sbloccata. Scorri verso l\'alto e tieni premuto per sbloccarla."</string>
     <string name="screen_pinning_description_accessible" msgid="7386449191953535332">"La schermata rimane visibile finché non viene sganciata. Per sganciarla, tieni premuto Panoramica."</string>
     <string name="screen_pinning_description_recents_invisible_accessible" msgid="2857071808674481986">"La schermata rimane visibile finché non viene disattivato il blocco su schermo. Per disattivarlo, tocca e tieni premuto Home."</string>
     <string name="screen_pinning_exposes_personal_data" msgid="8189852022981524789">"I dati personali potrebbero essere accessibili (ad esempio i contatti e i contenuti delle email)."</string>
-    <string name="screen_pinning_can_open_other_apps" msgid="7529756813231421455">"Un\'app bloccata potrebbe aprire altre app."</string>
+    <string name="screen_pinning_can_open_other_apps" msgid="7529756813231421455">"L\'app bloccata su schermo potrebbe aprire altre app."</string>
     <string name="screen_pinning_toast" msgid="8177286912533744328">"Per sbloccare questa app, tocca e tieni premuti i pulsanti Indietro e Panoramica"</string>
     <string name="screen_pinning_toast_recents_invisible" msgid="6850978077443052594">"Per sbloccare questa app, tocca e tieni premuti i pulsanti Indietro e Home"</string>
     <string name="screen_pinning_toast_gesture_nav" msgid="170699893395336705">"Per sbloccare questa app, scorri verso l\'alto e tieni premuto"</string>
@@ -721,7 +721,7 @@
     <string name="notification_priority_title" msgid="2079708866333537093">"Priorità"</string>
     <string name="no_shortcut" msgid="8257177117568230126">"<xliff:g id="APP_NAME">%1$s</xliff:g> non supporta le funzionalità delle conversazioni"</string>
     <string name="bubble_overflow_empty_title" msgid="3120029421991510842">"Nessuna bolla recente"</string>
-    <string name="bubble_overflow_empty_subtitle" msgid="2030874469510497397">"Le bolle recenti e ignorate verranno visualizzate qui"</string>
+    <string name="bubble_overflow_empty_subtitle" msgid="2030874469510497397">"Le bolle recenti e ignorate appariranno qui"</string>
     <string name="notification_unblockable_desc" msgid="2073030886006190804">"Impossibile modificare queste notifiche."</string>
     <string name="notification_multichannel_desc" msgid="7414593090056236179">"Qui non è possibile configurare questo gruppo di notifiche"</string>
     <string name="notification_delegate_header" msgid="1264510071031479920">"Notifica inviata al proxy"</string>
@@ -1002,7 +1002,7 @@
     <string name="bubble_accessibility_action_move_top_right" msgid="6916868852433483569">"Sposta in alto a destra"</string>
     <string name="bubble_accessibility_action_move_bottom_left" msgid="6339015902495504715">"Sposta in basso a sinistra"</string>
     <string name="bubble_accessibility_action_move_bottom_right" msgid="7471571700628346212">"Sposta in basso a destra"</string>
-    <string name="bubble_dismiss_text" msgid="7071770411580452911">"Ignora"</string>
+    <string name="bubble_dismiss_text" msgid="1314082410868930066">"Ignora bolla"</string>
     <string name="bubbles_dont_bubble_conversation" msgid="1033040343437428822">"Non utilizzare bolle per la conversazione"</string>
     <string name="bubbles_user_education_title" msgid="5547017089271445797">"Chatta utilizzando le bolle"</string>
     <string name="bubbles_user_education_description" msgid="1160281719576715211">"Le nuove conversazioni vengono visualizzate come icone mobili o bolle. Tocca per aprire la bolla. Trascinala per spostarla."</string>
@@ -1062,9 +1062,13 @@
     <string name="controls_structure_tooltip" msgid="4355922222944447867">"Scorri per vedere altro"</string>
     <string name="controls_seeding_in_progress" msgid="3033855341410264148">"Caricamento dei consigli"</string>
     <string name="controls_media_close_session" msgid="9023534788828414585">"Chiudi questa sessione multimediale"</string>
+    <string name="controls_media_resume" msgid="1933520684481586053">"Riprendi"</string>
     <string name="controls_error_timeout" msgid="794197289772728958">"Inattivo, controlla l\'app"</string>
     <string name="controls_error_retryable" msgid="864025882878378470">"Errore. Nuovo tentativo…"</string>
-    <string name="controls_error_removed" msgid="6299213591234723805">"Dispositivo rimosso"</string>
+    <string name="controls_error_removed" msgid="6675638069846014366">"Controllo non trovato"</string>
+    <string name="controls_error_removed_title" msgid="1207794911208047818">"Il controllo non è disponibile"</string>
+    <string name="controls_error_removed_message" msgid="2885911717034750542">"Impossibile accedere a: <xliff:g id="DEVICE">%1$s</xliff:g>. Verifica nell\'app <xliff:g id="APPLICATION">%2$s</xliff:g> che il controllo sia ancora disponibile e che le impostazioni dell\'app non siano cambiate."</string>
+    <string name="controls_open_app" msgid="483650971094300141">"Apri app"</string>
     <string name="controls_error_generic" msgid="352500456918362905">"Impossibile caricare lo stato"</string>
     <string name="controls_error_failed" msgid="960228639198558525">"Errore. Riprova"</string>
     <string name="controls_in_progress" msgid="4421080500238215939">"In corso"</string>
diff --git a/packages/SystemUI/res/values-iw/strings.xml b/packages/SystemUI/res/values-iw/strings.xml
index f23254a..9d2d0cc 100644
--- a/packages/SystemUI/res/values-iw/strings.xml
+++ b/packages/SystemUI/res/values-iw/strings.xml
@@ -516,7 +516,7 @@
     <string name="clear_all_notifications_text" msgid="348312370303046130">"ניקוי הכל"</string>
     <string name="manage_notifications_text" msgid="6885645344647733116">"ניהול"</string>
     <string name="manage_notifications_history_text" msgid="57055985396576230">"היסטוריה"</string>
-    <string name="notification_section_header_incoming" msgid="5295312809341711367">"התקבלו"</string>
+    <string name="notification_section_header_incoming" msgid="850925217908095197">"התראות חדשות"</string>
     <string name="notification_section_header_gentle" msgid="6804099527336337197">"שקט"</string>
     <string name="notification_section_header_alerting" msgid="5581175033680477651">"התראות"</string>
     <string name="notification_section_header_conversations" msgid="821834744538345661">"שיחות"</string>
@@ -601,7 +601,7 @@
     <string name="screen_pinning_title" msgid="9058007390337841305">"האפליקציה מוצמדת"</string>
     <string name="screen_pinning_description" msgid="8699395373875667743">"נשאר בתצוגה עד לביטול ההצמדה. יש ללחוץ לחיצה ארוכה על הלחצנים \'הקודם\' ו\'סקירה\' כדי לבטל את ההצמדה."</string>
     <string name="screen_pinning_description_recents_invisible" msgid="4564466648700390037">"נשאר בתצוגה עד לביטול ההצמדה. יש ללחוץ לחיצה ארוכה על הלחצנים \'הקודם\' ו\'דף הבית\' כדי לבטל את ההצמדה."</string>
-    <string name="screen_pinning_description_gestural" msgid="7246323931831232068">"נשאר בתצוגה עד לביטול ההצמדה. יש להחליק למעלה ולהחזיק כדי לבטל הצמדה."</string>
+    <string name="screen_pinning_description_gestural" msgid="7246323931831232068">"היא תמשיך להופיע עד שההצמדה תבוטל. כדי לבטל את ההצמדה, יש להחליק למעלה ולהחזיק."</string>
     <string name="screen_pinning_description_accessible" msgid="7386449191953535332">"נשאר בתצוגה עד לביטול ההצמדה. יש ללחוץ לחיצה ארוכה על הלחצן \'סקירה\' כדי לבטל את ההצמדה."</string>
     <string name="screen_pinning_description_recents_invisible_accessible" msgid="2857071808674481986">"נשאר בתצוגה עד לביטול ההצמדה. יש ללחוץ לחיצה ארוכה על הלחצן \'דף הבית\' כדי לבטל את ההצמדה."</string>
     <string name="screen_pinning_exposes_personal_data" msgid="8189852022981524789">"ייתכן שתתאפשר גישה למידע אישי (כמו אנשי קשר ותוכן מהאימייל)."</string>
@@ -1012,9 +1012,9 @@
     <string name="bubble_accessibility_action_move_top_right" msgid="6916868852433483569">"העברה לפינה הימנית העליונה"</string>
     <string name="bubble_accessibility_action_move_bottom_left" msgid="6339015902495504715">"העברה לפינה השמאלית התחתונה"</string>
     <string name="bubble_accessibility_action_move_bottom_right" msgid="7471571700628346212">"העברה לפינה הימנית התחתונה"</string>
-    <string name="bubble_dismiss_text" msgid="7071770411580452911">"סגירה"</string>
+    <string name="bubble_dismiss_text" msgid="1314082410868930066">"סגירת בועה"</string>
     <string name="bubbles_dont_bubble_conversation" msgid="1033040343437428822">"אין להציג בועות לשיחה"</string>
-    <string name="bubbles_user_education_title" msgid="5547017089271445797">"לדבר בצ\'אט באמצעות בועות"</string>
+    <string name="bubbles_user_education_title" msgid="5547017089271445797">"לדבר בבועות"</string>
     <string name="bubbles_user_education_description" msgid="1160281719576715211">"שיחות חדשות מופיעות כסמלים צפים, או בועות. יש להקיש כדי לפתוח בועה. יש לגרור כדי להזיז אותה."</string>
     <string name="bubbles_user_education_manage_title" msgid="2848511858160342320">"שליטה בבועות, בכל זמן"</string>
     <string name="bubbles_user_education_manage" msgid="1391639189507036423">"יש להקיש על \'ניהול\' כדי להשבית את הבועות מהאפליקציה הזו"</string>
@@ -1023,17 +1023,14 @@
     <string name="notification_content_system_nav_changed" msgid="5077913144844684544">"הניווט במערכת עודכן. אפשר לערוך שינויים דרך ההגדרות."</string>
     <string name="notification_content_gesture_nav_available" msgid="4431460803004659888">"יש לעבור להגדרות כדי לעדכן את הניווט במערכת"</string>
     <string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"המתנה"</string>
-    <!-- no translation found for priority_onboarding_title (2893070698479227616) -->
-    <skip />
-    <!-- no translation found for priority_onboarding_behavior (5342816047020432929) -->
-    <skip />
+    <string name="priority_onboarding_title" msgid="2893070698479227616">"השיחה הוגדרה כבעלת עדיפות גבוהה"</string>
+    <string name="priority_onboarding_behavior" msgid="5342816047020432929">"שיחות בעדיפות גבוהה:"</string>
     <string name="priority_onboarding_show_at_top_text" msgid="1678400241025513541">"מופיעות בחלק העליון של קטע השיחות"</string>
     <string name="priority_onboarding_show_avatar_text" msgid="5756291381124091508">"מציגות תמונת פרופיל במסך הנעילה"</string>
     <string name="priority_onboarding_appear_as_bubble_text" msgid="4227039772250263122">"מופיעות כבועה צפה מעל האפליקציות שלך"</string>
     <string name="priority_onboarding_ignores_dnd_text" msgid="2918952762719600529">"גוברות על ההגדרה \'נא לא להפריע\'"</string>
     <string name="priority_onboarding_done_button_title" msgid="4569550984286506007">"הבנתי"</string>
-    <!-- no translation found for priority_onboarding_settings_button_title (6663601574303585927) -->
-    <skip />
+    <string name="priority_onboarding_settings_button_title" msgid="6663601574303585927">"הגדרות"</string>
     <string name="magnification_overlay_title" msgid="6584179429612427958">"חלון ליצירת שכבת-על להגדלה"</string>
     <string name="magnification_window_title" msgid="4863914360847258333">"חלון הגדלה"</string>
     <string name="magnification_controls_title" msgid="8421106606708891519">"בקרות של חלון ההגדלה"</string>
@@ -1077,9 +1074,13 @@
     <string name="controls_structure_tooltip" msgid="4355922222944447867">"יש להחליק כדי להציג עוד פריטים"</string>
     <string name="controls_seeding_in_progress" msgid="3033855341410264148">"בטעינת המלצות"</string>
     <string name="controls_media_close_session" msgid="9023534788828414585">"סגירת הסשן הזה של המדיה"</string>
+    <string name="controls_media_resume" msgid="1933520684481586053">"המשך"</string>
     <string name="controls_error_timeout" msgid="794197289772728958">"לא פעיל, יש לבדוק את האפליקציה"</string>
     <string name="controls_error_retryable" msgid="864025882878378470">"שגיאה, מתבצע ניסיון חוזר…"</string>
-    <string name="controls_error_removed" msgid="6299213591234723805">"המכשיר הוסר"</string>
+    <string name="controls_error_removed" msgid="6675638069846014366">"לא נמצא"</string>
+    <string name="controls_error_removed_title" msgid="1207794911208047818">"הפקד לא זמין"</string>
+    <string name="controls_error_removed_message" msgid="2885911717034750542">"לא ניתן להתחבר אל <xliff:g id="DEVICE">%1$s</xliff:g>. יש לבדוק את האפליקציה <xliff:g id="APPLICATION">%2$s</xliff:g> כדי לוודא שהפקד עדיין זמין ושהגדרות האפליקציה לא השתנו."</string>
+    <string name="controls_open_app" msgid="483650971094300141">"לפתיחת האפליקציה"</string>
     <string name="controls_error_generic" msgid="352500456918362905">"לא ניתן לטעון את הסטטוס"</string>
     <string name="controls_error_failed" msgid="960228639198558525">"שגיאה, יש לנסות שוב"</string>
     <string name="controls_in_progress" msgid="4421080500238215939">"בתהליך"</string>
diff --git a/packages/SystemUI/res/values-ja/strings.xml b/packages/SystemUI/res/values-ja/strings.xml
index 6e7555a..4f6c785 100644
--- a/packages/SystemUI/res/values-ja/strings.xml
+++ b/packages/SystemUI/res/values-ja/strings.xml
@@ -510,7 +510,7 @@
     <string name="clear_all_notifications_text" msgid="348312370303046130">"すべて消去"</string>
     <string name="manage_notifications_text" msgid="6885645344647733116">"管理"</string>
     <string name="manage_notifications_history_text" msgid="57055985396576230">"履歴"</string>
-    <string name="notification_section_header_incoming" msgid="5295312809341711367">"新着"</string>
+    <string name="notification_section_header_incoming" msgid="850925217908095197">"新着"</string>
     <string name="notification_section_header_gentle" msgid="6804099527336337197">"サイレント"</string>
     <string name="notification_section_header_alerting" msgid="5581175033680477651">"通知"</string>
     <string name="notification_section_header_conversations" msgid="821834744538345661">"会話"</string>
@@ -603,7 +603,7 @@
     <string name="screen_pinning_toast" msgid="8177286912533744328">"このアプリの固定を解除するには [戻る] ボタンと [最近] ボタンを長押しします"</string>
     <string name="screen_pinning_toast_recents_invisible" msgid="6850978077443052594">"このアプリの固定を解除するには [戻る] ボタンと [ホーム] ボタンを長押しします"</string>
     <string name="screen_pinning_toast_gesture_nav" msgid="170699893395336705">"このアプリの固定を解除するには、上にスワイプして長押しします"</string>
-    <string name="screen_pinning_positive" msgid="3285785989665266984">"はい"</string>
+    <string name="screen_pinning_positive" msgid="3285785989665266984">"OK"</string>
     <string name="screen_pinning_negative" msgid="6882816864569211666">"いいえ"</string>
     <string name="screen_pinning_start" msgid="7483998671383371313">"固定したアプリ"</string>
     <string name="screen_pinning_exit" msgid="4553787518387346893">"固定を解除したアプリ"</string>
@@ -1002,9 +1002,9 @@
     <string name="bubble_accessibility_action_move_top_right" msgid="6916868852433483569">"右上に移動"</string>
     <string name="bubble_accessibility_action_move_bottom_left" msgid="6339015902495504715">"左下に移動"</string>
     <string name="bubble_accessibility_action_move_bottom_right" msgid="7471571700628346212">"右下に移動"</string>
-    <string name="bubble_dismiss_text" msgid="7071770411580452911">"閉じる"</string>
+    <string name="bubble_dismiss_text" msgid="1314082410868930066">"ふきだしを閉じる"</string>
     <string name="bubbles_dont_bubble_conversation" msgid="1033040343437428822">"会話をバブルで表示しない"</string>
-    <string name="bubbles_user_education_title" msgid="5547017089271445797">"チャットでのバブルの使用"</string>
+    <string name="bubbles_user_education_title" msgid="5547017089271445797">"チャットでバブルを使う"</string>
     <string name="bubbles_user_education_description" msgid="1160281719576715211">"新しい会話はフローティング アイコン(バブル)として表示されます。タップするとバブルが開きます。ドラッグしてバブルを移動できます。"</string>
     <string name="bubbles_user_education_manage_title" msgid="2848511858160342320">"いつでもバブルを管理"</string>
     <string name="bubbles_user_education_manage" msgid="1391639189507036423">"このアプリからのバブルをオフにするには、[管理] をタップしてください"</string>
@@ -1062,9 +1062,13 @@
     <string name="controls_structure_tooltip" msgid="4355922222944447867">"スワイプすると他の構造が表示されます"</string>
     <string name="controls_seeding_in_progress" msgid="3033855341410264148">"候補を読み込んでいます"</string>
     <string name="controls_media_close_session" msgid="9023534788828414585">"このメディア セッションを閉じる"</string>
+    <string name="controls_media_resume" msgid="1933520684481586053">"再開"</string>
     <string name="controls_error_timeout" msgid="794197289772728958">"無効: アプリをご確認ください"</string>
     <string name="controls_error_retryable" msgid="864025882878378470">"エラー。再試行しています…"</string>
-    <string name="controls_error_removed" msgid="6299213591234723805">"デバイスを削除しました"</string>
+    <string name="controls_error_removed" msgid="6675638069846014366">"見つかりませんでした"</string>
+    <string name="controls_error_removed_title" msgid="1207794911208047818">"コントロールを使用できません"</string>
+    <string name="controls_error_removed_message" msgid="2885911717034750542">"「<xliff:g id="DEVICE">%1$s</xliff:g>」にアクセスできませんでした<xliff:g id="APPLICATION">%2$s</xliff:g> アプリで、コントロールが使用可能な状態でアプリの設定が変更されていないことをご確認ください。"</string>
+    <string name="controls_open_app" msgid="483650971094300141">"アプリを開く"</string>
     <string name="controls_error_generic" msgid="352500456918362905">"ステータスを読み込めません"</string>
     <string name="controls_error_failed" msgid="960228639198558525">"エラー: もう一度お試しください"</string>
     <string name="controls_in_progress" msgid="4421080500238215939">"処理中"</string>
diff --git a/packages/SystemUI/res/values-ka/strings.xml b/packages/SystemUI/res/values-ka/strings.xml
index 4aea87b..aeee416 100644
--- a/packages/SystemUI/res/values-ka/strings.xml
+++ b/packages/SystemUI/res/values-ka/strings.xml
@@ -510,7 +510,7 @@
     <string name="clear_all_notifications_text" msgid="348312370303046130">"ყველას გასუფთავება"</string>
     <string name="manage_notifications_text" msgid="6885645344647733116">"მართვა"</string>
     <string name="manage_notifications_history_text" msgid="57055985396576230">"ისტორია"</string>
-    <string name="notification_section_header_incoming" msgid="5295312809341711367">"შემომავალი"</string>
+    <string name="notification_section_header_incoming" msgid="850925217908095197">"ახალი"</string>
     <string name="notification_section_header_gentle" msgid="6804099527336337197">"ჩუმი"</string>
     <string name="notification_section_header_alerting" msgid="5581175033680477651">"შეტყობინებები"</string>
     <string name="notification_section_header_conversations" msgid="821834744538345661">"საუბრები"</string>
@@ -1002,7 +1002,7 @@
     <string name="bubble_accessibility_action_move_top_right" msgid="6916868852433483569">"გადაანაცვლეთ ზევით და მარჯვნივ"</string>
     <string name="bubble_accessibility_action_move_bottom_left" msgid="6339015902495504715">"ქვევით და მარცხნივ გადატანა"</string>
     <string name="bubble_accessibility_action_move_bottom_right" msgid="7471571700628346212">"გადაანაცვ. ქვემოთ და მარჯვნივ"</string>
-    <string name="bubble_dismiss_text" msgid="7071770411580452911">"დახურვა"</string>
+    <string name="bubble_dismiss_text" msgid="1314082410868930066">"ბუშტის დახურვა"</string>
     <string name="bubbles_dont_bubble_conversation" msgid="1033040343437428822">"აიკრძალოს საუბრის ბუშტები"</string>
     <string name="bubbles_user_education_title" msgid="5547017089271445797">"ჩეთი ბუშტების გამოყენებით"</string>
     <string name="bubbles_user_education_description" msgid="1160281719576715211">"ახალი საუბრები გამოჩნდება როგორც მოტივტივე ხატულები ან ბუშტები. შეეხეთ ბუშტის გასახსნელად. გადაიტანეთ ჩავლებით."</string>
@@ -1062,9 +1062,13 @@
     <string name="controls_structure_tooltip" msgid="4355922222944447867">"გადაფურცლეთ მეტის სანახავად"</string>
     <string name="controls_seeding_in_progress" msgid="3033855341410264148">"მიმდინარეობს რეკომენდაციების ჩატვირთვა"</string>
     <string name="controls_media_close_session" msgid="9023534788828414585">"ამ მედია სესიის დახურვა"</string>
+    <string name="controls_media_resume" msgid="1933520684481586053">"გაგრძელება"</string>
     <string name="controls_error_timeout" msgid="794197289772728958">"არააქტიურია, გადაამოწმეთ აპი"</string>
     <string name="controls_error_retryable" msgid="864025882878378470">"შეცდომა, ხელახალი მცდელობა…"</string>
-    <string name="controls_error_removed" msgid="6299213591234723805">"მოწყობილობა ამოიშალა"</string>
+    <string name="controls_error_removed" msgid="6675638069846014366">"ვერ მოიძებნა"</string>
+    <string name="controls_error_removed_title" msgid="1207794911208047818">"კონტროლი მიუწვდომელია"</string>
+    <string name="controls_error_removed_message" msgid="2885911717034750542">"<xliff:g id="DEVICE">%1$s</xliff:g>-ზე წვდომა ვერ მოხერხდა. შეამოწმეთ <xliff:g id="APPLICATION">%2$s</xliff:g> აპი, რათა დარწმუნდეთ, რომ კონტროლი კვლავაც ხელმისაწვდომია და რომ აპის პარამეტრები არ შეცვლილა."</string>
+    <string name="controls_open_app" msgid="483650971094300141">"აპის გახსნა"</string>
     <string name="controls_error_generic" msgid="352500456918362905">"სტატუსი ვერ იტვირთება"</string>
     <string name="controls_error_failed" msgid="960228639198558525">"შეცდომა, ისევ ცადეთ"</string>
     <string name="controls_in_progress" msgid="4421080500238215939">"მუშავდება"</string>
diff --git a/packages/SystemUI/res/values-kk/strings.xml b/packages/SystemUI/res/values-kk/strings.xml
index bb4ee6b..356526c 100644
--- a/packages/SystemUI/res/values-kk/strings.xml
+++ b/packages/SystemUI/res/values-kk/strings.xml
@@ -101,7 +101,7 @@
     <string name="screenrecord_start" msgid="330991441575775004">"Бастау"</string>
     <string name="screenrecord_ongoing_screen_only" msgid="4459670242451527727">"Экрандағы бейне жазылуда."</string>
     <string name="screenrecord_ongoing_screen_and_audio" msgid="5351133763125180920">"Экрандағы бейне және аудио жазылуда."</string>
-    <string name="screenrecord_taps_label" msgid="1595690528298857649">"Экранды түртуді көрсету"</string>
+    <string name="screenrecord_taps_label" msgid="1595690528298857649">"Экранды түрткенде көрсету"</string>
     <string name="screenrecord_stop_text" msgid="6549288689506057686">"Тоқтату үшін түртіңіз"</string>
     <string name="screenrecord_stop_label" msgid="72699670052087989">"Тоқтату"</string>
     <string name="screenrecord_pause_label" msgid="6004054907104549857">"Тоқтата тұру"</string>
@@ -274,7 +274,7 @@
     <string name="accessibility_quick_settings_airplane_changed_off" msgid="8880183481476943754">"Ұшақ режимі өшірілді."</string>
     <string name="accessibility_quick_settings_airplane_changed_on" msgid="6327378061894076288">"Ұшақ режимі қосылды."</string>
     <string name="accessibility_quick_settings_dnd_none_on" msgid="3235552940146035383">"үнсіз"</string>
-    <string name="accessibility_quick_settings_dnd_alarms_on" msgid="3375848309132140014">"тек дабылдар"</string>
+    <string name="accessibility_quick_settings_dnd_alarms_on" msgid="3375848309132140014">"оятқыштар ғана"</string>
     <string name="accessibility_quick_settings_dnd" msgid="2415967452264206047">"Мазаламау."</string>
     <string name="accessibility_quick_settings_dnd_changed_off" msgid="1457150026842505799">"\"Мазаламау\" режимі өшірілді."</string>
     <string name="accessibility_quick_settings_dnd_changed_on" msgid="186315911607486129">"\"Мазаламау\" режимі қосылды."</string>
@@ -344,7 +344,7 @@
     <string name="quick_settings_header_onboarding_text" msgid="1918085351115504765">"Басқа опцияларды көру үшін белгішелерді түртіп ұстап тұрыңыз"</string>
     <string name="quick_settings_dnd_label" msgid="7728690179108024338">"Мазаламау"</string>
     <string name="quick_settings_dnd_priority_label" msgid="6251076422352664571">"Маңыздылары ғана"</string>
-    <string name="quick_settings_dnd_alarms_label" msgid="1241780970469630835">"Тек дабылдар"</string>
+    <string name="quick_settings_dnd_alarms_label" msgid="1241780970469630835">"Оятқыштар ғана"</string>
     <string name="quick_settings_dnd_none_label" msgid="8420869988472836354">"Толық тыныштық"</string>
     <string name="quick_settings_bluetooth_label" msgid="7018763367142041481">"Bluetooth"</string>
     <string name="quick_settings_bluetooth_multiple_devices_label" msgid="6595808498429809855">"Bluetooth (<xliff:g id="NUMBER">%d</xliff:g> құрылғылары)"</string>
@@ -462,7 +462,7 @@
     <string name="interruption_level_none_with_warning" msgid="8394434073508145437">"Толық тыныштық. Экранды оқу құралдары да өшеді."</string>
     <string name="interruption_level_none" msgid="219484038314193379">"Толық тыныштық"</string>
     <string name="interruption_level_priority" msgid="661294280016622209">"Маңыздылары ғана"</string>
-    <string name="interruption_level_alarms" msgid="2457850481335846959">"Тек дабылдар"</string>
+    <string name="interruption_level_alarms" msgid="2457850481335846959">"Оятқыштар ғана"</string>
     <string name="interruption_level_none_twoline" msgid="8579382742855486372">"Толық\nтыныштық"</string>
     <string name="interruption_level_priority_twoline" msgid="8523482736582498083">"Тек\nбасымдық"</string>
     <string name="interruption_level_alarms_twoline" msgid="2045067991335708767">"Тек\nдабылдар"</string>
@@ -510,7 +510,7 @@
     <string name="clear_all_notifications_text" msgid="348312370303046130">"Барлығын тазалау"</string>
     <string name="manage_notifications_text" msgid="6885645344647733116">"Басқару"</string>
     <string name="manage_notifications_history_text" msgid="57055985396576230">"Тарих"</string>
-    <string name="notification_section_header_incoming" msgid="5295312809341711367">"Кіріс"</string>
+    <string name="notification_section_header_incoming" msgid="850925217908095197">"Жаңа"</string>
     <string name="notification_section_header_gentle" msgid="6804099527336337197">"Үнсіз"</string>
     <string name="notification_section_header_alerting" msgid="5581175033680477651">"Хабарландырулар"</string>
     <string name="notification_section_header_conversations" msgid="821834744538345661">"Әңгімелер"</string>
@@ -721,7 +721,7 @@
     <string name="notification_priority_title" msgid="2079708866333537093">"Маңыздылығы"</string>
     <string name="no_shortcut" msgid="8257177117568230126">"<xliff:g id="APP_NAME">%1$s</xliff:g> әңгімелесу функцияларын қолдамайды."</string>
     <string name="bubble_overflow_empty_title" msgid="3120029421991510842">"Жақындағы қалқыма хабарлар жоқ"</string>
-    <string name="bubble_overflow_empty_subtitle" msgid="2030874469510497397">"Жақында ашылған және жабылған қалқыма хабарлар осы жерде көрсетіледі."</string>
+    <string name="bubble_overflow_empty_subtitle" msgid="2030874469510497397">"Соңғы және жабылған қалқыма хабарлар осы жерде көрсетіледі."</string>
     <string name="notification_unblockable_desc" msgid="2073030886006190804">"Бұл хабарландыруларды өзгерту мүмкін емес."</string>
     <string name="notification_multichannel_desc" msgid="7414593090056236179">"Мұндай хабарландырулар бұл жерде конфигурацияланбайды."</string>
     <string name="notification_delegate_header" msgid="1264510071031479920">"Прокси-сервер арқылы жіберілген хабарландыру"</string>
@@ -1002,9 +1002,9 @@
     <string name="bubble_accessibility_action_move_top_right" msgid="6916868852433483569">"Жоғары оң жаққа жылжыту"</string>
     <string name="bubble_accessibility_action_move_bottom_left" msgid="6339015902495504715">"Төменгі сол жаққа жылжыту"</string>
     <string name="bubble_accessibility_action_move_bottom_right" msgid="7471571700628346212">"Төменгі оң жаққа жылжыту"</string>
-    <string name="bubble_dismiss_text" msgid="7071770411580452911">"Жабу"</string>
+    <string name="bubble_dismiss_text" msgid="1314082410868930066">"Қалқымалы анықтаманы жабу"</string>
     <string name="bubbles_dont_bubble_conversation" msgid="1033040343437428822">"Әңгіменің қалқыма хабары көрсетілмесін"</string>
-    <string name="bubbles_user_education_title" msgid="5547017089271445797">"Сөйлесуге арналған қалқыма хабарлар"</string>
+    <string name="bubbles_user_education_title" msgid="5547017089271445797">"Қалқыма хабарлар арқылы сөйлесу"</string>
     <string name="bubbles_user_education_description" msgid="1160281719576715211">"Жаңа әңгімелер қалқыма белгішелер немесе хабарлар түрінде көрсетіледі. Қалқыма хабарды ашу үшін түртіңіз. Жылжыту үшін сүйреңіз."</string>
     <string name="bubbles_user_education_manage_title" msgid="2848511858160342320">"Қалқыма хабарларды реттеу"</string>
     <string name="bubbles_user_education_manage" msgid="1391639189507036423">"Бұл қолданбадан қалқыма хабарларды өшіру үшін \"Басқару\" түймесін түртіңіз."</string>
@@ -1062,9 +1062,13 @@
     <string name="controls_structure_tooltip" msgid="4355922222944447867">"Толығырақ ақпарат алу үшін сырғытыңыз."</string>
     <string name="controls_seeding_in_progress" msgid="3033855341410264148">"Жүктеуге қатысты ұсыныстар"</string>
     <string name="controls_media_close_session" msgid="9023534788828414585">"Мультимедиа сеансын жабу"</string>
+    <string name="controls_media_resume" msgid="1933520684481586053">"Жалғастыру"</string>
     <string name="controls_error_timeout" msgid="794197289772728958">"Өшірулі. Қолданба тексеріңіз."</string>
     <string name="controls_error_retryable" msgid="864025882878378470">"Қате, әрекет қайталануда…"</string>
-    <string name="controls_error_removed" msgid="6299213591234723805">"Құрылғы өшірілді."</string>
+    <string name="controls_error_removed" msgid="6675638069846014366">"Табылмады"</string>
+    <string name="controls_error_removed_title" msgid="1207794911208047818">"Басқару элементтері қолжетімді емес"</string>
+    <string name="controls_error_removed_message" msgid="2885911717034750542">"<xliff:g id="DEVICE">%1$s</xliff:g> ашылмады. Басқару элементтерінің әлі қолжетімді екенін және қолданба параметрлерінің өзгермегенін тексеру үшін <xliff:g id="APPLICATION">%2$s</xliff:g> қолданбасын қараңыз."</string>
+    <string name="controls_open_app" msgid="483650971094300141">"Қолданбаны ашу"</string>
     <string name="controls_error_generic" msgid="352500456918362905">"Күйді жүктеу мүмкін емес."</string>
     <string name="controls_error_failed" msgid="960228639198558525">"Қате шықты. Қайталап көріңіз."</string>
     <string name="controls_in_progress" msgid="4421080500238215939">"Орындалуда"</string>
diff --git a/packages/SystemUI/res/values-km/strings.xml b/packages/SystemUI/res/values-km/strings.xml
index c00549c..b0f90e2 100644
--- a/packages/SystemUI/res/values-km/strings.xml
+++ b/packages/SystemUI/res/values-km/strings.xml
@@ -510,7 +510,7 @@
     <string name="clear_all_notifications_text" msgid="348312370303046130">"សម្អាត​ទាំងអស់"</string>
     <string name="manage_notifications_text" msgid="6885645344647733116">"គ្រប់គ្រង"</string>
     <string name="manage_notifications_history_text" msgid="57055985396576230">"ប្រវត្តិ"</string>
-    <string name="notification_section_header_incoming" msgid="5295312809341711367">"មក​ដល់"</string>
+    <string name="notification_section_header_incoming" msgid="850925217908095197">"ថ្មី"</string>
     <string name="notification_section_header_gentle" msgid="6804099527336337197">"ស្ងាត់"</string>
     <string name="notification_section_header_alerting" msgid="5581175033680477651">"ការជូនដំណឹង"</string>
     <string name="notification_section_header_conversations" msgid="821834744538345661">"ការសន្ទនា"</string>
@@ -595,7 +595,7 @@
     <string name="screen_pinning_title" msgid="9058007390337841305">"កម្មវិធី​ត្រូវបានខ្ទាស់"</string>
     <string name="screen_pinning_description" msgid="8699395373875667743">"វា​នឹង​នៅតែ​បង្ហាញ រហូត​ទាល់​តែ​អ្នក​ដក​ការដៅ។ សូម​សង្កត់​ប៊ូតុង​ថយ​ក្រោយ និង​ប៊ូតុង​ទិដ្ឋភាពរួម​ឲ្យ​ជាប់ ដើម្បី​ដក​ការ​ដៅ។"</string>
     <string name="screen_pinning_description_recents_invisible" msgid="4564466648700390037">"វា​នឹង​នៅតែ​បង្ហាញ រហូត​ទាល់​តែ​អ្នក​ដក​ការដៅ។ សូម​ចុចប៊ូតុង​ថយក្រោយ និងប៊ូតុង​ទំព័រដើម​ឱ្យ​ជាប់ ដើម្បី​ដក​ការ​ដៅ។"</string>
-    <string name="screen_pinning_description_gestural" msgid="7246323931831232068">"វា​នឹង​នៅតែ​បង្ហាញ រហូតទាល់​តែអ្នក​ដកការដៅ។ អូសឡើងលើ​ឱ្យជាប់ ដើម្បី​ដក​ការដៅ។"</string>
+    <string name="screen_pinning_description_gestural" msgid="7246323931831232068">"វា​នឹង​នៅតែ​បង្ហាញ រហូតទាល់​តែអ្នក​ដកខ្ទាស់ចេញ។ អូសឡើងលើ​ឱ្យជាប់ ដើម្បី​ដក​ខ្ទាស់។"</string>
     <string name="screen_pinning_description_accessible" msgid="7386449191953535332">"វា​នឹង​នៅតែ​បង្ហាញ រហូត​ទាល់​តែ​អ្នក​ដក​ការ​ដៅ។ សូម​សង្កត់​ប៊ូតុង​ទិដ្ឋភាពរួម​​ឲ្យ​ជាប់ ដើម្បី​ដក​ការ​ដៅ។"</string>
     <string name="screen_pinning_description_recents_invisible_accessible" msgid="2857071808674481986">"វា​នឹង​នៅតែ​បង្ហាញ រហូត​ទាល់​តែ​អ្នក​ដក​ការដៅ។ សូម​ចុច​ប៊ូតុង​ទំព័រដើម​ឱ្យ​ជាប់ ដើម្បី​ដក​ការ​ដៅ។"</string>
     <string name="screen_pinning_exposes_personal_data" msgid="8189852022981524789">"អាចចូលប្រើ​ទិន្នន័យផ្ទាល់ខ្លួន​បាន (ដូចជា ទំនាក់ទំនង និងខ្លឹមសារ​អ៊ីមែលជាដើម)។"</string>
@@ -1002,7 +1002,7 @@
     <string name="bubble_accessibility_action_move_top_right" msgid="6916868852433483569">"ផ្លាស់ទីទៅផ្នែកខាងលើខាងស្ដាំ"</string>
     <string name="bubble_accessibility_action_move_bottom_left" msgid="6339015902495504715">"ផ្លាស់ទីទៅផ្នែកខាងក្រោមខាងឆ្វេង​"</string>
     <string name="bubble_accessibility_action_move_bottom_right" msgid="7471571700628346212">"ផ្លាស់ទីទៅផ្នែកខាងក្រោម​ខាងស្ដាំ"</string>
-    <string name="bubble_dismiss_text" msgid="7071770411580452911">"ច្រានចោល"</string>
+    <string name="bubble_dismiss_text" msgid="1314082410868930066">"ច្រានចោល​ពពុះ"</string>
     <string name="bubbles_dont_bubble_conversation" msgid="1033040343437428822">"កុំបង្ហាញ​ការសន្ទនា​ជាពពុះ"</string>
     <string name="bubbles_user_education_title" msgid="5547017089271445797">"ជជែក​ដោយប្រើ​ពពុះ"</string>
     <string name="bubbles_user_education_description" msgid="1160281719576715211">"ការសន្ទនាថ្មីៗ​បង្ហាញជា​​ពពុះ ឬរូបអណ្ដែត។ ចុច ដើម្បីបើក​ពពុះ។ អូស ដើម្បី​ផ្លាស់ទី​ពពុះនេះ។"</string>
@@ -1062,9 +1062,13 @@
     <string name="controls_structure_tooltip" msgid="4355922222944447867">"អូសដើម្បី​មើលច្រើនទៀត"</string>
     <string name="controls_seeding_in_progress" msgid="3033855341410264148">"កំពុងផ្ទុក​ការណែនាំ"</string>
     <string name="controls_media_close_session" msgid="9023534788828414585">"បិទវគ្គ​មេឌៀ​នេះ"</string>
+    <string name="controls_media_resume" msgid="1933520684481586053">"បន្ត"</string>
     <string name="controls_error_timeout" msgid="794197289772728958">"អសកម្ម ពិនិត្យមើល​កម្មវិធី"</string>
     <string name="controls_error_retryable" msgid="864025882878378470">"បញ្ហា កំពុងព្យាយាម​ម្ដងទៀត…"</string>
-    <string name="controls_error_removed" msgid="6299213591234723805">"បានលុប​ឧបករណ៍"</string>
+    <string name="controls_error_removed" msgid="6675638069846014366">"រកមិន​ឃើញទេ"</string>
+    <string name="controls_error_removed_title" msgid="1207794911208047818">"មិនអាច​គ្រប់គ្រង​បានទេ"</string>
+    <string name="controls_error_removed_message" msgid="2885911717034750542">"មិនអាច​ចូលប្រើ <xliff:g id="DEVICE">%1$s</xliff:g> បានទេ​។ សូមពិនិត្យមើល​កម្មវិធី <xliff:g id="APPLICATION">%2$s</xliff:g> ដើម្បីប្រាកដថា​នៅតែអាច​គ្រប់គ្រងបាន ហើយថា​ការកំណត់​កម្មវិធីនេះ​មិនបានផ្លាស់ប្ដូរឡើយ​។"</string>
+    <string name="controls_open_app" msgid="483650971094300141">"បើកកម្មវិធី"</string>
     <string name="controls_error_generic" msgid="352500456918362905">"មិនអាច​ផ្ទុក​ស្ថានភាព​បានទេ"</string>
     <string name="controls_error_failed" msgid="960228639198558525">"មានបញ្ហា សូម​ព្យាយាម​ម្តងទៀត"</string>
     <string name="controls_in_progress" msgid="4421080500238215939">"កំពុងដំណើរការ"</string>
diff --git a/packages/SystemUI/res/values-kn/strings.xml b/packages/SystemUI/res/values-kn/strings.xml
index 7b707b5..ed53425 100644
--- a/packages/SystemUI/res/values-kn/strings.xml
+++ b/packages/SystemUI/res/values-kn/strings.xml
@@ -510,7 +510,8 @@
     <string name="clear_all_notifications_text" msgid="348312370303046130">"ಎಲ್ಲವನ್ನೂ ತೆರವುಗೊಳಿಸಿ"</string>
     <string name="manage_notifications_text" msgid="6885645344647733116">"ನಿರ್ವಹಿಸಿ"</string>
     <string name="manage_notifications_history_text" msgid="57055985396576230">"ಇತಿಹಾಸ"</string>
-    <string name="notification_section_header_incoming" msgid="5295312809341711367">"ಒಳಬರುವ"</string>
+    <!-- no translation found for notification_section_header_incoming (850925217908095197) -->
+    <skip />
     <string name="notification_section_header_gentle" msgid="6804099527336337197">"ನಿಶ್ಶಬ್ದ"</string>
     <string name="notification_section_header_alerting" msgid="5581175033680477651">"ಅಧಿಸೂಚನೆಗಳು"</string>
     <string name="notification_section_header_conversations" msgid="821834744538345661">"ಸಂಭಾಷಣೆಗಳು"</string>
@@ -1002,7 +1003,7 @@
     <string name="bubble_accessibility_action_move_top_right" msgid="6916868852433483569">"ಬಲ ಮೇಲ್ಭಾಗಕ್ಕೆ ಸರಿಸಿ"</string>
     <string name="bubble_accessibility_action_move_bottom_left" msgid="6339015902495504715">"ಸ್ಕ್ರೀನ್‌ನ ಎಡ ಕೆಳಭಾಗಕ್ಕೆ ಸರಿಸಿ"</string>
     <string name="bubble_accessibility_action_move_bottom_right" msgid="7471571700628346212">"ಕೆಳಗಿನ ಬಲಭಾಗಕ್ಕೆ ಸರಿಸಿ"</string>
-    <string name="bubble_dismiss_text" msgid="7071770411580452911">"ವಜಾಗೊಳಿಸಿ"</string>
+    <string name="bubble_dismiss_text" msgid="1314082410868930066">"ಬಬಲ್ ವಜಾಗೊಳಿಸಿ"</string>
     <string name="bubbles_dont_bubble_conversation" msgid="1033040343437428822">"ಸಂಭಾಷಣೆಯನ್ನು ಬಬಲ್ ಮಾಡಬೇಡಿ"</string>
     <string name="bubbles_user_education_title" msgid="5547017089271445797">"ಬಬಲ್ಸ್ ಬಳಸಿ ಚಾಟ್ ಮಾಡಿ"</string>
     <string name="bubbles_user_education_description" msgid="1160281719576715211">"ಹೊಸ ಸಂಭಾಷಣೆಗಳು ತೇಲುವ ಐಕಾನ್‌ಗಳು ಅಥವಾ ಬಬಲ್ಸ್ ಆಗಿ ಗೋಚರಿಸುತ್ತವೆ. ಬಬಲ್ ತೆರೆಯಲು ಟ್ಯಾಪ್ ಮಾಡಿ. ಅದನ್ನು ಡ್ರ್ಯಾಗ್ ಮಾಡಲು ಎಳೆಯಿರಿ."</string>
@@ -1013,17 +1014,14 @@
     <string name="notification_content_system_nav_changed" msgid="5077913144844684544">"ಸಿಸ್ಟಂ ನ್ಯಾವಿಗೇಷನ ಅಪ್‌ಡೇಟ್ ಮಾಡಲಾಗಿದೆ ಬದಲಾವಣೆಗಳನ್ನು ಮಾಡಲು, ಸೆಟ್ಟಿಂಗ್‌ಗಳಿಗೆ ಹೋಗಿ."</string>
     <string name="notification_content_gesture_nav_available" msgid="4431460803004659888">"ಸಿಸ್ಟಂ ನ್ಯಾವಿಗೇಷನ್ ಅಪ್‌ಡೇಟ್ ಮಾಡಲು ಸೆಟ್ಟಿಂಗ್‌ಗಳಿಗೆ ಹೋಗಿ"</string>
     <string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"ಸ್ಟ್ಯಾಂಡ್‌ಬೈ"</string>
-    <!-- no translation found for priority_onboarding_title (2893070698479227616) -->
-    <skip />
-    <!-- no translation found for priority_onboarding_behavior (5342816047020432929) -->
-    <skip />
+    <string name="priority_onboarding_title" msgid="2893070698479227616">"ಸಂವಾದವನ್ನು ಆದ್ಯತೆಯಾಗಿ ಹೊಂದಿಸಲಾಗಿದೆ"</string>
+    <string name="priority_onboarding_behavior" msgid="5342816047020432929">"ಆದ್ಯತೆಯ ಸಂವಾದಗಳು:"</string>
     <string name="priority_onboarding_show_at_top_text" msgid="1678400241025513541">"ಸಂಭಾಷಣೆ ವಿಭಾಗದ ಮೇಲ್ಭಾಗದಲ್ಲಿ ತೋರಿಸಿ"</string>
     <string name="priority_onboarding_show_avatar_text" msgid="5756291381124091508">"ಲಾಕ್ ಸ್ಕ್ರೀನ್‌ ಮೇಲೆ ಪ್ರೊಫೈಲ್ ಚಿತ್ರವನ್ನು ತೋರಿಸಿ"</string>
     <string name="priority_onboarding_appear_as_bubble_text" msgid="4227039772250263122">"ಆ್ಯಪ್‌ಗಳ ಮೇಲ್ಭಾಗದಲ್ಲಿ ತೇಲುವ ಬಬಲ್‌ನಂತೆ ಗೋಚರಿಸಲಿ"</string>
     <string name="priority_onboarding_ignores_dnd_text" msgid="2918952762719600529">"ಅಡಚಣೆ ಮಾಡಬೇಡ ಅನ್ನು ಅಡ್ಡಿಪಡಿಸಿ"</string>
     <string name="priority_onboarding_done_button_title" msgid="4569550984286506007">"ಅರ್ಥವಾಯಿತು"</string>
-    <!-- no translation found for priority_onboarding_settings_button_title (6663601574303585927) -->
-    <skip />
+    <string name="priority_onboarding_settings_button_title" msgid="6663601574303585927">"ಸೆಟ್ಟಿಂಗ್‌ಗಳು"</string>
     <string name="magnification_overlay_title" msgid="6584179429612427958">"ವರ್ಧನೆಯ ಓವರ್‌ಲೇ ವಿಂಡೋ"</string>
     <string name="magnification_window_title" msgid="4863914360847258333">"ವರ್ಧನೆಯ ವಿಂಡೋ"</string>
     <string name="magnification_controls_title" msgid="8421106606708891519">"ವರ್ಧನೆಯ ವಿಂಡೋ ನಿಯಂತ್ರಣಗಳು"</string>
@@ -1065,9 +1063,13 @@
     <string name="controls_structure_tooltip" msgid="4355922222944447867">"ಇನ್ನಷ್ಟು ನೋಡಲು ಸ್ವೈಪ್ ಮಾಡಿ"</string>
     <string name="controls_seeding_in_progress" msgid="3033855341410264148">"ಶಿಫಾರಸುಗಳು ಲೋಡ್ ಆಗುತ್ತಿವೆ"</string>
     <string name="controls_media_close_session" msgid="9023534788828414585">"ಈ ಮಾಧ್ಯಮ ಸೆಶನ್ ಅನ್ನು ಮುಚ್ಚಿರಿ"</string>
+    <string name="controls_media_resume" msgid="1933520684481586053">"ಪುನರಾರಂಭಿಸಿ"</string>
     <string name="controls_error_timeout" msgid="794197289772728958">"ನಿಷ್ಕ್ರಿಯ, ಆ್ಯಪ್ ಪರಿಶೀಲಿಸಿ"</string>
     <string name="controls_error_retryable" msgid="864025882878378470">"ದೋಷ, ಮರುಪ್ರಯತ್ನಿಸಲಾಗುತ್ತಿದೆ…"</string>
-    <string name="controls_error_removed" msgid="6299213591234723805">"ಸಾಧನವನ್ನು ತೆಗೆದುಹಾಕಲಾಗಿದೆ"</string>
+    <string name="controls_error_removed" msgid="6675638069846014366">"ಕಂಡುಬಂದಿಲ್ಲ"</string>
+    <string name="controls_error_removed_title" msgid="1207794911208047818">"ನಿಯಂತ್ರಣ ಲಭ್ಯವಿಲ್ಲ"</string>
+    <string name="controls_error_removed_message" msgid="2885911717034750542">"<xliff:g id="DEVICE">%1$s</xliff:g> ಪ್ರವೇಶಿಸಲು ಸಾಧ್ಯವಾಗಲಿಲ್ಲ. ನಿಯಂತ್ರಣ ಈಗಲೂ ಲಭ್ಯವಿದೆ ಮತ್ತು ಆ್ಯಪ್ ಸೆಟ್ಟಿಂಗ್‌ಗಳನ್ನು ಬದಲಾಯಿಸಲಾಗಿಲ್ಲ ಎಂಬುದನ್ನು ಖಚಿತಪಡಿಸಿಕೊಳ್ಳಲು <xliff:g id="APPLICATION">%2$s</xliff:g> ಆ್ಯಪ್ ಅನ್ನು ಪರಿಶೀಲಿಸಿ."</string>
+    <string name="controls_open_app" msgid="483650971094300141">"ಆ್ಯಪ್ ತೆರೆಯಿರಿ"</string>
     <string name="controls_error_generic" msgid="352500456918362905">"ಸ್ಥಿತಿ ಲೋಡ್ ಮಾಡಲು ಸಾಧ್ಯವಿಲ್ಲ"</string>
     <string name="controls_error_failed" msgid="960228639198558525">"ದೋಷ, ಮತ್ತೆ ಪ್ರಯತ್ನಿಸಿ"</string>
     <string name="controls_in_progress" msgid="4421080500238215939">"ಪ್ರಗತಿಯಲ್ಲಿದೆ"</string>
diff --git a/packages/SystemUI/res/values-ko/strings.xml b/packages/SystemUI/res/values-ko/strings.xml
index 263c4dd..a27f4f7 100644
--- a/packages/SystemUI/res/values-ko/strings.xml
+++ b/packages/SystemUI/res/values-ko/strings.xml
@@ -510,7 +510,7 @@
     <string name="clear_all_notifications_text" msgid="348312370303046130">"모두 지우기"</string>
     <string name="manage_notifications_text" msgid="6885645344647733116">"관리"</string>
     <string name="manage_notifications_history_text" msgid="57055985396576230">"기록"</string>
-    <string name="notification_section_header_incoming" msgid="5295312809341711367">"최근 알림"</string>
+    <string name="notification_section_header_incoming" msgid="850925217908095197">"새 알림"</string>
     <string name="notification_section_header_gentle" msgid="6804099527336337197">"무음"</string>
     <string name="notification_section_header_alerting" msgid="5581175033680477651">"알림"</string>
     <string name="notification_section_header_conversations" msgid="821834744538345661">"대화"</string>
@@ -720,7 +720,7 @@
     <string name="notification_conversation_channel_settings" msgid="2409977688430606835">"설정"</string>
     <string name="notification_priority_title" msgid="2079708866333537093">"우선순위"</string>
     <string name="no_shortcut" msgid="8257177117568230126">"<xliff:g id="APP_NAME">%1$s</xliff:g> 앱은 대화 기능을 지원하지 않습니다."</string>
-    <string name="bubble_overflow_empty_title" msgid="3120029421991510842">"최근에 닫은 대화창 없음"</string>
+    <string name="bubble_overflow_empty_title" msgid="3120029421991510842">"최근 대화창 없음"</string>
     <string name="bubble_overflow_empty_subtitle" msgid="2030874469510497397">"최근 대화창과 내가 닫은 대화창이 여기에 표시됩니다."</string>
     <string name="notification_unblockable_desc" msgid="2073030886006190804">"이 알림은 수정할 수 없습니다."</string>
     <string name="notification_multichannel_desc" msgid="7414593090056236179">"이 알림 그룹은 여기에서 설정할 수 없습니다."</string>
@@ -1002,9 +1002,9 @@
     <string name="bubble_accessibility_action_move_top_right" msgid="6916868852433483569">"오른쪽 상단으로 이동"</string>
     <string name="bubble_accessibility_action_move_bottom_left" msgid="6339015902495504715">"왼쪽 하단으로 이동"</string>
     <string name="bubble_accessibility_action_move_bottom_right" msgid="7471571700628346212">"오른쪽 하단으로 이동"</string>
-    <string name="bubble_dismiss_text" msgid="7071770411580452911">"닫기"</string>
+    <string name="bubble_dismiss_text" msgid="1314082410868930066">"대화창 닫기"</string>
     <string name="bubbles_dont_bubble_conversation" msgid="1033040343437428822">"대화를 대화창으로 표시하지 않음"</string>
-    <string name="bubbles_user_education_title" msgid="5547017089271445797">"대화창을 사용하여 채팅하세요"</string>
+    <string name="bubbles_user_education_title" msgid="5547017089271445797">"대화창으로 채팅하기"</string>
     <string name="bubbles_user_education_description" msgid="1160281719576715211">"새로운 대화가 플로팅 아이콘인 대화창으로 표시됩니다. 대화창을 열려면 탭하세요. 드래그하여 이동할 수 있습니다."</string>
     <string name="bubbles_user_education_manage_title" msgid="2848511858160342320">"언제든지 대화창을 제어하세요"</string>
     <string name="bubbles_user_education_manage" msgid="1391639189507036423">"이 앱에서 대화창을 사용 중지하려면 관리를 탭하세요."</string>
@@ -1062,9 +1062,13 @@
     <string name="controls_structure_tooltip" msgid="4355922222944447867">"자세히 보려면 스와이프하세요."</string>
     <string name="controls_seeding_in_progress" msgid="3033855341410264148">"추천 제어 기능 로드 중"</string>
     <string name="controls_media_close_session" msgid="9023534788828414585">"이 미디어 세션 닫기"</string>
+    <string name="controls_media_resume" msgid="1933520684481586053">"다시 시작"</string>
     <string name="controls_error_timeout" msgid="794197289772728958">"비활성. 앱을 확인하세요."</string>
     <string name="controls_error_retryable" msgid="864025882878378470">"오류 발생, 다시 시도 중…"</string>
-    <string name="controls_error_removed" msgid="6299213591234723805">"기기가 삭제됨"</string>
+    <string name="controls_error_removed" msgid="6675638069846014366">"찾을 수 없음"</string>
+    <string name="controls_error_removed_title" msgid="1207794911208047818">"컨트롤을 사용할 수 없음"</string>
+    <string name="controls_error_removed_message" msgid="2885911717034750542">"<xliff:g id="DEVICE">%1$s</xliff:g>에 액세스할 수 없습니다. <xliff:g id="APPLICATION">%2$s</xliff:g> 앱에서 컨트롤을 계속 사용할 수 있는지와 앱 설정이 변경되지 않았는지 확인하세요."</string>
+    <string name="controls_open_app" msgid="483650971094300141">"앱 열기"</string>
     <string name="controls_error_generic" msgid="352500456918362905">"통계를 로드할 수 없음"</string>
     <string name="controls_error_failed" msgid="960228639198558525">"오류. 다시 시도하세요."</string>
     <string name="controls_in_progress" msgid="4421080500238215939">"진행 중"</string>
diff --git a/packages/SystemUI/res/values-ky/strings.xml b/packages/SystemUI/res/values-ky/strings.xml
index dcd10cc..74f43e8 100644
--- a/packages/SystemUI/res/values-ky/strings.xml
+++ b/packages/SystemUI/res/values-ky/strings.xml
@@ -95,7 +95,7 @@
     <string name="screenrecord_description" msgid="1123231719680353736">"Жаздыруу учурунда Android тутуму экраныңызда көрүнүп турган жана түзмөктө ойноп жаткан бардык купуя маалыматты жаздырып алат. Буга сырсөздөр, төлөм маалыматы, сүрөттөр, билдирүүлөр жана аудио файлдар кирет."</string>
     <string name="screenrecord_audio_label" msgid="6183558856175159629">"Аудио жаздыруу"</string>
     <string name="screenrecord_device_audio_label" msgid="9016927171280567791">"Түзмөктүн аудиосу"</string>
-    <string name="screenrecord_device_audio_description" msgid="4922694220572186193">"Музыка, чалуулар жана рингтондор сыяктуу түзмөгүңүздөгү добуштар"</string>
+    <string name="screenrecord_device_audio_description" msgid="4922694220572186193">"Музыка, чалуулар жана шыңгырлар сыяктуу түзмөгүңүздөгү добуштар"</string>
     <string name="screenrecord_mic_label" msgid="2111264835791332350">"Микрофон"</string>
     <string name="screenrecord_device_audio_and_mic_label" msgid="1831323771978646841">"Түзмөктүн аудиосу жана микрофон"</string>
     <string name="screenrecord_start" msgid="330991441575775004">"Баштадык"</string>
@@ -506,11 +506,11 @@
     <string name="media_projection_dialog_service_text" msgid="958000992162214611">"Бул функцияны аткарган кызматка экраныңыздагы бардык маалымат же түзмөктө ойнотулуп жаткан нерсе, сырсөздөр, төлөмдөрдүн чоо-жайы, сүрөттөр, билдирүүлөр жана аудио файлдар жеткиликтүү болот."</string>
     <string name="media_projection_dialog_service_title" msgid="2888507074107884040">"Жаздырып же тышкы экранга чыгарып баштайсызбы?"</string>
     <string name="media_projection_dialog_title" msgid="3316063622495360646">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> менен жаздырылып же тышкы экранга чыгарылып башталсынбы?"</string>
-    <string name="media_projection_remember_text" msgid="6896767327140422951">"Экинчи көрсөтүлбөсүн"</string>
+    <string name="media_projection_remember_text" msgid="6896767327140422951">"Экинчи көрүнбөсүн"</string>
     <string name="clear_all_notifications_text" msgid="348312370303046130">"Баарын тазалап салуу"</string>
     <string name="manage_notifications_text" msgid="6885645344647733116">"Башкаруу"</string>
     <string name="manage_notifications_history_text" msgid="57055985396576230">"Таржымал"</string>
-    <string name="notification_section_header_incoming" msgid="5295312809341711367">"Кирүүчү"</string>
+    <string name="notification_section_header_incoming" msgid="850925217908095197">"Жаңы"</string>
     <string name="notification_section_header_gentle" msgid="6804099527336337197">"Үнсүз"</string>
     <string name="notification_section_header_alerting" msgid="5581175033680477651">"Билдирмелер"</string>
     <string name="notification_section_header_conversations" msgid="821834744538345661">"Жазышуулар"</string>
@@ -598,7 +598,7 @@
     <string name="screen_pinning_description_gestural" msgid="7246323931831232068">"Ал бошотулмайынча көрүнө берет. Бошотуу үчүн өйдө сүрүп, коё бербей басып туруңуз."</string>
     <string name="screen_pinning_description_accessible" msgid="7386449191953535332">"Ал бошотулмайынча көрүнө берет. Бошотуу үчүн, \"Карап чыгуу\" баскычын басып, кармап туруңуз."</string>
     <string name="screen_pinning_description_recents_invisible_accessible" msgid="2857071808674481986">"Ал бошотулмайынча көрүнө берет. Бошотуу үчүн, \"Башкы бет\" баскычын басып, кармап туруңуз."</string>
-    <string name="screen_pinning_exposes_personal_data" msgid="8189852022981524789">"Байланыштар жана электрондук почталардын мазмуну сыяктуу жеке дайындар ачык болушу мүмкүн."</string>
+    <string name="screen_pinning_exposes_personal_data" msgid="8189852022981524789">"Байланыштар жана электрондук почталардын мазмуну сыяктуу жеке маалымат ачык болушу мүмкүн."</string>
     <string name="screen_pinning_can_open_other_apps" msgid="7529756813231421455">"Кадалган колдонмо башка колдонмолорду ача алат."</string>
     <string name="screen_pinning_toast" msgid="8177286912533744328">"Бул колдонмону бошотуу үчүн \"Артка\" жана \"Назар салуу\" баскычтарын басып, кармап туруңуз"</string>
     <string name="screen_pinning_toast_recents_invisible" msgid="6850978077443052594">"Бул колдонмону бошотуу үчүн \"Артка\" жана \"Башкы бет\" баскычтарын басып, кармап туруңуз"</string>
@@ -714,14 +714,14 @@
     <string name="notification_channel_summary_low" msgid="4860617986908931158">"Үнү чыкпайт жана дирилдебейт"</string>
     <string name="notification_conversation_summary_low" msgid="1734433426085468009">"Үнү чыгып же дирилдебейт жана жазышуу бөлүмүнүн ылдый жагында көрүнөт"</string>
     <string name="notification_channel_summary_default" msgid="3282930979307248890">"Телефондун жөндөөлөрүнө жараша шыңгырап же дирилдеши мүмкүн"</string>
-    <string name="notification_channel_summary_default_with_bubbles" msgid="1782419896613644568">"Телефондун жөндөөлөрүнө жараша шыңгырап же дирилдеши мүмкүн. <xliff:g id="APP_NAME">%1$s</xliff:g> колдонмосундагы жазышуулар демейки жөндөө боюнча калкып чыкма билдирмелер болуп көрүнөт."</string>
+    <string name="notification_channel_summary_default_with_bubbles" msgid="1782419896613644568">"Телефондун жөндөөлөрүнө жараша шыңгырап же дирилдеши мүмкүн. <xliff:g id="APP_NAME">%1$s</xliff:g> колдонмосундагы жазышуулар демейки жөндөө боюнча калкып чыкма билдирмелер түрүндө көрүнөт."</string>
     <string name="notification_channel_summary_bubble" msgid="7235935211580860537">"Калкыма ыкчам баскыч менен көңүлүңүздү бул мазмунга буруп турат."</string>
     <string name="notification_channel_summary_priority" msgid="7952654515769021553">"Жазышуу бөлүмүнүн жогорку жагында калкып чыкма билдирме түрүндө көрүнүп, профиль сүрөтү кулпуланган экрандан чагылдырылат"</string>
     <string name="notification_conversation_channel_settings" msgid="2409977688430606835">"Жөндөөлөр"</string>
     <string name="notification_priority_title" msgid="2079708866333537093">"Маанилүүлүгү"</string>
     <string name="no_shortcut" msgid="8257177117568230126">"<xliff:g id="APP_NAME">%1$s</xliff:g> жазышуу функцияларын колдоого албайт"</string>
-    <string name="bubble_overflow_empty_title" msgid="3120029421991510842">"Акыркы калкып чыкма билдирмелер жок"</string>
-    <string name="bubble_overflow_empty_subtitle" msgid="2030874469510497397">"Кайра жөнөтүлгөн жана жабылган калкып чыкма билдирмелер ушул жерде көрүнөт"</string>
+    <string name="bubble_overflow_empty_title" msgid="3120029421991510842">"Азырынча эч нерсе жок"</string>
+    <string name="bubble_overflow_empty_subtitle" msgid="2030874469510497397">"Акыркы жана жабылган калкып чыкма билдирмелер ушул жерде көрүнөт"</string>
     <string name="notification_unblockable_desc" msgid="2073030886006190804">"Бул билдирмелерди өзгөртүүгө болбойт."</string>
     <string name="notification_multichannel_desc" msgid="7414593090056236179">"Бул билдирмелердин тобун бул жерде конфигурациялоого болбойт"</string>
     <string name="notification_delegate_header" msgid="1264510071031479920">"Прокси билдирмеси"</string>
@@ -864,12 +864,12 @@
   <string-array name="clock_options">
     <item msgid="3986445361435142273">"Сааттар, мүнөттөр жана секунддар"</item>
     <item msgid="1271006222031257266">"Сааттар жана мүнөттөр (демейки шартта)"</item>
-    <item msgid="6135970080453877218">"Бул сүрөтчө көрсөтүлбөсүн"</item>
+    <item msgid="6135970080453877218">"Бул сүрөтчө көрүнбөсүн"</item>
   </string-array>
   <string-array name="battery_options">
     <item msgid="7714004721411852551">"Ар дайым пайызы көрсөтүлсүн"</item>
     <item msgid="3805744470661798712">"Кубаттоо учурунда пайызы көрсөтүлсүн (демейки)"</item>
-    <item msgid="8619482474544321778">"Бул сүрөтчө көрсөтүлбөсүн"</item>
+    <item msgid="8619482474544321778">"Бул сүрөтчө көрүнбөсүн"</item>
   </string-array>
     <string name="tuner_low_priority" msgid="8412666814123009820">"Анча маанилүү эмес билдирменин сүрөтчөлөрүн көрсөтүү"</string>
     <string name="other" msgid="429768510980739978">"Башка"</string>
@@ -1002,10 +1002,10 @@
     <string name="bubble_accessibility_action_move_top_right" msgid="6916868852433483569">"Жогорку оң жакка жылдырыңыз"</string>
     <string name="bubble_accessibility_action_move_bottom_left" msgid="6339015902495504715">"Төмөнкү сол жакка жылдыруу"</string>
     <string name="bubble_accessibility_action_move_bottom_right" msgid="7471571700628346212">"Төмөнкү оң жакка жылдырыңыз"</string>
-    <string name="bubble_dismiss_text" msgid="7071770411580452911">"Жабуу"</string>
+    <string name="bubble_dismiss_text" msgid="1314082410868930066">"Калкып чыкма билдирмени жабуу"</string>
     <string name="bubbles_dont_bubble_conversation" msgid="1033040343437428822">"Жазышуу калкып чыкма билдирмеде көрүнбөсүн"</string>
     <string name="bubbles_user_education_title" msgid="5547017089271445797">"Калкып чыкма билдирмелер аркылуу маектешүү"</string>
-    <string name="bubbles_user_education_description" msgid="1160281719576715211">"Жаңы жазышуулар калкыма сүрөтчөлөр же калкып чыкма билдирмелер болуп көрүнөт. Калкып чыкма билдирмелерди ачуу үчүн таптап коюңуз. Жылдыруу үчүн сүйрөңүз."</string>
+    <string name="bubbles_user_education_description" msgid="1160281719576715211">"Жаңы жазышуулар калкыма сүрөтчөлөр же калкып чыкма билдирмелер түрүндө көрүнөт. Калкып чыкма билдирмелерди ачуу үчүн таптап коюңуз. Жылдыруу үчүн сүйрөңүз."</string>
     <string name="bubbles_user_education_manage_title" msgid="2848511858160342320">"Калкып чыкма билдирмелерди каалаган убакта көзөмөлдөңүз"</string>
     <string name="bubbles_user_education_manage" msgid="1391639189507036423">"Бул колдонмодогу калкып чыкма билдирмелерди өчүрүү үчүн \"Башкарууну\" басыңыз"</string>
     <string name="bubbles_user_education_got_it" msgid="8282812431953161143">"Түшүндүм"</string>
@@ -1062,9 +1062,13 @@
     <string name="controls_structure_tooltip" msgid="4355922222944447867">"Дагы көрүү үчүн экранды сүрүп коюңуз"</string>
     <string name="controls_seeding_in_progress" msgid="3033855341410264148">"Сунуштар жүктөлүүдө"</string>
     <string name="controls_media_close_session" msgid="9023534788828414585">"Бул медиа сеансын жабуу"</string>
+    <string name="controls_media_resume" msgid="1933520684481586053">"Улантуу"</string>
     <string name="controls_error_timeout" msgid="794197289772728958">"Жигерсиз. Колдонмону текшериңиз"</string>
     <string name="controls_error_retryable" msgid="864025882878378470">"Ката, дагы аракет жасалууда…"</string>
-    <string name="controls_error_removed" msgid="6299213591234723805">"Түзмөктү көзөмөлдөө өчүрүлдү"</string>
+    <string name="controls_error_removed" msgid="6675638069846014366">"Табылган жок"</string>
+    <string name="controls_error_removed_title" msgid="1207794911208047818">"Көзөмөл жеткиликтүү эмес"</string>
+    <string name="controls_error_removed_message" msgid="2885911717034750542">"<xliff:g id="DEVICE">%1$s</xliff:g> түзмөгүнө кирүү мүмкүнчүлүгү жок. <xliff:g id="APPLICATION">%2$s</xliff:g> колдонмосуна өтүп, көзөмөл жеткиликтүү экенин жана колдонмонун жөндөөлөрү өзгөрбөгөнүн текшериңиз."</string>
+    <string name="controls_open_app" msgid="483650971094300141">"Колдонмону ачуу"</string>
     <string name="controls_error_generic" msgid="352500456918362905">"Абалы жүктөлгөн жок"</string>
     <string name="controls_error_failed" msgid="960228639198558525">"Ката, кайталап көрүңүз"</string>
     <string name="controls_in_progress" msgid="4421080500238215939">"Аткарылууда"</string>
diff --git a/packages/SystemUI/res/values-land/dimens.xml b/packages/SystemUI/res/values-land/dimens.xml
index d118d89..2d42ce6 100644
--- a/packages/SystemUI/res/values-land/dimens.xml
+++ b/packages/SystemUI/res/values-land/dimens.xml
@@ -31,7 +31,6 @@
     <dimen name="battery_detail_graph_space_bottom">9dp</dimen>
 
     <integer name="quick_settings_num_columns">4</integer>
-    <bool name="quick_settings_wide">true</bool>
     <dimen name="qs_detail_margin_top">0dp</dimen>
 
     <dimen name="volume_tool_tip_right_margin">136dp</dimen>
diff --git a/packages/SystemUI/res/values-lo/strings.xml b/packages/SystemUI/res/values-lo/strings.xml
index a7e9d8d..0fe47aa 100644
--- a/packages/SystemUI/res/values-lo/strings.xml
+++ b/packages/SystemUI/res/values-lo/strings.xml
@@ -510,7 +510,7 @@
     <string name="clear_all_notifications_text" msgid="348312370303046130">"ລຶບລ້າງທັງໝົດ"</string>
     <string name="manage_notifications_text" msgid="6885645344647733116">"ຈັດການ"</string>
     <string name="manage_notifications_history_text" msgid="57055985396576230">"ປະຫວັດ"</string>
-    <string name="notification_section_header_incoming" msgid="5295312809341711367">"ຂາເຂົ້າ"</string>
+    <string name="notification_section_header_incoming" msgid="850925217908095197">"ໃໝ່"</string>
     <string name="notification_section_header_gentle" msgid="6804099527336337197">"ປິດສຽງ"</string>
     <string name="notification_section_header_alerting" msgid="5581175033680477651">"ການແຈ້ງເຕືອນ"</string>
     <string name="notification_section_header_conversations" msgid="821834744538345661">"ການສົນທະນາ"</string>
@@ -598,7 +598,7 @@
     <string name="screen_pinning_description_gestural" msgid="7246323931831232068">"ນີ້ຈະເຮັດໃຫ້ມັນຢູ່ໃນມຸມມອງຈົນກວ່າທ່ານຈະເຊົາປັກໝຸດ. ປັດຂຶ້ນຄ້າງໄວ້ເພື່ອເຊົາປັກໝຸດ."</string>
     <string name="screen_pinning_description_accessible" msgid="7386449191953535332">"ນີ້ຈະສະແດງມັນໃນໜ້າຈໍຈົນກວ່າທ່ານຈະເຊົາປັກມຸດ. ໃຫ້ແຕະປຸ່ມພາບຮວມຄ້າງໄວ້ເພື່ອຍົກເລີກການປັກມຸດ."</string>
     <string name="screen_pinning_description_recents_invisible_accessible" msgid="2857071808674481986">"ນີ້ຈະສະແດງມັນໃນໜ້າຈໍຈົນກວ່າທ່ານຈະເຊົາປັກໝຸດ. ໃຫ້ແຕະປຸ່ມພາບຮວມຄ້າງໄວ້ເພື່ອຍົກເລີກການປັກໝຸດ."</string>
-    <string name="screen_pinning_exposes_personal_data" msgid="8189852022981524789">"ອາດສາມາດເຂົ້າເຖິງຂໍ້ມູນສ່ວນຕົວໄດ້ (ເຊັ່ນ: ລາຍຊື່ຜູ້ຕິດຕໍ່ ແລະ ເນື້ອຫາອີເມວ)"</string>
+    <string name="screen_pinning_exposes_personal_data" msgid="8189852022981524789">"ອາດສາມາດເຂົ້າເຖິງຂໍ້ມູນສ່ວນຕົວໄດ້ (ເຊັ່ນ: ລາຍຊື່ຜູ້ຕິດຕໍ່ ແລະ ເນື້ອຫາອີເມວ)."</string>
     <string name="screen_pinning_can_open_other_apps" msgid="7529756813231421455">"ແອັບທີ່ປັກໝຸດໄວ້ອາດເປີດແອັບອື່ນ."</string>
     <string name="screen_pinning_toast" msgid="8177286912533744328">"ເພື່ອຍົກເລີກການປັກໝຸດແອັບນີ້, ໃຫ້ແຕະປຸ່ມກັບຄືນ ແລະ ປຸ່ມພາບຮວມຄ້າງໄວ້"</string>
     <string name="screen_pinning_toast_recents_invisible" msgid="6850978077443052594">"ເພື່ອຍົກເລີກການປັກໝຸດແອັບນີ້, ໃຫ້ແຕະປຸ່ມກັບຄືນ ແລະ ປຸ່ມພາບຮວມຄ້າງໄວ້"</string>
@@ -1002,7 +1002,7 @@
     <string name="bubble_accessibility_action_move_top_right" msgid="6916868852433483569">"ຍ້າຍຂວາເທິງ"</string>
     <string name="bubble_accessibility_action_move_bottom_left" msgid="6339015902495504715">"ຍ້າຍຊ້າຍລຸ່ມ"</string>
     <string name="bubble_accessibility_action_move_bottom_right" msgid="7471571700628346212">"ຍ້າຍຂວາລຸ່ມ"</string>
-    <string name="bubble_dismiss_text" msgid="7071770411580452911">"ປິດໄວ້"</string>
+    <string name="bubble_dismiss_text" msgid="1314082410868930066">"ປິດ bubble ໄວ້"</string>
     <string name="bubbles_dont_bubble_conversation" msgid="1033040343437428822">"ຢ່າໃຊ້ຟອງໃນການສົນທະນາ"</string>
     <string name="bubbles_user_education_title" msgid="5547017089271445797">"ສົນທະນາໂດຍໃຊ້ຟອງ"</string>
     <string name="bubbles_user_education_description" msgid="1160281719576715211">"ການສົນທະນາໃໝ່ຈະປາກົດເປັນໄອຄອນ ຫຼື ຟອງແບບລອຍ. ແຕະເພື່ອເປີດຟອງ. ລາກເພື່ອຍ້າຍມັນ."</string>
@@ -1062,9 +1062,13 @@
     <string name="controls_structure_tooltip" msgid="4355922222944447867">"ປັດເພື່ອເບິ່ງເພີ່ມເຕີມ"</string>
     <string name="controls_seeding_in_progress" msgid="3033855341410264148">"ກຳລັງໂຫຼດຄຳແນະນຳ"</string>
     <string name="controls_media_close_session" msgid="9023534788828414585">"ປິດເຊດຊັນມີເດຍນີ້"</string>
+    <string name="controls_media_resume" msgid="1933520684481586053">"ສືບຕໍ່"</string>
     <string name="controls_error_timeout" msgid="794197289772728958">"ບໍ່ເຮັດວຽກ, ກະລຸນາກວດສອບແອັບ"</string>
     <string name="controls_error_retryable" msgid="864025882878378470">"ຜິດພາດ, ກໍາລັງ​ລອງ​ໃໝ່…"</string>
-    <string name="controls_error_removed" msgid="6299213591234723805">"ລຶບອຸປະກອນອອກແລ້ວ"</string>
+    <string name="controls_error_removed" msgid="6675638069846014366">"ບໍ່ພົບ"</string>
+    <string name="controls_error_removed_title" msgid="1207794911208047818">"ບໍ່ສາມາດໃຊ້ການຄວບຄຸມໄດ້"</string>
+    <string name="controls_error_removed_message" msgid="2885911717034750542">"ບໍ່ສາມາດເຂົ້າເຖິງ <xliff:g id="DEVICE">%1$s</xliff:g> ໄດ້. ກະລຸນາກວດສອບແອັບ <xliff:g id="APPLICATION">%2$s</xliff:g> ເພື່ອເບິ່ງວ່າຍັງສາມາດໃຊ້ການຄວບຄຸມໄດ້ຫຼືບໍ່ ແລະ ຍັງບໍ່ໄດ້ປ່ຽນການຕັ້ງຄ່າແອັບເທື່ອ."</string>
+    <string name="controls_open_app" msgid="483650971094300141">"ເປີດແອັບ"</string>
     <string name="controls_error_generic" msgid="352500456918362905">"ບໍ່ສາມາດໂຫຼດສະຖານະໄດ້"</string>
     <string name="controls_error_failed" msgid="960228639198558525">"​ຜິດ​ພາດ​, ກະລຸນາລອງໃໝ່"</string>
     <string name="controls_in_progress" msgid="4421080500238215939">"ກຳລັງດຳເນີນການຢູ່"</string>
diff --git a/packages/SystemUI/res/values-lt/strings.xml b/packages/SystemUI/res/values-lt/strings.xml
index a090319..59cab57 100644
--- a/packages/SystemUI/res/values-lt/strings.xml
+++ b/packages/SystemUI/res/values-lt/strings.xml
@@ -516,7 +516,7 @@
     <string name="clear_all_notifications_text" msgid="348312370303046130">"Viską išvalyti"</string>
     <string name="manage_notifications_text" msgid="6885645344647733116">"Tvarkyti"</string>
     <string name="manage_notifications_history_text" msgid="57055985396576230">"Istorija"</string>
-    <string name="notification_section_header_incoming" msgid="5295312809341711367">"Gaunami"</string>
+    <string name="notification_section_header_incoming" msgid="850925217908095197">"Nauja"</string>
     <string name="notification_section_header_gentle" msgid="6804099527336337197">"Tylūs"</string>
     <string name="notification_section_header_alerting" msgid="5581175033680477651">"Pranešimai"</string>
     <string name="notification_section_header_conversations" msgid="821834744538345661">"Pokalbiai"</string>
@@ -724,10 +724,10 @@
     <string name="notification_channel_summary_bubble" msgid="7235935211580860537">"Naudojant slankųjį spartųjį klavišą lengviau sutelkti dėmesį į šį turinį."</string>
     <string name="notification_channel_summary_priority" msgid="7952654515769021553">"Rodoma pokalbių skilties viršuje, rodoma kaip slankusis burbulas, pateikiama profilio nuotrauka užrakinimo ekrane"</string>
     <string name="notification_conversation_channel_settings" msgid="2409977688430606835">"Nustatymai"</string>
-    <string name="notification_priority_title" msgid="2079708866333537093">"Prioritetas"</string>
+    <string name="notification_priority_title" msgid="2079708866333537093">"Prioritetiniai"</string>
     <string name="no_shortcut" msgid="8257177117568230126">"Programa „<xliff:g id="APP_NAME">%1$s</xliff:g>“ nepalaiko pokalbių funkcijų"</string>
     <string name="bubble_overflow_empty_title" msgid="3120029421991510842">"Nėra naujausių burbulų"</string>
-    <string name="bubble_overflow_empty_subtitle" msgid="2030874469510497397">"Naujausi ir atsisakyti burbulus bus rodomi čia"</string>
+    <string name="bubble_overflow_empty_subtitle" msgid="2030874469510497397">"Naujausi ir atsisakyti burbulai bus rodomi čia"</string>
     <string name="notification_unblockable_desc" msgid="2073030886006190804">"Šių pranešimų keisti negalima."</string>
     <string name="notification_multichannel_desc" msgid="7414593090056236179">"Šios grupės pranešimai čia nekonfigūruojami"</string>
     <string name="notification_delegate_header" msgid="1264510071031479920">"Per tarpinį serverį gautas pranešimas"</string>
@@ -1012,10 +1012,10 @@
     <string name="bubble_accessibility_action_move_top_right" msgid="6916868852433483569">"Perkelti į viršų dešinėje"</string>
     <string name="bubble_accessibility_action_move_bottom_left" msgid="6339015902495504715">"Perkelti į apačią kairėje"</string>
     <string name="bubble_accessibility_action_move_bottom_right" msgid="7471571700628346212">"Perkelti į apačią dešinėje"</string>
-    <string name="bubble_dismiss_text" msgid="7071770411580452911">"Atmesti"</string>
+    <string name="bubble_dismiss_text" msgid="1314082410868930066">"Atsisakyti burbulo"</string>
     <string name="bubbles_dont_bubble_conversation" msgid="1033040343437428822">"Nerodyti pokalbio burbule"</string>
     <string name="bubbles_user_education_title" msgid="5547017089271445797">"Pokalbis naudojant burbulus"</string>
-    <string name="bubbles_user_education_description" msgid="1160281719576715211">"Nauji pokalbiai rodomi kaip slankiosios piktogramos arba burbulus. Palieskite, kad atidarytumėte burbulą. Vilkite, kad perkeltumėte."</string>
+    <string name="bubbles_user_education_description" msgid="1160281719576715211">"Nauji pokalbiai rodomi kaip slankiosios piktogramos arba burbulai. Palieskite, kad atidarytumėte burbulą. Vilkite, kad perkeltumėte."</string>
     <string name="bubbles_user_education_manage_title" msgid="2848511858160342320">"Bet kada valdyti burbulus"</string>
     <string name="bubbles_user_education_manage" msgid="1391639189507036423">"Palieskite „Tvarkyti“, kad išjungtumėte burbulus šioje programoje"</string>
     <string name="bubbles_user_education_got_it" msgid="8282812431953161143">"Supratau"</string>
@@ -1074,9 +1074,13 @@
     <string name="controls_structure_tooltip" msgid="4355922222944447867">"Perbraukite, kad peržiūrėtumėte daugiau"</string>
     <string name="controls_seeding_in_progress" msgid="3033855341410264148">"Įkeliamos rekomendacijos"</string>
     <string name="controls_media_close_session" msgid="9023534788828414585">"Uždaryti šį medijos seansą"</string>
+    <string name="controls_media_resume" msgid="1933520684481586053">"Tęsti"</string>
     <string name="controls_error_timeout" msgid="794197289772728958">"Neaktyvu, patikrinkite progr."</string>
     <string name="controls_error_retryable" msgid="864025882878378470">"Klaida, bandoma iš naujo…"</string>
-    <string name="controls_error_removed" msgid="6299213591234723805">"Įrenginys pašalintas"</string>
+    <string name="controls_error_removed" msgid="6675638069846014366">"Nerasta"</string>
+    <string name="controls_error_removed_title" msgid="1207794911208047818">"Valdiklis nepasiekiamas"</string>
+    <string name="controls_error_removed_message" msgid="2885911717034750542">"Nepavyko pasiekti: <xliff:g id="DEVICE">%1$s</xliff:g>. Eikite į programą „<xliff:g id="APPLICATION">%2$s</xliff:g>“ ir įsitikinkite, kad valdiklis vis dar pasiekiamas ir kad programos nustatymai nepakeisti."</string>
+    <string name="controls_open_app" msgid="483650971094300141">"Atidaryti programą"</string>
     <string name="controls_error_generic" msgid="352500456918362905">"Nepavyko įkelti būsenos"</string>
     <string name="controls_error_failed" msgid="960228639198558525">"Klaida, bandykite dar kartą"</string>
     <string name="controls_in_progress" msgid="4421080500238215939">"Vyksta"</string>
diff --git a/packages/SystemUI/res/values-lv/strings.xml b/packages/SystemUI/res/values-lv/strings.xml
index f107de9c..bc15702 100644
--- a/packages/SystemUI/res/values-lv/strings.xml
+++ b/packages/SystemUI/res/values-lv/strings.xml
@@ -513,7 +513,7 @@
     <string name="clear_all_notifications_text" msgid="348312370303046130">"Dzēst visu"</string>
     <string name="manage_notifications_text" msgid="6885645344647733116">"Pārvaldīt"</string>
     <string name="manage_notifications_history_text" msgid="57055985396576230">"Vēsture"</string>
-    <string name="notification_section_header_incoming" msgid="5295312809341711367">"Ienākošie"</string>
+    <string name="notification_section_header_incoming" msgid="850925217908095197">"Jauni"</string>
     <string name="notification_section_header_gentle" msgid="6804099527336337197">"Klusums"</string>
     <string name="notification_section_header_alerting" msgid="5581175033680477651">"Paziņojumi"</string>
     <string name="notification_section_header_conversations" msgid="821834744538345661">"Sarunas"</string>
@@ -1007,7 +1007,7 @@
     <string name="bubble_accessibility_action_move_top_right" msgid="6916868852433483569">"Pārvietot augšpusē pa labi"</string>
     <string name="bubble_accessibility_action_move_bottom_left" msgid="6339015902495504715">"Pārvietot apakšpusē pa kreisi"</string>
     <string name="bubble_accessibility_action_move_bottom_right" msgid="7471571700628346212">"Pārvietot apakšpusē pa labi"</string>
-    <string name="bubble_dismiss_text" msgid="7071770411580452911">"Nerādīt"</string>
+    <string name="bubble_dismiss_text" msgid="1314082410868930066">"Nerādīt burbuli"</string>
     <string name="bubbles_dont_bubble_conversation" msgid="1033040343437428822">"Nerādīt sarunu burbuļos"</string>
     <string name="bubbles_user_education_title" msgid="5547017089271445797">"Tērzēšana, izmantojot burbuļus"</string>
     <string name="bubbles_user_education_description" msgid="1160281719576715211">"Jaunas sarunas tiek rādītas kā peldošas ikonas vai burbuļi. Pieskarieties, lai atvērtu burbuli. Velciet, lai to pārvietotu."</string>
@@ -1068,9 +1068,13 @@
     <string name="controls_structure_tooltip" msgid="4355922222944447867">"Velciet, lai skatītu citus vienumus"</string>
     <string name="controls_seeding_in_progress" msgid="3033855341410264148">"Notiek ieteikumu ielāde"</string>
     <string name="controls_media_close_session" msgid="9023534788828414585">"Aizvērt multivides sesiju"</string>
+    <string name="controls_media_resume" msgid="1933520684481586053">"Atsākt"</string>
     <string name="controls_error_timeout" msgid="794197289772728958">"Neaktīva, pārbaudiet lietotni"</string>
     <string name="controls_error_retryable" msgid="864025882878378470">"Radās kļūda. Mēģina vēlreiz…"</string>
-    <string name="controls_error_removed" msgid="6299213591234723805">"Ierīce ir noņemta."</string>
+    <string name="controls_error_removed" msgid="6675638069846014366">"Netika atrasta"</string>
+    <string name="controls_error_removed_title" msgid="1207794911208047818">"Vadīkla nav pieejama"</string>
+    <string name="controls_error_removed_message" msgid="2885911717034750542">"Nevarēja piekļūt ierīcei “<xliff:g id="DEVICE">%1$s</xliff:g>”. Lietotnē <xliff:g id="APPLICATION">%2$s</xliff:g> pārbaudiet, vai vadīkla joprojām ir pieejama un vai nav mainīti lietotnes iestatījumi."</string>
+    <string name="controls_open_app" msgid="483650971094300141">"Atvērt lietotni"</string>
     <string name="controls_error_generic" msgid="352500456918362905">"Nevar ielādēt statusu."</string>
     <string name="controls_error_failed" msgid="960228639198558525">"Radās kļūda. Mēģiniet vēlreiz."</string>
     <string name="controls_in_progress" msgid="4421080500238215939">"Sākta"</string>
diff --git a/packages/SystemUI/res/values-mk/strings.xml b/packages/SystemUI/res/values-mk/strings.xml
index 0361eed..09e7ff1 100644
--- a/packages/SystemUI/res/values-mk/strings.xml
+++ b/packages/SystemUI/res/values-mk/strings.xml
@@ -479,7 +479,7 @@
     <string name="guest_exit_guest_dialog_title" msgid="5015697561580641422">"Да се отстрани гостинот?"</string>
     <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Сите апликации и податоци во сесијата ќе се избришат."</string>
     <string name="guest_exit_guest_dialog_remove" msgid="7505817591242703757">"Отстрани"</string>
-    <string name="guest_wipe_session_title" msgid="7147965814683990944">"Добредојде назад, гостине!"</string>
+    <string name="guest_wipe_session_title" msgid="7147965814683990944">"Добре дојде пак, гостине!"</string>
     <string name="guest_wipe_session_message" msgid="3393823610257065457">"Дали сакате да продолжите со сесијата?"</string>
     <string name="guest_wipe_session_wipe" msgid="8056836584445473309">"Почни одново"</string>
     <string name="guest_wipe_session_dontwipe" msgid="3211052048269304205">"Да, продолжи"</string>
@@ -510,7 +510,7 @@
     <string name="clear_all_notifications_text" msgid="348312370303046130">"Избриши сѐ"</string>
     <string name="manage_notifications_text" msgid="6885645344647733116">"Управувајте"</string>
     <string name="manage_notifications_history_text" msgid="57055985396576230">"Историја"</string>
-    <string name="notification_section_header_incoming" msgid="5295312809341711367">"Дојдовни"</string>
+    <string name="notification_section_header_incoming" msgid="850925217908095197">"Нов"</string>
     <string name="notification_section_header_gentle" msgid="6804099527336337197">"Безгласно"</string>
     <string name="notification_section_header_alerting" msgid="5581175033680477651">"Известувања"</string>
     <string name="notification_section_header_conversations" msgid="821834744538345661">"Разговори"</string>
@@ -592,20 +592,20 @@
     <string name="volume_odi_captions_hint_enable" msgid="2073091194012843195">"овозможи"</string>
     <string name="volume_odi_captions_hint_disable" msgid="2518846326748183407">"оневозможи"</string>
     <string name="accessibility_output_chooser" msgid="7807898688967194183">"Префрлете го излезниот уред"</string>
-    <string name="screen_pinning_title" msgid="9058007390337841305">"Апликацијата е прикачена"</string>
+    <string name="screen_pinning_title" msgid="9058007390337841305">"Апликацијата е закачена"</string>
     <string name="screen_pinning_description" msgid="8699395373875667743">"Ќе се гледа сѐ додека не го откачите. Допрете и држете „Назад“ и „Краток преглед“ за откачување."</string>
     <string name="screen_pinning_description_recents_invisible" msgid="4564466648700390037">"Ќе се гледа сѐ додека не го откачите. Допрете и задржете „Назад“ и „Почетен екран“ за откачување."</string>
-    <string name="screen_pinning_description_gestural" msgid="7246323931831232068">"Ќе се гледа сѐ додека не го откачите. Лизгајте нагоре и задржете за откачување."</string>
+    <string name="screen_pinning_description_gestural" msgid="7246323931831232068">"Ќе се гледа сѐ додека не ја откачите. Повлечете нагоре и задржете за откачување."</string>
     <string name="screen_pinning_description_accessible" msgid="7386449191953535332">"Ќе се гледа сѐ додека не го откачите. Допрете и држете „Краток преглед“ за откачување."</string>
     <string name="screen_pinning_description_recents_invisible_accessible" msgid="2857071808674481986">"Ќе се гледа сѐ додека не го откачите. Допрете и задржете „Почетен екран“ за откачување."</string>
-    <string name="screen_pinning_exposes_personal_data" msgid="8189852022981524789">"Личните податоци може да се пристапни (како контакти и содржини од е-пошта)."</string>
-    <string name="screen_pinning_can_open_other_apps" msgid="7529756813231421455">"Прикачените апликации може да отворат други апликации."</string>
+    <string name="screen_pinning_exposes_personal_data" msgid="8189852022981524789">"Може да бидат достапни лични податоци (како контакти и содржини од е-пошта)."</string>
+    <string name="screen_pinning_can_open_other_apps" msgid="7529756813231421455">"Закачената апликација може да отвора други апликации."</string>
     <string name="screen_pinning_toast" msgid="8177286912533744328">"За откачување на апликацијава, допрете и држете на копчињата „Назад“ и „Преглед“"</string>
     <string name="screen_pinning_toast_recents_invisible" msgid="6850978077443052594">"За откачување на апликацијава, допрете и држете на копчињата „Назад“ и „Почетен екран“"</string>
     <string name="screen_pinning_toast_gesture_nav" msgid="170699893395336705">"За откачување на апликацијава, повлечете нагоре и држете"</string>
     <string name="screen_pinning_positive" msgid="3285785989665266984">"Сфатив"</string>
     <string name="screen_pinning_negative" msgid="6882816864569211666">"Не, фала"</string>
-    <string name="screen_pinning_start" msgid="7483998671383371313">"Апликацијата е прикачена"</string>
+    <string name="screen_pinning_start" msgid="7483998671383371313">"Апликацијата е закачена"</string>
     <string name="screen_pinning_exit" msgid="4553787518387346893">"Апликацијата е откачена"</string>
     <string name="quick_settings_reset_confirmation_title" msgid="463533331480997595">"Сокриј <xliff:g id="TILE_LABEL">%1$s</xliff:g>?"</string>
     <string name="quick_settings_reset_confirmation_message" msgid="2320586180785674186">"Ќе се појави повторно следниот пат кога ќе го вклучите во поставки."</string>
@@ -1002,7 +1002,7 @@
     <string name="bubble_accessibility_action_move_top_right" msgid="6916868852433483569">"Премести горе десно"</string>
     <string name="bubble_accessibility_action_move_bottom_left" msgid="6339015902495504715">"Премести долу лево"</string>
     <string name="bubble_accessibility_action_move_bottom_right" msgid="7471571700628346212">"Премести долу десно"</string>
-    <string name="bubble_dismiss_text" msgid="7071770411580452911">"Отфрли"</string>
+    <string name="bubble_dismiss_text" msgid="1314082410868930066">"Отфрли балонче"</string>
     <string name="bubbles_dont_bubble_conversation" msgid="1033040343437428822">"Не прикажувај го разговорот во балончиња"</string>
     <string name="bubbles_user_education_title" msgid="5547017089271445797">"Разговор во балончиња"</string>
     <string name="bubbles_user_education_description" msgid="1160281719576715211">"Новите разговори ќе се појавуваат како лебдечки икони или балончиња. Допрете за отворање на балончето. Повлечете за да го преместите."</string>
@@ -1062,9 +1062,13 @@
     <string name="controls_structure_tooltip" msgid="4355922222944447867">"Повлечете за да видите повеќе"</string>
     <string name="controls_seeding_in_progress" msgid="3033855341410264148">"Се вчитуваат препораки"</string>
     <string name="controls_media_close_session" msgid="9023534788828414585">"Затвори ја аудиовизуелнава сесија"</string>
+    <string name="controls_media_resume" msgid="1933520684481586053">"Продолжи"</string>
     <string name="controls_error_timeout" msgid="794197289772728958">"Неактивна, провери апликација"</string>
     <string name="controls_error_retryable" msgid="864025882878378470">"Грешка, повторен обид…"</string>
-    <string name="controls_error_removed" msgid="6299213591234723805">"Уредот е отстранет"</string>
+    <string name="controls_error_removed" msgid="6675638069846014366">"Не е најдено"</string>
+    <string name="controls_error_removed_title" msgid="1207794911208047818">"Контролата не е достапна"</string>
+    <string name="controls_error_removed_message" msgid="2885911717034750542">"Не може да се пристапи до <xliff:g id="DEVICE">%1$s</xliff:g>. Проверете ја апликацијата <xliff:g id="APPLICATION">%2$s</xliff:g> за да се осигурите дека контролата е сè уште достапна и дека поставките за апликацијата не се сменети."</string>
+    <string name="controls_open_app" msgid="483650971094300141">"Отвори ја апликација"</string>
     <string name="controls_error_generic" msgid="352500456918362905">"Не може да се вчита статусот"</string>
     <string name="controls_error_failed" msgid="960228639198558525">"Грешка, обидете се повторно"</string>
     <string name="controls_in_progress" msgid="4421080500238215939">"Во тек"</string>
diff --git a/packages/SystemUI/res/values-ml/strings.xml b/packages/SystemUI/res/values-ml/strings.xml
index 5c80eb3..e4d4ba4 100644
--- a/packages/SystemUI/res/values-ml/strings.xml
+++ b/packages/SystemUI/res/values-ml/strings.xml
@@ -510,7 +510,8 @@
     <string name="clear_all_notifications_text" msgid="348312370303046130">"എല്ലാം മായ്‌ക്കുക"</string>
     <string name="manage_notifications_text" msgid="6885645344647733116">"മാനേജ് ചെയ്യുക"</string>
     <string name="manage_notifications_history_text" msgid="57055985396576230">"ചരിത്രം"</string>
-    <string name="notification_section_header_incoming" msgid="5295312809341711367">"ഇൻകമിംഗ്"</string>
+    <!-- no translation found for notification_section_header_incoming (850925217908095197) -->
+    <skip />
     <string name="notification_section_header_gentle" msgid="6804099527336337197">"നിശബ്‌ദം"</string>
     <string name="notification_section_header_alerting" msgid="5581175033680477651">"അറിയിപ്പുകൾ"</string>
     <string name="notification_section_header_conversations" msgid="821834744538345661">"സംഭാഷണങ്ങൾ"</string>
@@ -1002,10 +1003,10 @@
     <string name="bubble_accessibility_action_move_top_right" msgid="6916868852433483569">"മുകളിൽ വലതുഭാഗത്തേക്ക് നീക്കുക"</string>
     <string name="bubble_accessibility_action_move_bottom_left" msgid="6339015902495504715">"ചുവടെ ഇടതുഭാഗത്തേക്ക് നീക്കുക"</string>
     <string name="bubble_accessibility_action_move_bottom_right" msgid="7471571700628346212">"ചുവടെ വലതുഭാഗത്തേക്ക് നീക്കുക"</string>
-    <string name="bubble_dismiss_text" msgid="7071770411580452911">"ഡിസ്‌മിസ് ചെയ്യുക"</string>
+    <string name="bubble_dismiss_text" msgid="1314082410868930066">"ബബിൾ ഡിസ്മിസ് ചെയ്യൂ"</string>
     <string name="bubbles_dont_bubble_conversation" msgid="1033040343437428822">"സംഭാഷണം ബബിൾ ചെയ്യരുത്"</string>
     <string name="bubbles_user_education_title" msgid="5547017089271445797">"ബബിളുകൾ ഉപയോഗിച്ച് ചാറ്റ് ചെയ്യുക"</string>
-    <string name="bubbles_user_education_description" msgid="1160281719576715211">"പുതിയ സംഭാഷണങ്ങൾ ഫ്ലോട്ടിംഗ് ഐക്കണുകളോ ബബിളുകളോ ആയി ദൃശ്യമാവുന്നു. ബബിൾ തുറക്കാൻ ടാപ്പ് ചെയ്യു. ഇത് നീക്കാൻ വലിച്ചിടുക."</string>
+    <string name="bubbles_user_education_description" msgid="1160281719576715211">"പുതിയ സംഭാഷണങ്ങൾ ഫ്ലോട്ടിംഗ് ഐക്കണുകളോ ബബിളുകളോ ആയി ദൃശ്യമാവുന്നു. ബബിൾ തുറക്കാൻ ടാപ്പ് ചെയ്യൂ. ഇത് നീക്കാൻ വലിച്ചിടുക."</string>
     <string name="bubbles_user_education_manage_title" msgid="2848511858160342320">"ബബിളുകൾ ഏതുസമയത്തും നിയന്ത്രിക്കുക"</string>
     <string name="bubbles_user_education_manage" msgid="1391639189507036423">"ഈ ആപ്പിൽ നിന്നുള്ള ബബിളുകൾ ഓഫാക്കാൻ മാനേജ് ചെയ്യുക ടാപ്പ് ചെയ്യുക"</string>
     <string name="bubbles_user_education_got_it" msgid="8282812431953161143">"ലഭിച്ചു"</string>
@@ -1013,17 +1014,14 @@
     <string name="notification_content_system_nav_changed" msgid="5077913144844684544">"സിസ്‌റ്റം നാവിഗേഷൻ അപ്‌ഡേറ്റ് ചെയ്‌തു. മാറ്റങ്ങൾ വരുത്താൻ ക്രമീകരണത്തിലേക്ക് പോവുക."</string>
     <string name="notification_content_gesture_nav_available" msgid="4431460803004659888">"സിസ്‌റ്റം നാവിഗേഷൻ അപ്‌ഡേറ്റ് ചെയ്യാൻ ക്രമീകരണത്തിലേക്ക് പോവുക"</string>
     <string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"സ്‌റ്റാൻഡ്‌ബൈ"</string>
-    <!-- no translation found for priority_onboarding_title (2893070698479227616) -->
-    <skip />
-    <!-- no translation found for priority_onboarding_behavior (5342816047020432929) -->
-    <skip />
+    <string name="priority_onboarding_title" msgid="2893070698479227616">"സംഭാഷണം മുൻഗണനയുള്ളതായി സജ്ജീകരിച്ചു"</string>
+    <string name="priority_onboarding_behavior" msgid="5342816047020432929">"മുൻഗണനാ സംഭാഷണങ്ങൾ ഇനിപ്പറയുന്നവ ചെയ്യും:"</string>
     <string name="priority_onboarding_show_at_top_text" msgid="1678400241025513541">"സംഭാഷണ വിഭാഗത്തിന്റെ മുകളിൽ കാണിക്കുക"</string>
     <string name="priority_onboarding_show_avatar_text" msgid="5756291381124091508">"ലോക്ക് സ്ക്രീനിൽ പ്രൊഫൈൽ ചിത്രം കാണിക്കുക"</string>
     <string name="priority_onboarding_appear_as_bubble_text" msgid="4227039772250263122">"ആപ്പുകളുടെ മുകളിൽ ഫ്ലോട്ടിംഗ് ബബിൾ ആയി ദൃശ്യമാകും"</string>
     <string name="priority_onboarding_ignores_dnd_text" msgid="2918952762719600529">"\'ശല്യപ്പെടുത്തരുത്\' തടസ്സപ്പെടുത്തുക"</string>
     <string name="priority_onboarding_done_button_title" msgid="4569550984286506007">"മനസ്സിലായി"</string>
-    <!-- no translation found for priority_onboarding_settings_button_title (6663601574303585927) -->
-    <skip />
+    <string name="priority_onboarding_settings_button_title" msgid="6663601574303585927">"ക്രമീകരണം"</string>
     <string name="magnification_overlay_title" msgid="6584179429612427958">"മാഗ്നിഫിക്കേഷൻ ഓവർലേ വിൻഡോ"</string>
     <string name="magnification_window_title" msgid="4863914360847258333">"മാഗ്നിഫിക്കേഷൻ വിൻഡോ"</string>
     <string name="magnification_controls_title" msgid="8421106606708891519">"മാഗ്നിഫിക്കേഷൻ വിൻഡോ നിയന്ത്രണങ്ങൾ"</string>
@@ -1065,9 +1063,13 @@
     <string name="controls_structure_tooltip" msgid="4355922222944447867">"കൂടുതൽ കാണാൻ സ്വൈപ്പ് ചെയ്യുക"</string>
     <string name="controls_seeding_in_progress" msgid="3033855341410264148">"നിർദ്ദേശങ്ങൾ ലോഡ് ചെയ്യുന്നു"</string>
     <string name="controls_media_close_session" msgid="9023534788828414585">"ഈ മീഡിയ സെഷൻ അടയ്ക്കുക"</string>
+    <string name="controls_media_resume" msgid="1933520684481586053">"പുനരാരംഭിക്കുക"</string>
     <string name="controls_error_timeout" msgid="794197289772728958">"നിഷ്‌ക്രിയം, ആപ്പ് പരിശോധിക്കൂ"</string>
     <string name="controls_error_retryable" msgid="864025882878378470">"പിശക്, വീണ്ടും ശ്രമിക്കുന്നു…"</string>
-    <string name="controls_error_removed" msgid="6299213591234723805">"ഉപകരണം നീക്കം ചെയ്തു"</string>
+    <string name="controls_error_removed" msgid="6675638069846014366">"കണ്ടെത്തിയില്ല"</string>
+    <string name="controls_error_removed_title" msgid="1207794911208047818">"നിയന്ത്രണം ലഭ്യമല്ല"</string>
+    <string name="controls_error_removed_message" msgid="2885911717034750542">"<xliff:g id="DEVICE">%1$s</xliff:g> ആക്‌സസ് ചെയ്യാനായില്ല. നിയന്ത്രണം ഇപ്പോഴും ലഭ്യമാണെന്നും ആപ്പ് ക്രമീകരണം മാറ്റിയിട്ടില്ലെന്നും ഉറപ്പാക്കാൻ <xliff:g id="APPLICATION">%2$s</xliff:g> ആപ്പ് പരിശോധിക്കുക."</string>
+    <string name="controls_open_app" msgid="483650971094300141">"ആപ്പ് തുറക്കുക"</string>
     <string name="controls_error_generic" msgid="352500456918362905">"നില ലോഡ് ചെയ്യാനാകുന്നില്ല"</string>
     <string name="controls_error_failed" msgid="960228639198558525">"പിശക്, വീണ്ടും ശ്രമിക്കുക"</string>
     <string name="controls_in_progress" msgid="4421080500238215939">"പുരോഗതിയിലാണ്"</string>
diff --git a/packages/SystemUI/res/values-mn/strings.xml b/packages/SystemUI/res/values-mn/strings.xml
index f04df527..4ab58f0 100644
--- a/packages/SystemUI/res/values-mn/strings.xml
+++ b/packages/SystemUI/res/values-mn/strings.xml
@@ -510,7 +510,7 @@
     <string name="clear_all_notifications_text" msgid="348312370303046130">"Бүгдийг арилгах"</string>
     <string name="manage_notifications_text" msgid="6885645344647733116">"Удирдах"</string>
     <string name="manage_notifications_history_text" msgid="57055985396576230">"Түүх"</string>
-    <string name="notification_section_header_incoming" msgid="5295312809341711367">"Ирж буй"</string>
+    <string name="notification_section_header_incoming" msgid="850925217908095197">"Шинэ"</string>
     <string name="notification_section_header_gentle" msgid="6804099527336337197">"Чимээгүй"</string>
     <string name="notification_section_header_alerting" msgid="5581175033680477651">"Мэдэгдлүүд"</string>
     <string name="notification_section_header_conversations" msgid="821834744538345661">"Харилцан яриа"</string>
@@ -1002,7 +1002,7 @@
     <string name="bubble_accessibility_action_move_top_right" msgid="6916868852433483569">"Баруун дээш зөөх"</string>
     <string name="bubble_accessibility_action_move_bottom_left" msgid="6339015902495504715">"Зүүн доош зөөх"</string>
     <string name="bubble_accessibility_action_move_bottom_right" msgid="7471571700628346212">"Баруун доош зөөх"</string>
-    <string name="bubble_dismiss_text" msgid="7071770411580452911">"Үл хэрэгсэх"</string>
+    <string name="bubble_dismiss_text" msgid="1314082410868930066">"Бөмбөлгийг хаах"</string>
     <string name="bubbles_dont_bubble_conversation" msgid="1033040343437428822">"Харилцан яриаг бүү бөмбөлөг болго"</string>
     <string name="bubbles_user_education_title" msgid="5547017089271445797">"Бөмбөлөг ашиглан чатлаарай"</string>
     <string name="bubbles_user_education_description" msgid="1160281719576715211">"Шинэ харилцан яриа нь хөвөгч дүрс тэмдэг эсвэл бөмбөлөг хэлбэрээр харагддаг. Бөмбөлгийг нээхийн тулд товшино уу. Түүнийг зөөхийн тулд чирнэ үү."</string>
@@ -1062,9 +1062,13 @@
     <string name="controls_structure_tooltip" msgid="4355922222944447867">"Илүү ихийг харахын тулд шударна уу"</string>
     <string name="controls_seeding_in_progress" msgid="3033855341410264148">"Зөвлөмжүүдийг ачаалж байна"</string>
     <string name="controls_media_close_session" msgid="9023534788828414585">"Медианы энэ харилцан үйлдлийг хаах"</string>
+    <string name="controls_media_resume" msgid="1933520684481586053">"Үргэлжлүүлэх"</string>
     <string name="controls_error_timeout" msgid="794197289772728958">"Идэвхгүй байна, аппыг шалгана уу"</string>
     <string name="controls_error_retryable" msgid="864025882878378470">"Алдаа, дахин оролдож байна…"</string>
-    <string name="controls_error_removed" msgid="6299213591234723805">"Төхөөрөмжийг хассан"</string>
+    <string name="controls_error_removed" msgid="6675638069846014366">"Олдсонгүй"</string>
+    <string name="controls_error_removed_title" msgid="1207794911208047818">"Хяналт боломжгүй байна"</string>
+    <string name="controls_error_removed_message" msgid="2885911717034750542">"<xliff:g id="DEVICE">%1$s</xliff:g>-д хандаж чадсангүй. Хяналт боломжтой хэвээр байгаа бөгөөд аппын тохиргоог өөрчлөөгүй эсэхийг нягтлахын тулд <xliff:g id="APPLICATION">%2$s</xliff:g> аппыг шалгана уу."</string>
+    <string name="controls_open_app" msgid="483650971094300141">"Аппыг нээх"</string>
     <string name="controls_error_generic" msgid="352500456918362905">"Статус ачаалах боломжгүй"</string>
     <string name="controls_error_failed" msgid="960228639198558525">"Алдаа гарав, дахин оролдоно уу"</string>
     <string name="controls_in_progress" msgid="4421080500238215939">"Үргэлжилж байна"</string>
diff --git a/packages/SystemUI/res/values-mr/strings.xml b/packages/SystemUI/res/values-mr/strings.xml
index 8994141..d49f46d8 100644
--- a/packages/SystemUI/res/values-mr/strings.xml
+++ b/packages/SystemUI/res/values-mr/strings.xml
@@ -510,7 +510,8 @@
     <string name="clear_all_notifications_text" msgid="348312370303046130">"सर्व साफ करा"</string>
     <string name="manage_notifications_text" msgid="6885645344647733116">"व्यवस्थापित करा"</string>
     <string name="manage_notifications_history_text" msgid="57055985396576230">"इतिहास"</string>
-    <string name="notification_section_header_incoming" msgid="5295312809341711367">"आलेल्या"</string>
+    <!-- no translation found for notification_section_header_incoming (850925217908095197) -->
+    <skip />
     <string name="notification_section_header_gentle" msgid="6804099527336337197">"सायलंट"</string>
     <string name="notification_section_header_alerting" msgid="5581175033680477651">"सूचना"</string>
     <string name="notification_section_header_conversations" msgid="821834744538345661">"संभाषणे"</string>
@@ -1002,7 +1003,7 @@
     <string name="bubble_accessibility_action_move_top_right" msgid="6916868852433483569">"वर उजवीकडे हलवा"</string>
     <string name="bubble_accessibility_action_move_bottom_left" msgid="6339015902495504715">"तळाशी डावीकडे हलवा"</string>
     <string name="bubble_accessibility_action_move_bottom_right" msgid="7471571700628346212">"तळाशी उजवीकडे हलवा"</string>
-    <string name="bubble_dismiss_text" msgid="7071770411580452911">"डिसमिस करा"</string>
+    <string name="bubble_dismiss_text" msgid="1314082410868930066">"बबल डिसमिस करा"</string>
     <string name="bubbles_dont_bubble_conversation" msgid="1033040343437428822">"संभाषणाला बबल करू नका"</string>
     <string name="bubbles_user_education_title" msgid="5547017089271445797">"बबल वापरून चॅट करा"</string>
     <string name="bubbles_user_education_description" msgid="1160281719576715211">"नवीन संभाषणे फ्लोटिंग आयकन किंवा बबल म्हणून दिसतात. बबल उघडण्यासाठी टॅप करा. हे हलवण्यासाठी ड्रॅग करा."</string>
@@ -1013,17 +1014,14 @@
     <string name="notification_content_system_nav_changed" msgid="5077913144844684544">"सिस्टम नेव्हिगेशन अपडेट केले. बदल करण्यासाठी, सेटिंग्जवर जा."</string>
     <string name="notification_content_gesture_nav_available" msgid="4431460803004659888">"सिस्टम नेव्हिगेशन अपडेट करण्यासाठी सेटिंग्जवर जा"</string>
     <string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"स्टँडबाय"</string>
-    <!-- no translation found for priority_onboarding_title (2893070698479227616) -->
-    <skip />
-    <!-- no translation found for priority_onboarding_behavior (5342816047020432929) -->
-    <skip />
+    <string name="priority_onboarding_title" msgid="2893070698479227616">"संभाषणाला प्राधान्य म्हणून सेट केले आहे"</string>
+    <string name="priority_onboarding_behavior" msgid="5342816047020432929">"प्राधान्य दिलेली संभाषणे:"</string>
     <string name="priority_onboarding_show_at_top_text" msgid="1678400241025513541">"संभाषण विभागाच्या सर्वात वरती दाखवा"</string>
     <string name="priority_onboarding_show_avatar_text" msgid="5756291381124091508">"लॉक स्‍क्रीनवर प्रोफाइल फोटो दाखवा"</string>
     <string name="priority_onboarding_appear_as_bubble_text" msgid="4227039772250263122">"ॲप्सच्या सर्वात वरती फ्लोटिंग बबल म्हणून दिसतील"</string>
     <string name="priority_onboarding_ignores_dnd_text" msgid="2918952762719600529">"व्यत्यय आणू नका मध्ये अडथळा आणतील"</string>
     <string name="priority_onboarding_done_button_title" msgid="4569550984286506007">"समजले"</string>
-    <!-- no translation found for priority_onboarding_settings_button_title (6663601574303585927) -->
-    <skip />
+    <string name="priority_onboarding_settings_button_title" msgid="6663601574303585927">"सेटिंग्ज"</string>
     <string name="magnification_overlay_title" msgid="6584179429612427958">"मॅग्निफिकेशन ओव्हरले विंडो"</string>
     <string name="magnification_window_title" msgid="4863914360847258333">"मॅग्निफिकेशन विंडो"</string>
     <string name="magnification_controls_title" msgid="8421106606708891519">"मॅग्निफिकेशन विंडो नियंत्रणे"</string>
@@ -1065,9 +1063,13 @@
     <string name="controls_structure_tooltip" msgid="4355922222944447867">"अधिक पाहण्यासाठी स्वाइप करा"</string>
     <string name="controls_seeding_in_progress" msgid="3033855341410264148">"शिफारशी लोड करत आहे"</string>
     <string name="controls_media_close_session" msgid="9023534788828414585">"हे मीडिया सेशन बंद करा"</string>
+    <string name="controls_media_resume" msgid="1933520684481586053">"पुन्हा सुरू करा"</string>
     <string name="controls_error_timeout" msgid="794197289772728958">"निष्क्रिय, ॲप तपासा"</string>
     <string name="controls_error_retryable" msgid="864025882878378470">"एरर, पुन्हा प्रयत्न करत आहे…"</string>
-    <string name="controls_error_removed" msgid="6299213591234723805">"डिव्हाइस काढून टाकले आहे"</string>
+    <string name="controls_error_removed" msgid="6675638069846014366">"आढळले नाही"</string>
+    <string name="controls_error_removed_title" msgid="1207794911208047818">"नियंत्रण उपलब्ध नाही"</string>
+    <string name="controls_error_removed_message" msgid="2885911717034750542">"<xliff:g id="DEVICE">%1$s</xliff:g> अ‍ॅक्सेस करता आले नाही. नियंत्रण अजूनही उपलब्ध असल्याची आणि ॲपची सेटिंग्ज बदलली नसल्याची खात्री करण्यासाठी <xliff:g id="APPLICATION">%2$s</xliff:g> ॲप तपासा."</string>
+    <string name="controls_open_app" msgid="483650971094300141">"अ‍ॅप उघडा"</string>
     <string name="controls_error_generic" msgid="352500456918362905">"स्थिती लोड करू शकत नाही"</string>
     <string name="controls_error_failed" msgid="960228639198558525">"एरर, पुन्हा प्रयत्न करा"</string>
     <string name="controls_in_progress" msgid="4421080500238215939">"प्रगतीपथावर आहे"</string>
diff --git a/packages/SystemUI/res/values-ms/strings.xml b/packages/SystemUI/res/values-ms/strings.xml
index a251c3d..be17ead 100644
--- a/packages/SystemUI/res/values-ms/strings.xml
+++ b/packages/SystemUI/res/values-ms/strings.xml
@@ -510,7 +510,7 @@
     <string name="clear_all_notifications_text" msgid="348312370303046130">"Kosongkan semua"</string>
     <string name="manage_notifications_text" msgid="6885645344647733116">"Urus"</string>
     <string name="manage_notifications_history_text" msgid="57055985396576230">"Sejarah"</string>
-    <string name="notification_section_header_incoming" msgid="5295312809341711367">"Masuk"</string>
+    <string name="notification_section_header_incoming" msgid="850925217908095197">"Baharu"</string>
     <string name="notification_section_header_gentle" msgid="6804099527336337197">"Senyap"</string>
     <string name="notification_section_header_alerting" msgid="5581175033680477651">"Pemberitahuan"</string>
     <string name="notification_section_header_conversations" msgid="821834744538345661">"Perbualan"</string>
@@ -1002,7 +1002,7 @@
     <string name="bubble_accessibility_action_move_top_right" msgid="6916868852433483569">"Alihkan ke atas sebelah kanan"</string>
     <string name="bubble_accessibility_action_move_bottom_left" msgid="6339015902495504715">"Alihkan ke bawah sebelah kiri"</string>
     <string name="bubble_accessibility_action_move_bottom_right" msgid="7471571700628346212">"Alihkan ke bawah sebelah kanan"</string>
-    <string name="bubble_dismiss_text" msgid="7071770411580452911">"Ketepikan"</string>
+    <string name="bubble_dismiss_text" msgid="1314082410868930066">"Ketepikan gelembung"</string>
     <string name="bubbles_dont_bubble_conversation" msgid="1033040343437428822">"Jangan jadikan perbualan dalam bentuk gelembung"</string>
     <string name="bubbles_user_education_title" msgid="5547017089271445797">"Bersembang menggunakan gelembung"</string>
     <string name="bubbles_user_education_description" msgid="1160281719576715211">"Perbualan baharu muncul sebagai ikon terapung atau gelembung. Ketik untuk membuka gelembung. Seret untuk mengalihkan gelembung tersebut."</string>
@@ -1062,9 +1062,13 @@
     <string name="controls_structure_tooltip" msgid="4355922222944447867">"Leret untuk melihat selanjutnya"</string>
     <string name="controls_seeding_in_progress" msgid="3033855341410264148">"Memuatkan cadangan"</string>
     <string name="controls_media_close_session" msgid="9023534788828414585">"Tutup sesi media ini"</string>
+    <string name="controls_media_resume" msgid="1933520684481586053">"Sambung semula"</string>
     <string name="controls_error_timeout" msgid="794197289772728958">"Tidak aktif, semak apl"</string>
     <string name="controls_error_retryable" msgid="864025882878378470">"Ralat, mencuba semula…"</string>
-    <string name="controls_error_removed" msgid="6299213591234723805">"Peranti dialih keluar"</string>
+    <string name="controls_error_removed" msgid="6675638069846014366">"Tidak ditemui"</string>
+    <string name="controls_error_removed_title" msgid="1207794911208047818">"Kawalan tidak tersedia"</string>
+    <string name="controls_error_removed_message" msgid="2885911717034750542">"Tidak dapat mengakses <xliff:g id="DEVICE">%1$s</xliff:g>. Periksa apl <xliff:g id="APPLICATION">%2$s</xliff:g> untuk memastikan kawalan masih tersedia dan tetapan apl tidak berubah."</string>
+    <string name="controls_open_app" msgid="483650971094300141">"Buka apl"</string>
     <string name="controls_error_generic" msgid="352500456918362905">"Tidak dapat memuatkan status"</string>
     <string name="controls_error_failed" msgid="960228639198558525">"Ralat, cuba lagi"</string>
     <string name="controls_in_progress" msgid="4421080500238215939">"Sedang berlangsung"</string>
diff --git a/packages/SystemUI/res/values-my/strings.xml b/packages/SystemUI/res/values-my/strings.xml
index 810388d..eaf4157 100644
--- a/packages/SystemUI/res/values-my/strings.xml
+++ b/packages/SystemUI/res/values-my/strings.xml
@@ -101,7 +101,7 @@
     <string name="screenrecord_start" msgid="330991441575775004">"စတင်ရန်"</string>
     <string name="screenrecord_ongoing_screen_only" msgid="4459670242451527727">"ဖန်သားပြင်ကို ရိုက်ကူးနေသည်"</string>
     <string name="screenrecord_ongoing_screen_and_audio" msgid="5351133763125180920">"အသံနှင့် ဖန်သားပြင်ကို ရိုက်ကူးနေသည်"</string>
-    <string name="screenrecord_taps_label" msgid="1595690528298857649">"မျက်နှာပြင်ပေါ်တွင် ထိချက်များ ပြသည်"</string>
+    <string name="screenrecord_taps_label" msgid="1595690528298857649">"မျက်နှာပြင်ပေါ်တွင် ထိချက်များ ပြရန်"</string>
     <string name="screenrecord_stop_text" msgid="6549288689506057686">"ရပ်ရန် တို့ပါ"</string>
     <string name="screenrecord_stop_label" msgid="72699670052087989">"ရပ်ရန်"</string>
     <string name="screenrecord_pause_label" msgid="6004054907104549857">"ခဏရပ်ရန်"</string>
@@ -510,7 +510,7 @@
     <string name="clear_all_notifications_text" msgid="348312370303046130">"အားလုံး ဖယ်ရှားရန်"</string>
     <string name="manage_notifications_text" msgid="6885645344647733116">"စီမံရန်"</string>
     <string name="manage_notifications_history_text" msgid="57055985396576230">"မှတ်တမ်း"</string>
-    <string name="notification_section_header_incoming" msgid="5295312809341711367">"အဝင်"</string>
+    <string name="notification_section_header_incoming" msgid="850925217908095197">"အသစ်"</string>
     <string name="notification_section_header_gentle" msgid="6804099527336337197">"အသံတိတ်ခြင်း"</string>
     <string name="notification_section_header_alerting" msgid="5581175033680477651">"အကြောင်းကြားချက်များ"</string>
     <string name="notification_section_header_conversations" msgid="821834744538345661">"စကားဝိုင်းများ"</string>
@@ -598,7 +598,7 @@
     <string name="screen_pinning_description_gestural" msgid="7246323931831232068">"သင်က ပင်မဖြုတ်မချင်း ၎င်းကို ပြသထားပါမည်။ ပင်ဖြုတ်ရန် အပေါ်သို့ပွတ်ဆွဲပြီး ဖိထားပါ။"</string>
     <string name="screen_pinning_description_accessible" msgid="7386449191953535332">"သင်ပင်မဖြုတ်မချင်း ၎င်းကိုပြသထားပါမည်။ ပင်ဖြုတ်ရန် Overview ကိုထိပြီး ဖိထားပါ။"</string>
     <string name="screen_pinning_description_recents_invisible_accessible" msgid="2857071808674481986">"သင်က ပင်မဖြုတ်မချင်း ၎င်းကိုပြသထားပါမည်။ ပင်ဖြုတ်ရန် \'ပင်မ\' ခလုတ်ကို တို့၍ဖိထားပါ။"</string>
-    <string name="screen_pinning_exposes_personal_data" msgid="8189852022981524789">"(အဆက်အသွယ်နှင့် အီးမေးလ်အကြောင်းအရာများကဲ့သို့) ကိုယ်ရေးကိုယ်တာ ဒေတာများကို အသုံးပြုနိုင်ပါသည်။"</string>
+    <string name="screen_pinning_exposes_personal_data" msgid="8189852022981524789">"ကိုယ်ရေးကိုယ်တာ ဒေတာများ (အဆက်အသွယ်နှင့် အီးမေးလ် အကြောင်းအရာများကဲ့သို့) ကို အသုံးပြုနိုင်ပါသည်။"</string>
     <string name="screen_pinning_can_open_other_apps" msgid="7529756813231421455">"ပင်ထိုးထားသည့်အက်ပ်က အခြားအက်ပ်များကို ဖွင့်နိုင်သည်။"</string>
     <string name="screen_pinning_toast" msgid="8177286912533744328">"ဤအက်ပ်ကိုပင်ဖြုတ်ရန် \'နောက်သို့\' နှင့် \'အနှစ်ချုပ်\' ခလုတ်များကို ထိ၍နှိပ်ထားပါ"</string>
     <string name="screen_pinning_toast_recents_invisible" msgid="6850978077443052594">"ဤအက်ပ်ကိုပင်ဖြုတ်ရန် \'နောက်သို့\' နှင့် \'ပင်မ\' ခလုတ်တို့ကို ထိ၍နှိပ်ထားပါ"</string>
@@ -1002,7 +1002,7 @@
     <string name="bubble_accessibility_action_move_top_right" msgid="6916868852433483569">"ညာဘက်ထိပ်သို့ ရွှေ့ပါ"</string>
     <string name="bubble_accessibility_action_move_bottom_left" msgid="6339015902495504715">"ဘယ်အောက်ခြေသို့ ရွှေ့ရန်"</string>
     <string name="bubble_accessibility_action_move_bottom_right" msgid="7471571700628346212">"ညာအောက်ခြေသို့ ရွှေ့ပါ"</string>
-    <string name="bubble_dismiss_text" msgid="7071770411580452911">"ပယ်ရန်"</string>
+    <string name="bubble_dismiss_text" msgid="1314082410868930066">"ပူဖောင်းကွက် ပယ်ရန်"</string>
     <string name="bubbles_dont_bubble_conversation" msgid="1033040343437428822">"စကားဝိုင်းကို ပူဖောင်းကွက် မပြုလုပ်ပါနှင့်"</string>
     <string name="bubbles_user_education_title" msgid="5547017089271445797">"ပူဖောင်းကွက် သုံး၍ ချတ်လုပ်ခြင်း"</string>
     <string name="bubbles_user_education_description" msgid="1160281719576715211">"စကားဝိုင်းအသစ်များကို မျောနေသည့် သင်္ကေတများ သို့မဟုတ် ပူဖောင်းကွက်များအဖြစ် မြင်ရပါမည်။ ပူဖောင်းကွက်ကိုဖွင့်ရန် တို့ပါ။ ရွှေ့ရန် ၎င်းကို ဖိဆွဲပါ။"</string>
@@ -1062,9 +1062,13 @@
     <string name="controls_structure_tooltip" msgid="4355922222944447867">"ပိုမိုကြည့်ရှုရန် ပွတ်ဆွဲပါ"</string>
     <string name="controls_seeding_in_progress" msgid="3033855341410264148">"အကြံပြုချက်များ ဖွင့်နေသည်"</string>
     <string name="controls_media_close_session" msgid="9023534788828414585">"ဤမီဒီယာစက်ရှင်ကို ပိတ်ပါ"</string>
+    <string name="controls_media_resume" msgid="1933520684481586053">"ဆက်လုပ်ရန်"</string>
     <string name="controls_error_timeout" msgid="794197289772728958">"ရပ်နေသည်၊ အက်ပ်ကို စစ်ဆေးပါ"</string>
     <string name="controls_error_retryable" msgid="864025882878378470">"မှားသွားသည်၊ ပြန်စမ်းနေသည်…"</string>
-    <string name="controls_error_removed" msgid="6299213591234723805">"စက်ကို ဖယ်ရှားထားသည်"</string>
+    <string name="controls_error_removed" msgid="6675638069846014366">"မတွေ့ပါ"</string>
+    <string name="controls_error_removed_title" msgid="1207794911208047818">"ထိန်းချုပ်၍ မရတော့ပါ"</string>
+    <string name="controls_error_removed_message" msgid="2885911717034750542">"<xliff:g id="DEVICE">%1$s</xliff:g> အသုံးပြု၍ မရပါ။ ထိန်းချုပ်၍ ရသေးကြောင်းနှင့် အက်ပ်ဆက်တင်များ ပြောင်းမထားကြောင်း သေချာစေရန် <xliff:g id="APPLICATION">%2$s</xliff:g> အက်ပ်ကို စစ်ဆေးပါ။"</string>
+    <string name="controls_open_app" msgid="483650971094300141">"အက်ပ်ဖွင့်ရန်"</string>
     <string name="controls_error_generic" msgid="352500456918362905">"အခြေအနေကို ဖွင့်၍မရပါ"</string>
     <string name="controls_error_failed" msgid="960228639198558525">"မှားသွားသည်၊ ပြန်စမ်းကြည့်ပါ"</string>
     <string name="controls_in_progress" msgid="4421080500238215939">"ဆောင်ရွက်နေသည်"</string>
diff --git a/packages/SystemUI/res/values-nb/strings.xml b/packages/SystemUI/res/values-nb/strings.xml
index b208cf2..aee2dd2 100644
--- a/packages/SystemUI/res/values-nb/strings.xml
+++ b/packages/SystemUI/res/values-nb/strings.xml
@@ -510,7 +510,7 @@
     <string name="clear_all_notifications_text" msgid="348312370303046130">"Fjern alt"</string>
     <string name="manage_notifications_text" msgid="6885645344647733116">"Administrer"</string>
     <string name="manage_notifications_history_text" msgid="57055985396576230">"Logg"</string>
-    <string name="notification_section_header_incoming" msgid="5295312809341711367">"Innkommende"</string>
+    <string name="notification_section_header_incoming" msgid="850925217908095197">"Ny"</string>
     <string name="notification_section_header_gentle" msgid="6804099527336337197">"Lydløs"</string>
     <string name="notification_section_header_alerting" msgid="5581175033680477651">"Varsler"</string>
     <string name="notification_section_header_conversations" msgid="821834744538345661">"Samtaler"</string>
@@ -1002,10 +1002,10 @@
     <string name="bubble_accessibility_action_move_top_right" msgid="6916868852433483569">"Flytt til øverst til høyre"</string>
     <string name="bubble_accessibility_action_move_bottom_left" msgid="6339015902495504715">"Flytt til nederst til venstre"</string>
     <string name="bubble_accessibility_action_move_bottom_right" msgid="7471571700628346212">"Flytt til nederst til høyre"</string>
-    <string name="bubble_dismiss_text" msgid="7071770411580452911">"Avvis"</string>
+    <string name="bubble_dismiss_text" msgid="1314082410868930066">"Lukk boblen"</string>
     <string name="bubbles_dont_bubble_conversation" msgid="1033040343437428822">"Ikke vis samtaler i bobler"</string>
     <string name="bubbles_user_education_title" msgid="5547017089271445797">"Chat med bobler"</string>
-    <string name="bubbles_user_education_description" msgid="1160281719576715211">"Nye samtaler vises som flytende ikoner, eller bobler. Trykk for å åpne bobler. Dra for å flytte dem."</string>
+    <string name="bubbles_user_education_description" msgid="1160281719576715211">"Nye samtaler vises som flytende ikoner eller bobler. Trykk for å åpne bobler. Dra for å flytte dem."</string>
     <string name="bubbles_user_education_manage_title" msgid="2848511858160342320">"Kontrollér bobler når som helst"</string>
     <string name="bubbles_user_education_manage" msgid="1391639189507036423">"Trykk på Administrer for å slå av bobler for denne appen"</string>
     <string name="bubbles_user_education_got_it" msgid="8282812431953161143">"Greit"</string>
@@ -1062,9 +1062,13 @@
     <string name="controls_structure_tooltip" msgid="4355922222944447867">"Sveip for å se flere"</string>
     <string name="controls_seeding_in_progress" msgid="3033855341410264148">"Laster inn anbefalinger"</string>
     <string name="controls_media_close_session" msgid="9023534788828414585">"Lukk denne medieøkten"</string>
+    <string name="controls_media_resume" msgid="1933520684481586053">"Gjenoppta"</string>
     <string name="controls_error_timeout" msgid="794197289772728958">"Inaktiv. Sjekk appen"</string>
     <string name="controls_error_retryable" msgid="864025882878378470">"Feil. Prøver igjen …"</string>
-    <string name="controls_error_removed" msgid="6299213591234723805">"Enheten er fjernet"</string>
+    <string name="controls_error_removed" msgid="6675638069846014366">"Ikke funnet"</string>
+    <string name="controls_error_removed_title" msgid="1207794911208047818">"Kontrollen er utilgjengelig"</string>
+    <string name="controls_error_removed_message" msgid="2885911717034750542">"Fikk ikke tilgang til <xliff:g id="DEVICE">%1$s</xliff:g>. Sjekk <xliff:g id="APPLICATION">%2$s</xliff:g>-appen for å sjekke at kontrollen fremdeles er tilgjengelig, og at appinnstillingene ikke er endret."</string>
+    <string name="controls_open_app" msgid="483650971094300141">"Åpne appen"</string>
     <string name="controls_error_generic" msgid="352500456918362905">"Kan ikke laste inn status"</string>
     <string name="controls_error_failed" msgid="960228639198558525">"En feil oppsto. Prøv på nytt"</string>
     <string name="controls_in_progress" msgid="4421080500238215939">"Pågår"</string>
diff --git a/packages/SystemUI/res/values-ne/strings.xml b/packages/SystemUI/res/values-ne/strings.xml
index abfb4c8..fda85cc 100644
--- a/packages/SystemUI/res/values-ne/strings.xml
+++ b/packages/SystemUI/res/values-ne/strings.xml
@@ -510,7 +510,8 @@
     <string name="clear_all_notifications_text" msgid="348312370303046130">"सबै हटाउनुहोस्"</string>
     <string name="manage_notifications_text" msgid="6885645344647733116">"व्यवस्थित गर्नुहोस्"</string>
     <string name="manage_notifications_history_text" msgid="57055985396576230">"इतिहास"</string>
-    <string name="notification_section_header_incoming" msgid="5295312809341711367">"हालसालै प्राप्त भएका सूचनाहरू"</string>
+    <!-- no translation found for notification_section_header_incoming (850925217908095197) -->
+    <skip />
     <string name="notification_section_header_gentle" msgid="6804099527336337197">"मौन"</string>
     <string name="notification_section_header_alerting" msgid="5581175033680477651">"सूचनाहरू"</string>
     <string name="notification_section_header_conversations" msgid="821834744538345661">"वार्तालापहरू"</string>
@@ -595,7 +596,7 @@
     <string name="screen_pinning_title" msgid="9058007390337841305">"एप पिन गरिएको छ"</string>
     <string name="screen_pinning_description" msgid="8699395373875667743">"तपाईंले अनपिन नगरेसम्म यसले त्यसलाई दृश्यमा कायम राख्छ। अनपिन गर्न पछाडि र परिदृश्य बटनलाई छोइराख्नुहोस्।"</string>
     <string name="screen_pinning_description_recents_invisible" msgid="4564466648700390037">"तपाईंले अनपिन नगरेसम्म यसले त्यसलाई दृश्यमा कायम राख्छ। अनपिन गर्न पछाडि र गृह नामक बटनहरूलाई छोइराख्नुहोस्।"</string>
-    <string name="screen_pinning_description_gestural" msgid="7246323931831232068">"तपाईंले अनपिन नगरेसम्म यस कार्यले यसलाई दृश्यमा राख्छ। अनपिन गर्न माथितिर स्वाइप गरी होल्ड गर्नुहोस्।"</string>
+    <string name="screen_pinning_description_gestural" msgid="7246323931831232068">"तपाईंले यो एप अनपिन नगरेसम्म यो एप यहाँ देखिइरहने छ। अनपिन गर्न माथितिर स्वाइप गरी होल्ड गर्नुहोस्।"</string>
     <string name="screen_pinning_description_accessible" msgid="7386449191953535332">"तपाईंले अनपिन नगरेसम्म यसले त्यसलाई दृश्यमा कायम राख्छ। अनपिन गर्न परिदृश्य बटनलाई छोइराख्नुहोस्।"</string>
     <string name="screen_pinning_description_recents_invisible_accessible" msgid="2857071808674481986">"तपाईंले अनपिन नगरेसम्म यसले त्यसलाई दृश्यमा कायम राख्छ। अनपिन गर्न गृह नामक बटनलाई छोइराख्नुहोस्।"</string>
     <string name="screen_pinning_exposes_personal_data" msgid="8189852022981524789">"स्क्रिनमा व्यक्तिगत डेटा (जस्तै सम्पर्क ठेगाना र इमेलको सामग्री) देखिन सक्छ।"</string>
@@ -1002,7 +1003,7 @@
     <string name="bubble_accessibility_action_move_top_right" msgid="6916868852433483569">"सिरानमा दायाँतिर सार्नुहोस्"</string>
     <string name="bubble_accessibility_action_move_bottom_left" msgid="6339015902495504715">"पुछारमा बायाँतिर सार्नुहोस्"</string>
     <string name="bubble_accessibility_action_move_bottom_right" msgid="7471571700628346212">"पुछारमा दायाँतिर सार्नुहोस्"</string>
-    <string name="bubble_dismiss_text" msgid="7071770411580452911">"हटाउनुहोस्"</string>
+    <string name="bubble_dismiss_text" msgid="1314082410868930066">"बबल खारेज गर्नुहोस्"</string>
     <string name="bubbles_dont_bubble_conversation" msgid="1033040343437428822">"वार्तालाप बबलको रूपमा नदेखाइयोस्"</string>
     <string name="bubbles_user_education_title" msgid="5547017089271445797">"बबलहरू प्रयोग गरी कुराकानी गर्नुहोस्"</string>
     <string name="bubbles_user_education_description" msgid="1160281719576715211">"नयाँ वार्तालापहरू तैरने आइकन वा बबलका रूपमा देखिन्छन्। बबल खोल्न ट्याप गर्नुहोस्। बबल सार्न सो बबललाई ड्र्याग गर्नुहोस्।"</string>
@@ -1013,17 +1014,14 @@
     <string name="notification_content_system_nav_changed" msgid="5077913144844684544">"प्रणालीको नेभिगेसन अद्यावधिक गरियो। परिवर्तन गर्न सेटिङमा जानुहोस्।"</string>
     <string name="notification_content_gesture_nav_available" msgid="4431460803004659888">"प्रणालीको नेभिगेसन अद्यावधिक गर्न सेटिङमा जानुहोस्"</string>
     <string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"स्ट्यान्डबाई"</string>
-    <!-- no translation found for priority_onboarding_title (2893070698479227616) -->
-    <skip />
-    <!-- no translation found for priority_onboarding_behavior (5342816047020432929) -->
-    <skip />
+    <string name="priority_onboarding_title" msgid="2893070698479227616">"वार्तालापको प्राथमिकता निर्धारण गरी महत्त्वपूर्ण बनाइयो"</string>
+    <string name="priority_onboarding_behavior" msgid="5342816047020432929">"महत्वपूर्ण वार्तालापहरू यहाँ देखिने छन्:"</string>
     <string name="priority_onboarding_show_at_top_text" msgid="1678400241025513541">"वार्तालाप खण्डको सिरानमा देखाइयोस्"</string>
     <string name="priority_onboarding_show_avatar_text" msgid="5756291381124091508">"लक स्क्रिनमा प्रोफाइल तस्बिर देखाइयोस्"</string>
     <string name="priority_onboarding_appear_as_bubble_text" msgid="4227039772250263122">"एपहरूमाथि तैरिने बबलका रूपमा देखाइयोस्"</string>
     <string name="priority_onboarding_ignores_dnd_text" msgid="2918952762719600529">"बाधा नपुऱ्याउनुहोस् मोडलाई बेवास्ता गरियोस्"</string>
     <string name="priority_onboarding_done_button_title" msgid="4569550984286506007">"बुझेँ"</string>
-    <!-- no translation found for priority_onboarding_settings_button_title (6663601574303585927) -->
-    <skip />
+    <string name="priority_onboarding_settings_button_title" msgid="6663601574303585927">"सेटिङ"</string>
     <string name="magnification_overlay_title" msgid="6584179429612427958">"म्याग्निफिकेसन ओभरले विन्डो"</string>
     <string name="magnification_window_title" msgid="4863914360847258333">"म्याग्निफिकेसन विन्डो"</string>
     <string name="magnification_controls_title" msgid="8421106606708891519">"म्याग्निफिकेसन विन्डोका नियन्त्रणहरू"</string>
@@ -1065,9 +1063,13 @@
     <string name="controls_structure_tooltip" msgid="4355922222944447867">"थप हेर्न स्वाइप गर्नुहोस्"</string>
     <string name="controls_seeding_in_progress" msgid="3033855341410264148">"सिफारिसहरू लोड गर्दै"</string>
     <string name="controls_media_close_session" msgid="9023534788828414585">"यो मिडिया सत्र बन्द गर्नुहोस्"</string>
+    <string name="controls_media_resume" msgid="1933520684481586053">"सुचारु गर्नुहोस्"</string>
     <string name="controls_error_timeout" msgid="794197289772728958">"निष्क्रिय छ, एप जाँच गर्नु…"</string>
     <string name="controls_error_retryable" msgid="864025882878378470">"त्रुटि भयो, फेरि प्रयास गर्दै…"</string>
-    <string name="controls_error_removed" msgid="6299213591234723805">"यन्त्र हटाइयो"</string>
+    <string name="controls_error_removed" msgid="6675638069846014366">"फेला परेन"</string>
+    <string name="controls_error_removed_title" msgid="1207794911208047818">"नियन्त्रण उपलब्ध छैन"</string>
+    <string name="controls_error_removed_message" msgid="2885911717034750542">"<xliff:g id="DEVICE">%1$s</xliff:g> प्रयोग गर्न सकिएन। यो नियन्त्रण सुविधा अझै पनि उपलब्ध छ र <xliff:g id="APPLICATION">%2$s</xliff:g> एपका सेटिङ परिवर्तन गरिएका छैनन् भन्ने कुरा सुनिश्चित गर्न यो एप जाँच्नुहोस्।"</string>
+    <string name="controls_open_app" msgid="483650971094300141">"एप खोल्नुहोस्"</string>
     <string name="controls_error_generic" msgid="352500456918362905">"वस्तुस्थिति लोड गर्न सकिएन"</string>
     <string name="controls_error_failed" msgid="960228639198558525">"त्रुटि भयो, फेरि प्रयास गर्नु…"</string>
     <string name="controls_in_progress" msgid="4421080500238215939">"कार्य हुँदै छ"</string>
diff --git a/packages/SystemUI/res/values-night/styles.xml b/packages/SystemUI/res/values-night/styles.xml
index 50261e1..4fdeb6f 100644
--- a/packages/SystemUI/res/values-night/styles.xml
+++ b/packages/SystemUI/res/values-night/styles.xml
@@ -29,9 +29,4 @@
         <item name="android:textColor">?android:attr/textColorPrimary</item>
     </style>
 
-    <style name="qs_security_footer" parent="@style/qs_theme">
-        <item name="android:textColor">#B3FFFFFF</item> <!-- 70% white -->
-        <item name="android:tint">#FFFFFFFF</item>
-    </style>
-
 </resources>
diff --git a/packages/SystemUI/res/values-nl/strings.xml b/packages/SystemUI/res/values-nl/strings.xml
index f578c2d..87f072b 100644
--- a/packages/SystemUI/res/values-nl/strings.xml
+++ b/packages/SystemUI/res/values-nl/strings.xml
@@ -259,10 +259,10 @@
     <string name="accessibility_bubble_dismissed" msgid="270358867566720729">"Bubbel gesloten."</string>
     <string name="accessibility_desc_notification_shade" msgid="5355229129428759989">"Meldingenpaneel."</string>
     <string name="accessibility_desc_quick_settings" msgid="4374766941484719179">"Snelle instellingen."</string>
-    <string name="accessibility_desc_lock_screen" msgid="5983125095181194887">"Vergrendelingsscherm."</string>
+    <string name="accessibility_desc_lock_screen" msgid="5983125095181194887">"Vergrendelscherm."</string>
     <string name="accessibility_desc_settings" msgid="6728577365389151969">"Instellingen"</string>
     <string name="accessibility_desc_recent_apps" msgid="1748675199348914194">"Overzicht."</string>
-    <string name="accessibility_desc_work_lock" msgid="4355620395354680575">"Vergrendelingsscherm voor werk"</string>
+    <string name="accessibility_desc_work_lock" msgid="4355620395354680575">"Vergrendelscherm voor werk"</string>
     <string name="accessibility_desc_close" msgid="8293708213442107755">"Sluiten"</string>
     <string name="accessibility_quick_settings_wifi" msgid="167707325133803052">"<xliff:g id="SIGNAL">%1$s</xliff:g>."</string>
     <string name="accessibility_quick_settings_wifi_changed_off" msgid="2230487165558877262">"Wifi uitgeschakeld."</string>
@@ -510,7 +510,7 @@
     <string name="clear_all_notifications_text" msgid="348312370303046130">"Alles wissen"</string>
     <string name="manage_notifications_text" msgid="6885645344647733116">"Beheren"</string>
     <string name="manage_notifications_history_text" msgid="57055985396576230">"Geschiedenis"</string>
-    <string name="notification_section_header_incoming" msgid="5295312809341711367">"Inkomend"</string>
+    <string name="notification_section_header_incoming" msgid="850925217908095197">"Nieuw"</string>
     <string name="notification_section_header_gentle" msgid="6804099527336337197">"Stil"</string>
     <string name="notification_section_header_alerting" msgid="5581175033680477651">"Meldingen"</string>
     <string name="notification_section_header_conversations" msgid="821834744538345661">"Gesprekken"</string>
@@ -595,7 +595,7 @@
     <string name="screen_pinning_title" msgid="9058007390337841305">"App is vastgezet"</string>
     <string name="screen_pinning_description" msgid="8699395373875667743">"Het scherm blijft zichtbaar totdat je het losmaakt. Tik op Terug en Overzicht en houd deze vast om het scherm los te maken."</string>
     <string name="screen_pinning_description_recents_invisible" msgid="4564466648700390037">"Het scherm blijft zichtbaar totdat je het losmaakt. Tik op Terug en Home en houd deze vast om het scherm los te maken."</string>
-    <string name="screen_pinning_description_gestural" msgid="7246323931831232068">"Zo blijft het scherm zichtbaar totdat je dit losmaakt. Veeg omhoog en houd vast om los te maken."</string>
+    <string name="screen_pinning_description_gestural" msgid="7246323931831232068">"Zo blijft het scherm zichtbaar totdat je dit losmaakt. Swipe omhoog en houd vast om los te maken."</string>
     <string name="screen_pinning_description_accessible" msgid="7386449191953535332">"Het scherm blijft zichtbaar totdat je het losmaakt. Tik op Overzicht en houd dit vast om het scherm los te maken."</string>
     <string name="screen_pinning_description_recents_invisible_accessible" msgid="2857071808674481986">"Het scherm blijft zichtbaar totdat je het losmaakt. Tik op Home en houd dit vast om het scherm los te maken."</string>
     <string name="screen_pinning_exposes_personal_data" msgid="8189852022981524789">"Persoonlijke informatie kan toegankelijk zijn (zoals contacten en e-mailcontent)."</string>
@@ -687,7 +687,7 @@
     <string name="tuner_full_importance_settings" msgid="1388025816553459059">"Beheeropties voor meldingen met betrekking tot stroomverbruik"</string>
     <string name="tuner_full_importance_settings_on" msgid="917981436602311547">"Aan"</string>
     <string name="tuner_full_importance_settings_off" msgid="5580102038749680829">"Uit"</string>
-    <string name="power_notification_controls_description" msgid="1334963837572708952">"Met beheeropties voor meldingen met betrekking tot stroomverbruik kun je een belangrijkheidsniveau van 0 tot 5 instellen voor de meldingen van een app. \n\n"<b>"Niveau 5"</b>" \n- Boven aan de lijst met meldingen weergeven \n- Onderbreking op volledig scherm toestaan \n- Altijd korte weergave \n\n"<b>"Niveau 4"</b>" \n- Geen onderbreking op volledig scherm \n- Altijd korte weergave \n\n"<b>"Niveau 3"</b>" \n- Geen onderbreking op volledig scherm \n- Nooit korte weergave \n\n"<b>"Niveau 2"</b>" \n- Geen onderbreking op volledig scherm \n- Nooit korte weergave \n- Nooit geluid laten horen of trillen \n\n"<b>"Niveau 1"</b>" \n- Geen onderbreking op volledig scherm \n- Nooit korte weergave \n- Nooit geluid laten horen of trillen \n- Verbergen op vergrendelingsscherm en statusbalk \n- Onder aan de lijst met meldingen weergeven \n\n"<b>"Niveau 0"</b>" \n- Alle meldingen van de app blokkeren"</string>
+    <string name="power_notification_controls_description" msgid="1334963837572708952">"Met beheeropties voor meldingen met betrekking tot stroomverbruik kun je een belangrijkheidsniveau van 0 tot 5 instellen voor de meldingen van een app. \n\n"<b>"Niveau 5"</b>" \n- Boven aan de lijst met meldingen weergeven \n- Onderbreking op volledig scherm toestaan \n- Altijd korte weergave \n\n"<b>"Niveau 4"</b>" \n- Geen onderbreking op volledig scherm \n- Altijd korte weergave \n\n"<b>"Niveau 3"</b>" \n- Geen onderbreking op volledig scherm \n- Nooit korte weergave \n\n"<b>"Niveau 2"</b>" \n- Geen onderbreking op volledig scherm \n- Nooit korte weergave \n- Nooit geluid laten horen of trillen \n\n"<b>"Niveau 1"</b>" \n- Geen onderbreking op volledig scherm \n- Nooit korte weergave \n- Nooit geluid laten horen of trillen \n- Verbergen op vergrendelscherm en statusbalk \n- Onder aan de lijst met meldingen weergeven \n\n"<b>"Niveau 0"</b>" \n- Alle meldingen van de app blokkeren"</string>
     <string name="notification_header_default_channel" msgid="225454696914642444">"Meldingen"</string>
     <string name="notification_channel_disabled" msgid="928065923928416337">"Meldingen worden niet meer weergegeven"</string>
     <string name="notification_channel_minimized" msgid="6892672757877552959">"Deze meldingen worden geminimaliseerd"</string>
@@ -716,7 +716,7 @@
     <string name="notification_channel_summary_default" msgid="3282930979307248890">"Kan overgaan of trillen op basis van de telefooninstellingen"</string>
     <string name="notification_channel_summary_default_with_bubbles" msgid="1782419896613644568">"Kan overgaan of trillen op basis van de telefooninstellingen. Gesprekken uit <xliff:g id="APP_NAME">%1$s</xliff:g> worden standaard als bubbels weergegeven."</string>
     <string name="notification_channel_summary_bubble" msgid="7235935211580860537">"Trekt de aandacht met een zwevende snelkoppeling naar deze content."</string>
-    <string name="notification_channel_summary_priority" msgid="7952654515769021553">"Wordt bovenaan het gedeelte met gesprekken weergegeven, verschijnt als zwevende bubbel, geeft de profielfoto weer op het vergrendelingsscherm"</string>
+    <string name="notification_channel_summary_priority" msgid="7952654515769021553">"Wordt bovenaan het gedeelte met gesprekken weergegeven, verschijnt als zwevende bubbel, geeft de profielfoto weer op het vergrendelscherm"</string>
     <string name="notification_conversation_channel_settings" msgid="2409977688430606835">"Instellingen"</string>
     <string name="notification_priority_title" msgid="2079708866333537093">"Prioriteit"</string>
     <string name="no_shortcut" msgid="8257177117568230126">"<xliff:g id="APP_NAME">%1$s</xliff:g> ondersteunt geen gespreksfuncties"</string>
@@ -907,7 +907,7 @@
     <string name="accessibility_quick_settings_open_settings" msgid="536838345505030893">"<xliff:g id="ID_1">%s</xliff:g>-instellingen openen."</string>
     <string name="accessibility_quick_settings_edit" msgid="1523745183383815910">"Volgorde van instellingen bewerken."</string>
     <string name="accessibility_quick_settings_page" msgid="7506322631645550961">"Pagina <xliff:g id="ID_1">%1$d</xliff:g> van <xliff:g id="ID_2">%2$d</xliff:g>"</string>
-    <string name="tuner_lock_screen" msgid="2267383813241144544">"Vergrendelingsscherm"</string>
+    <string name="tuner_lock_screen" msgid="2267383813241144544">"Vergrendelscherm"</string>
     <string name="pip_phone_expand" msgid="1424988917240616212">"Uitvouwen"</string>
     <string name="pip_phone_minimize" msgid="9057117033655996059">"Minimaliseren"</string>
     <string name="pip_phone_close" msgid="8801864042095341824">"Sluiten"</string>
@@ -1002,7 +1002,7 @@
     <string name="bubble_accessibility_action_move_top_right" msgid="6916868852433483569">"Naar rechtsboven verplaatsen"</string>
     <string name="bubble_accessibility_action_move_bottom_left" msgid="6339015902495504715">"Naar linksonder verplaatsen"</string>
     <string name="bubble_accessibility_action_move_bottom_right" msgid="7471571700628346212">"Naar rechtsonder verplaatsen"</string>
-    <string name="bubble_dismiss_text" msgid="7071770411580452911">"Sluiten"</string>
+    <string name="bubble_dismiss_text" msgid="1314082410868930066">"Bubbel sluiten"</string>
     <string name="bubbles_dont_bubble_conversation" msgid="1033040343437428822">"Gesprekken niet in bubbels weergeven"</string>
     <string name="bubbles_user_education_title" msgid="5547017089271445797">"Chatten met bubbels"</string>
     <string name="bubbles_user_education_description" msgid="1160281719576715211">"Nieuwe gesprekken worden weergegeven als zwevende iconen of \'bubbels\'. Tik om een bubbel te openen. Sleep om de bubbel te verplaatsen."</string>
@@ -1016,7 +1016,7 @@
     <string name="priority_onboarding_title" msgid="2893070698479227616">"Gesprek ingesteld als prioriteit"</string>
     <string name="priority_onboarding_behavior" msgid="5342816047020432929">"Bij prioriteitsgesprekken gebeurt het volgende:"</string>
     <string name="priority_onboarding_show_at_top_text" msgid="1678400241025513541">"Worden bovenaan het gespreksgedeelte weergegeven"</string>
-    <string name="priority_onboarding_show_avatar_text" msgid="5756291381124091508">"Tonen profielafbeelding op vergrendelingsscherm"</string>
+    <string name="priority_onboarding_show_avatar_text" msgid="5756291381124091508">"Tonen profielafbeelding op vergrendelscherm"</string>
     <string name="priority_onboarding_appear_as_bubble_text" msgid="4227039772250263122">"Worden als zwevende ballon weergegeven vóór apps"</string>
     <string name="priority_onboarding_ignores_dnd_text" msgid="2918952762719600529">"Onderbreken \'Niet storen\'"</string>
     <string name="priority_onboarding_done_button_title" msgid="4569550984286506007">"OK"</string>
@@ -1062,9 +1062,13 @@
     <string name="controls_structure_tooltip" msgid="4355922222944447867">"Swipe om meer te zien"</string>
     <string name="controls_seeding_in_progress" msgid="3033855341410264148">"Aanbevelingen laden"</string>
     <string name="controls_media_close_session" msgid="9023534788828414585">"Deze mediasessie sluiten"</string>
+    <string name="controls_media_resume" msgid="1933520684481586053">"Hervatten"</string>
     <string name="controls_error_timeout" msgid="794197289772728958">"Inactief, check de app"</string>
     <string name="controls_error_retryable" msgid="864025882878378470">"Fout. Opnieuw proberen…"</string>
-    <string name="controls_error_removed" msgid="6299213591234723805">"Apparaat verwijderd"</string>
+    <string name="controls_error_removed" msgid="6675638069846014366">"Niet gevonden"</string>
+    <string name="controls_error_removed_title" msgid="1207794911208047818">"Beheeroptie niet beschikbaar"</string>
+    <string name="controls_error_removed_message" msgid="2885911717034750542">"Kan geen toegang krijgen tot <xliff:g id="DEVICE">%1$s</xliff:g>. Check de <xliff:g id="APPLICATION">%2$s</xliff:g>-app om na te gaan of de beheeroptie nog steeds beschikbaar is en of de app-instellingen niet zijn gewijzigd."</string>
+    <string name="controls_open_app" msgid="483650971094300141">"App openen"</string>
     <string name="controls_error_generic" msgid="352500456918362905">"Kan status niet laden"</string>
     <string name="controls_error_failed" msgid="960228639198558525">"Fout, probeer het opnieuw"</string>
     <string name="controls_in_progress" msgid="4421080500238215939">"Bezig"</string>
diff --git a/packages/SystemUI/res/values-or/strings.xml b/packages/SystemUI/res/values-or/strings.xml
index 27a04dd..426bd2e 100644
--- a/packages/SystemUI/res/values-or/strings.xml
+++ b/packages/SystemUI/res/values-or/strings.xml
@@ -273,7 +273,7 @@
     <string name="accessibility_quick_settings_airplane_on" msgid="8106176561295294255">"ଏୟାର୍‌ପ୍ଲେନ୍‌ ମୋଡ୍‌ ଅନ୍ ଅଛି।"</string>
     <string name="accessibility_quick_settings_airplane_changed_off" msgid="8880183481476943754">"ଏୟାର୍‌ପ୍ଲେନ୍‌ ମୋଡ୍‌କୁ ବନ୍ଦ କରାଯାଇଛି।"</string>
     <string name="accessibility_quick_settings_airplane_changed_on" msgid="6327378061894076288">"ଏୟାର୍‌ପ୍ଲେନ୍‌ ମୋଡ୍‌କୁ ଚାଲୁ କରାଯାଇଛି।"</string>
-    <string name="accessibility_quick_settings_dnd_none_on" msgid="3235552940146035383">"ସମ୍ପୂର୍ଣ୍ଣ ନିରବ"</string>
+    <string name="accessibility_quick_settings_dnd_none_on" msgid="3235552940146035383">"ସମ୍ପୂର୍ଣ୍ଣ ନୀରବତା"</string>
     <string name="accessibility_quick_settings_dnd_alarms_on" msgid="3375848309132140014">"କେବଳ ଆଲାର୍ମ"</string>
     <string name="accessibility_quick_settings_dnd" msgid="2415967452264206047">"ବିରକ୍ତ କରନ୍ତୁ ନାହିଁ।"</string>
     <string name="accessibility_quick_settings_dnd_changed_off" msgid="1457150026842505799">"\"ବିରକ୍ତ କରନ୍ତୁ ନାହିଁ\"କୁ ବନ୍ଦ କରାଯାଇଛି।"</string>
@@ -345,7 +345,7 @@
     <string name="quick_settings_dnd_label" msgid="7728690179108024338">"ବିରକ୍ତ କରନ୍ତୁ ନାହିଁ"</string>
     <string name="quick_settings_dnd_priority_label" msgid="6251076422352664571">"କେବଳ ପ୍ରାଥମିକତା"</string>
     <string name="quick_settings_dnd_alarms_label" msgid="1241780970469630835">"କେବଳ ଆଲାର୍ମ"</string>
-    <string name="quick_settings_dnd_none_label" msgid="8420869988472836354">"ସମ୍ପୂର୍ଣ୍ଣ ନୀରବ"</string>
+    <string name="quick_settings_dnd_none_label" msgid="8420869988472836354">"ସମ୍ପୂର୍ଣ୍ଣ ନୀରବତା"</string>
     <string name="quick_settings_bluetooth_label" msgid="7018763367142041481">"ବ୍ଲୁଟୁଥ"</string>
     <string name="quick_settings_bluetooth_multiple_devices_label" msgid="6595808498429809855">"ବ୍ଲୁଟୂଥ୍‍‌ (<xliff:g id="NUMBER">%d</xliff:g>ଟି ଡିଭାଇସ୍‌)"</string>
     <string name="quick_settings_bluetooth_off_label" msgid="6375098046500790870">"ବ୍ଲୁଟୂଥ୍‍‌ ଅଫ୍"</string>
@@ -460,7 +460,7 @@
     <string name="voice_hint" msgid="7476017460191291417">"ଭଏସ୍‍ ସହାୟକ ପାଇଁ ଆଇକନରୁ ସ୍ୱାଇପ୍‍ କରନ୍ତୁ"</string>
     <string name="camera_hint" msgid="4519495795000658637">"କ୍ୟାମେରା ପାଇଁ ଆଇକନରୁ ସ୍ୱାଇପ୍‍ କରନ୍ତୁ"</string>
     <string name="interruption_level_none_with_warning" msgid="8394434073508145437">"ସମ୍ପୂର୍ଣ୍ଣ ନୀରବ। ଏହାଦ୍ୱାରା ସ୍କ୍ରୀନ୍‍ ରିଡର୍‍ ମଧ୍ୟ ନୀରବ ହୋଇଯିବ।"</string>
-    <string name="interruption_level_none" msgid="219484038314193379">"ସମ୍ପୂର୍ଣ୍ଣ ନୀରବ"</string>
+    <string name="interruption_level_none" msgid="219484038314193379">"ସମ୍ପୂର୍ଣ୍ଣ ନୀରବତା"</string>
     <string name="interruption_level_priority" msgid="661294280016622209">"କେବଳ ପ୍ରାଥମିକତା"</string>
     <string name="interruption_level_alarms" msgid="2457850481335846959">"କେବଳ ଆଲାର୍ମ"</string>
     <string name="interruption_level_none_twoline" msgid="8579382742855486372">"ସମ୍ପୂର୍ଣ୍ଣ\nନୀରବ"</string>
@@ -510,7 +510,8 @@
     <string name="clear_all_notifications_text" msgid="348312370303046130">"ସମସ୍ତ ଖାଲି କରନ୍ତୁ"</string>
     <string name="manage_notifications_text" msgid="6885645344647733116">"ପରିଚାଳନା କରନ୍ତୁ"</string>
     <string name="manage_notifications_history_text" msgid="57055985396576230">"ଇତିହାସ"</string>
-    <string name="notification_section_header_incoming" msgid="5295312809341711367">"ଇନକମିଂ"</string>
+    <!-- no translation found for notification_section_header_incoming (850925217908095197) -->
+    <skip />
     <string name="notification_section_header_gentle" msgid="6804099527336337197">"ନୀରବ"</string>
     <string name="notification_section_header_alerting" msgid="5581175033680477651">"ବିଜ୍ଞପ୍ତିଗୁଡ଼ିକ"</string>
     <string name="notification_section_header_conversations" msgid="821834744538345661">"ବାର୍ତ୍ତାଳାପଗୁଡ଼ିକ"</string>
@@ -595,7 +596,7 @@
     <string name="screen_pinning_title" msgid="9058007390337841305">"ଆପକୁ ପିନ୍ କରାଯାଇଛି"</string>
     <string name="screen_pinning_description" msgid="8699395373875667743">"ଆପଣ ଅନପିନ୍‍ ନକରିବା ପର୍ଯ୍ୟନ୍ତ ଏହା ଦେଖାଉଥିବ। ଅନପିନ୍‍ କରିବାକୁ ସ୍ପର୍ଶ କରି ଧରିରଖନ୍ତୁ ଓ ଦେଖନ୍ତୁ।"</string>
     <string name="screen_pinning_description_recents_invisible" msgid="4564466648700390037">"ଆପଣ ଅନପିନ୍‍ ନକରିବା ପର୍ଯ୍ୟନ୍ତ ଏହା ଦେଖାଉଥିବ। ଅନପିନ୍‍ କରିବା ପାଇଁ ହୋମ୍ ଓ ବ୍ୟାକ୍ ବଟନ୍‌କୁ ଧରିରଖନ୍ତୁ।"</string>
-    <string name="screen_pinning_description_gestural" msgid="7246323931831232068">"ଆପଣ ଅନ୍‌ପିନ୍ ନକରିବା ପର୍ଯ୍ୟନ୍ତ ଏହା ଦେଖାଯାଉଥିବ। ଅନ୍‌ପିନ୍ କରିବା ପାଇଁ ଉପରକୁ ସ୍ୱାଇପ୍‌ କରି ଧରି ରଖନ୍ତୁ"</string>
+    <string name="screen_pinning_description_gestural" msgid="7246323931831232068">"ଆପଣ ଅନ୍‌ପିନ୍ ନକରିବା ପର୍ଯ୍ୟନ୍ତ ଏହା ଦେଖାଯାଉଥିବ। ଅନ୍‌ପିନ୍ କରିବା ପାଇଁ ଉପରକୁ ସ୍ୱାଇପ୍‌ କରି ଧରି ରଖନ୍ତୁ।"</string>
     <string name="screen_pinning_description_accessible" msgid="7386449191953535332">"ଆପଣ ଅନପିନ୍‍ ନକରିବା ପର୍ଯ୍ୟନ୍ତ ଏହା ଦେଖାଉଥିବ। ଅନପିନ୍‍ କରିବାକୁ ସ୍ପର୍ଶ କରନ୍ତୁ ଏବଂ ଓଭରଭ୍ୟୁକୁ ଧରିରଖନ୍ତୁ।"</string>
     <string name="screen_pinning_description_recents_invisible_accessible" msgid="2857071808674481986">"ଆପଣ ଅନପିନ୍‍ ନକରିବା ପର୍ଯ୍ୟନ୍ତ ଏହା ଦେଖାଉଥିବ। ଅନପିନ୍‍ କରିବା ପର୍ଯ୍ୟନ୍ତ ହୋମ୍‌କୁ ଦାବିଧରନ୍ତୁ।"</string>
     <string name="screen_pinning_exposes_personal_data" msgid="8189852022981524789">"ବ୍ୟକ୍ତିଗତ ଡାଟାକୁ ଆକ୍ସେସ୍ କରାଯାଇପାରେ (ଯେପରିକି ଯୋଗାଯୋଗଗୁଡ଼ିକ ଏବଂ ଇମେଲ୍ ବିଷୟବସ୍ତୁ)।"</string>
@@ -1002,7 +1003,7 @@
     <string name="bubble_accessibility_action_move_top_right" msgid="6916868852433483569">"ଉପର-ଡାହାଣକୁ ନିଅନ୍ତୁ"</string>
     <string name="bubble_accessibility_action_move_bottom_left" msgid="6339015902495504715">"ତଳ ବାମକୁ ନିଅନ୍ତୁ"</string>
     <string name="bubble_accessibility_action_move_bottom_right" msgid="7471571700628346212">"ତଳ ଡାହାଣକୁ ନିଅନ୍ତୁ"</string>
-    <string name="bubble_dismiss_text" msgid="7071770411580452911">"ଖାରଜ କରନ୍ତୁ"</string>
+    <string name="bubble_dismiss_text" msgid="1314082410868930066">"ବବଲ୍ ଖାରଜ କରନ୍ତୁ"</string>
     <string name="bubbles_dont_bubble_conversation" msgid="1033040343437428822">"ବାର୍ତ୍ତାଳାପକୁ ବବଲ୍ କରନ୍ତୁ ନାହିଁ"</string>
     <string name="bubbles_user_education_title" msgid="5547017089271445797">"ବବଲଗୁଡ଼ିକୁ ବ୍ୟବହାର କରି ଚାଟ୍ କରନ୍ତୁ"</string>
     <string name="bubbles_user_education_description" msgid="1160281719576715211">"ନୂଆ ବାର୍ତ୍ତାଳାପଗୁଡ଼ିକ ଫ୍ଲୋଟିଂ ଆଇକନ୍ କିମ୍ବା ବବଲ୍ ଭାବେ ଦେଖାଯିବ। ବବଲ୍ ଖୋଲିବାକୁ ଟାପ୍ କରନ୍ତୁ। ଏହାକୁ ମୁଭ୍ କରିବାକୁ ଟାଣନ୍ତୁ।"</string>
@@ -1013,17 +1014,14 @@
     <string name="notification_content_system_nav_changed" msgid="5077913144844684544">"ସିଷ୍ଟମ୍ ନାଭିଗେସନ୍ ଅପ୍‌ଡେଟ୍ ହୋଇଛି। ପରିବର୍ତ୍ତନ କରିବା ପାଇଁ, ସେଟିଂସ୍‌କୁ ଯାଆନ୍ତୁ।"</string>
     <string name="notification_content_gesture_nav_available" msgid="4431460803004659888">"ସିଷ୍ଟମ୍ ନାଭିଗେସନ୍ ଅପ୍‌ଡେଟ୍ କରିବା ପାଇଁ ସେଟିଂସ୍‍କୁ ଯାଆନ୍ତୁ"</string>
     <string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"ଷ୍ଟାଣ୍ଡବାଏ"</string>
-    <!-- no translation found for priority_onboarding_title (2893070698479227616) -->
-    <skip />
-    <!-- no translation found for priority_onboarding_behavior (5342816047020432929) -->
-    <skip />
+    <string name="priority_onboarding_title" msgid="2893070698479227616">"ବାର୍ତ୍ତାଳାପ ପ୍ରାଥମିକରେ ସେଟ୍ କରାଯାଇଛି"</string>
+    <string name="priority_onboarding_behavior" msgid="5342816047020432929">"ପ୍ରାଥମିକ ବାର୍ତ୍ତାଳାପଗୁଡ଼ିକ ଏଠାରେ ଦେଖାଯିବ:"</string>
     <string name="priority_onboarding_show_at_top_text" msgid="1678400241025513541">"ବାର୍ତ୍ତାଳାପ ବିଭାଗର ଶୀର୍ଷରେ ଦେଖାନ୍ତୁ"</string>
     <string name="priority_onboarding_show_avatar_text" msgid="5756291381124091508">"ଲକ୍ ସ୍କ୍ରିନରେ ପ୍ରୋଫାଇଲ୍ ଛବି ଦେଖାନ୍ତୁ"</string>
     <string name="priority_onboarding_appear_as_bubble_text" msgid="4227039772250263122">"ଆପଗୁଡ଼ିକ ଉପରେ ଫ୍ଲୋଟିଂ ବବଲ୍ ପରି ଦେଖାଯିବ"</string>
     <string name="priority_onboarding_ignores_dnd_text" msgid="2918952762719600529">"\'ବିରକ୍ତ କରନ୍ତୁ ନାହିଁ\' ମୋଡରେ ବାଧା"</string>
     <string name="priority_onboarding_done_button_title" msgid="4569550984286506007">"ବୁଝିଗଲି"</string>
-    <!-- no translation found for priority_onboarding_settings_button_title (6663601574303585927) -->
-    <skip />
+    <string name="priority_onboarding_settings_button_title" msgid="6663601574303585927">"ସେଟିଂସ୍"</string>
     <string name="magnification_overlay_title" msgid="6584179429612427958">"ମ୍ୟାଗ୍ନିଫିକେସନ୍ ଓଭର୍‌ଲେ ୱିଣ୍ଡୋ"</string>
     <string name="magnification_window_title" msgid="4863914360847258333">"ମ୍ୟାଗ୍ନିଫିକେସନ୍ ୱିଣ୍ଡୋ"</string>
     <string name="magnification_controls_title" msgid="8421106606708891519">"ମ୍ୟାଗ୍ନିଫିକେସନ୍ ୱିଣ୍ଡୋ ନିୟନ୍ତ୍ରଣଗୁଡ଼ିକ"</string>
@@ -1065,9 +1063,13 @@
     <string name="controls_structure_tooltip" msgid="4355922222944447867">"ଅଧିକ ଦେଖିବାକୁ ସ୍ୱାଇପ୍ କରନ୍ତୁ"</string>
     <string name="controls_seeding_in_progress" msgid="3033855341410264148">"ସୁପାରିଶଗୁଡ଼ିକ ଲୋଡ୍ କରାଯାଉଛି"</string>
     <string name="controls_media_close_session" msgid="9023534788828414585">"ଏହି ମିଡିଆ ସେସନ୍ ବନ୍ଦ କରନ୍ତୁ"</string>
+    <string name="controls_media_resume" msgid="1933520684481586053">"ପୁଣି ଆରମ୍ଭ କରନ୍ତୁ"</string>
     <string name="controls_error_timeout" msgid="794197289772728958">"ନିଷ୍କ୍ରିୟ ଅଛି, ଆପ ଯାଞ୍ଚ କରନ୍ତୁ"</string>
     <string name="controls_error_retryable" msgid="864025882878378470">"ତ୍ରୁଟି, ପୁଣି ଚେଷ୍ଟା କରୁଛି…"</string>
-    <string name="controls_error_removed" msgid="6299213591234723805">"ଡିଭାଇସ୍ କାଢ଼ି ଦିଆଯାଇଛି"</string>
+    <string name="controls_error_removed" msgid="6675638069846014366">"ମିଳିଲା ନାହିଁ"</string>
+    <string name="controls_error_removed_title" msgid="1207794911208047818">"ନିୟନ୍ତ୍ରଣ ଉପଲବ୍ଧ ନାହିଁ"</string>
+    <string name="controls_error_removed_message" msgid="2885911717034750542">"<xliff:g id="DEVICE">%1$s</xliff:g>କୁ ଆକ୍ସେସ୍ କରିହେଲା ନାହିଁ। ନିୟନ୍ତ୍ରଣ ଏବେ ବି ଉପଲବ୍ଧ ଅଛି ଏବଂ ଆପ୍ ସେଟିଂସ୍ ବଦଳାଯାଇ ନାହିଁ ବୋଲି ସୁନିଶ୍ଚିତ କରିବାକୁ <xliff:g id="APPLICATION">%2$s</xliff:g> ଆପକୁ ଯାଞ୍ଚ କରନ୍ତୁ।"</string>
+    <string name="controls_open_app" msgid="483650971094300141">"ଆପ୍ ଖୋଲନ୍ତୁ"</string>
     <string name="controls_error_generic" msgid="352500456918362905">"ସ୍ଥିତି ଲୋଡ୍ କରାଯାଇପାରିବ ନାହିଁ"</string>
     <string name="controls_error_failed" msgid="960228639198558525">"ତ୍ରୁଟି ହୋଇଛି, ପୁଣି ଚେଷ୍ଟା କର"</string>
     <string name="controls_in_progress" msgid="4421080500238215939">"ପ୍ରଗତିରେ ଅଛି"</string>
diff --git a/packages/SystemUI/res/values-pa/strings.xml b/packages/SystemUI/res/values-pa/strings.xml
index b8bf05b..ccafc49 100644
--- a/packages/SystemUI/res/values-pa/strings.xml
+++ b/packages/SystemUI/res/values-pa/strings.xml
@@ -273,7 +273,7 @@
     <string name="accessibility_quick_settings_airplane_on" msgid="8106176561295294255">"ਏਅਰਪਲੇਨ ਮੋਡ ਚਾਲੂ।"</string>
     <string name="accessibility_quick_settings_airplane_changed_off" msgid="8880183481476943754">"ਏਅਰਪਲੇਨ ਮੋਡ ਬੰਦ ਹੈ।"</string>
     <string name="accessibility_quick_settings_airplane_changed_on" msgid="6327378061894076288">"ਏਅਰਪਲੇਨ ਮੋਡ ਚਾਲੂ ਹੋਇਆ"</string>
-    <string name="accessibility_quick_settings_dnd_none_on" msgid="3235552940146035383">"ਸੰਪੂਰਨ ਖਾਮੋਸ਼ੀ"</string>
+    <string name="accessibility_quick_settings_dnd_none_on" msgid="3235552940146035383">"ਪੂਰਾ ਸ਼ਾਂਤ"</string>
     <string name="accessibility_quick_settings_dnd_alarms_on" msgid="3375848309132140014">"ਸਿਰਫ਼ ਅਲਾਰਮ"</string>
     <string name="accessibility_quick_settings_dnd" msgid="2415967452264206047">"ਪਰੇਸ਼ਾਨ ਨਾ ਕਰੋ।"</string>
     <string name="accessibility_quick_settings_dnd_changed_off" msgid="1457150026842505799">"\'ਪਰੇਸ਼ਾਨ ਨਾ ਕਰੋ\' ਨੂੰ ਬੰਦ ਕੀਤਾ ਗਿਆ।"</string>
@@ -510,7 +510,7 @@
     <string name="clear_all_notifications_text" msgid="348312370303046130">"ਸਭ ਕਲੀਅਰ ਕਰੋ"</string>
     <string name="manage_notifications_text" msgid="6885645344647733116">"ਪ੍ਰਬੰਧਨ ਕਰੋ"</string>
     <string name="manage_notifications_history_text" msgid="57055985396576230">"ਇਤਿਹਾਸ"</string>
-    <string name="notification_section_header_incoming" msgid="5295312809341711367">"ਇਨਕਮਿੰਗ"</string>
+    <string name="notification_section_header_incoming" msgid="850925217908095197">"ਨਵਾਂ"</string>
     <string name="notification_section_header_gentle" msgid="6804099527336337197">"ਸ਼ਾਂਤ"</string>
     <string name="notification_section_header_alerting" msgid="5581175033680477651">"ਸੂਚਨਾਵਾਂ"</string>
     <string name="notification_section_header_conversations" msgid="821834744538345661">"ਗੱਲਾਂਬਾਤਾਂ"</string>
@@ -1002,7 +1002,7 @@
     <string name="bubble_accessibility_action_move_top_right" msgid="6916868852433483569">"ਉੱਪਰ ਵੱਲ ਸੱਜੇ ਲਿਜਾਓ"</string>
     <string name="bubble_accessibility_action_move_bottom_left" msgid="6339015902495504715">"ਹੇਠਾਂ ਵੱਲ ਖੱਬੇ ਲਿਜਾਓ"</string>
     <string name="bubble_accessibility_action_move_bottom_right" msgid="7471571700628346212">"ਹੇਠਾਂ ਵੱਲ ਸੱਜੇ ਲਿਜਾਓ"</string>
-    <string name="bubble_dismiss_text" msgid="7071770411580452911">"ਖਾਰਜ ਕਰੋ"</string>
+    <string name="bubble_dismiss_text" msgid="1314082410868930066">"ਬਬਲ ਨੂੰ ਖਾਰਜ ਕਰੋ"</string>
     <string name="bubbles_dont_bubble_conversation" msgid="1033040343437428822">"ਗੱਲਬਾਤ \'ਤੇ ਬਬਲ ਨਾ ਲਾਓ"</string>
     <string name="bubbles_user_education_title" msgid="5547017089271445797">"ਬਬਲ ਵਰਤਦੇ ਹੋਏ ਚੈਟ ਕਰੋ"</string>
     <string name="bubbles_user_education_description" msgid="1160281719576715211">"ਨਵੀਆਂ ਗੱਲਾਂਬਾਤਾਂ ਫਲੋਟਿੰਗ ਪ੍ਰਤੀਕਾਂ ਜਾਂ ਬਬਲ ਦੇ ਰੂਪ ਵਿੱਚ ਦਿਸਦੀਆਂ ਹਨ। ਬਬਲ ਨੂੰ ਖੋਲ੍ਹਣ ਲਈ ਟੈਪ ਕਰੋ। ਇਸਨੂੰ ਲਿਜਾਣ ਲਈ ਘਸੀਟੋ।"</string>
@@ -1062,9 +1062,13 @@
     <string name="controls_structure_tooltip" msgid="4355922222944447867">"ਹੋਰ ਦੇਖਣ ਲਈ ਸਵਾਈਪ ਕਰੋ"</string>
     <string name="controls_seeding_in_progress" msgid="3033855341410264148">"ਸਿਫ਼ਾਰਸ਼ਾਂ ਲੋਡ ਹੋ ਰਹੀਆਂ ਹਨ"</string>
     <string name="controls_media_close_session" msgid="9023534788828414585">"ਇਸ ਮੀਡੀਆ ਸੈਸ਼ਨ ਨੂੰ ਬੰਦ ਕਰੋ"</string>
+    <string name="controls_media_resume" msgid="1933520684481586053">"ਮੁੜ-ਚਾਲੂ ਕਰੋ"</string>
     <string name="controls_error_timeout" msgid="794197289772728958">"ਅਕਿਰਿਆਸ਼ੀਲ, ਐਪ ਦੀ ਜਾਂਚ ਕਰੋ"</string>
     <string name="controls_error_retryable" msgid="864025882878378470">"ਗੜਬੜ, ਮੁੜ ਕੋਸ਼ਿਸ਼ ਹੋ ਰਹੀ ਹੈ…"</string>
-    <string name="controls_error_removed" msgid="6299213591234723805">"ਡੀਵਾਈਸ ਹਟਾਇਆ ਗਿਆ"</string>
+    <string name="controls_error_removed" msgid="6675638069846014366">"ਨਹੀਂ ਮਿਲਿਆ"</string>
+    <string name="controls_error_removed_title" msgid="1207794911208047818">"ਕੰਟਰੋਲ ਉਪਲਬਧ ਨਹੀਂ ਹੈ"</string>
+    <string name="controls_error_removed_message" msgid="2885911717034750542">"<xliff:g id="DEVICE">%1$s</xliff:g> ਤੱਕ ਪਹੁੰਚ ਨਹੀਂ ਕੀਤੀ ਜਾ ਸਕੀ। ਇਹ ਪੱਕਾ ਕਰਨ ਲਈ <xliff:g id="APPLICATION">%2$s</xliff:g> ਐਪ ਦੀ ਜਾਂਚ ਕਰੋ ਕਿ ਕੰਟਰੋਲ ਹਾਲੇ ਉਪਲਬਧ ਹੈ ਅਤੇ ਐਪ ਸੈਟਿੰਗਾਂ ਨਹੀਂ ਬਦਲੀਆਂ ਹਨ।"</string>
+    <string name="controls_open_app" msgid="483650971094300141">"ਐਪ ਖੋਲ੍ਹੋ"</string>
     <string name="controls_error_generic" msgid="352500456918362905">"ਸਥਿਤੀ ਲੋਡ ਨਹੀਂ ਕੀਤੀ ਜਾ ਸਕਦੀ"</string>
     <string name="controls_error_failed" msgid="960228639198558525">"ਗੜਬੜ, ਦੁਬਾਰਾ ਕੋਸ਼ਿਸ਼ ਕਰੋ"</string>
     <string name="controls_in_progress" msgid="4421080500238215939">"ਜਾਰੀ ਹੈ"</string>
diff --git a/packages/SystemUI/res/values-pl/strings.xml b/packages/SystemUI/res/values-pl/strings.xml
index 8b56f8d..cf63b11 100644
--- a/packages/SystemUI/res/values-pl/strings.xml
+++ b/packages/SystemUI/res/values-pl/strings.xml
@@ -168,7 +168,7 @@
     <string name="biometric_dialog_last_password_attempt_before_wipe_profile" msgid="8538032972389729253">"Jeśli następnym razem podasz nieprawidłowe hasło, profil służbowy oraz powiązane z nim dane zostaną usunięte."</string>
     <string name="biometric_dialog_failed_attempts_now_wiping_device" msgid="6585503524026243042">"Zbyt wiele nieudanych prób. Dane na urządzeniu zostaną usunięte."</string>
     <string name="biometric_dialog_failed_attempts_now_wiping_user" msgid="7015008539146949115">"Zbyt wiele nieudanych prób. Użytkownik zostanie usunięty."</string>
-    <string name="biometric_dialog_failed_attempts_now_wiping_profile" msgid="5239378521440749682">"Zbyt wiele nieudanych prób. Profil do pracy i powiązane z nim dane zostaną usunięte."</string>
+    <string name="biometric_dialog_failed_attempts_now_wiping_profile" msgid="5239378521440749682">"Zbyt wiele nieudanych prób. Profil służbowy i powiązane z nim dane zostaną usunięte."</string>
     <string name="biometric_dialog_now_wiping_dialog_dismiss" msgid="7189432882125106154">"Zamknij"</string>
     <string name="fingerprint_dialog_touch_sensor" msgid="2817887108047658975">"Dotknij czytnika linii papilarnych"</string>
     <string name="accessibility_fingerprint_dialog_fingerprint_icon" msgid="4465698996175640549">"Ikona odcisku palca"</string>
@@ -516,7 +516,7 @@
     <string name="clear_all_notifications_text" msgid="348312370303046130">"Usuń wszystkie"</string>
     <string name="manage_notifications_text" msgid="6885645344647733116">"Zarządzaj"</string>
     <string name="manage_notifications_history_text" msgid="57055985396576230">"Historia"</string>
-    <string name="notification_section_header_incoming" msgid="5295312809341711367">"Przychodzące"</string>
+    <string name="notification_section_header_incoming" msgid="850925217908095197">"Nowe"</string>
     <string name="notification_section_header_gentle" msgid="6804099527336337197">"Ciche"</string>
     <string name="notification_section_header_alerting" msgid="5581175033680477651">"Powiadomienia"</string>
     <string name="notification_section_header_conversations" msgid="821834744538345661">"Rozmowy"</string>
@@ -604,7 +604,7 @@
     <string name="screen_pinning_description_gestural" msgid="7246323931831232068">"Ekran będzie widoczny, dopóki go nie odepniesz. Przesuń palcem w górę i przytrzymaj, by odpiąć."</string>
     <string name="screen_pinning_description_accessible" msgid="7386449191953535332">"Ekran będzie widoczny, dopóki go nie odepniesz. Aby to zrobić, kliknij i przytrzymaj Przegląd."</string>
     <string name="screen_pinning_description_recents_invisible_accessible" msgid="2857071808674481986">"Ekran będzie widoczny, dopóki go nie odepniesz. Aby to zrobić, naciśnij i przytrzymaj Ekran główny."</string>
-    <string name="screen_pinning_exposes_personal_data" msgid="8189852022981524789">"Dane osobowe mogą być dostępne (np. kontakty czy treść e-maili)."</string>
+    <string name="screen_pinning_exposes_personal_data" msgid="8189852022981524789">"Dane osobowe (np. kontakty czy treść e-maili) mogą być dostępne."</string>
     <string name="screen_pinning_can_open_other_apps" msgid="7529756813231421455">"Przypięta aplikacja może otwierać inne aplikacje."</string>
     <string name="screen_pinning_toast" msgid="8177286912533744328">"Aby odpiąć tę aplikację, naciśnij i przytrzymaj przyciski Wstecz oraz Przegląd"</string>
     <string name="screen_pinning_toast_recents_invisible" msgid="6850978077443052594">"Aby odpiąć tę aplikację, naciśnij i przytrzymaj przyciski Wstecz oraz Ekran główny"</string>
@@ -1012,7 +1012,7 @@
     <string name="bubble_accessibility_action_move_top_right" msgid="6916868852433483569">"Przenieś w prawy górny róg"</string>
     <string name="bubble_accessibility_action_move_bottom_left" msgid="6339015902495504715">"Przenieś w lewy dolny róg"</string>
     <string name="bubble_accessibility_action_move_bottom_right" msgid="7471571700628346212">"Przenieś w prawy dolny róg"</string>
-    <string name="bubble_dismiss_text" msgid="7071770411580452911">"Zamknij"</string>
+    <string name="bubble_dismiss_text" msgid="1314082410868930066">"Zamknij dymek"</string>
     <string name="bubbles_dont_bubble_conversation" msgid="1033040343437428822">"Nie wyświetlaj rozmowy jako dymku"</string>
     <string name="bubbles_user_education_title" msgid="5547017089271445797">"Czatuj, korzystając z dymków"</string>
     <string name="bubbles_user_education_description" msgid="1160281719576715211">"Nowe rozmowy będą wyświetlane jako pływające ikony lub dymki. Kliknij, by otworzyć dymek. Przeciągnij, by go przenieść."</string>
@@ -1074,9 +1074,13 @@
     <string name="controls_structure_tooltip" msgid="4355922222944447867">"Przesuń palcem, by zobaczyć więcej"</string>
     <string name="controls_seeding_in_progress" msgid="3033855341410264148">"Wczytuję rekomendacje"</string>
     <string name="controls_media_close_session" msgid="9023534788828414585">"Zamknij tę sesję multimediów"</string>
+    <string name="controls_media_resume" msgid="1933520684481586053">"Wznów"</string>
     <string name="controls_error_timeout" msgid="794197289772728958">"Nieaktywny, sprawdź aplikację"</string>
     <string name="controls_error_retryable" msgid="864025882878378470">"Błąd, próbuję jeszcze raz…"</string>
-    <string name="controls_error_removed" msgid="6299213591234723805">"Usunięto urządzenie"</string>
+    <string name="controls_error_removed" msgid="6675638069846014366">"Nie znaleziono"</string>
+    <string name="controls_error_removed_title" msgid="1207794911208047818">"Element jest niedostępny"</string>
+    <string name="controls_error_removed_message" msgid="2885911717034750542">"Nie udało się połączyć z urządzeniem: <xliff:g id="DEVICE">%1$s</xliff:g>. Sprawdź aplikację <xliff:g id="APPLICATION">%2$s</xliff:g>, aby upewnić się, że element sterujący jest wciąż dostępny i ustawienia aplikacji się nie zmieniły."</string>
+    <string name="controls_open_app" msgid="483650971094300141">"Otwórz aplikację"</string>
     <string name="controls_error_generic" msgid="352500456918362905">"Nie udało się wczytać stanu"</string>
     <string name="controls_error_failed" msgid="960228639198558525">"Błąd, spróbuj ponownie"</string>
     <string name="controls_in_progress" msgid="4421080500238215939">"W toku"</string>
diff --git a/packages/SystemUI/res/values-pt-rBR/strings.xml b/packages/SystemUI/res/values-pt-rBR/strings.xml
index 5a2005e..9b3976e 100644
--- a/packages/SystemUI/res/values-pt-rBR/strings.xml
+++ b/packages/SystemUI/res/values-pt-rBR/strings.xml
@@ -510,7 +510,7 @@
     <string name="clear_all_notifications_text" msgid="348312370303046130">"Limpar tudo"</string>
     <string name="manage_notifications_text" msgid="6885645344647733116">"Gerenciar"</string>
     <string name="manage_notifications_history_text" msgid="57055985396576230">"Histórico"</string>
-    <string name="notification_section_header_incoming" msgid="5295312809341711367">"Recebidas"</string>
+    <string name="notification_section_header_incoming" msgid="850925217908095197">"Novas"</string>
     <string name="notification_section_header_gentle" msgid="6804099527336337197">"Silenciosas"</string>
     <string name="notification_section_header_alerting" msgid="5581175033680477651">"Notificações"</string>
     <string name="notification_section_header_conversations" msgid="821834744538345661">"Conversas"</string>
@@ -595,7 +595,7 @@
     <string name="screen_pinning_title" msgid="9058007390337841305">"O app está fixado"</string>
     <string name="screen_pinning_description" msgid="8699395373875667743">"Ela é mantida à vista até que seja liberada. Toque em Voltar e em Visão geral e mantenha essas opções pressionadas para liberar."</string>
     <string name="screen_pinning_description_recents_invisible" msgid="4564466648700390037">"Ela é mantida à vista até que seja liberada. Toque em Voltar e em Início e mantenha essas opções pressionadas para liberar."</string>
-    <string name="screen_pinning_description_gestural" msgid="7246323931831232068">"Ela é mantida à vista até que seja liberada. Deslize para cima e a mantenha pressionada para liberar."</string>
+    <string name="screen_pinning_description_gestural" msgid="7246323931831232068">"Ele é mantido à vista até que seja liberado. Deslize para cima e mantenha pressionado para liberar."</string>
     <string name="screen_pinning_description_accessible" msgid="7386449191953535332">"Ela é mantida à vista até que seja liberada. Toque em Visão geral e mantenha essa opção pressionada para liberar."</string>
     <string name="screen_pinning_description_recents_invisible_accessible" msgid="2857071808674481986">"Ela é mantida à vista até que seja liberada. Toque em Início e mantenha essa opção pressionada para liberar."</string>
     <string name="screen_pinning_exposes_personal_data" msgid="8189852022981524789">"Dados pessoais podem ficar acessíveis (como contatos e conteúdo de e-mail)."</string>
@@ -1002,7 +1002,7 @@
     <string name="bubble_accessibility_action_move_top_right" msgid="6916868852433483569">"Mover para canto superior direito"</string>
     <string name="bubble_accessibility_action_move_bottom_left" msgid="6339015902495504715">"Mover para canto inferior esquerdo"</string>
     <string name="bubble_accessibility_action_move_bottom_right" msgid="7471571700628346212">"Mover para canto inferior direito"</string>
-    <string name="bubble_dismiss_text" msgid="7071770411580452911">"Dispensar"</string>
+    <string name="bubble_dismiss_text" msgid="1314082410868930066">"Dispensar balão"</string>
     <string name="bubbles_dont_bubble_conversation" msgid="1033040343437428822">"Não criar balões de conversa"</string>
     <string name="bubbles_user_education_title" msgid="5547017089271445797">"Converse usando balões"</string>
     <string name="bubbles_user_education_description" msgid="1160281719576715211">"Novas conversas aparecerão como ícones flutuantes, ou balões. Toque para abrir o balão. Arraste para movê-lo."</string>
@@ -1062,9 +1062,13 @@
     <string name="controls_structure_tooltip" msgid="4355922222944447867">"Deslize para ver mais"</string>
     <string name="controls_seeding_in_progress" msgid="3033855341410264148">"Carregando recomendações"</string>
     <string name="controls_media_close_session" msgid="9023534788828414585">"Encerrar esta sessão de mídia"</string>
+    <string name="controls_media_resume" msgid="1933520684481586053">"Retomar"</string>
     <string name="controls_error_timeout" msgid="794197289772728958">"Inativo, verifique o app"</string>
     <string name="controls_error_retryable" msgid="864025882878378470">"Erro. Tentando novamente…"</string>
-    <string name="controls_error_removed" msgid="6299213591234723805">"Dispositivo removido"</string>
+    <string name="controls_error_removed" msgid="6675638069846014366">"Não encontrado"</string>
+    <string name="controls_error_removed_title" msgid="1207794911208047818">"O controle está indisponível"</string>
+    <string name="controls_error_removed_message" msgid="2885911717034750542">"Não foi possível acessar <xliff:g id="DEVICE">%1$s</xliff:g>. Verifique o app <xliff:g id="APPLICATION">%2$s</xliff:g> para garantir que o controle ainda esteja disponível e as configurações não tenham sido modificadas."</string>
+    <string name="controls_open_app" msgid="483650971094300141">"Abrir app"</string>
     <string name="controls_error_generic" msgid="352500456918362905">"Falha ao carregar o status"</string>
     <string name="controls_error_failed" msgid="960228639198558525">"Erro. Tente novamente"</string>
     <string name="controls_in_progress" msgid="4421080500238215939">"Em andamento"</string>
diff --git a/packages/SystemUI/res/values-pt-rPT/strings.xml b/packages/SystemUI/res/values-pt-rPT/strings.xml
index dec586e..55b5af1 100644
--- a/packages/SystemUI/res/values-pt-rPT/strings.xml
+++ b/packages/SystemUI/res/values-pt-rPT/strings.xml
@@ -510,7 +510,7 @@
     <string name="clear_all_notifications_text" msgid="348312370303046130">"Limpar tudo"</string>
     <string name="manage_notifications_text" msgid="6885645344647733116">"Gerir"</string>
     <string name="manage_notifications_history_text" msgid="57055985396576230">"Histórico"</string>
-    <string name="notification_section_header_incoming" msgid="5295312809341711367">"A receber"</string>
+    <string name="notification_section_header_incoming" msgid="850925217908095197">"Nova"</string>
     <string name="notification_section_header_gentle" msgid="6804099527336337197">"Silencioso"</string>
     <string name="notification_section_header_alerting" msgid="5581175033680477651">"Notificações"</string>
     <string name="notification_section_header_conversations" msgid="821834744538345661">"Conversas"</string>
@@ -595,7 +595,7 @@
     <string name="screen_pinning_title" msgid="9058007390337841305">"A app está fixada"</string>
     <string name="screen_pinning_description" msgid="8699395373875667743">"Esta opção mantém o item visível até o soltar. Toque sem soltar em Anterior e em Vista geral para soltar."</string>
     <string name="screen_pinning_description_recents_invisible" msgid="4564466648700390037">"Esta opção mantém o item visível até o soltar. Toque sem soltar em Anterior e em Página inicial para soltar."</string>
-    <string name="screen_pinning_description_gestural" msgid="7246323931831232068">"Esta opção mantém o item visível até o soltar. Deslize rapidamente para cima e mantenha o gesto para soltar."</string>
+    <string name="screen_pinning_description_gestural" msgid="7246323931831232068">"Esta opção mantém o item visível até o soltar. Deslize rapidamente para cima e mantenha pressionado para soltar."</string>
     <string name="screen_pinning_description_accessible" msgid="7386449191953535332">"Esta opção mantém o item visível até o soltar. Toque sem soltar em Vista geral para soltar."</string>
     <string name="screen_pinning_description_recents_invisible_accessible" msgid="2857071808674481986">"Esta opção mantém o item visível até o soltar. Toque sem soltar em Página inicial para soltar."</string>
     <string name="screen_pinning_exposes_personal_data" msgid="8189852022981524789">"Os dados pessoais podem ficar acessíveis (tais como contactos e conteúdo do email)."</string>
@@ -1002,7 +1002,7 @@
     <string name="bubble_accessibility_action_move_top_right" msgid="6916868852433483569">"Mover parte superior direita"</string>
     <string name="bubble_accessibility_action_move_bottom_left" msgid="6339015902495504715">"Mover p/ parte infer. esquerda"</string>
     <string name="bubble_accessibility_action_move_bottom_right" msgid="7471571700628346212">"Mover parte inferior direita"</string>
-    <string name="bubble_dismiss_text" msgid="7071770411580452911">"Ignorar"</string>
+    <string name="bubble_dismiss_text" msgid="1314082410868930066">"Ignorar balão"</string>
     <string name="bubbles_dont_bubble_conversation" msgid="1033040343437428822">"Não apresentar a conversa em balões"</string>
     <string name="bubbles_user_education_title" msgid="5547017089271445797">"Converse no chat através de balões"</string>
     <string name="bubbles_user_education_description" msgid="1160281719576715211">"As novas conversas aparecem como ícones flutuantes ou balões. Toque para abrir o balão. Arraste para o mover."</string>
@@ -1062,9 +1062,13 @@
     <string name="controls_structure_tooltip" msgid="4355922222944447867">"Deslize rapidamente para ver mais."</string>
     <string name="controls_seeding_in_progress" msgid="3033855341410264148">"A carregar recomendações…"</string>
     <string name="controls_media_close_session" msgid="9023534788828414585">"Fechar esta sessão multimédia"</string>
+    <string name="controls_media_resume" msgid="1933520684481586053">"Retomar"</string>
     <string name="controls_error_timeout" msgid="794197289772728958">"Inativa. Consulte a app."</string>
     <string name="controls_error_retryable" msgid="864025882878378470">"Erro. A tentar novamente…"</string>
-    <string name="controls_error_removed" msgid="6299213591234723805">"Dispositivo removido."</string>
+    <string name="controls_error_removed" msgid="6675638069846014366">"Não encontrado."</string>
+    <string name="controls_error_removed_title" msgid="1207794911208047818">"O controlo está indisponível"</string>
+    <string name="controls_error_removed_message" msgid="2885911717034750542">"Não foi possível aceder a <xliff:g id="DEVICE">%1$s</xliff:g>. Verifique a app <xliff:g id="APPLICATION">%2$s</xliff:g> para se certificar de que o controlo ainda está disponível e que as definições da mesma não foram alteradas."</string>
+    <string name="controls_open_app" msgid="483650971094300141">"Abrir app"</string>
     <string name="controls_error_generic" msgid="352500456918362905">"Impossível carregar o estado."</string>
     <string name="controls_error_failed" msgid="960228639198558525">"Erro. Tente novamente."</string>
     <string name="controls_in_progress" msgid="4421080500238215939">"Em curso"</string>
diff --git a/packages/SystemUI/res/values-pt/strings.xml b/packages/SystemUI/res/values-pt/strings.xml
index 5a2005e..9b3976e 100644
--- a/packages/SystemUI/res/values-pt/strings.xml
+++ b/packages/SystemUI/res/values-pt/strings.xml
@@ -510,7 +510,7 @@
     <string name="clear_all_notifications_text" msgid="348312370303046130">"Limpar tudo"</string>
     <string name="manage_notifications_text" msgid="6885645344647733116">"Gerenciar"</string>
     <string name="manage_notifications_history_text" msgid="57055985396576230">"Histórico"</string>
-    <string name="notification_section_header_incoming" msgid="5295312809341711367">"Recebidas"</string>
+    <string name="notification_section_header_incoming" msgid="850925217908095197">"Novas"</string>
     <string name="notification_section_header_gentle" msgid="6804099527336337197">"Silenciosas"</string>
     <string name="notification_section_header_alerting" msgid="5581175033680477651">"Notificações"</string>
     <string name="notification_section_header_conversations" msgid="821834744538345661">"Conversas"</string>
@@ -595,7 +595,7 @@
     <string name="screen_pinning_title" msgid="9058007390337841305">"O app está fixado"</string>
     <string name="screen_pinning_description" msgid="8699395373875667743">"Ela é mantida à vista até que seja liberada. Toque em Voltar e em Visão geral e mantenha essas opções pressionadas para liberar."</string>
     <string name="screen_pinning_description_recents_invisible" msgid="4564466648700390037">"Ela é mantida à vista até que seja liberada. Toque em Voltar e em Início e mantenha essas opções pressionadas para liberar."</string>
-    <string name="screen_pinning_description_gestural" msgid="7246323931831232068">"Ela é mantida à vista até que seja liberada. Deslize para cima e a mantenha pressionada para liberar."</string>
+    <string name="screen_pinning_description_gestural" msgid="7246323931831232068">"Ele é mantido à vista até que seja liberado. Deslize para cima e mantenha pressionado para liberar."</string>
     <string name="screen_pinning_description_accessible" msgid="7386449191953535332">"Ela é mantida à vista até que seja liberada. Toque em Visão geral e mantenha essa opção pressionada para liberar."</string>
     <string name="screen_pinning_description_recents_invisible_accessible" msgid="2857071808674481986">"Ela é mantida à vista até que seja liberada. Toque em Início e mantenha essa opção pressionada para liberar."</string>
     <string name="screen_pinning_exposes_personal_data" msgid="8189852022981524789">"Dados pessoais podem ficar acessíveis (como contatos e conteúdo de e-mail)."</string>
@@ -1002,7 +1002,7 @@
     <string name="bubble_accessibility_action_move_top_right" msgid="6916868852433483569">"Mover para canto superior direito"</string>
     <string name="bubble_accessibility_action_move_bottom_left" msgid="6339015902495504715">"Mover para canto inferior esquerdo"</string>
     <string name="bubble_accessibility_action_move_bottom_right" msgid="7471571700628346212">"Mover para canto inferior direito"</string>
-    <string name="bubble_dismiss_text" msgid="7071770411580452911">"Dispensar"</string>
+    <string name="bubble_dismiss_text" msgid="1314082410868930066">"Dispensar balão"</string>
     <string name="bubbles_dont_bubble_conversation" msgid="1033040343437428822">"Não criar balões de conversa"</string>
     <string name="bubbles_user_education_title" msgid="5547017089271445797">"Converse usando balões"</string>
     <string name="bubbles_user_education_description" msgid="1160281719576715211">"Novas conversas aparecerão como ícones flutuantes, ou balões. Toque para abrir o balão. Arraste para movê-lo."</string>
@@ -1062,9 +1062,13 @@
     <string name="controls_structure_tooltip" msgid="4355922222944447867">"Deslize para ver mais"</string>
     <string name="controls_seeding_in_progress" msgid="3033855341410264148">"Carregando recomendações"</string>
     <string name="controls_media_close_session" msgid="9023534788828414585">"Encerrar esta sessão de mídia"</string>
+    <string name="controls_media_resume" msgid="1933520684481586053">"Retomar"</string>
     <string name="controls_error_timeout" msgid="794197289772728958">"Inativo, verifique o app"</string>
     <string name="controls_error_retryable" msgid="864025882878378470">"Erro. Tentando novamente…"</string>
-    <string name="controls_error_removed" msgid="6299213591234723805">"Dispositivo removido"</string>
+    <string name="controls_error_removed" msgid="6675638069846014366">"Não encontrado"</string>
+    <string name="controls_error_removed_title" msgid="1207794911208047818">"O controle está indisponível"</string>
+    <string name="controls_error_removed_message" msgid="2885911717034750542">"Não foi possível acessar <xliff:g id="DEVICE">%1$s</xliff:g>. Verifique o app <xliff:g id="APPLICATION">%2$s</xliff:g> para garantir que o controle ainda esteja disponível e as configurações não tenham sido modificadas."</string>
+    <string name="controls_open_app" msgid="483650971094300141">"Abrir app"</string>
     <string name="controls_error_generic" msgid="352500456918362905">"Falha ao carregar o status"</string>
     <string name="controls_error_failed" msgid="960228639198558525">"Erro. Tente novamente"</string>
     <string name="controls_in_progress" msgid="4421080500238215939">"Em andamento"</string>
diff --git a/packages/SystemUI/res/values-ro/strings.xml b/packages/SystemUI/res/values-ro/strings.xml
index ee844d0..0f0f598 100644
--- a/packages/SystemUI/res/values-ro/strings.xml
+++ b/packages/SystemUI/res/values-ro/strings.xml
@@ -513,7 +513,7 @@
     <string name="clear_all_notifications_text" msgid="348312370303046130">"Ștergeți toate notificările"</string>
     <string name="manage_notifications_text" msgid="6885645344647733116">"Gestionați"</string>
     <string name="manage_notifications_history_text" msgid="57055985396576230">"Istoric"</string>
-    <string name="notification_section_header_incoming" msgid="5295312809341711367">"Primite"</string>
+    <string name="notification_section_header_incoming" msgid="850925217908095197">"Noi"</string>
     <string name="notification_section_header_gentle" msgid="6804099527336337197">"Silențioase"</string>
     <string name="notification_section_header_alerting" msgid="5581175033680477651">"Notificări"</string>
     <string name="notification_section_header_conversations" msgid="821834744538345661">"Conversații"</string>
@@ -598,7 +598,7 @@
     <string name="screen_pinning_title" msgid="9058007390337841305">"Aplicația este fixată"</string>
     <string name="screen_pinning_description" msgid="8699395373875667743">"Astfel rămâne afișat până anulați fixarea. Atingeți lung opțiunile Înapoi și Recente pentru a anula fixarea."</string>
     <string name="screen_pinning_description_recents_invisible" msgid="4564466648700390037">"Astfel rămâne afișat până anulați fixarea. Atingeți lung opțiunile Înapoi și Acasă pentru a anula fixarea."</string>
-    <string name="screen_pinning_description_gestural" msgid="7246323931831232068">"Astfel rămâne afișat până anulați fixarea. Glisați în sus și țineți apăsat pentru a anula fixarea."</string>
+    <string name="screen_pinning_description_gestural" msgid="7246323931831232068">"Astfel rămâne afișată până anulați fixarea. Glisați în sus și țineți apăsat pentru a anula fixarea."</string>
     <string name="screen_pinning_description_accessible" msgid="7386449191953535332">"Astfel rămâne afișat până anulați fixarea. Atingeți lung opțiunea Recente pentru a anula fixarea."</string>
     <string name="screen_pinning_description_recents_invisible_accessible" msgid="2857071808674481986">"Astfel rămâne afișat până anulați fixarea. Atingeți lung opțiunea Acasă pentru a anula fixarea."</string>
     <string name="screen_pinning_exposes_personal_data" msgid="8189852022981524789">"Pot fi accesate date cu caracter personal (cum ar fi agenda și conținutul e-mailurilor)."</string>
@@ -1007,9 +1007,9 @@
     <string name="bubble_accessibility_action_move_top_right" msgid="6916868852433483569">"Mutați în dreapta sus"</string>
     <string name="bubble_accessibility_action_move_bottom_left" msgid="6339015902495504715">"Mutați în stânga jos"</string>
     <string name="bubble_accessibility_action_move_bottom_right" msgid="7471571700628346212">"Mutați în dreapta jos"</string>
-    <string name="bubble_dismiss_text" msgid="7071770411580452911">"Închideți"</string>
+    <string name="bubble_dismiss_text" msgid="1314082410868930066">"Închideți balonul"</string>
     <string name="bubbles_dont_bubble_conversation" msgid="1033040343437428822">"Nu afișați conversația în balon"</string>
-    <string name="bubbles_user_education_title" msgid="5547017089271445797">"Discutați pe chat folosind baloanele"</string>
+    <string name="bubbles_user_education_title" msgid="5547017089271445797">"Chat cu baloane"</string>
     <string name="bubbles_user_education_description" msgid="1160281719576715211">"Conversațiile noi apar ca pictograme flotante sau baloane. Atingeți pentru a deschide balonul. Trageți pentru a-l muta."</string>
     <string name="bubbles_user_education_manage_title" msgid="2848511858160342320">"Controlați oricând baloanele"</string>
     <string name="bubbles_user_education_manage" msgid="1391639189507036423">"Atingeți Gestionați pentru a dezactiva baloanele din această aplicație"</string>
@@ -1068,9 +1068,13 @@
     <string name="controls_structure_tooltip" msgid="4355922222944447867">"Glisați pentru a vedea mai multe"</string>
     <string name="controls_seeding_in_progress" msgid="3033855341410264148">"Se încarcă recomandările"</string>
     <string name="controls_media_close_session" msgid="9023534788828414585">"Închideți această sesiune media"</string>
+    <string name="controls_media_resume" msgid="1933520684481586053">"Reia"</string>
     <string name="controls_error_timeout" msgid="794197289772728958">"Inactiv, verificați aplicația"</string>
     <string name="controls_error_retryable" msgid="864025882878378470">"Eroare, se încearcă din nou…"</string>
-    <string name="controls_error_removed" msgid="6299213591234723805">"Dispozitivul a fost eliminat"</string>
+    <string name="controls_error_removed" msgid="6675638069846014366">"Nu s-a găsit"</string>
+    <string name="controls_error_removed_title" msgid="1207794911208047818">"Comanda este indisponibilă"</string>
+    <string name="controls_error_removed_message" msgid="2885911717034750542">"Nu s-a putut accesa <xliff:g id="DEVICE">%1$s</xliff:g>. Accesați aplicația <xliff:g id="APPLICATION">%2$s</xliff:g> pentru a vă asigura de disponibilitatea comenzii și că setările aplicației nu s-au schimbat."</string>
+    <string name="controls_open_app" msgid="483650971094300141">"Deschideți aplicația"</string>
     <string name="controls_error_generic" msgid="352500456918362905">"Starea nu se poate încărca"</string>
     <string name="controls_error_failed" msgid="960228639198558525">"Eroare, încercați din nou"</string>
     <string name="controls_in_progress" msgid="4421080500238215939">"În curs"</string>
diff --git a/packages/SystemUI/res/values-ru/strings.xml b/packages/SystemUI/res/values-ru/strings.xml
index 902d948..d2bda6e 100644
--- a/packages/SystemUI/res/values-ru/strings.xml
+++ b/packages/SystemUI/res/values-ru/strings.xml
@@ -516,7 +516,7 @@
     <string name="clear_all_notifications_text" msgid="348312370303046130">"Очистить все"</string>
     <string name="manage_notifications_text" msgid="6885645344647733116">"Настроить"</string>
     <string name="manage_notifications_history_text" msgid="57055985396576230">"История"</string>
-    <string name="notification_section_header_incoming" msgid="5295312809341711367">"Входящие"</string>
+    <string name="notification_section_header_incoming" msgid="850925217908095197">"Новое"</string>
     <string name="notification_section_header_gentle" msgid="6804099527336337197">"Без звука"</string>
     <string name="notification_section_header_alerting" msgid="5581175033680477651">"Уведомления"</string>
     <string name="notification_section_header_conversations" msgid="821834744538345661">"Разговоры"</string>
@@ -601,7 +601,7 @@
     <string name="screen_pinning_title" msgid="9058007390337841305">"Приложение закреплено"</string>
     <string name="screen_pinning_description" msgid="8699395373875667743">"Приложение останется активным, пока вы не отмените блокировку, нажав и удерживая кнопки \"Назад\" и \"Обзор\"."</string>
     <string name="screen_pinning_description_recents_invisible" msgid="4564466648700390037">"Приложение останется активным, пока вы не отмените блокировку, нажав и удерживая кнопки \"Назад\" и \"Главный экран\"."</string>
-    <string name="screen_pinning_description_gestural" msgid="7246323931831232068">"Экран будет зафиксирован, пока вы не отмените блокировку (для этого нужно провести вверх и удерживать)."</string>
+    <string name="screen_pinning_description_gestural" msgid="7246323931831232068">"Оно будет показываться на экране, пока вы его не открепите (для этого нужно провести вверх и удерживать)."</string>
     <string name="screen_pinning_description_accessible" msgid="7386449191953535332">"Приложение останется активным, пока вы не отмените блокировку, нажав и удерживая кнопку \"Обзор\"."</string>
     <string name="screen_pinning_description_recents_invisible_accessible" msgid="2857071808674481986">"Приложение останется активным, пока вы не отмените блокировку, нажав и удерживая кнопку \"Главный экран\"."</string>
     <string name="screen_pinning_exposes_personal_data" msgid="8189852022981524789">"Может быть получен доступ к персональным данным (например, контактам и содержимому электронных писем)."</string>
@@ -727,7 +727,7 @@
     <string name="notification_priority_title" msgid="2079708866333537093">"Приоритет"</string>
     <string name="no_shortcut" msgid="8257177117568230126">"Приложение \"<xliff:g id="APP_NAME">%1$s</xliff:g>\" не поддерживает функции разговоров."</string>
     <string name="bubble_overflow_empty_title" msgid="3120029421991510842">"Нет недавних всплывающих чатов"</string>
-    <string name="bubble_overflow_empty_subtitle" msgid="2030874469510497397">"Здесь будут появляться недавние и закрытые всплывающие чаты."</string>
+    <string name="bubble_overflow_empty_subtitle" msgid="2030874469510497397">"Здесь будут появляться недавние и скрытые всплывающие чаты."</string>
     <string name="notification_unblockable_desc" msgid="2073030886006190804">"Эти уведомления нельзя изменить."</string>
     <string name="notification_multichannel_desc" msgid="7414593090056236179">"Эту группу уведомлений нельзя настроить здесь."</string>
     <string name="notification_delegate_header" msgid="1264510071031479920">"Уведомление отправлено через прокси-сервер."</string>
@@ -1012,9 +1012,9 @@
     <string name="bubble_accessibility_action_move_top_right" msgid="6916868852433483569">"Перенести в правый верхний угол"</string>
     <string name="bubble_accessibility_action_move_bottom_left" msgid="6339015902495504715">"Перенести в левый нижний угол"</string>
     <string name="bubble_accessibility_action_move_bottom_right" msgid="7471571700628346212">"Перенести в правый нижний угол"</string>
-    <string name="bubble_dismiss_text" msgid="7071770411580452911">"Закрыть"</string>
+    <string name="bubble_dismiss_text" msgid="1314082410868930066">"Закрыть всплывающий чат"</string>
     <string name="bubbles_dont_bubble_conversation" msgid="1033040343437428822">"Не показывать всплывающие чаты для разговоров"</string>
-    <string name="bubbles_user_education_title" msgid="5547017089271445797">"Всплывающие чаты для разговоров"</string>
+    <string name="bubbles_user_education_title" msgid="5547017089271445797">"Всплывающие чаты"</string>
     <string name="bubbles_user_education_description" msgid="1160281719576715211">"Новые разговоры будут появляться в виде плавающих значков, или всплывающих чатов. Чтобы открыть чат, нажмите на него, а чтобы переместить – перетащите."</string>
     <string name="bubbles_user_education_manage_title" msgid="2848511858160342320">"Настройки всплывающих чатов"</string>
     <string name="bubbles_user_education_manage" msgid="1391639189507036423">"Чтобы отключить всплывающие чаты от приложения, нажмите \"Настроить\"."</string>
@@ -1074,9 +1074,13 @@
     <string name="controls_structure_tooltip" msgid="4355922222944447867">"Проведите по экрану, чтобы увидеть больше"</string>
     <string name="controls_seeding_in_progress" msgid="3033855341410264148">"Загрузка рекомендаций…"</string>
     <string name="controls_media_close_session" msgid="9023534788828414585">"Закрыть этот мультимедийный сеанс"</string>
+    <string name="controls_media_resume" msgid="1933520684481586053">"Возобновить"</string>
     <string name="controls_error_timeout" msgid="794197289772728958">"Нет ответа. Проверьте приложение."</string>
     <string name="controls_error_retryable" msgid="864025882878378470">"Ошибка. Повторная попытка…"</string>
-    <string name="controls_error_removed" msgid="6299213591234723805">"Устройство удалено."</string>
+    <string name="controls_error_removed" msgid="6675638069846014366">"Не найдено."</string>
+    <string name="controls_error_removed_title" msgid="1207794911208047818">"Управление недоступно"</string>
+    <string name="controls_error_removed_message" msgid="2885911717034750542">"Нет доступа к устройству (<xliff:g id="DEVICE">%1$s</xliff:g>). Проверьте, доступно ли управление в приложении \"<xliff:g id="APPLICATION">%2$s</xliff:g>\" и не изменились ли настройки этого приложения."</string>
+    <string name="controls_open_app" msgid="483650971094300141">"Открыть приложение"</string>
     <string name="controls_error_generic" msgid="352500456918362905">"Не удалось загрузить статус."</string>
     <string name="controls_error_failed" msgid="960228639198558525">"Ошибка. Повторите попытку."</string>
     <string name="controls_in_progress" msgid="4421080500238215939">"Выполняется"</string>
diff --git a/packages/SystemUI/res/values-si/strings.xml b/packages/SystemUI/res/values-si/strings.xml
index c49843c..b9b95ac 100644
--- a/packages/SystemUI/res/values-si/strings.xml
+++ b/packages/SystemUI/res/values-si/strings.xml
@@ -510,7 +510,7 @@
     <string name="clear_all_notifications_text" msgid="348312370303046130">"සියල්ල හිස් කරන්න"</string>
     <string name="manage_notifications_text" msgid="6885645344647733116">"කළමනාකරණය කරන්න"</string>
     <string name="manage_notifications_history_text" msgid="57055985396576230">"ඉතිහාසය"</string>
-    <string name="notification_section_header_incoming" msgid="5295312809341711367">"එන"</string>
+    <string name="notification_section_header_incoming" msgid="850925217908095197">"නව"</string>
     <string name="notification_section_header_gentle" msgid="6804099527336337197">"නිහඬ"</string>
     <string name="notification_section_header_alerting" msgid="5581175033680477651">"දැනුම් දීම්"</string>
     <string name="notification_section_header_conversations" msgid="821834744538345661">"සංවාද"</string>
@@ -1002,7 +1002,7 @@
     <string name="bubble_accessibility_action_move_top_right" msgid="6916868852433483569">"ඉහළ දකුණට ගෙන යන්න"</string>
     <string name="bubble_accessibility_action_move_bottom_left" msgid="6339015902495504715">"පහළ වමට ගෙන යන්න"</string>
     <string name="bubble_accessibility_action_move_bottom_right" msgid="7471571700628346212">"පහළ දකුණට ගෙන යන්න"</string>
-    <string name="bubble_dismiss_text" msgid="7071770411580452911">"ඉවතලන්න"</string>
+    <string name="bubble_dismiss_text" msgid="1314082410868930066">"බුබුලු ඉවත ලන්න"</string>
     <string name="bubbles_dont_bubble_conversation" msgid="1033040343437428822">"සංවාදය බුබුලු නොදමන්න"</string>
     <string name="bubbles_user_education_title" msgid="5547017089271445797">"බුබුලු භාවිතයෙන් කතාබහ කරන්න"</string>
     <string name="bubbles_user_education_description" msgid="1160281719576715211">"නව සංවාද පාවෙන අයිකන හෝ බුබුලු ලෙස දිස් වේ. බුබුල විවෘත කිරීමට තට්ටු කරන්න. එය ගෙන යාමට අදින්න."</string>
@@ -1062,9 +1062,13 @@
     <string name="controls_structure_tooltip" msgid="4355922222944447867">"තව බැලීමට ස්වයිප් කරන්න"</string>
     <string name="controls_seeding_in_progress" msgid="3033855341410264148">"නිර්දේශ පූරණය කරමින්"</string>
     <string name="controls_media_close_session" msgid="9023534788828414585">"මෙම මාධ්‍ය සැසිය වසන්න"</string>
+    <string name="controls_media_resume" msgid="1933520684481586053">"නැවත පටන් ගන්න"</string>
     <string name="controls_error_timeout" msgid="794197289772728958">"අක්‍රියයි, යෙදුම පරීක්ෂා කරන්න"</string>
     <string name="controls_error_retryable" msgid="864025882878378470">"දෝෂයකි, නැවත උත්සාහ කරමින්…"</string>
-    <string name="controls_error_removed" msgid="6299213591234723805">"උපාංගය ඉවත් කර ඇත"</string>
+    <string name="controls_error_removed" msgid="6675638069846014366">"හමු නොවිණි"</string>
+    <string name="controls_error_removed_title" msgid="1207794911208047818">"පාලනය ලබා ගත නොහැකිය"</string>
+    <string name="controls_error_removed_message" msgid="2885911717034750542">"<xliff:g id="DEVICE">%1$s</xliff:g> වෙත ප්‍රවේශ විය නොහැකි විය. පාලනය තිබෙන බව සහ යෙදුම් සැකසීම් වෙනස් වී ඇති බව සහතික කර ගැනීමට <xliff:g id="APPLICATION">%2$s</xliff:g> යෙදුම පරීක්ෂා කරන්න."</string>
+    <string name="controls_open_app" msgid="483650971094300141">"යෙදුම විවෘත කරන්න"</string>
     <string name="controls_error_generic" msgid="352500456918362905">"තත්ත්වය පූරණය කළ නොහැකිය"</string>
     <string name="controls_error_failed" msgid="960228639198558525">"දෝෂයකි, නැවත උත්සාහ කරන්න"</string>
     <string name="controls_in_progress" msgid="4421080500238215939">"ප්‍රගතියේ පවතී"</string>
diff --git a/packages/SystemUI/res/values-sk/strings.xml b/packages/SystemUI/res/values-sk/strings.xml
index 920fdd1..c776f2e 100644
--- a/packages/SystemUI/res/values-sk/strings.xml
+++ b/packages/SystemUI/res/values-sk/strings.xml
@@ -516,7 +516,7 @@
     <string name="clear_all_notifications_text" msgid="348312370303046130">"Vymazať všetko"</string>
     <string name="manage_notifications_text" msgid="6885645344647733116">"Spravovať"</string>
     <string name="manage_notifications_history_text" msgid="57055985396576230">"História"</string>
-    <string name="notification_section_header_incoming" msgid="5295312809341711367">"Prichádzajúce"</string>
+    <string name="notification_section_header_incoming" msgid="850925217908095197">"Nové"</string>
     <string name="notification_section_header_gentle" msgid="6804099527336337197">"Ticho"</string>
     <string name="notification_section_header_alerting" msgid="5581175033680477651">"Upozornenia"</string>
     <string name="notification_section_header_conversations" msgid="821834744538345661">"Konverzácie"</string>
@@ -601,10 +601,10 @@
     <string name="screen_pinning_title" msgid="9058007390337841305">"Aplikácia je pripnutá"</string>
     <string name="screen_pinning_description" msgid="8699395373875667743">"Obsah bude pripnutý v zobrazení, dokým ho neuvoľníte. Uvoľníte ho stlačením a podržaním tlačidiel Späť a Prehľad."</string>
     <string name="screen_pinning_description_recents_invisible" msgid="4564466648700390037">"Obsah bude pripnutý v zobrazení, dokým ho neuvoľníte. Uvoľníte ho pridržaním tlačidiel Späť a Domov."</string>
-    <string name="screen_pinning_description_gestural" msgid="7246323931831232068">"Táto možnosť ponechá položku v zobrazení, dokým ju neodopnete. Odpojíte potiahnutím a pridržaním."</string>
+    <string name="screen_pinning_description_gestural" msgid="7246323931831232068">"Táto možnosť ponechá položku v zobrazení, dokým ju neodopnete. Odpojíte ju potiahnutím nahor a pridržaním."</string>
     <string name="screen_pinning_description_accessible" msgid="7386449191953535332">"Obsah bude pripnutý v zobrazení, dokým ho neuvoľníte. Uvoľníte ho stlačením a podržaním tlačidla Prehľad."</string>
     <string name="screen_pinning_description_recents_invisible_accessible" msgid="2857071808674481986">"Obsah bude pripnutý v zobrazení, dokým ho neuvoľníte. Uvoľníte ho pridržaním tlačidla Domov."</string>
-    <string name="screen_pinning_exposes_personal_data" msgid="8189852022981524789">"Môžu byť prístupné osobné údaje (napríklad kontakty a obsah správ)."</string>
+    <string name="screen_pinning_exposes_personal_data" msgid="8189852022981524789">"Môže mať prístup k osobným údajom (napríklad kontaktom a obsahu správ)."</string>
     <string name="screen_pinning_can_open_other_apps" msgid="7529756813231421455">"Pripnutá aplikácia môže otvoriť iné aplikácie."</string>
     <string name="screen_pinning_toast" msgid="8177286912533744328">"Túto aplikáciu odopnete pridržaním tlačidiel Späť a Prehľad"</string>
     <string name="screen_pinning_toast_recents_invisible" msgid="6850978077443052594">"Túto aplikáciu odopnete pridržaním tlačidiel Späť a Domov"</string>
@@ -1012,7 +1012,7 @@
     <string name="bubble_accessibility_action_move_top_right" msgid="6916868852433483569">"Presunúť doprava nahor"</string>
     <string name="bubble_accessibility_action_move_bottom_left" msgid="6339015902495504715">"Presunúť doľava nadol"</string>
     <string name="bubble_accessibility_action_move_bottom_right" msgid="7471571700628346212">"Presunúť doprava nadol"</string>
-    <string name="bubble_dismiss_text" msgid="7071770411580452911">"Zavrieť"</string>
+    <string name="bubble_dismiss_text" msgid="1314082410868930066">"Zavrieť bublinu"</string>
     <string name="bubbles_dont_bubble_conversation" msgid="1033040343437428822">"Nezobrazovať konverzáciu ako bublinu"</string>
     <string name="bubbles_user_education_title" msgid="5547017089271445797">"Čet pomocou bublín"</string>
     <string name="bubbles_user_education_description" msgid="1160281719576715211">"Nové konverzácie sa zobrazujú ako plávajúce ikony či bubliny. Bublinu otvoríte klepnutím. Premiestnite ju presunutím."</string>
@@ -1074,9 +1074,13 @@
     <string name="controls_structure_tooltip" msgid="4355922222944447867">"Potiahnutím zobrazíte ďalšie položky"</string>
     <string name="controls_seeding_in_progress" msgid="3033855341410264148">"Načítavajú sa odporúčania"</string>
     <string name="controls_media_close_session" msgid="9023534788828414585">"Zavrieť túto reláciu média"</string>
+    <string name="controls_media_resume" msgid="1933520684481586053">"Pokračovať"</string>
     <string name="controls_error_timeout" msgid="794197289772728958">"Neaktívne, preverte aplikáciu"</string>
     <string name="controls_error_retryable" msgid="864025882878378470">"Chyba, skúša sa znova…"</string>
-    <string name="controls_error_removed" msgid="6299213591234723805">"Zariadenie je odstránené"</string>
+    <string name="controls_error_removed" msgid="6675638069846014366">"Nenájdené"</string>
+    <string name="controls_error_removed_title" msgid="1207794911208047818">"Ovládanie nie je k dispozícii"</string>
+    <string name="controls_error_removed_message" msgid="2885911717034750542">"Nepodarilo sa získať prístup k zariadeniu <xliff:g id="DEVICE">%1$s</xliff:g>. V aplikácii <xliff:g id="APPLICATION">%2$s</xliff:g> skontrolujte, či je ovládanie stále k dispozícii a či sa nezmenili nastavenia."</string>
+    <string name="controls_open_app" msgid="483650971094300141">"Otvoriť aplikáciu"</string>
     <string name="controls_error_generic" msgid="352500456918362905">"Stav sa nepodarilo načítať"</string>
     <string name="controls_error_failed" msgid="960228639198558525">"Chyba, skúste to znova"</string>
     <string name="controls_in_progress" msgid="4421080500238215939">"Prebieha"</string>
diff --git a/packages/SystemUI/res/values-sl/strings.xml b/packages/SystemUI/res/values-sl/strings.xml
index 0b6d3a7..326ae97 100644
--- a/packages/SystemUI/res/values-sl/strings.xml
+++ b/packages/SystemUI/res/values-sl/strings.xml
@@ -516,7 +516,7 @@
     <string name="clear_all_notifications_text" msgid="348312370303046130">"Izbriši vse"</string>
     <string name="manage_notifications_text" msgid="6885645344647733116">"Upravljanje"</string>
     <string name="manage_notifications_history_text" msgid="57055985396576230">"Zgodovina"</string>
-    <string name="notification_section_header_incoming" msgid="5295312809341711367">"Dohodno"</string>
+    <string name="notification_section_header_incoming" msgid="850925217908095197">"Novo"</string>
     <string name="notification_section_header_gentle" msgid="6804099527336337197">"Tiho"</string>
     <string name="notification_section_header_alerting" msgid="5581175033680477651">"Obvestila"</string>
     <string name="notification_section_header_conversations" msgid="821834744538345661">"Pogovori"</string>
@@ -599,11 +599,11 @@
     <string name="volume_odi_captions_hint_disable" msgid="2518846326748183407">"onemogoči"</string>
     <string name="accessibility_output_chooser" msgid="7807898688967194183">"Izbira druge izhodne naprave"</string>
     <string name="screen_pinning_title" msgid="9058007390337841305">"Aplikacija je pripeta"</string>
-    <string name="screen_pinning_description" msgid="8699395373875667743">"S tem ostane zaslon viden, dokler ga ne odpnete. Če ga želite odpeti, hkrati pridržite gumba za nazaj in pregled."</string>
-    <string name="screen_pinning_description_recents_invisible" msgid="4564466648700390037">"S tem ostane zaslon viden, dokler ga ne odpnete. Če ga želite odpeti, hkrati pridržite gumba za nazaj in za začetni zaslon."</string>
-    <string name="screen_pinning_description_gestural" msgid="7246323931831232068">"S tem ostane zaslon viden, dokler ga ne odpnete. Če ga želite odpeti, povlecite navzgor in pridržite."</string>
-    <string name="screen_pinning_description_accessible" msgid="7386449191953535332">"S tem ostane zaslon viden, dokler ga ne odpnete. Če ga želite odpeti, pridržite gumb za pregled."</string>
-    <string name="screen_pinning_description_recents_invisible_accessible" msgid="2857071808674481986">"S tem ostane zaslon viden, dokler ga ne odpnete. Če ga želite odpeti, pridržite gumb za začetni zaslon."</string>
+    <string name="screen_pinning_description" msgid="8699395373875667743">"S tem ostane vidna, dokler je ne odpnete. Če jo želite odpeti, hkrati pridržite gumba za nazaj in pregled."</string>
+    <string name="screen_pinning_description_recents_invisible" msgid="4564466648700390037">"S tem ostane vidna, dokler je ne odpnete. Če jo želite odpeti, hkrati pridržite gumba za nazaj in za začetni zaslon."</string>
+    <string name="screen_pinning_description_gestural" msgid="7246323931831232068">"S tem ostane vidna, dokler je ne odpnete. Če jo želite odpeti, povlecite navzgor in pridržite."</string>
+    <string name="screen_pinning_description_accessible" msgid="7386449191953535332">"S tem ostane vidna, dokler je ne odpnete. Če jo želite odpeti, pridržite gumb za pregled."</string>
+    <string name="screen_pinning_description_recents_invisible_accessible" msgid="2857071808674481986">"S tem ostane vidna, dokler je ne odpnete. Če jo želite odpeti, pridržite gumb za začetni zaslon."</string>
     <string name="screen_pinning_exposes_personal_data" msgid="8189852022981524789">"Dostopni so lahko osebni podatki (na primer stiki in vsebina e-poštnih sporočil)."</string>
     <string name="screen_pinning_can_open_other_apps" msgid="7529756813231421455">"Pripeta aplikacija lahko odpre druge aplikacije."</string>
     <string name="screen_pinning_toast" msgid="8177286912533744328">"Če želite odpeti to aplikacijo, hkrati pridržite gumba za nazaj in za pregled."</string>
@@ -1012,7 +1012,7 @@
     <string name="bubble_accessibility_action_move_top_right" msgid="6916868852433483569">"Premakni zgoraj desno"</string>
     <string name="bubble_accessibility_action_move_bottom_left" msgid="6339015902495504715">"Premakni spodaj levo"</string>
     <string name="bubble_accessibility_action_move_bottom_right" msgid="7471571700628346212">"Premakni spodaj desno"</string>
-    <string name="bubble_dismiss_text" msgid="7071770411580452911">"Opusti"</string>
+    <string name="bubble_dismiss_text" msgid="1314082410868930066">"Opusti oblaček"</string>
     <string name="bubbles_dont_bubble_conversation" msgid="1033040343437428822">"Pogovora ne prikaži v oblačku"</string>
     <string name="bubbles_user_education_title" msgid="5547017089271445797">"Klepet z oblački"</string>
     <string name="bubbles_user_education_description" msgid="1160281719576715211">"Novi pogovori so prikazani kot lebdeče ikone ali oblački. Če želite odpreti oblaček, se ga dotaknite. Če ga želite premakniti, ga povlecite."</string>
@@ -1074,9 +1074,13 @@
     <string name="controls_structure_tooltip" msgid="4355922222944447867">"Če si želite ogledati več, povlecite"</string>
     <string name="controls_seeding_in_progress" msgid="3033855341410264148">"Nalaganje priporočil"</string>
     <string name="controls_media_close_session" msgid="9023534788828414585">"Zapri to sejo predstavnosti"</string>
+    <string name="controls_media_resume" msgid="1933520684481586053">"Nadaljuj"</string>
     <string name="controls_error_timeout" msgid="794197289772728958">"Neaktivno, poglejte aplikacijo"</string>
     <string name="controls_error_retryable" msgid="864025882878378470">"Napaka, vnovični poskus …"</string>
-    <string name="controls_error_removed" msgid="6299213591234723805">"Naprava je bila odstranjena"</string>
+    <string name="controls_error_removed" msgid="6675638069846014366">"Ni mogoče najti"</string>
+    <string name="controls_error_removed_title" msgid="1207794911208047818">"Kontrolnik ni na voljo"</string>
+    <string name="controls_error_removed_message" msgid="2885911717034750542">"Ni bilo mogoče dostopiti do: <xliff:g id="DEVICE">%1$s</xliff:g>. Preverite aplikacijo <xliff:g id="APPLICATION">%2$s</xliff:g> in se prepričajte, da je kontrolnik še vedno na voljo ter da se nastavitve aplikacije niso spremenile."</string>
+    <string name="controls_open_app" msgid="483650971094300141">"Odpri aplikacijo"</string>
     <string name="controls_error_generic" msgid="352500456918362905">"Stanja ni mogoče naložiti"</string>
     <string name="controls_error_failed" msgid="960228639198558525">"Napaka, poskusite znova"</string>
     <string name="controls_in_progress" msgid="4421080500238215939">"V teku"</string>
diff --git a/packages/SystemUI/res/values-sq/strings.xml b/packages/SystemUI/res/values-sq/strings.xml
index a514750..d0d16c3 100644
--- a/packages/SystemUI/res/values-sq/strings.xml
+++ b/packages/SystemUI/res/values-sq/strings.xml
@@ -35,7 +35,7 @@
     <string name="battery_low_why" msgid="2056750982959359863">"Cilësimet"</string>
     <string name="battery_saver_confirmation_title" msgid="1234998463717398453">"Të aktivizohet \"Kursyesi i baterisë\"?"</string>
     <string name="battery_saver_confirmation_title_generic" msgid="2299231884234959849">"Rreth \"Kursyesit të baterisë\""</string>
-    <string name="battery_saver_confirmation_ok" msgid="5042136476802816494">"Ndiz"</string>
+    <string name="battery_saver_confirmation_ok" msgid="5042136476802816494">"Aktivizo"</string>
     <string name="battery_saver_start_action" msgid="4553256017945469937">"Aktivizo \"Kursyesin e baterisë\""</string>
     <string name="status_bar_settings_settings_button" msgid="534331565185171556">"Cilësimet"</string>
     <string name="status_bar_settings_wifi_button" msgid="7243072479837270946">"Wi-Fi"</string>
@@ -510,7 +510,7 @@
     <string name="clear_all_notifications_text" msgid="348312370303046130">"Pastroji të gjitha"</string>
     <string name="manage_notifications_text" msgid="6885645344647733116">"Menaxho"</string>
     <string name="manage_notifications_history_text" msgid="57055985396576230">"Historiku"</string>
-    <string name="notification_section_header_incoming" msgid="5295312809341711367">"Hyrëse"</string>
+    <string name="notification_section_header_incoming" msgid="850925217908095197">"Të reja"</string>
     <string name="notification_section_header_gentle" msgid="6804099527336337197">"Në heshtje"</string>
     <string name="notification_section_header_alerting" msgid="5581175033680477651">"Njoftimet"</string>
     <string name="notification_section_header_conversations" msgid="821834744538345661">"Bisedat"</string>
@@ -595,7 +595,7 @@
     <string name="screen_pinning_title" msgid="9058007390337841305">"Aplikacioni është i gozhduar"</string>
     <string name="screen_pinning_description" msgid="8699395373875667743">"Kjo e ruan në pamje deri sa ta heqësh nga gozhdimi. Prek dhe mbaj të shtypur \"Prapa\" dhe \"Përmbledhje\" për ta hequr nga gozhdimi."</string>
     <string name="screen_pinning_description_recents_invisible" msgid="4564466648700390037">"Kjo e ruan në pamje deri sa ta heqësh nga gozhdimi. Prek dhe mbaj të shtypur \"Prapa\" dhe \"Kreu\" për ta hequr nga gozhdimi."</string>
-    <string name="screen_pinning_description_gestural" msgid="7246323931831232068">"Kjo e ruan në pamje deri sa ta zhgozhdosh. Rrëshqit shpejt lart dhe mbaje të shtypur për ta hequr zhgozhduar."</string>
+    <string name="screen_pinning_description_gestural" msgid="7246323931831232068">"Kjo e ruan në pamje deri sa ta zhgozhdosh. Rrëshqit shpejt lart dhe mbaje të shtypur për ta zhgozhduar."</string>
     <string name="screen_pinning_description_accessible" msgid="7386449191953535332">"Kjo e ruan në pamje deri sa ta heqësh nga gozhdimi. Prek dhe mbaj të shtypur \"Përmbledhje\" për ta hequr nga gozhdimi."</string>
     <string name="screen_pinning_description_recents_invisible_accessible" msgid="2857071808674481986">"Kjo e ruan në pamje deri sa ta heqësh nga gozhdimi. Prek dhe mbaj të shtypur \"Kreu\" për ta hequr nga gozhdimi."</string>
     <string name="screen_pinning_exposes_personal_data" msgid="8189852022981524789">"Të dhënat personale mund të jenë të qasshme (si kontaktet dhe përmbajtja e email-eve)"</string>
@@ -1002,7 +1002,7 @@
     <string name="bubble_accessibility_action_move_top_right" msgid="6916868852433483569">"Lëviz lart djathtas"</string>
     <string name="bubble_accessibility_action_move_bottom_left" msgid="6339015902495504715">"Zhvendos poshtë majtas"</string>
     <string name="bubble_accessibility_action_move_bottom_right" msgid="7471571700628346212">"Lëvize poshtë djathtas"</string>
-    <string name="bubble_dismiss_text" msgid="7071770411580452911">"Hiq"</string>
+    <string name="bubble_dismiss_text" msgid="1314082410868930066">"Hiqe flluskën"</string>
     <string name="bubbles_dont_bubble_conversation" msgid="1033040343437428822">"Mos e vendos bisedën në flluskë"</string>
     <string name="bubbles_user_education_title" msgid="5547017089271445797">"Bisedo duke përdorur flluskat"</string>
     <string name="bubbles_user_education_description" msgid="1160281719576715211">"Bisedat e reja shfaqen si ikona pluskuese ose flluska. Trokit për të hapur flluskën. Zvarrit për ta zhvendosur."</string>
@@ -1062,9 +1062,13 @@
     <string name="controls_structure_tooltip" msgid="4355922222944447867">"Rrëshqit shpejt për të shikuar më shumë"</string>
     <string name="controls_seeding_in_progress" msgid="3033855341410264148">"Po ngarkon rekomandimet"</string>
     <string name="controls_media_close_session" msgid="9023534788828414585">"Mbyll këtë sesion të medias"</string>
+    <string name="controls_media_resume" msgid="1933520684481586053">"Vazhdo"</string>
     <string name="controls_error_timeout" msgid="794197289772728958">"Joaktive, kontrollo aplikacionin"</string>
     <string name="controls_error_retryable" msgid="864025882878378470">"Gabim, po provohet përsëri"</string>
-    <string name="controls_error_removed" msgid="6299213591234723805">"Pajisja u hoq"</string>
+    <string name="controls_error_removed" msgid="6675638069846014366">"Nuk u gjet"</string>
+    <string name="controls_error_removed_title" msgid="1207794911208047818">"Kontrolli është i padisponueshëm"</string>
+    <string name="controls_error_removed_message" msgid="2885911717034750542">"Nuk mundi të qasej te <xliff:g id="DEVICE">%1$s</xliff:g>. Kontrollo aplikacionin <xliff:g id="APPLICATION">%2$s</xliff:g> për t\'u siguruar që kontrolli të jetë ende i disponueshëm dhe që cilësimet e aplikacionit të mos kenë ndryshuar."</string>
+    <string name="controls_open_app" msgid="483650971094300141">"Hap aplikacionin"</string>
     <string name="controls_error_generic" msgid="352500456918362905">"Statusi nuk mund të ngarkohet"</string>
     <string name="controls_error_failed" msgid="960228639198558525">"Gabim, provo sërish"</string>
     <string name="controls_in_progress" msgid="4421080500238215939">"Në vazhdim"</string>
diff --git a/packages/SystemUI/res/values-sr/strings.xml b/packages/SystemUI/res/values-sr/strings.xml
index 7855ec1..f692e1c 100644
--- a/packages/SystemUI/res/values-sr/strings.xml
+++ b/packages/SystemUI/res/values-sr/strings.xml
@@ -513,7 +513,7 @@
     <string name="clear_all_notifications_text" msgid="348312370303046130">"Обриши све"</string>
     <string name="manage_notifications_text" msgid="6885645344647733116">"Управљајте"</string>
     <string name="manage_notifications_history_text" msgid="57055985396576230">"Историја"</string>
-    <string name="notification_section_header_incoming" msgid="5295312809341711367">"Долазно"</string>
+    <string name="notification_section_header_incoming" msgid="850925217908095197">"Ново"</string>
     <string name="notification_section_header_gentle" msgid="6804099527336337197">"Нечујно"</string>
     <string name="notification_section_header_alerting" msgid="5581175033680477651">"Обавештења"</string>
     <string name="notification_section_header_conversations" msgid="821834744538345661">"Конверзације"</string>
@@ -598,7 +598,7 @@
     <string name="screen_pinning_title" msgid="9058007390337841305">"Апликација је закачена"</string>
     <string name="screen_pinning_description" msgid="8699395373875667743">"На овај начин се ово стално приказује док га не откачите. Додирните и задржите Назад и Преглед да бисте га откачили."</string>
     <string name="screen_pinning_description_recents_invisible" msgid="4564466648700390037">"На овај начин се ово стално приказује док га не откачите. Додирните и задржите Назад и Почетна да бисте га откачили."</string>
-    <string name="screen_pinning_description_gestural" msgid="7246323931831232068">"На овај начин се стално приказује док га не откачите. Превуците нагоре и задржите да бисте га откачили."</string>
+    <string name="screen_pinning_description_gestural" msgid="7246323931831232068">"Стално ће се приказивати док је не откачите. Превуците нагоре и задржите да бисте је откачили."</string>
     <string name="screen_pinning_description_accessible" msgid="7386449191953535332">"На овај начин се ово стално приказује док га не откачите. Додирните и задржите Преглед да бисте га откачили."</string>
     <string name="screen_pinning_description_recents_invisible_accessible" msgid="2857071808674481986">"На овај начин се ово стално приказује док га не откачите. Додирните и задржите Почетна да бисте га откачили."</string>
     <string name="screen_pinning_exposes_personal_data" msgid="8189852022981524789">"Могу да буду доступни лични подаци (као што су контакти и садржај имејлова)."</string>
@@ -1007,9 +1007,9 @@
     <string name="bubble_accessibility_action_move_top_right" msgid="6916868852433483569">"Премести горе десно"</string>
     <string name="bubble_accessibility_action_move_bottom_left" msgid="6339015902495504715">"Премести доле лево"</string>
     <string name="bubble_accessibility_action_move_bottom_right" msgid="7471571700628346212">"Премести доле десно"</string>
-    <string name="bubble_dismiss_text" msgid="7071770411580452911">"Одбаци"</string>
+    <string name="bubble_dismiss_text" msgid="1314082410868930066">"Одбацивање облачића"</string>
     <string name="bubbles_dont_bubble_conversation" msgid="1033040343437428822">"Не користи облачиће за конверзацију"</string>
-    <string name="bubbles_user_education_title" msgid="5547017089271445797">"Ћаскајте помоћу облачића"</string>
+    <string name="bubbles_user_education_title" msgid="5547017089271445797">"Ћаскајте у облачићима"</string>
     <string name="bubbles_user_education_description" msgid="1160281719576715211">"Нове конверзације се приказују као плутајуће иконе или облачићи. Додирните да бисте отворили облачић. Превуците да бисте га преместили."</string>
     <string name="bubbles_user_education_manage_title" msgid="2848511858160342320">"Контролишите облачиће у било ком тренутку"</string>
     <string name="bubbles_user_education_manage" msgid="1391639189507036423">"Додирните Управљајте да бисте искључили облачиће из ове апликације"</string>
@@ -1068,9 +1068,13 @@
     <string name="controls_structure_tooltip" msgid="4355922222944447867">"Превуците да бисте видели још"</string>
     <string name="controls_seeding_in_progress" msgid="3033855341410264148">"Учитавају се препоруке"</string>
     <string name="controls_media_close_session" msgid="9023534788828414585">"Затворите ову сесију медија"</string>
+    <string name="controls_media_resume" msgid="1933520684481586053">"Настави"</string>
     <string name="controls_error_timeout" msgid="794197289772728958">"Неактивно. Видите апликацију"</string>
     <string name="controls_error_retryable" msgid="864025882878378470">"Грешка, покушава се поново…"</string>
-    <string name="controls_error_removed" msgid="6299213591234723805">"Уређај је уклоњен"</string>
+    <string name="controls_error_removed" msgid="6675638069846014366">"Није пронађено"</string>
+    <string name="controls_error_removed_title" msgid="1207794911208047818">"Контрола није доступна"</string>
+    <string name="controls_error_removed_message" msgid="2885911717034750542">"Приступање уређају <xliff:g id="DEVICE">%1$s</xliff:g> није успело. Погледајте апликацију <xliff:g id="APPLICATION">%2$s</xliff:g> да бисте се уверили да је контрола још увек доступна и да се подешавања апликације нису променила."</string>
+    <string name="controls_open_app" msgid="483650971094300141">"Отвори апликацију"</string>
     <string name="controls_error_generic" msgid="352500456918362905">"Учитавање статуса није успело"</string>
     <string name="controls_error_failed" msgid="960228639198558525">"Грешка. Пробајте поново"</string>
     <string name="controls_in_progress" msgid="4421080500238215939">"У току"</string>
diff --git a/packages/SystemUI/res/values-sv/strings.xml b/packages/SystemUI/res/values-sv/strings.xml
index e6fb28e..f7d19ac 100644
--- a/packages/SystemUI/res/values-sv/strings.xml
+++ b/packages/SystemUI/res/values-sv/strings.xml
@@ -510,7 +510,7 @@
     <string name="clear_all_notifications_text" msgid="348312370303046130">"Rensa alla"</string>
     <string name="manage_notifications_text" msgid="6885645344647733116">"Hantera"</string>
     <string name="manage_notifications_history_text" msgid="57055985396576230">"Historik"</string>
-    <string name="notification_section_header_incoming" msgid="5295312809341711367">"Inkommande"</string>
+    <string name="notification_section_header_incoming" msgid="850925217908095197">"Ny"</string>
     <string name="notification_section_header_gentle" msgid="6804099527336337197">"Ljudlöst"</string>
     <string name="notification_section_header_alerting" msgid="5581175033680477651">"Aviseringar"</string>
     <string name="notification_section_header_conversations" msgid="821834744538345661">"Konversationer"</string>
@@ -599,7 +599,7 @@
     <string name="screen_pinning_description_accessible" msgid="7386449191953535332">"Skärmen visas tills du lossar den. Tryck länge på Översikt om du vill lossa skärmen."</string>
     <string name="screen_pinning_description_recents_invisible_accessible" msgid="2857071808674481986">"Skärmen visas tills du lossar den. Tryck länge på Startsida om du vill lossa skärmen."</string>
     <string name="screen_pinning_exposes_personal_data" msgid="8189852022981524789">"Personliga uppgifter kan bli tillgängliga (t.ex. kontakter och innehåll i e-post)."</string>
-    <string name="screen_pinning_can_open_other_apps" msgid="7529756813231421455">"Det kan gå att öppna andra appar med appen du har fäst."</string>
+    <string name="screen_pinning_can_open_other_apps" msgid="7529756813231421455">"Den fästa appen kan öppna andra appar."</string>
     <string name="screen_pinning_toast" msgid="8177286912533744328">"Om du vill lossa appen trycker du länge på knapparna Tillbaka och Översikt"</string>
     <string name="screen_pinning_toast_recents_invisible" msgid="6850978077443052594">"Om du vill lossa appen trycker du länge på knapparna Tillbaka och Startsida"</string>
     <string name="screen_pinning_toast_gesture_nav" msgid="170699893395336705">"Svep uppåt och håll kvar fingret om du vill lossa appen"</string>
@@ -1002,7 +1002,7 @@
     <string name="bubble_accessibility_action_move_top_right" msgid="6916868852433483569">"Flytta högst upp till höger"</string>
     <string name="bubble_accessibility_action_move_bottom_left" msgid="6339015902495504715">"Flytta längst ned till vänster"</string>
     <string name="bubble_accessibility_action_move_bottom_right" msgid="7471571700628346212">"Flytta längst ned till höger"</string>
-    <string name="bubble_dismiss_text" msgid="7071770411580452911">"Stäng"</string>
+    <string name="bubble_dismiss_text" msgid="1314082410868930066">"Stäng bubbla"</string>
     <string name="bubbles_dont_bubble_conversation" msgid="1033040343437428822">"Visa inte konversationen i bubblor"</string>
     <string name="bubbles_user_education_title" msgid="5547017089271445797">"Chatta med bubblor"</string>
     <string name="bubbles_user_education_description" msgid="1160281719576715211">"Nya konversationer visas som flytande ikoner, så kallade bubblor. Tryck på bubblan om du vill öppna den. Dra den om du vill flytta den."</string>
@@ -1062,9 +1062,13 @@
     <string name="controls_structure_tooltip" msgid="4355922222944447867">"Svep om du vill se mer"</string>
     <string name="controls_seeding_in_progress" msgid="3033855341410264148">"Rekommendationer läses in"</string>
     <string name="controls_media_close_session" msgid="9023534788828414585">"Stäng den här sessionen"</string>
+    <string name="controls_media_resume" msgid="1933520684481586053">"Återuppta"</string>
     <string name="controls_error_timeout" msgid="794197289772728958">"Inaktiv, kolla appen"</string>
     <string name="controls_error_retryable" msgid="864025882878378470">"Fel, försöker igen …"</string>
-    <string name="controls_error_removed" msgid="6299213591234723805">"Enheten har tagits bort"</string>
+    <string name="controls_error_removed" msgid="6675638069846014366">"Hittades inte"</string>
+    <string name="controls_error_removed_title" msgid="1207794911208047818">"Styrning är inte tillgänglig"</string>
+    <string name="controls_error_removed_message" msgid="2885911717034750542">"Det gick inte att komma åt <xliff:g id="DEVICE">%1$s</xliff:g>. Kontrollera att enheten fortfarande är tillgänglig för styrning och att appinställningarna inte har ändrats i <xliff:g id="APPLICATION">%2$s</xliff:g>-appen."</string>
+    <string name="controls_open_app" msgid="483650971094300141">"Öppna appen"</string>
     <string name="controls_error_generic" msgid="352500456918362905">"Ingen status lästes in"</string>
     <string name="controls_error_failed" msgid="960228639198558525">"Fel, försök igen"</string>
     <string name="controls_in_progress" msgid="4421080500238215939">"Pågår"</string>
diff --git a/packages/SystemUI/res/values-sw/strings.xml b/packages/SystemUI/res/values-sw/strings.xml
index c7962f9..1a0b9ec 100644
--- a/packages/SystemUI/res/values-sw/strings.xml
+++ b/packages/SystemUI/res/values-sw/strings.xml
@@ -92,7 +92,7 @@
     <string name="screenrecord_background_processing_label" msgid="7244617554884238898">"Inachakata rekodi ya skrini"</string>
     <string name="screenrecord_channel_description" msgid="4147077128486138351">"Arifa inayoendelea ya kipindi cha kurekodi skrini"</string>
     <string name="screenrecord_start_label" msgid="1750350278888217473">"Ungependa kuanza kurekodi?"</string>
-    <string name="screenrecord_description" msgid="1123231719680353736">"Wakati wa kurekodi, Mfumo wa Android unaweza kusana maelezo yoyote nyeti yanayoonekana kwenye skrini au yanayochezwa kwenye kifaa chako. Hii ni pamoja na manenosiri, maelezo ya malipo, picha, ujumbe na sauti."</string>
+    <string name="screenrecord_description" msgid="1123231719680353736">"Wakati wa kurekodi, Mfumo wa Android unaweza kunasa maelezo yoyote nyeti yanayoonekana kwenye skrini au yanayochezwa kwenye kifaa chako. Hii ni pamoja na manenosiri, maelezo ya malipo, picha, ujumbe na sauti."</string>
     <string name="screenrecord_audio_label" msgid="6183558856175159629">"Rekodi sauti"</string>
     <string name="screenrecord_device_audio_label" msgid="9016927171280567791">"Sauti ya kifaa"</string>
     <string name="screenrecord_device_audio_description" msgid="4922694220572186193">"Sauti kutoka kwenye kifaa chako, kama vile muziki, simu na milio ya simu"</string>
@@ -510,7 +510,7 @@
     <string name="clear_all_notifications_text" msgid="348312370303046130">"Futa zote"</string>
     <string name="manage_notifications_text" msgid="6885645344647733116">"Dhibiti"</string>
     <string name="manage_notifications_history_text" msgid="57055985396576230">"Historia"</string>
-    <string name="notification_section_header_incoming" msgid="5295312809341711367">"Simu inayoingia"</string>
+    <string name="notification_section_header_incoming" msgid="850925217908095197">"Mpya"</string>
     <string name="notification_section_header_gentle" msgid="6804099527336337197">"Kimya"</string>
     <string name="notification_section_header_alerting" msgid="5581175033680477651">"Arifa"</string>
     <string name="notification_section_header_conversations" msgid="821834744538345661">"Mazungumzo"</string>
@@ -1002,7 +1002,7 @@
     <string name="bubble_accessibility_action_move_top_right" msgid="6916868852433483569">"Sogeza juu kulia"</string>
     <string name="bubble_accessibility_action_move_bottom_left" msgid="6339015902495504715">"Sogeza chini kushoto"</string>
     <string name="bubble_accessibility_action_move_bottom_right" msgid="7471571700628346212">"Sogeza chini kulia"</string>
-    <string name="bubble_dismiss_text" msgid="7071770411580452911">"Ondoa"</string>
+    <string name="bubble_dismiss_text" msgid="1314082410868930066">"Ondoa kiputo"</string>
     <string name="bubbles_dont_bubble_conversation" msgid="1033040343437428822">"Usiweke viputo kwenye mazungumzo"</string>
     <string name="bubbles_user_education_title" msgid="5547017089271445797">"Piga gumzo ukitumia viputo"</string>
     <string name="bubbles_user_education_description" msgid="1160281719576715211">"Mazungumzo mapya huonekena kama aikoni au viputo vinavyoelea. Gusa ili ufungue kiputo. Buruta ili ukisogeze."</string>
@@ -1062,9 +1062,13 @@
     <string name="controls_structure_tooltip" msgid="4355922222944447867">"Telezesha kidole ili uone zaidi"</string>
     <string name="controls_seeding_in_progress" msgid="3033855341410264148">"Inapakia mapendekezo"</string>
     <string name="controls_media_close_session" msgid="9023534788828414585">"Funga kipindi hiki cha maudhui"</string>
+    <string name="controls_media_resume" msgid="1933520684481586053">"Endelea"</string>
     <string name="controls_error_timeout" msgid="794197289772728958">"Haitumiki, angalia programu"</string>
     <string name="controls_error_retryable" msgid="864025882878378470">"Hitilafu, inajaribu tena…"</string>
-    <string name="controls_error_removed" msgid="6299213591234723805">"Kifaa kimeondolewa"</string>
+    <string name="controls_error_removed" msgid="6675638069846014366">"Hakipatikani"</string>
+    <string name="controls_error_removed_title" msgid="1207794911208047818">"Kidhibiti hakipatikani"</string>
+    <string name="controls_error_removed_message" msgid="2885911717034750542">"Imeshindwa kufikia <xliff:g id="DEVICE">%1$s</xliff:g>. Angalia programu ya <xliff:g id="APPLICATION">%2$s</xliff:g> ili uhakikishe kuwa bado kidhibiti kipo na kuwa mipangilio ya programu haijabadilika."</string>
+    <string name="controls_open_app" msgid="483650971094300141">"Fungua programu"</string>
     <string name="controls_error_generic" msgid="352500456918362905">"Imeshindwa kupakia hali"</string>
     <string name="controls_error_failed" msgid="960228639198558525">"Hitilafu, jaribu tena"</string>
     <string name="controls_in_progress" msgid="4421080500238215939">"Inaendelea"</string>
diff --git a/packages/SystemUI/res/values-sw600dp-land/config.xml b/packages/SystemUI/res/values-sw600dp-land/config.xml
index c4c4671..3b00ad1 100644
--- a/packages/SystemUI/res/values-sw600dp-land/config.xml
+++ b/packages/SystemUI/res/values-sw600dp-land/config.xml
@@ -15,8 +15,5 @@
   ~ limitations under the License
   -->
 <resources>
-    <!-- Whether QuickSettings is in a phone landscape -->
-    <bool name="quick_settings_wide">false</bool>
-
     <integer name="quick_settings_num_columns">3</integer>
 </resources>
diff --git a/packages/SystemUI/res/color/qs_user_detail_avatar_tint.xml b/packages/SystemUI/res/values-sw600dp-port/dimens.xml
similarity index 64%
copy from packages/SystemUI/res/color/qs_user_detail_avatar_tint.xml
copy to packages/SystemUI/res/values-sw600dp-port/dimens.xml
index 696e9b1..40838f3 100644
--- a/packages/SystemUI/res/color/qs_user_detail_avatar_tint.xml
+++ b/packages/SystemUI/res/values-sw600dp-port/dimens.xml
@@ -1,7 +1,6 @@
 <?xml version="1.0" encoding="utf-8"?>
-
 <!--
-  ~ Copyright (C) 2016 The Android Open Source Project
+  ~ Copyright (C) 2020 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.
@@ -13,10 +12,10 @@
   ~ 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
+  ~ limitations under the License.
   -->
+<resources>
+    <!-- Size of the panel of large phones on portrait. This shouldn't fill, but have some padding on the side -->
+    <dimen name="notification_panel_width">416dp</dimen>
 
-<selector xmlns:android="http://schemas.android.com/apk/res/android">
-    <item android:state_enabled="false" android:color="?android:attr/textColorPrimary" />
-    <item android:color="@android:color/transparent" />
-</selector>
+</resources>
diff --git a/packages/SystemUI/res/values-sw600dp/dimens.xml b/packages/SystemUI/res/values-sw600dp/dimens.xml
index 8f73d23..fdf4e3b 100644
--- a/packages/SystemUI/res/values-sw600dp/dimens.xml
+++ b/packages/SystemUI/res/values-sw600dp/dimens.xml
@@ -16,8 +16,6 @@
 */
 -->
 <resources>
-    <!-- Standard notification width + gravity -->
-    <dimen name="notification_panel_width">416dp</dimen>
 
     <!-- Diameter of outer shape drawable shown in navbar search-->
     <dimen name="navbar_search_outerring_diameter">430dip</dimen>
diff --git a/packages/SystemUI/res/values-sw900dp-land/dimen.xml b/packages/SystemUI/res/values-sw900dp-land/dimen.xml
deleted file mode 100644
index 1e0600e..0000000
--- a/packages/SystemUI/res/values-sw900dp-land/dimen.xml
+++ /dev/null
@@ -1,23 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
- * Copyright (c) 2012, 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.
-*/
--->
-<resources>
-    <!-- Standard notification width + gravity for tablet large screen device -->
-    <dimen name="notification_panel_width">544dp</dimen>
-
-</resources>
-
diff --git a/packages/SystemUI/res/values-ta/strings.xml b/packages/SystemUI/res/values-ta/strings.xml
index edd8bde..29a186f 100644
--- a/packages/SystemUI/res/values-ta/strings.xml
+++ b/packages/SystemUI/res/values-ta/strings.xml
@@ -146,7 +146,7 @@
     <string name="biometric_dialog_face_icon_description_authenticating" msgid="3401633342366146535">"உங்கள் முகத்தை அங்கீகரிக்கிறது"</string>
     <string name="biometric_dialog_face_icon_description_authenticated" msgid="2242167416140740920">"முகம் அங்கீகரிக்கப்பட்டது"</string>
     <string name="biometric_dialog_face_icon_description_confirmed" msgid="7918067993953940778">"உறுதிப்படுத்தப்பட்டது"</string>
-    <string name="biometric_dialog_tap_confirm" msgid="9166350738859143358">"முடிக்க \'உறுதிப்படுத்து\' என்பதை தட்டவும்"</string>
+    <string name="biometric_dialog_tap_confirm" msgid="9166350738859143358">"முடிக்க \'உறுதிப்படுத்துக\' என்பதை தட்டவும்"</string>
     <string name="biometric_dialog_authenticated" msgid="7337147327545272484">"அங்கீகரிக்கப்பட்டது"</string>
     <string name="biometric_dialog_use_pin" msgid="8385294115283000709">"பின்னைப் பயன்படுத்து"</string>
     <string name="biometric_dialog_use_pattern" msgid="2315593393167211194">"பேட்டர்னைப் பயன்படுத்து"</string>
@@ -168,7 +168,7 @@
     <string name="biometric_dialog_last_password_attempt_before_wipe_profile" msgid="8538032972389729253">"அடுத்த முறை தவறான கடவுச்சொல்லை உள்ளிட்டால் உங்கள் பணிக் கணக்கும் அதன் தரவும் நீக்கப்படும்."</string>
     <string name="biometric_dialog_failed_attempts_now_wiping_device" msgid="6585503524026243042">"பலமுறை தவறாக முயன்ற காரணத்தால் இந்தச் சாதனத்தின் தரவு நீக்கப்படும்."</string>
     <string name="biometric_dialog_failed_attempts_now_wiping_user" msgid="7015008539146949115">"பலமுறை தவறாக முயன்ற காரணத்தால் இந்தப் பயனர் நீக்கப்படுவார்."</string>
-    <string name="biometric_dialog_failed_attempts_now_wiping_profile" msgid="5239378521440749682">"பலமுறை தவறாக முயன்ற காரணத்தால் இந்தப் பணிக் கணக்கும் அதன் தரவும் நீக்கப்படும்."</string>
+    <string name="biometric_dialog_failed_attempts_now_wiping_profile" msgid="5239378521440749682">"பலமுறை தவறாக முயன்றதால், இந்தப் பணிக் கணக்கும் அதன் தரவும் நீக்கப்படும்"</string>
     <string name="biometric_dialog_now_wiping_dialog_dismiss" msgid="7189432882125106154">"நிராகரி"</string>
     <string name="fingerprint_dialog_touch_sensor" msgid="2817887108047658975">"கைரேகை சென்சாரைத் தொடவும்"</string>
     <string name="accessibility_fingerprint_dialog_fingerprint_icon" msgid="4465698996175640549">"கைரேகை ஐகான்"</string>
@@ -510,7 +510,7 @@
     <string name="clear_all_notifications_text" msgid="348312370303046130">"எல்லாவற்றையும் அழி"</string>
     <string name="manage_notifications_text" msgid="6885645344647733116">"அறிவிப்புகளை நிர்வகி"</string>
     <string name="manage_notifications_history_text" msgid="57055985396576230">"வரலாறு"</string>
-    <string name="notification_section_header_incoming" msgid="5295312809341711367">"உள்வருவது"</string>
+    <string name="notification_section_header_incoming" msgid="850925217908095197">"புதிது"</string>
     <string name="notification_section_header_gentle" msgid="6804099527336337197">"நிசப்தம்"</string>
     <string name="notification_section_header_alerting" msgid="5581175033680477651">"அறிவிப்புகள்"</string>
     <string name="notification_section_header_conversations" msgid="821834744538345661">"உரையாடல்கள்"</string>
@@ -1002,7 +1002,7 @@
     <string name="bubble_accessibility_action_move_top_right" msgid="6916868852433483569">"மேலே வலப்புறமாக நகர்த்து"</string>
     <string name="bubble_accessibility_action_move_bottom_left" msgid="6339015902495504715">"கீழே இடப்புறமாக நகர்த்து"</string>
     <string name="bubble_accessibility_action_move_bottom_right" msgid="7471571700628346212">"கீழே வலதுபுறமாக நகர்த்து"</string>
-    <string name="bubble_dismiss_text" msgid="7071770411580452911">"மூடுக"</string>
+    <string name="bubble_dismiss_text" msgid="1314082410868930066">"குமிழை அகற்று"</string>
     <string name="bubbles_dont_bubble_conversation" msgid="1033040343437428822">"உரையாடலைக் குமிழாக்காதே"</string>
     <string name="bubbles_user_education_title" msgid="5547017089271445797">"குமிழ்களைப் பயன்படுத்தி அரட்டையடியுங்கள்"</string>
     <string name="bubbles_user_education_description" msgid="1160281719576715211">"புதிய உரையாடல்கள் மிதக்கும் ஐகான்களாகவோ குமிழ்களாகவோ தோன்றும். குமிழைத் திறக்க தட்டவும். நகர்த்த இழுக்கவும்."</string>
@@ -1062,9 +1062,13 @@
     <string name="controls_structure_tooltip" msgid="4355922222944447867">"மேலும் பார்க்க ஸ்வைப் செய்யவும்"</string>
     <string name="controls_seeding_in_progress" msgid="3033855341410264148">"பரிந்துரைகளை ஏற்றுகிறது"</string>
     <string name="controls_media_close_session" msgid="9023534788828414585">"இந்த மீடியா அமர்வை மூடுக"</string>
+    <string name="controls_media_resume" msgid="1933520684481586053">"தொடர்க"</string>
     <string name="controls_error_timeout" msgid="794197289772728958">"செயலில் இல்லை , சரிபார்க்கவும்"</string>
     <string name="controls_error_retryable" msgid="864025882878378470">"பிழை, மீண்டும் முயல்கிறது…"</string>
-    <string name="controls_error_removed" msgid="6299213591234723805">"சாதனம் அகற்றப்பட்டது"</string>
+    <string name="controls_error_removed" msgid="6675638069846014366">"இல்லை"</string>
+    <string name="controls_error_removed_title" msgid="1207794911208047818">"கட்டுப்பாடு இல்லை"</string>
+    <string name="controls_error_removed_message" msgid="2885911717034750542">"<xliff:g id="DEVICE">%1$s</xliff:g> சாதனத்தை அணுக இயலவில்லை. இப்போதும் கட்டுப்பாடு உள்ளது என்பதையும் ஆப்ஸ் அமைப்புகள் மாறவில்லை என்பதையும் உறுதிப்படுத்த <xliff:g id="APPLICATION">%2$s</xliff:g> ஆப்ஸைப் பார்க்கவும்."</string>
+    <string name="controls_open_app" msgid="483650971094300141">"ஆப்ஸைத் திற"</string>
     <string name="controls_error_generic" msgid="352500456918362905">"நிலையைக் காட்ட முடியவில்லை"</string>
     <string name="controls_error_failed" msgid="960228639198558525">"பிழை, மீண்டும் முயலவும்"</string>
     <string name="controls_in_progress" msgid="4421080500238215939">"செயல்பாட்டிலுள்ளது"</string>
diff --git a/packages/SystemUI/res/values-te/strings.xml b/packages/SystemUI/res/values-te/strings.xml
index a08d0d4..4b56e15 100644
--- a/packages/SystemUI/res/values-te/strings.xml
+++ b/packages/SystemUI/res/values-te/strings.xml
@@ -510,7 +510,7 @@
     <string name="clear_all_notifications_text" msgid="348312370303046130">"అన్నీ క్లియర్ చేయండి"</string>
     <string name="manage_notifications_text" msgid="6885645344647733116">"నిర్వహించండి"</string>
     <string name="manage_notifications_history_text" msgid="57055985396576230">"చరిత్ర"</string>
-    <string name="notification_section_header_incoming" msgid="5295312809341711367">"ఇన్‌కమింగ్"</string>
+    <string name="notification_section_header_incoming" msgid="850925217908095197">"కొత్తవి"</string>
     <string name="notification_section_header_gentle" msgid="6804099527336337197">"నిశ్శబ్దం"</string>
     <string name="notification_section_header_alerting" msgid="5581175033680477651">"నోటిఫికేషన్‌లు"</string>
     <string name="notification_section_header_conversations" msgid="821834744538345661">"సంభాషణలు"</string>
@@ -721,7 +721,7 @@
     <string name="notification_priority_title" msgid="2079708866333537093">"ప్రాధాన్యత"</string>
     <string name="no_shortcut" msgid="8257177117568230126">"<xliff:g id="APP_NAME">%1$s</xliff:g> సంభాషణ ఫీచర్‌లను సపోర్ట్ చేయదు"</string>
     <string name="bubble_overflow_empty_title" msgid="3120029421991510842">"ఇటీవలి బబుల్స్ ఏవీ లేవు"</string>
-    <string name="bubble_overflow_empty_subtitle" msgid="2030874469510497397">"ఇటీవలి బబుల్స్, తీసివేసిన బబుల్స్ ఇక్కడ కనిపిస్తాయి"</string>
+    <string name="bubble_overflow_empty_subtitle" msgid="2030874469510497397">"ఇటీవలి బబుల్స్ మరియు తీసివేసిన బబుల్స్ ఇక్కడ కనిపిస్తాయి"</string>
     <string name="notification_unblockable_desc" msgid="2073030886006190804">"ఈ నోటిఫికేషన్‌లను సవరించడం వీలుపడదు."</string>
     <string name="notification_multichannel_desc" msgid="7414593090056236179">"ఈ నోటిఫికేషన్‌ల సమూహాన్ని ఇక్కడ కాన్ఫిగర్ చేయలేము"</string>
     <string name="notification_delegate_header" msgid="1264510071031479920">"ప్రాక్సీ చేయబడిన నోటిఫికేషన్"</string>
@@ -1002,7 +1002,7 @@
     <string name="bubble_accessibility_action_move_top_right" msgid="6916868852433483569">"ఎగువ కుడివైపునకు జరుపు"</string>
     <string name="bubble_accessibility_action_move_bottom_left" msgid="6339015902495504715">"దిగువ ఎడమవైపునకు తరలించు"</string>
     <string name="bubble_accessibility_action_move_bottom_right" msgid="7471571700628346212">"దిగవు కుడివైపునకు జరుపు"</string>
-    <string name="bubble_dismiss_text" msgid="7071770411580452911">"విస్మరించు"</string>
+    <string name="bubble_dismiss_text" msgid="1314082410868930066">"బబుల్‌ను విస్మరించు"</string>
     <string name="bubbles_dont_bubble_conversation" msgid="1033040343437428822">"సంభాషణను బబుల్ చేయవద్దు"</string>
     <string name="bubbles_user_education_title" msgid="5547017089271445797">"బబుల్స్‌ను ఉపయోగించి చాట్ చేయండి"</string>
     <string name="bubbles_user_education_description" msgid="1160281719576715211">"కొత్త సంభాషణలు తేలియాడే చిహ్నాలుగా లేదా బబుల్స్ లాగా కనిపిస్తాయి. బబుల్‌ని తెరవడానికి నొక్కండి. తరలించడానికి లాగండి."</string>
@@ -1062,9 +1062,13 @@
     <string name="controls_structure_tooltip" msgid="4355922222944447867">"మరిన్నింటిని చూడటం కోసం స్వైప్ చేయండి"</string>
     <string name="controls_seeding_in_progress" msgid="3033855341410264148">"సిఫార్సులు లోడ్ అవుతున్నాయి"</string>
     <string name="controls_media_close_session" msgid="9023534788828414585">"ఈ మీడియా సెషన్‌ని మూసివేయండి"</string>
+    <string name="controls_media_resume" msgid="1933520684481586053">"కొనసాగించండి"</string>
     <string name="controls_error_timeout" msgid="794197289772728958">"ఇన్‌యాక్టివ్, యాప్ చెక్ చేయండి"</string>
     <string name="controls_error_retryable" msgid="864025882878378470">"లోపం, మళ్లీ ప్రయత్నిస్తోంది..."</string>
-    <string name="controls_error_removed" msgid="6299213591234723805">"పరికరం తీసివేయబడింది"</string>
+    <string name="controls_error_removed" msgid="6675638069846014366">"కనుగొనబడలేదు"</string>
+    <string name="controls_error_removed_title" msgid="1207794911208047818">"కంట్రోల్ అందుబాటులో లేదు"</string>
+    <string name="controls_error_removed_message" msgid="2885911717034750542">"<xliff:g id="DEVICE">%1$s</xliff:g>ను యాక్సెస్ చేయడం సాధ్యపడలేదు. <xliff:g id="APPLICATION">%2$s</xliff:g> యాప్‌ను తనిఖీ చేసి, కంట్రోల్ ఇప్పటికీ అందుబాటులో ఉందని, యాప్ సెట్టింగ్‌లు మారలేదని నిర్ధారించుకోండి."</string>
+    <string name="controls_open_app" msgid="483650971094300141">"యాప్‌ను తెరువు"</string>
     <string name="controls_error_generic" msgid="352500456918362905">"స్థితిని లోడ్ చేయడం సాధ్యపడదు"</string>
     <string name="controls_error_failed" msgid="960228639198558525">"ఎర్రర్, మళ్లీ ప్రయత్నించండి"</string>
     <string name="controls_in_progress" msgid="4421080500238215939">"పురోగతిలో ఉంది"</string>
diff --git a/packages/SystemUI/res/values-th/strings.xml b/packages/SystemUI/res/values-th/strings.xml
index 5638f2a51..ba16feb 100644
--- a/packages/SystemUI/res/values-th/strings.xml
+++ b/packages/SystemUI/res/values-th/strings.xml
@@ -92,7 +92,7 @@
     <string name="screenrecord_background_processing_label" msgid="7244617554884238898">"กำลังประมวลผลการอัดหน้าจอ"</string>
     <string name="screenrecord_channel_description" msgid="4147077128486138351">"การแจ้งเตือนต่อเนื่องสำหรับเซสชันการบันทึกหน้าจอ"</string>
     <string name="screenrecord_start_label" msgid="1750350278888217473">"เริ่มบันทึกเลยไหม"</string>
-    <string name="screenrecord_description" msgid="1123231719680353736">"ขณะบันทึก ระบบ Android จะบันทึกข้อมูลที่ละเอียดอ่อนที่ปรากฏบนหน้าจอหรือเล่นในอุปกรณ์ได้ ซึ่งรวมถึงรหัสผ่าน ข้อมูลการชำระเงิน รูปภาพ ข้อความ และเสียง"</string>
+    <string name="screenrecord_description" msgid="1123231719680353736">"ขณะบันทึก ระบบ Android อาจบันทึกข้อมูลที่ละเอียดอ่อนที่ปรากฏบนหน้าจอหรือเล่นในอุปกรณ์ได้ ซึ่งรวมถึงรหัสผ่าน ข้อมูลการชำระเงิน รูปภาพ ข้อความ และเสียง"</string>
     <string name="screenrecord_audio_label" msgid="6183558856175159629">"บันทึกเสียง"</string>
     <string name="screenrecord_device_audio_label" msgid="9016927171280567791">"เสียงจากอุปกรณ์"</string>
     <string name="screenrecord_device_audio_description" msgid="4922694220572186193">"เสียงจากอุปกรณ์ เช่น เพลง การโทร และเสียงเรียกเข้า"</string>
@@ -510,7 +510,7 @@
     <string name="clear_all_notifications_text" msgid="348312370303046130">"ล้างทั้งหมด"</string>
     <string name="manage_notifications_text" msgid="6885645344647733116">"จัดการ"</string>
     <string name="manage_notifications_history_text" msgid="57055985396576230">"ประวัติ"</string>
-    <string name="notification_section_header_incoming" msgid="5295312809341711367">"เข้ามาใหม่"</string>
+    <string name="notification_section_header_incoming" msgid="850925217908095197">"ใหม่"</string>
     <string name="notification_section_header_gentle" msgid="6804099527336337197">"เงียบ"</string>
     <string name="notification_section_header_alerting" msgid="5581175033680477651">"การแจ้งเตือน"</string>
     <string name="notification_section_header_conversations" msgid="821834744538345661">"การสนทนา"</string>
@@ -595,7 +595,7 @@
     <string name="screen_pinning_title" msgid="9058007390337841305">"ตรึงแอปอยู่"</string>
     <string name="screen_pinning_description" msgid="8699395373875667743">"การดำเนินการนี้จะแสดงหน้าจอนี้ไว้เสมอจนกว่าคุณจะเลิกตรึง แตะ \"กลับ\" และ \"ภาพรวม\" ค้างไว้เพื่อเลิกตรึง"</string>
     <string name="screen_pinning_description_recents_invisible" msgid="4564466648700390037">"การดำเนินการนี้จะแสดงหน้าจอนี้ไว้เสมอจนกว่าคุณจะเลิกตรึง แตะ \"กลับ\" และ \"หน้าแรก\" ค้างไว้เพื่อเลิกตรึง"</string>
-    <string name="screen_pinning_description_gestural" msgid="7246323931831232068">"วิธีนี้ช่วยให้เห็นหน้าจอตลอดจนกว่าจะเลิกตรึง เลื่อนขึ้นค้างไว้เพื่อเลิกตรึง"</string>
+    <string name="screen_pinning_description_gestural" msgid="7246323931831232068">"วิธีนี้ช่วยให้เห็นแอปบนหน้าจอตลอดจนกว่าจะเลิกตรึง เลื่อนขึ้นค้างไว้เพื่อเลิกตรึง"</string>
     <string name="screen_pinning_description_accessible" msgid="7386449191953535332">"การดำเนินการนี้จะแสดงหน้าจอนี้ไว้เสมอจนกว่าคุณจะเลิกตรึง แตะ \"ภาพรวม\" ค้างไว้เพื่อเลิกตรึง"</string>
     <string name="screen_pinning_description_recents_invisible_accessible" msgid="2857071808674481986">"การดำเนินการนี้จะแสดงหน้าจอนี้ไว้เสมอจนกว่าคุณจะเลิกตรึง แตะ \"หน้าแรก\" ค้างไว้เพื่อเลิกตรึง"</string>
     <string name="screen_pinning_exposes_personal_data" msgid="8189852022981524789">"อาจมีการเข้าถึงข้อมูลส่วนตัว (เช่น รายชื่อติดต่อและเนื้อหาในอีเมล)"</string>
@@ -1002,7 +1002,7 @@
     <string name="bubble_accessibility_action_move_top_right" msgid="6916868852433483569">"ย้ายไปด้านขวาบน"</string>
     <string name="bubble_accessibility_action_move_bottom_left" msgid="6339015902495504715">"ย้ายไปด้านซ้ายล่าง"</string>
     <string name="bubble_accessibility_action_move_bottom_right" msgid="7471571700628346212">"ย้ายไปด้านขาวล่าง"</string>
-    <string name="bubble_dismiss_text" msgid="7071770411580452911">"ปิด"</string>
+    <string name="bubble_dismiss_text" msgid="1314082410868930066">"ปิดบับเบิล"</string>
     <string name="bubbles_dont_bubble_conversation" msgid="1033040343437428822">"ไม่ต้องแสดงการสนทนาเป็นบับเบิล"</string>
     <string name="bubbles_user_education_title" msgid="5547017089271445797">"แชทโดยใช้บับเบิล"</string>
     <string name="bubbles_user_education_description" msgid="1160281719576715211">"การสนทนาใหม่ๆ จะปรากฏเป็นไอคอนแบบลอยหรือบับเบิล แตะเพื่อเปิดบับเบิล ลากเพื่อย้ายที่"</string>
@@ -1062,9 +1062,13 @@
     <string name="controls_structure_tooltip" msgid="4355922222944447867">"เลื่อนเพื่อดูเพิ่มเติม"</string>
     <string name="controls_seeding_in_progress" msgid="3033855341410264148">"กำลังโหลดคำแนะนำ"</string>
     <string name="controls_media_close_session" msgid="9023534788828414585">"ปิดเซสชันสื่อนี้"</string>
+    <string name="controls_media_resume" msgid="1933520684481586053">"เล่นต่อ"</string>
     <string name="controls_error_timeout" msgid="794197289772728958">"ไม่มีการใช้งาน โปรดตรวจสอบแอป"</string>
     <string name="controls_error_retryable" msgid="864025882878378470">"มีข้อผิดพลาด กำลังลองอีกครั้ง…"</string>
-    <string name="controls_error_removed" msgid="6299213591234723805">"นำอุปกรณ์ออกแล้ว"</string>
+    <string name="controls_error_removed" msgid="6675638069846014366">"ไม่พบ"</string>
+    <string name="controls_error_removed_title" msgid="1207794911208047818">"ใช้การควบคุมไม่ได้"</string>
+    <string name="controls_error_removed_message" msgid="2885911717034750542">"เข้าถึง <xliff:g id="DEVICE">%1$s</xliff:g> ไม่ได้ ตรวจสอบแอป <xliff:g id="APPLICATION">%2$s</xliff:g> ให้แน่ใจว่ายังใช้การควบคุมได้และการตั้งค่าของแอปไม่เปลี่ยนแปลง"</string>
+    <string name="controls_open_app" msgid="483650971094300141">"เปิดแอป"</string>
     <string name="controls_error_generic" msgid="352500456918362905">"โหลดสถานะไม่ได้"</string>
     <string name="controls_error_failed" msgid="960228639198558525">"พบข้อผิดพลาด โปรดลองอีกครั้ง"</string>
     <string name="controls_in_progress" msgid="4421080500238215939">"กำลังดำเนินการ"</string>
diff --git a/packages/SystemUI/res/values-tl/strings.xml b/packages/SystemUI/res/values-tl/strings.xml
index b9b379c..e25e52b 100644
--- a/packages/SystemUI/res/values-tl/strings.xml
+++ b/packages/SystemUI/res/values-tl/strings.xml
@@ -122,7 +122,7 @@
     <string name="accessibility_back" msgid="6530104400086152611">"Bumalik"</string>
     <string name="accessibility_home" msgid="5430449841237966217">"Home"</string>
     <string name="accessibility_menu" msgid="2701163794470513040">"Menu"</string>
-    <string name="accessibility_accessibility_button" msgid="4089042473497107709">"Pagiging Accessible"</string>
+    <string name="accessibility_accessibility_button" msgid="4089042473497107709">"Accessibility"</string>
     <string name="accessibility_rotate_button" msgid="1238584767612362586">"I-rotate ang screen"</string>
     <string name="accessibility_recent" msgid="901641734769533575">"Overview"</string>
     <string name="accessibility_search_light" msgid="524741790416076988">"Hanapin"</string>
@@ -510,7 +510,7 @@
     <string name="clear_all_notifications_text" msgid="348312370303046130">"I-clear lahat"</string>
     <string name="manage_notifications_text" msgid="6885645344647733116">"Pamahalaan"</string>
     <string name="manage_notifications_history_text" msgid="57055985396576230">"History"</string>
-    <string name="notification_section_header_incoming" msgid="5295312809341711367">"Papasok"</string>
+    <string name="notification_section_header_incoming" msgid="850925217908095197">"Bago"</string>
     <string name="notification_section_header_gentle" msgid="6804099527336337197">"Naka-silent"</string>
     <string name="notification_section_header_alerting" msgid="5581175033680477651">"Mga Notification"</string>
     <string name="notification_section_header_conversations" msgid="821834744538345661">"Mga Pag-uusap"</string>
@@ -595,7 +595,7 @@
     <string name="screen_pinning_title" msgid="9058007390337841305">"Naka-pin ang app"</string>
     <string name="screen_pinning_description" msgid="8699395373875667743">"Pinapanatili nitong nakikita ito hanggang sa mag-unpin ka. Pindutin nang matagal ang Bumalik at Overview upang mag-unpin."</string>
     <string name="screen_pinning_description_recents_invisible" msgid="4564466648700390037">"Pinapanatili nitong nakikita ito hanggang sa mag-unpin ka. Pindutin nang matagal ang Bumalik at Home upang mag-unpin."</string>
-    <string name="screen_pinning_description_gestural" msgid="7246323931831232068">"Pinapanatili nitong nakikita ito hanggang sa mag-unpin ka. Mag-swipe pataas at i-hold para i-unpin."</string>
+    <string name="screen_pinning_description_gestural" msgid="7246323931831232068">"Mananatiling nakikita ang app hanggang sa mag-unpin ka. Mag-swipe pataas at i-hold para i-unpin."</string>
     <string name="screen_pinning_description_accessible" msgid="7386449191953535332">"Pinapanatili nitong nakikita ito hanggang sa mag-unpin ka. Pindutin nang matagal ang Overview upang mag-unpin."</string>
     <string name="screen_pinning_description_recents_invisible_accessible" msgid="2857071808674481986">"Pinapanatili nitong nakikita ito hanggang sa mag-unpin ka. Pindutin nang matagal ang Home upang mag-unpin."</string>
     <string name="screen_pinning_exposes_personal_data" msgid="8189852022981524789">"Puwedeng ma-access ang personal na data (tulad ng mga contact at content ng email)."</string>
@@ -618,7 +618,7 @@
     <string name="stream_notification" msgid="7930294049046243939">"Notification"</string>
     <string name="stream_bluetooth_sco" msgid="6234562365528664331">"Bluetooth"</string>
     <string name="stream_dtmf" msgid="7322536356554673067">"Dual multi tone frequency"</string>
-    <string name="stream_accessibility" msgid="3873610336741987152">"Pagiging Accessible"</string>
+    <string name="stream_accessibility" msgid="3873610336741987152">"Accessibility"</string>
     <string name="ring_toggle_title" msgid="5973120187287633224">"Mga Tawag"</string>
     <string name="volume_ringer_status_normal" msgid="1339039682222461143">"Ipa-ring"</string>
     <string name="volume_ringer_status_vibrate" msgid="6970078708957857825">"I-vibrate"</string>
@@ -1002,9 +1002,9 @@
     <string name="bubble_accessibility_action_move_top_right" msgid="6916868852433483569">"Ilipat sa kanan sa itaas"</string>
     <string name="bubble_accessibility_action_move_bottom_left" msgid="6339015902495504715">"Ilipat sa kaliwa sa ibaba"</string>
     <string name="bubble_accessibility_action_move_bottom_right" msgid="7471571700628346212">"Ilipat sa kanan sa ibaba"</string>
-    <string name="bubble_dismiss_text" msgid="7071770411580452911">"I-dismiss"</string>
+    <string name="bubble_dismiss_text" msgid="1314082410868930066">"I-dismiss ang bubble"</string>
     <string name="bubbles_dont_bubble_conversation" msgid="1033040343437428822">"Huwag ipakita sa bubble ang mga pag-uusap"</string>
-    <string name="bubbles_user_education_title" msgid="5547017089271445797">"Makipag-chat gamit ang mga bubble"</string>
+    <string name="bubbles_user_education_title" msgid="5547017089271445797">"Mag-chat gamit ang bubbles"</string>
     <string name="bubbles_user_education_description" msgid="1160281719576715211">"Lumalabas bilang mga nakalutang na icon o bubble ang mga bagong pag-uusap. I-tap para buksan ang bubble. I-drag para ilipat ito."</string>
     <string name="bubbles_user_education_manage_title" msgid="2848511858160342320">"Kontrolin ang mga bubble anumang oras"</string>
     <string name="bubbles_user_education_manage" msgid="1391639189507036423">"I-tap ang Pamahalaan para i-off ang mga bubble mula sa app na ito"</string>
@@ -1062,9 +1062,13 @@
     <string name="controls_structure_tooltip" msgid="4355922222944447867">"Mag-swipe para tumingin ng higit pa"</string>
     <string name="controls_seeding_in_progress" msgid="3033855341410264148">"Nilo-load ang rekomendasyon"</string>
     <string name="controls_media_close_session" msgid="9023534788828414585">"Isara ang session ng media na ito"</string>
+    <string name="controls_media_resume" msgid="1933520684481586053">"Ituloy"</string>
     <string name="controls_error_timeout" msgid="794197289772728958">"Hindi aktibo, tingnan ang app"</string>
     <string name="controls_error_retryable" msgid="864025882878378470">"Nagka-error, sinusubukan ulit…"</string>
-    <string name="controls_error_removed" msgid="6299213591234723805">"Inalis ang device"</string>
+    <string name="controls_error_removed" msgid="6675638069846014366">"Hindi nahanap"</string>
+    <string name="controls_error_removed_title" msgid="1207794911208047818">"Hindi available ang kontrol"</string>
+    <string name="controls_error_removed_message" msgid="2885911717034750542">"Hindi ma-access ang <xliff:g id="DEVICE">%1$s</xliff:g>. Tingnan ang <xliff:g id="APPLICATION">%2$s</xliff:g> app para matiyak na available pa rin ang kontrol at hindi nabago ang mga setting ng app."</string>
+    <string name="controls_open_app" msgid="483650971094300141">"Buksan ang app"</string>
     <string name="controls_error_generic" msgid="352500456918362905">"Hindi ma-load ang status"</string>
     <string name="controls_error_failed" msgid="960228639198558525">"Nagka-error, subukan ulit"</string>
     <string name="controls_in_progress" msgid="4421080500238215939">"Isinasagawa"</string>
diff --git a/packages/SystemUI/res/values-tr/strings.xml b/packages/SystemUI/res/values-tr/strings.xml
index 48268e7..6c6b5bf 100644
--- a/packages/SystemUI/res/values-tr/strings.xml
+++ b/packages/SystemUI/res/values-tr/strings.xml
@@ -139,7 +139,7 @@
     <string name="voice_assist_label" msgid="3725967093735929020">"sesli yardımı aç"</string>
     <string name="camera_label" msgid="8253821920931143699">"kamerayı aç"</string>
     <string name="cancel" msgid="1089011503403416730">"İptal"</string>
-    <string name="biometric_dialog_confirm" msgid="2005978443007344895">"Onaylayın"</string>
+    <string name="biometric_dialog_confirm" msgid="2005978443007344895">"Onayla"</string>
     <string name="biometric_dialog_try_again" msgid="8575345628117768844">"Tekrar dene"</string>
     <string name="biometric_dialog_empty_space_description" msgid="3330555462071453396">"Kimlik doğrulama işlemini iptal etmek için dokunun"</string>
     <string name="biometric_dialog_face_icon_description_idle" msgid="4351777022315116816">"Lütfen tekrar deneyin"</string>
@@ -510,7 +510,7 @@
     <string name="clear_all_notifications_text" msgid="348312370303046130">"Tümünü temizle"</string>
     <string name="manage_notifications_text" msgid="6885645344647733116">"Yönet"</string>
     <string name="manage_notifications_history_text" msgid="57055985396576230">"Geçmiş"</string>
-    <string name="notification_section_header_incoming" msgid="5295312809341711367">"Gelen"</string>
+    <string name="notification_section_header_incoming" msgid="850925217908095197">"Yeni"</string>
     <string name="notification_section_header_gentle" msgid="6804099527336337197">"Sessiz"</string>
     <string name="notification_section_header_alerting" msgid="5581175033680477651">"Bildirimler"</string>
     <string name="notification_section_header_conversations" msgid="821834744538345661">"Görüşmeler"</string>
@@ -1002,7 +1002,7 @@
     <string name="bubble_accessibility_action_move_top_right" msgid="6916868852433483569">"Sağ üste taşı"</string>
     <string name="bubble_accessibility_action_move_bottom_left" msgid="6339015902495504715">"Sol alta taşı"</string>
     <string name="bubble_accessibility_action_move_bottom_right" msgid="7471571700628346212">"Sağ alta taşı"</string>
-    <string name="bubble_dismiss_text" msgid="7071770411580452911">"Kapat"</string>
+    <string name="bubble_dismiss_text" msgid="1314082410868930066">"Baloncuğu kapat"</string>
     <string name="bubbles_dont_bubble_conversation" msgid="1033040343437428822">"Görüşmeyi baloncuk olarak görüntüleme"</string>
     <string name="bubbles_user_education_title" msgid="5547017089271445797">"Baloncukları kullanarak sohbet edin"</string>
     <string name="bubbles_user_education_description" msgid="1160281719576715211">"Yeni görüşmeler kayan simgeler veya baloncuk olarak görünür. Açmak için baloncuğa dokunun. Baloncuğu taşımak için sürükleyin."</string>
@@ -1062,9 +1062,13 @@
     <string name="controls_structure_tooltip" msgid="4355922222944447867">"Diğer öğeleri görmek için hızlıca kaydırın"</string>
     <string name="controls_seeding_in_progress" msgid="3033855341410264148">"Öneriler yükleniyor"</string>
     <string name="controls_media_close_session" msgid="9023534788828414585">"Bu medya oturumunu kapat"</string>
+    <string name="controls_media_resume" msgid="1933520684481586053">"Devam ettir"</string>
     <string name="controls_error_timeout" msgid="794197289772728958">"Devre dışı, uygulamaya bakın"</string>
     <string name="controls_error_retryable" msgid="864025882878378470">"Hata, yeniden deneniyor…"</string>
-    <string name="controls_error_removed" msgid="6299213591234723805">"Cihaz kaldırıldı"</string>
+    <string name="controls_error_removed" msgid="6675638069846014366">"Bulunamadı"</string>
+    <string name="controls_error_removed_title" msgid="1207794911208047818">"Kontrol kullanılamıyor"</string>
+    <string name="controls_error_removed_message" msgid="2885911717034750542">"<xliff:g id="DEVICE">%1$s</xliff:g> cihazına erişilemedi Kontrolün hâlâ kullanılabilir olduğundan ve uygulama ayarlarının değişmediğinden emin olmak için <xliff:g id="APPLICATION">%2$s</xliff:g> uygulamasını kontrol edin."</string>
+    <string name="controls_open_app" msgid="483650971094300141">"Uygulama aç"</string>
     <string name="controls_error_generic" msgid="352500456918362905">"Durum yüklenemiyor"</string>
     <string name="controls_error_failed" msgid="960228639198558525">"Hata, yeniden deneyin"</string>
     <string name="controls_in_progress" msgid="4421080500238215939">"Devam ediyor"</string>
diff --git a/packages/SystemUI/res/values-uk/strings.xml b/packages/SystemUI/res/values-uk/strings.xml
index 38a478c..e192c12 100644
--- a/packages/SystemUI/res/values-uk/strings.xml
+++ b/packages/SystemUI/res/values-uk/strings.xml
@@ -516,7 +516,7 @@
     <string name="clear_all_notifications_text" msgid="348312370303046130">"Очистити все"</string>
     <string name="manage_notifications_text" msgid="6885645344647733116">"Керувати"</string>
     <string name="manage_notifications_history_text" msgid="57055985396576230">"Історія"</string>
-    <string name="notification_section_header_incoming" msgid="5295312809341711367">"Нові"</string>
+    <string name="notification_section_header_incoming" msgid="850925217908095197">"Нові"</string>
     <string name="notification_section_header_gentle" msgid="6804099527336337197">"Без звуку"</string>
     <string name="notification_section_header_alerting" msgid="5581175033680477651">"Сповіщення"</string>
     <string name="notification_section_header_conversations" msgid="821834744538345661">"Розмови"</string>
@@ -609,7 +609,7 @@
     <string name="screen_pinning_toast" msgid="8177286912533744328">"Щоб відкріпити цей додаток, натисніть і утримуйте кнопки \"Назад\" та \"Огляд\""</string>
     <string name="screen_pinning_toast_recents_invisible" msgid="6850978077443052594">"Щоб відкріпити цей додаток, натисніть і утримуйте кнопки \"Назад\" та \"Головний екран\""</string>
     <string name="screen_pinning_toast_gesture_nav" msgid="170699893395336705">"Щоб відкріпити цей додаток, проведіть пальцем вгору й утримуйте його на екрані"</string>
-    <string name="screen_pinning_positive" msgid="3285785989665266984">"Зрозуміло"</string>
+    <string name="screen_pinning_positive" msgid="3285785989665266984">"OK"</string>
     <string name="screen_pinning_negative" msgid="6882816864569211666">"Ні, дякую"</string>
     <string name="screen_pinning_start" msgid="7483998671383371313">"Додаток закріплено"</string>
     <string name="screen_pinning_exit" msgid="4553787518387346893">"Додаток відкріплено"</string>
@@ -673,7 +673,7 @@
     <string name="tuner_warning_title" msgid="7721976098452135267">"Це цікаво, але будьте обачні"</string>
     <string name="tuner_warning" msgid="1861736288458481650">"System UI Tuner пропонує нові способи налаштувати та персоналізувати інтерфейс користувача Android. Ці експериментальні функції можуть змінюватися, не працювати чи зникати в майбутніх версіях. Будьте обачні."</string>
     <string name="tuner_persistent_warning" msgid="230466285569307806">"Ці експериментальні функції можуть змінюватися, не працювати чи зникати в майбутніх версіях. Будьте обачні."</string>
-    <string name="got_it" msgid="477119182261892069">"Зрозуміло"</string>
+    <string name="got_it" msgid="477119182261892069">"OK"</string>
     <string name="tuner_toast" msgid="3812684836514766951">"Вітаємо! System UI Tuner установлено в додатку Налаштування"</string>
     <string name="remove_from_settings" msgid="633775561782209994">"Видалити з додатка Налаштування"</string>
     <string name="remove_from_settings_prompt" msgid="551565437265615426">"Видалити інструмент System UI Tuner із додатка Налаштування та припинити користуватися всіма його функціями?"</string>
@@ -1012,13 +1012,13 @@
     <string name="bubble_accessibility_action_move_top_right" msgid="6916868852433483569">"Перемістити праворуч угору"</string>
     <string name="bubble_accessibility_action_move_bottom_left" msgid="6339015902495504715">"Перемістити ліворуч униз"</string>
     <string name="bubble_accessibility_action_move_bottom_right" msgid="7471571700628346212">"Перемістити праворуч униз"</string>
-    <string name="bubble_dismiss_text" msgid="7071770411580452911">"Закрити"</string>
+    <string name="bubble_dismiss_text" msgid="1314082410868930066">"Закрити підказку"</string>
     <string name="bubbles_dont_bubble_conversation" msgid="1033040343437428822">"Не показувати спливаючі чати для розмов"</string>
-    <string name="bubbles_user_education_title" msgid="5547017089271445797">"Чат зі спливаючими сповіщеннями"</string>
+    <string name="bubbles_user_education_title" msgid="5547017089271445797">"Спливаючий чат"</string>
     <string name="bubbles_user_education_description" msgid="1160281719576715211">"Нові повідомлення чату з\'являються у вигляді спливаючих значків. Щоб відкрити чат, натисніть його, а щоб перемістити – перетягніть."</string>
     <string name="bubbles_user_education_manage_title" msgid="2848511858160342320">"Налаштовуйте спливаючі чати будь-коли"</string>
     <string name="bubbles_user_education_manage" msgid="1391639189507036423">"Натисніть \"Налаштувати\", щоб вимкнути спливаючі чати від цього додатка"</string>
-    <string name="bubbles_user_education_got_it" msgid="8282812431953161143">"Зрозуміло"</string>
+    <string name="bubbles_user_education_got_it" msgid="8282812431953161143">"OK"</string>
     <string name="bubbles_app_settings" msgid="5779443644062348657">"Налаштування параметра \"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g>\""</string>
     <string name="notification_content_system_nav_changed" msgid="5077913144844684544">"Навігацію в системі оновлено. Щоб внести зміни, перейдіть у налаштування."</string>
     <string name="notification_content_gesture_nav_available" msgid="4431460803004659888">"Перейдіть у налаштування, щоб оновити навігацію в системі"</string>
@@ -1074,9 +1074,13 @@
     <string name="controls_structure_tooltip" msgid="4355922222944447867">"Гортайте, щоб переглянути інші"</string>
     <string name="controls_seeding_in_progress" msgid="3033855341410264148">"Завантаження рекомендацій"</string>
     <string name="controls_media_close_session" msgid="9023534788828414585">"Закрити цей сеанс медіа"</string>
+    <string name="controls_media_resume" msgid="1933520684481586053">"Відновити"</string>
     <string name="controls_error_timeout" msgid="794197289772728958">"Неактивно, перейдіть у додаток"</string>
     <string name="controls_error_retryable" msgid="864025882878378470">"Помилка. Повторна спроба…"</string>
-    <string name="controls_error_removed" msgid="6299213591234723805">"Пристрій вилучено"</string>
+    <string name="controls_error_removed" msgid="6675638069846014366">"Не знайдено"</string>
+    <string name="controls_error_removed_title" msgid="1207794911208047818">"Елемент керування недоступний"</string>
+    <string name="controls_error_removed_message" msgid="2885911717034750542">"<xliff:g id="DEVICE">%1$s</xliff:g>: немає доступу. Перевірте в додатку <xliff:g id="APPLICATION">%2$s</xliff:g>, чи його налаштування не змінились і чи елемент керування доступний."</string>
+    <string name="controls_open_app" msgid="483650971094300141">"Відкрити додаток"</string>
     <string name="controls_error_generic" msgid="352500456918362905">"Не вдалося завантажити статус"</string>
     <string name="controls_error_failed" msgid="960228639198558525">"Помилка. Спробуйте знову"</string>
     <string name="controls_in_progress" msgid="4421080500238215939">"Виконується"</string>
diff --git a/packages/SystemUI/res/values-ur/strings.xml b/packages/SystemUI/res/values-ur/strings.xml
index ac99a7b..d382f423 100644
--- a/packages/SystemUI/res/values-ur/strings.xml
+++ b/packages/SystemUI/res/values-ur/strings.xml
@@ -510,7 +510,7 @@
     <string name="clear_all_notifications_text" msgid="348312370303046130">"سبھی کو صاف کریں"</string>
     <string name="manage_notifications_text" msgid="6885645344647733116">"نظم کریں"</string>
     <string name="manage_notifications_history_text" msgid="57055985396576230">"سرگزشت"</string>
-    <string name="notification_section_header_incoming" msgid="5295312809341711367">"اِن کمنگ"</string>
+    <string name="notification_section_header_incoming" msgid="850925217908095197">"نیا"</string>
     <string name="notification_section_header_gentle" msgid="6804099527336337197">"خاموش"</string>
     <string name="notification_section_header_alerting" msgid="5581175033680477651">"اطلاعات"</string>
     <string name="notification_section_header_conversations" msgid="821834744538345661">"گفتگوئیں"</string>
@@ -595,7 +595,7 @@
     <string name="screen_pinning_title" msgid="9058007390337841305">"ایپ کو پن کر دیا گیا ہے"</string>
     <string name="screen_pinning_description" msgid="8699395373875667743">"یہ اسے اس وقت تک نظر میں رکھتا ہے جب تک آپ اس سے پن ہٹا نہیں دیتے۔ پن ہٹانے کیلئے پیچھے اور مجموعی جائزہ بٹنز کو ٹچ کریں اور دبائے رکھیں۔"</string>
     <string name="screen_pinning_description_recents_invisible" msgid="4564466648700390037">"یہ اس کو اس وقت تک مد نظر رکھتا ہے جب تک آپ اس سے پن نہیں ہٹا دیتے۔ پن ہٹانے کیلئے \"پیچھے\" اور \"ہوم\" بٹنز کو ٹچ کریں اور دبائے رکھیں۔"</string>
-    <string name="screen_pinning_description_gestural" msgid="7246323931831232068">"یہ اس کو اس وقت تک مد نظر رکھتا ہے جب تک آپ اس سے پن نہیں ہٹا دیتے۔ پن ہٹانے کے لیے سوائپ کریں اور پکڑ کر رکھیں۔"</string>
+    <string name="screen_pinning_description_gestural" msgid="7246323931831232068">"یہ اس کو اس وقت تک مد نظر رکھتا ہے جب تک آپ اس سے پن نہیں ہٹا دیتے۔ پن ہٹانے کے لیے اوپر سوائپ کریں اور پکڑ کر رکھیں۔"</string>
     <string name="screen_pinning_description_accessible" msgid="7386449191953535332">"یہ اسے اس وقت تک نظر میں رکھتا ہے جب تک آپ اس سے پن ہٹا نہیں دیتے۔ پن ہٹانے کیلئے مجموعی جائزہ بٹن کو ٹچ کریں اور دبائے رکھیں۔"</string>
     <string name="screen_pinning_description_recents_invisible_accessible" msgid="2857071808674481986">"یہ اس کو اس وقت تک مد نظر رکھتا ہے جب تک آپ اس سے پن نہیں ہٹا دیتے۔ پن ہٹانے کیلئے \"ہوم\" بٹن کو ٹچ کریں اور دبائے رکھیں۔"</string>
     <string name="screen_pinning_exposes_personal_data" msgid="8189852022981524789">"ذاتی ڈیٹا قابل رسائی ہو سکتا ہے (جیسے رابطے اور ای میل کا مواد)۔"</string>
@@ -1002,7 +1002,7 @@
     <string name="bubble_accessibility_action_move_top_right" msgid="6916868852433483569">"اوپر دائیں جانب لے جائيں"</string>
     <string name="bubble_accessibility_action_move_bottom_left" msgid="6339015902495504715">"نیچے بائیں جانب لے جائیں"</string>
     <string name="bubble_accessibility_action_move_bottom_right" msgid="7471571700628346212">"نیچے دائیں جانب لے جائیں"</string>
-    <string name="bubble_dismiss_text" msgid="7071770411580452911">"برخاست کریں"</string>
+    <string name="bubble_dismiss_text" msgid="1314082410868930066">"بلبلہ برخاست کریں"</string>
     <string name="bubbles_dont_bubble_conversation" msgid="1033040343437428822">"بلبلہ گفتگو نہ کریں"</string>
     <string name="bubbles_user_education_title" msgid="5547017089271445797">"بلبلے کے ذریعے چیٹ کریں"</string>
     <string name="bubbles_user_education_description" msgid="1160281719576715211">"نئی گفتگوئیں فلوٹنگ آئیکن یا بلبلے کے طور پر ظاہر ہوں گی۔ بلبلہ کھولنے کے لیے تھپتھپائیں۔ اسے منتقل کرنے کے لیے گھسیٹیں۔"</string>
@@ -1013,17 +1013,14 @@
     <string name="notification_content_system_nav_changed" msgid="5077913144844684544">"سسٹم نیویگیشن اپ ڈیٹ کیا گیا۔ تبدیلیاں کرنے کے لیے، ترتیبات پر جائیں۔"</string>
     <string name="notification_content_gesture_nav_available" msgid="4431460803004659888">"سسٹم نیویگیشن اپ ڈیٹ کرنے کے لیے ترتیبات پر جائیں"</string>
     <string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"اسٹینڈ بائی"</string>
-    <!-- no translation found for priority_onboarding_title (2893070698479227616) -->
-    <skip />
-    <!-- no translation found for priority_onboarding_behavior (5342816047020432929) -->
-    <skip />
+    <string name="priority_onboarding_title" msgid="2893070698479227616">"گفتگو کو ترجیح پر سیٹ کیا گیا"</string>
+    <string name="priority_onboarding_behavior" msgid="5342816047020432929">"ترجیحی گفتگوئیں یہ ہوگی:"</string>
     <string name="priority_onboarding_show_at_top_text" msgid="1678400241025513541">"گفتگو کے سیکشن میں سب سے اوپر دکھائیں"</string>
     <string name="priority_onboarding_show_avatar_text" msgid="5756291381124091508">"مقفل سکرین پر پروفائل کی تصویر دکھائیں"</string>
     <string name="priority_onboarding_appear_as_bubble_text" msgid="4227039772250263122">"ایپس کے سب سے اوپر فلوٹنگ بلبلہ کے طور پر ظاہر ہوں"</string>
     <string name="priority_onboarding_ignores_dnd_text" msgid="2918952762719600529">"ڈسٹرب نہ کریں میں مداخلت کریں"</string>
     <string name="priority_onboarding_done_button_title" msgid="4569550984286506007">"سمجھ آ گئی"</string>
-    <!-- no translation found for priority_onboarding_settings_button_title (6663601574303585927) -->
-    <skip />
+    <string name="priority_onboarding_settings_button_title" msgid="6663601574303585927">"ترتیبات"</string>
     <string name="magnification_overlay_title" msgid="6584179429612427958">"میگنیفیکیشن اوورلے ونڈو"</string>
     <string name="magnification_window_title" msgid="4863914360847258333">"میگنیفکیشن ونڈو"</string>
     <string name="magnification_controls_title" msgid="8421106606708891519">"میگنیفکیشن ونڈو کنٹرولز"</string>
@@ -1065,9 +1062,13 @@
     <string name="controls_structure_tooltip" msgid="4355922222944447867">"مزید دیکھنے کیلئے سوائپ کریں"</string>
     <string name="controls_seeding_in_progress" msgid="3033855341410264148">"تجاویز لوڈ ہو رہی ہیں"</string>
     <string name="controls_media_close_session" msgid="9023534788828414585">"اس میڈیا سیشن کو بند کریں"</string>
+    <string name="controls_media_resume" msgid="1933520684481586053">"دوبارہ شروع کریں"</string>
     <string name="controls_error_timeout" msgid="794197289772728958">"غیر فعال، ایپ چیک کریں"</string>
     <string name="controls_error_retryable" msgid="864025882878378470">"خرابی، دوبارہ کوشش کی جا رہی ہے…"</string>
-    <string name="controls_error_removed" msgid="6299213591234723805">"آلہ ہٹا دیا گیا"</string>
+    <string name="controls_error_removed" msgid="6675638069846014366">"نہیں ملا"</string>
+    <string name="controls_error_removed_title" msgid="1207794911208047818">"کنٹرول دستیاب نہیں ہے"</string>
+    <string name="controls_error_removed_message" msgid="2885911717034750542">"<xliff:g id="DEVICE">%1$s</xliff:g> تک رسائی حاصل نہیں ہو سکی۔ اس بات کو یقینی بنانے کے لیے کہ کنٹرول ابھی بھی دستیاب ہے اور ایپ کی ترتیبات تبدیل نہیں ہوئی، تو <xliff:g id="APPLICATION">%2$s</xliff:g> ایپ چیک کریں۔"</string>
+    <string name="controls_open_app" msgid="483650971094300141">"ایپ کھولیں"</string>
     <string name="controls_error_generic" msgid="352500456918362905">"صورتحال لوڈ نہیں ہو سکتی"</string>
     <string name="controls_error_failed" msgid="960228639198558525">"خرابی، دوبارہ کوشش کریں"</string>
     <string name="controls_in_progress" msgid="4421080500238215939">"پیشرفت میں"</string>
diff --git a/packages/SystemUI/res/values-uz/strings.xml b/packages/SystemUI/res/values-uz/strings.xml
index 518f60c..3099270 100644
--- a/packages/SystemUI/res/values-uz/strings.xml
+++ b/packages/SystemUI/res/values-uz/strings.xml
@@ -510,7 +510,7 @@
     <string name="clear_all_notifications_text" msgid="348312370303046130">"Hammasini tozalash"</string>
     <string name="manage_notifications_text" msgid="6885645344647733116">"Boshqarish"</string>
     <string name="manage_notifications_history_text" msgid="57055985396576230">"Tarix"</string>
-    <string name="notification_section_header_incoming" msgid="5295312809341711367">"Kiruvchi"</string>
+    <string name="notification_section_header_incoming" msgid="850925217908095197">"Yangi"</string>
     <string name="notification_section_header_gentle" msgid="6804099527336337197">"Sokin"</string>
     <string name="notification_section_header_alerting" msgid="5581175033680477651">"Bildirishnomalar"</string>
     <string name="notification_section_header_conversations" msgid="821834744538345661">"Suhbatlar"</string>
@@ -725,7 +725,7 @@
     <string name="notification_unblockable_desc" msgid="2073030886006190804">"Bu bildirishnomalarni tahrirlash imkonsiz."</string>
     <string name="notification_multichannel_desc" msgid="7414593090056236179">"Ushbu bildirishnomalar guruhi bu yerda sozlanmaydi"</string>
     <string name="notification_delegate_header" msgid="1264510071031479920">"Ishonchli bildirishnoma"</string>
-    <string name="notification_channel_dialog_title" msgid="6856514143093200019">"<xliff:g id="APP_NAME">%1$s</xliff:g> ilovasining barcha bildirishnomalari"</string>
+    <string name="notification_channel_dialog_title" msgid="6856514143093200019">"Barcha <xliff:g id="APP_NAME">%1$s</xliff:g> bildirishnomalari"</string>
     <string name="see_more_title" msgid="7409317011708185729">"Yana"</string>
     <string name="appops_camera" msgid="5215967620896725715">"Bu ilova kameradan foydalanmoqda."</string>
     <string name="appops_microphone" msgid="8805468338613070149">"Bu ilova mikrofondan foydalanmoqda."</string>
@@ -1002,7 +1002,7 @@
     <string name="bubble_accessibility_action_move_top_right" msgid="6916868852433483569">"Yuqori oʻngga surish"</string>
     <string name="bubble_accessibility_action_move_bottom_left" msgid="6339015902495504715">"Quyi chapga surish"</string>
     <string name="bubble_accessibility_action_move_bottom_right" msgid="7471571700628346212">"Quyi oʻngga surish"</string>
-    <string name="bubble_dismiss_text" msgid="7071770411580452911">"Yopish"</string>
+    <string name="bubble_dismiss_text" msgid="1314082410868930066">"Pufakni yopish"</string>
     <string name="bubbles_dont_bubble_conversation" msgid="1033040343437428822">"Suhbatlar bulutchalar shaklida chiqmasin"</string>
     <string name="bubbles_user_education_title" msgid="5547017089271445797">"Bulutchalar yordamida subhatlashish"</string>
     <string name="bubbles_user_education_description" msgid="1160281719576715211">"Yangi xabarlar qalqib chiquvchi belgilar yoki bulutchalar kabi chiqadi. Xabarni ochish uchun bildirishnoma ustiga bosing. Xabarni qayta joylash uchun bildirishnomani suring."</string>
@@ -1062,9 +1062,13 @@
     <string name="controls_structure_tooltip" msgid="4355922222944447867">"Batafsil axborot olish uchun suring"</string>
     <string name="controls_seeding_in_progress" msgid="3033855341410264148">"Tavsiyalar yuklanmoqda"</string>
     <string name="controls_media_close_session" msgid="9023534788828414585">"Bu media seansni yopish"</string>
+    <string name="controls_media_resume" msgid="1933520684481586053">"Davom etish"</string>
     <string name="controls_error_timeout" msgid="794197289772728958">"Nofaol. Ilovani tekshiring"</string>
     <string name="controls_error_retryable" msgid="864025882878378470">"Xato, qayta urinilmoqda…"</string>
-    <string name="controls_error_removed" msgid="6299213591234723805">"Qurilma olib tashlandi"</string>
+    <string name="controls_error_removed" msgid="6675638069846014366">"Topilmadi"</string>
+    <string name="controls_error_removed_title" msgid="1207794911208047818">"Boshqarish imkonsiz"</string>
+    <string name="controls_error_removed_message" msgid="2885911717034750542">"<xliff:g id="DEVICE">%1$s</xliff:g> ochilmadi. <xliff:g id="APPLICATION">%2$s</xliff:g> ilovasining sozlamalari oʻzgarmaganini va hali ham boshqarishga ruxsat borligini tekshiring."</string>
+    <string name="controls_open_app" msgid="483650971094300141">"Ilovani ochish"</string>
     <string name="controls_error_generic" msgid="352500456918362905">"Holat axboroti yuklanmadi"</string>
     <string name="controls_error_failed" msgid="960228639198558525">"Xato, qayta urining"</string>
     <string name="controls_in_progress" msgid="4421080500238215939">"Bajarilmoqda"</string>
diff --git a/packages/SystemUI/res/values-vi/strings.xml b/packages/SystemUI/res/values-vi/strings.xml
index 00e0cf7..cc6a8fd2 100644
--- a/packages/SystemUI/res/values-vi/strings.xml
+++ b/packages/SystemUI/res/values-vi/strings.xml
@@ -510,7 +510,7 @@
     <string name="clear_all_notifications_text" msgid="348312370303046130">"Xóa tất cả"</string>
     <string name="manage_notifications_text" msgid="6885645344647733116">"Quản lý"</string>
     <string name="manage_notifications_history_text" msgid="57055985396576230">"Lịch sử"</string>
-    <string name="notification_section_header_incoming" msgid="5295312809341711367">"Hiển thị gần đây"</string>
+    <string name="notification_section_header_incoming" msgid="850925217908095197">"Mới"</string>
     <string name="notification_section_header_gentle" msgid="6804099527336337197">"Im lặng"</string>
     <string name="notification_section_header_alerting" msgid="5581175033680477651">"Thông báo"</string>
     <string name="notification_section_header_conversations" msgid="821834744538345661">"Cuộc trò chuyện"</string>
@@ -593,12 +593,12 @@
     <string name="volume_odi_captions_hint_disable" msgid="2518846326748183407">"tắt"</string>
     <string name="accessibility_output_chooser" msgid="7807898688967194183">"Chuyển đổi thiết bị đầu ra"</string>
     <string name="screen_pinning_title" msgid="9058007390337841305">"Đã ghim ứng dụng"</string>
-    <string name="screen_pinning_description" msgid="8699395373875667743">"Thao tác này sẽ duy trì hiển thị màn hình cho đến khi bạn bỏ ghim. Hãy chạm và giữ Quay lại và Tổng quan để bỏ ghim."</string>
-    <string name="screen_pinning_description_recents_invisible" msgid="4564466648700390037">"Thao tác này sẽ duy trì hiển thị màn hình cho đến khi bạn bỏ ghim. Hãy chạm và giữ nút Quay lại và nút Màn hình chính để bỏ ghim."</string>
-    <string name="screen_pinning_description_gestural" msgid="7246323931831232068">"Màn hình tiếp tục hiển thị cho tới khi bạn bỏ ghim. Hãy vuốt lên và giữ để bỏ ghim."</string>
-    <string name="screen_pinning_description_accessible" msgid="7386449191953535332">"Thao tác này sẽ duy trì hiển thị màn hình cho đến khi bạn bỏ ghim. Hãy chạm và giữ Tổng quan để bỏ ghim."</string>
-    <string name="screen_pinning_description_recents_invisible_accessible" msgid="2857071808674481986">"Thao tác này sẽ duy trì hiển thị màn hình cho đến khi bạn bỏ ghim. Hãy chạm và giữ nút Màn hình chính để bỏ ghim."</string>
-    <string name="screen_pinning_exposes_personal_data" msgid="8189852022981524789">"Dữ liệu cá nhân có thể bị truy cập (chẳng hạn như danh bạ và nội dung email)."</string>
+    <string name="screen_pinning_description" msgid="8699395373875667743">"Ứng dụng này sẽ ở cố định trên màn hình cho đến khi bạn bỏ ghim. Hãy chạm và giữ Quay lại và Tổng quan để bỏ ghim."</string>
+    <string name="screen_pinning_description_recents_invisible" msgid="4564466648700390037">"Ứng dụng này sẽ ở cố định trên màn hình cho đến khi bạn bỏ ghim. Hãy chạm và giữ nút Quay lại và nút Màn hình chính để bỏ ghim."</string>
+    <string name="screen_pinning_description_gestural" msgid="7246323931831232068">"Ứng dụng này sẽ ở cố định trên màn hình cho đến khi bạn bỏ ghim. Hãy vuốt lên và giữ để bỏ ghim."</string>
+    <string name="screen_pinning_description_accessible" msgid="7386449191953535332">"Ứng dụng này sẽ ở cố định trên màn hình cho đến khi bạn bỏ ghim. Hãy chạm và giữ Tổng quan để bỏ ghim."</string>
+    <string name="screen_pinning_description_recents_invisible_accessible" msgid="2857071808674481986">"Ứng dụng này sẽ ở cố định trên màn hình cho đến khi bạn bỏ ghim. Hãy chạm và giữ nút Màn hình chính để bỏ ghim."</string>
+    <string name="screen_pinning_exposes_personal_data" msgid="8189852022981524789">"Ứng dụng này có thể truy cập dữ liệu cá nhân (chẳng hạn như danh bạ và nội dung email)."</string>
     <string name="screen_pinning_can_open_other_apps" msgid="7529756813231421455">"Ứng dụng đã ghim có thể mở các ứng dụng khác."</string>
     <string name="screen_pinning_toast" msgid="8177286912533744328">"Để bỏ ghim ứng dụng này, hãy chạm và giữ nút Quay lại và nút Tổng quan"</string>
     <string name="screen_pinning_toast_recents_invisible" msgid="6850978077443052594">"Để bỏ ghim ứng dụng này, hãy chạm và giữ nút Quay lại và nút Màn hình chính"</string>
@@ -1002,10 +1002,10 @@
     <string name="bubble_accessibility_action_move_top_right" msgid="6916868852433483569">"Chuyển lên trên cùng bên phải"</string>
     <string name="bubble_accessibility_action_move_bottom_left" msgid="6339015902495504715">"Chuyển tới dưới cùng bên trái"</string>
     <string name="bubble_accessibility_action_move_bottom_right" msgid="7471571700628346212">"Chuyển tới dưới cùng bên phải"</string>
-    <string name="bubble_dismiss_text" msgid="7071770411580452911">"Loại bỏ"</string>
+    <string name="bubble_dismiss_text" msgid="1314082410868930066">"Đóng bong bóng"</string>
     <string name="bubbles_dont_bubble_conversation" msgid="1033040343437428822">"Dừng trò chuyện bằng bong bóng"</string>
     <string name="bubbles_user_education_title" msgid="5547017089271445797">"Trò chuyện bằng bong bóng trò chuyện"</string>
-    <string name="bubbles_user_education_description" msgid="1160281719576715211">"Các cuộc trò chuyện mới hiển thị dưới dạng biểu tượng nổi hoặc bong bóng trò chuyện. Nhấn để mở bong bóng trò chuyện. Kéo để di chuyển bong bóng trò chuyện."</string>
+    <string name="bubbles_user_education_description" msgid="1160281719576715211">"Các cuộc trò chuyện mới sẽ xuất hiện dưới dạng biểu tượng nổi hoặc bong bóng trò chuyện. Nhấn để mở bong bóng trò chuyện. Kéo để di chuyển bong bóng trò chuyện."</string>
     <string name="bubbles_user_education_manage_title" msgid="2848511858160342320">"Kiểm soát tùy chọn cài đặt bong bóng trò chuyện bất mọi lúc"</string>
     <string name="bubbles_user_education_manage" msgid="1391639189507036423">"Nhấn vào nút Quản lý để tắt bong bóng trò chuyện từ ứng dụng này"</string>
     <string name="bubbles_user_education_got_it" msgid="8282812431953161143">"OK"</string>
@@ -1062,9 +1062,13 @@
     <string name="controls_structure_tooltip" msgid="4355922222944447867">"Vuốt để xem thêm"</string>
     <string name="controls_seeding_in_progress" msgid="3033855341410264148">"Đang tải các đề xuất"</string>
     <string name="controls_media_close_session" msgid="9023534788828414585">"Đóng phiên đa phương tiện này"</string>
+    <string name="controls_media_resume" msgid="1933520684481586053">"Tiếp tục"</string>
     <string name="controls_error_timeout" msgid="794197289772728958">"Không hoạt động, hãy kiểm tra ứng dụng"</string>
     <string name="controls_error_retryable" msgid="864025882878378470">"Lỗi, đang thử lại…"</string>
-    <string name="controls_error_removed" msgid="6299213591234723805">"Đã xóa thiết bị"</string>
+    <string name="controls_error_removed" msgid="6675638069846014366">"Không tìm thấy"</string>
+    <string name="controls_error_removed_title" msgid="1207794911208047818">"Không có chức năng điều khiển"</string>
+    <string name="controls_error_removed_message" msgid="2885911717034750542">"Không thể sử dụng <xliff:g id="DEVICE">%1$s</xliff:g>. Hãy kiểm tra ứng dụng <xliff:g id="APPLICATION">%2$s</xliff:g> để đảm bảo rằng vẫn chức năng điều khiển vẫn dùng được và thông tin cài đặt của ứng dụng chưa thay đổi."</string>
+    <string name="controls_open_app" msgid="483650971094300141">"Mở ứng dụng"</string>
     <string name="controls_error_generic" msgid="352500456918362905">"Không tải được trạng thái"</string>
     <string name="controls_error_failed" msgid="960228639198558525">"Lỗi, hãy thử lại"</string>
     <string name="controls_in_progress" msgid="4421080500238215939">"Đang thực hiện"</string>
diff --git a/packages/SystemUI/res/values-w550dp-land/config.xml b/packages/SystemUI/res/values-w550dp-land/config.xml
index 16d5317..a33f131 100644
--- a/packages/SystemUI/res/values-w550dp-land/config.xml
+++ b/packages/SystemUI/res/values-w550dp-land/config.xml
@@ -20,9 +20,5 @@
 <!-- These resources are around just to allow their values to be customized
      for different hardware and product builds. -->
 <resources>
-
-    <!-- Whether QuickSettings is in a phone landscape -->
-    <bool name="quick_settings_wide">true</bool>
-
-    <integer name="quick_settings_num_columns">4</integer>
+    <integer name="quick_settings_num_columns">6</integer>
 </resources>
diff --git a/packages/SystemUI/res/values-w550dp-land/dimens.xml b/packages/SystemUI/res/values-w550dp-land/dimens.xml
deleted file mode 100644
index 017ca69..0000000
--- a/packages/SystemUI/res/values-w550dp-land/dimens.xml
+++ /dev/null
@@ -1,22 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
- * Copyright (c) 2016, 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.
-*/
--->
-<resources>
-    <!-- Standard notification width + gravity -->
-    <dimen name="notification_panel_width">544dp</dimen>
-
-</resources>
diff --git a/packages/SystemUI/res/color/qs_user_detail_avatar_tint.xml b/packages/SystemUI/res/values-w650dp-land/dimens.xml
similarity index 64%
copy from packages/SystemUI/res/color/qs_user_detail_avatar_tint.xml
copy to packages/SystemUI/res/values-w650dp-land/dimens.xml
index 696e9b1..108d6cf 100644
--- a/packages/SystemUI/res/color/qs_user_detail_avatar_tint.xml
+++ b/packages/SystemUI/res/values-w650dp-land/dimens.xml
@@ -1,7 +1,6 @@
 <?xml version="1.0" encoding="utf-8"?>
-
 <!--
-  ~ Copyright (C) 2016 The Android Open Source Project
+  ~ Copyright (C) 2020 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.
@@ -13,10 +12,10 @@
   ~ 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
+  ~ limitations under the License.
   -->
+<resources>
+    <!-- Standard notification width + gravity -->
+    <dimen name="notification_panel_width">644dp</dimen>
 
-<selector xmlns:android="http://schemas.android.com/apk/res/android">
-    <item android:state_enabled="false" android:color="?android:attr/textColorPrimary" />
-    <item android:color="@android:color/transparent" />
-</selector>
+</resources>
diff --git a/packages/SystemUI/res/values-zh-rCN/strings.xml b/packages/SystemUI/res/values-zh-rCN/strings.xml
index 2664830..73fac04 100644
--- a/packages/SystemUI/res/values-zh-rCN/strings.xml
+++ b/packages/SystemUI/res/values-zh-rCN/strings.xml
@@ -510,7 +510,7 @@
     <string name="clear_all_notifications_text" msgid="348312370303046130">"全部清除"</string>
     <string name="manage_notifications_text" msgid="6885645344647733116">"管理"</string>
     <string name="manage_notifications_history_text" msgid="57055985396576230">"历史记录"</string>
-    <string name="notification_section_header_incoming" msgid="5295312809341711367">"收到的通知"</string>
+    <string name="notification_section_header_incoming" msgid="850925217908095197">"新"</string>
     <string name="notification_section_header_gentle" msgid="6804099527336337197">"静音"</string>
     <string name="notification_section_header_alerting" msgid="5581175033680477651">"通知"</string>
     <string name="notification_section_header_conversations" msgid="821834744538345661">"对话"</string>
@@ -1002,7 +1002,7 @@
     <string name="bubble_accessibility_action_move_top_right" msgid="6916868852433483569">"移至右上角"</string>
     <string name="bubble_accessibility_action_move_bottom_left" msgid="6339015902495504715">"移至左下角"</string>
     <string name="bubble_accessibility_action_move_bottom_right" msgid="7471571700628346212">"移至右下角"</string>
-    <string name="bubble_dismiss_text" msgid="7071770411580452911">"关闭"</string>
+    <string name="bubble_dismiss_text" msgid="1314082410868930066">"关闭对话泡"</string>
     <string name="bubbles_dont_bubble_conversation" msgid="1033040343437428822">"不以对话泡形式显示对话"</string>
     <string name="bubbles_user_education_title" msgid="5547017089271445797">"使用对话泡聊天"</string>
     <string name="bubbles_user_education_description" msgid="1160281719576715211">"新对话会以浮动图标或对话泡形式显示。点按即可打开对话泡。拖动即可移动对话泡。"</string>
@@ -1062,9 +1062,13 @@
     <string name="controls_structure_tooltip" msgid="4355922222944447867">"滑动可查看更多结构"</string>
     <string name="controls_seeding_in_progress" msgid="3033855341410264148">"正在加载推荐内容"</string>
     <string name="controls_media_close_session" msgid="9023534788828414585">"关闭此媒体会话"</string>
+    <string name="controls_media_resume" msgid="1933520684481586053">"继续播放"</string>
     <string name="controls_error_timeout" msgid="794197289772728958">"无效,请检查应用"</string>
     <string name="controls_error_retryable" msgid="864025882878378470">"出现错误,正在重试…"</string>
-    <string name="controls_error_removed" msgid="6299213591234723805">"设备已移除"</string>
+    <string name="controls_error_removed" msgid="6675638069846014366">"未找到"</string>
+    <string name="controls_error_removed_title" msgid="1207794911208047818">"控件不可用"</string>
+    <string name="controls_error_removed_message" msgid="2885911717034750542">"无法访问<xliff:g id="DEVICE">%1$s</xliff:g>。请查看<xliff:g id="APPLICATION">%2$s</xliff:g>应用,确保其中仍有该控件,并且应用设置没有更改。"</string>
+    <string name="controls_open_app" msgid="483650971094300141">"打开应用"</string>
     <string name="controls_error_generic" msgid="352500456918362905">"无法加载状态"</string>
     <string name="controls_error_failed" msgid="960228639198558525">"出现错误,请重试"</string>
     <string name="controls_in_progress" msgid="4421080500238215939">"正在进行"</string>
diff --git a/packages/SystemUI/res/values-zh-rHK/strings.xml b/packages/SystemUI/res/values-zh-rHK/strings.xml
index 34b7690..5f5c85f 100644
--- a/packages/SystemUI/res/values-zh-rHK/strings.xml
+++ b/packages/SystemUI/res/values-zh-rHK/strings.xml
@@ -510,7 +510,7 @@
     <string name="clear_all_notifications_text" msgid="348312370303046130">"全部清除"</string>
     <string name="manage_notifications_text" msgid="6885645344647733116">"管理"</string>
     <string name="manage_notifications_history_text" msgid="57055985396576230">"記錄"</string>
-    <string name="notification_section_header_incoming" msgid="5295312809341711367">"收到的通知"</string>
+    <string name="notification_section_header_incoming" msgid="850925217908095197">"新"</string>
     <string name="notification_section_header_gentle" msgid="6804099527336337197">"靜音"</string>
     <string name="notification_section_header_alerting" msgid="5581175033680477651">"通知"</string>
     <string name="notification_section_header_conversations" msgid="821834744538345661">"對話"</string>
@@ -1002,7 +1002,7 @@
     <string name="bubble_accessibility_action_move_top_right" msgid="6916868852433483569">"移去右上角"</string>
     <string name="bubble_accessibility_action_move_bottom_left" msgid="6339015902495504715">"移去左下角"</string>
     <string name="bubble_accessibility_action_move_bottom_right" msgid="7471571700628346212">"移去右下角"</string>
-    <string name="bubble_dismiss_text" msgid="7071770411580452911">"關閉"</string>
+    <string name="bubble_dismiss_text" msgid="1314082410868930066">"關閉對話氣泡"</string>
     <string name="bubbles_dont_bubble_conversation" msgid="1033040343437428822">"不要透過小視窗顯示對話"</string>
     <string name="bubbles_user_education_title" msgid="5547017089271445797">"使用小視窗進行即時通訊"</string>
     <string name="bubbles_user_education_description" msgid="1160281719576715211">"新對話會以浮動圖示 (小視窗) 顯示。輕按即可開啟小視窗。拖曳即可移動小視窗。"</string>
@@ -1062,9 +1062,13 @@
     <string name="controls_structure_tooltip" msgid="4355922222944447867">"滑動以查看更多"</string>
     <string name="controls_seeding_in_progress" msgid="3033855341410264148">"正在載入建議"</string>
     <string name="controls_media_close_session" msgid="9023534788828414585">"關閉此媒體版面"</string>
+    <string name="controls_media_resume" msgid="1933520684481586053">"繼續播放"</string>
     <string name="controls_error_timeout" msgid="794197289772728958">"已停用,請檢查應用程式"</string>
     <string name="controls_error_retryable" msgid="864025882878378470">"發生錯誤,正在重試…"</string>
-    <string name="controls_error_removed" msgid="6299213591234723805">"已移除裝置"</string>
+    <string name="controls_error_removed" msgid="6675638069846014366">"找不到"</string>
+    <string name="controls_error_removed_title" msgid="1207794911208047818">"無法使用控制功能"</string>
+    <string name="controls_error_removed_message" msgid="2885911717034750542">"無法存取 <xliff:g id="DEVICE">%1$s</xliff:g>。請檢查 <xliff:g id="APPLICATION">%2$s</xliff:g> 應用程式,確定控制功能仍可使用,同時應用程式設定並無變更。"</string>
+    <string name="controls_open_app" msgid="483650971094300141">"開啟應用程式"</string>
     <string name="controls_error_generic" msgid="352500456918362905">"無法載入狀態"</string>
     <string name="controls_error_failed" msgid="960228639198558525">"發生錯誤,請再試一次"</string>
     <string name="controls_in_progress" msgid="4421080500238215939">"進行中"</string>
diff --git a/packages/SystemUI/res/values-zh-rTW/strings.xml b/packages/SystemUI/res/values-zh-rTW/strings.xml
index 5f3911a..9847871 100644
--- a/packages/SystemUI/res/values-zh-rTW/strings.xml
+++ b/packages/SystemUI/res/values-zh-rTW/strings.xml
@@ -510,7 +510,7 @@
     <string name="clear_all_notifications_text" msgid="348312370303046130">"全部清除"</string>
     <string name="manage_notifications_text" msgid="6885645344647733116">"管理"</string>
     <string name="manage_notifications_history_text" msgid="57055985396576230">"記錄"</string>
-    <string name="notification_section_header_incoming" msgid="5295312809341711367">"收到的通知"</string>
+    <string name="notification_section_header_incoming" msgid="850925217908095197">"最新"</string>
     <string name="notification_section_header_gentle" msgid="6804099527336337197">"靜音"</string>
     <string name="notification_section_header_alerting" msgid="5581175033680477651">"通知"</string>
     <string name="notification_section_header_conversations" msgid="821834744538345661">"對話"</string>
@@ -595,11 +595,11 @@
     <string name="screen_pinning_title" msgid="9058007390337841305">"應用程式已固定"</string>
     <string name="screen_pinning_description" msgid="8699395373875667743">"這會讓目前的螢幕畫面保持顯示狀態,直到取消固定為止。按住 [返回] 按鈕和 [總覽] 按鈕即可取消固定。"</string>
     <string name="screen_pinning_description_recents_invisible" msgid="4564466648700390037">"這會讓應用程式顯示在螢幕上,直到取消固定為止。按住 [返回] 按鈕和主螢幕按鈕即可取消固定。"</string>
-    <string name="screen_pinning_description_gestural" msgid="7246323931831232068">"這會讓目前的螢幕畫面保持顯示狀態,直到取消固定為止。向上滑動並按住即可取消固定。"</string>
+    <string name="screen_pinning_description_gestural" msgid="7246323931831232068">"這會讓目前的螢幕畫面保持顯示,直到取消固定為止。向上滑動並按住即可取消固定。"</string>
     <string name="screen_pinning_description_accessible" msgid="7386449191953535332">"這會讓目前的螢幕畫面保持顯示狀態,直到取消固定為止。按住 [總覽] 按鈕即可取消固定。"</string>
     <string name="screen_pinning_description_recents_invisible_accessible" msgid="2857071808674481986">"這會讓應用程式顯示在螢幕上,直到取消固定為止。按住主螢幕按鈕即可取消固定。"</string>
     <string name="screen_pinning_exposes_personal_data" msgid="8189852022981524789">"個人資料 (例如聯絡人和電子郵件內容) 可能會遭存取。"</string>
-    <string name="screen_pinning_can_open_other_apps" msgid="7529756813231421455">"已設為固定的應用程式或許仍可開啟其他應用程式。"</string>
+    <string name="screen_pinning_can_open_other_apps" msgid="7529756813231421455">"已設為固定的應用程式仍可開啟其他應用程式。"</string>
     <string name="screen_pinning_toast" msgid="8177286912533744328">"如要取消固定這個應用程式,請按住「返回」按鈕和「總覽」按鈕"</string>
     <string name="screen_pinning_toast_recents_invisible" msgid="6850978077443052594">"如要取消固定這個應用程式,請按住「返回」按鈕和主畫面按鈕"</string>
     <string name="screen_pinning_toast_gesture_nav" msgid="170699893395336705">"如要取消固定這個應用程式,請向上滑動並按住"</string>
@@ -1002,9 +1002,9 @@
     <string name="bubble_accessibility_action_move_top_right" msgid="6916868852433483569">"移至右上方"</string>
     <string name="bubble_accessibility_action_move_bottom_left" msgid="6339015902495504715">"移至左下方"</string>
     <string name="bubble_accessibility_action_move_bottom_right" msgid="7471571700628346212">"移至右下方"</string>
-    <string name="bubble_dismiss_text" msgid="7071770411580452911">"關閉"</string>
+    <string name="bubble_dismiss_text" msgid="1314082410868930066">"關閉對話框"</string>
     <string name="bubbles_dont_bubble_conversation" msgid="1033040343437428822">"不要以對話框形式顯示對話"</string>
-    <string name="bubbles_user_education_title" msgid="5547017089271445797">"使用對話框進行即時通訊"</string>
+    <string name="bubbles_user_education_title" msgid="5547017089271445797">"透過對話框來聊天"</string>
     <string name="bubbles_user_education_description" msgid="1160281719576715211">"新的對話會以浮動圖示或對話框形式顯示。輕觸即可開啟對話框,拖曳則可移動對話框。"</string>
     <string name="bubbles_user_education_manage_title" msgid="2848511858160342320">"你隨時可以控管對話框的各項設定"</string>
     <string name="bubbles_user_education_manage" msgid="1391639189507036423">"輕觸 [管理] 即可關閉來自這個應用程式的對話框"</string>
@@ -1062,9 +1062,13 @@
     <string name="controls_structure_tooltip" msgid="4355922222944447867">"滑動即可查看其他結構"</string>
     <string name="controls_seeding_in_progress" msgid="3033855341410264148">"正在載入建議控制項"</string>
     <string name="controls_media_close_session" msgid="9023534788828414585">"關閉這個媒體工作階段"</string>
+    <string name="controls_media_resume" msgid="1933520684481586053">"繼續播放"</string>
     <string name="controls_error_timeout" msgid="794197289772728958">"無效,請查看應用程式"</string>
     <string name="controls_error_retryable" msgid="864025882878378470">"發生錯誤,正在重試…"</string>
-    <string name="controls_error_removed" msgid="6299213591234723805">"裝置已遭到移除"</string>
+    <string name="controls_error_removed" msgid="6675638069846014366">"找不到控制項"</string>
+    <string name="controls_error_removed_title" msgid="1207794911208047818">"無法使用控制項"</string>
+    <string name="controls_error_removed_message" msgid="2885911717034750542">"無法存取「<xliff:g id="DEVICE">%1$s</xliff:g>」。請查看 <xliff:g id="APPLICATION">%2$s</xliff:g> 應用程式,確認當中是否仍有相關控制項,且應用程式設定沒有任何異動。"</string>
+    <string name="controls_open_app" msgid="483650971094300141">"開啟應用程式"</string>
     <string name="controls_error_generic" msgid="352500456918362905">"無法載入狀態"</string>
     <string name="controls_error_failed" msgid="960228639198558525">"發生錯誤,請再試一次"</string>
     <string name="controls_in_progress" msgid="4421080500238215939">"進行中"</string>
diff --git a/packages/SystemUI/res/values-zu/strings.xml b/packages/SystemUI/res/values-zu/strings.xml
index 9b56c20..9b76660e 100644
--- a/packages/SystemUI/res/values-zu/strings.xml
+++ b/packages/SystemUI/res/values-zu/strings.xml
@@ -510,7 +510,7 @@
     <string name="clear_all_notifications_text" msgid="348312370303046130">"Sula konke"</string>
     <string name="manage_notifications_text" msgid="6885645344647733116">"Phatha"</string>
     <string name="manage_notifications_history_text" msgid="57055985396576230">"Umlando"</string>
-    <string name="notification_section_header_incoming" msgid="5295312809341711367">"Okungenayo"</string>
+    <string name="notification_section_header_incoming" msgid="850925217908095197">"Okusha"</string>
     <string name="notification_section_header_gentle" msgid="6804099527336337197">"Kuthulile"</string>
     <string name="notification_section_header_alerting" msgid="5581175033680477651">"Izaziso"</string>
     <string name="notification_section_header_conversations" msgid="821834744538345661">"Izingxoxo"</string>
@@ -1002,7 +1002,7 @@
     <string name="bubble_accessibility_action_move_top_right" msgid="6916868852433483569">"Hambisa phezulu ngakwesokudla"</string>
     <string name="bubble_accessibility_action_move_bottom_left" msgid="6339015902495504715">"Hambisa inkinobho ngakwesokunxele"</string>
     <string name="bubble_accessibility_action_move_bottom_right" msgid="7471571700628346212">"Hambisa inkinobho ngakwesokudla"</string>
-    <string name="bubble_dismiss_text" msgid="7071770411580452911">"Cashisa"</string>
+    <string name="bubble_dismiss_text" msgid="1314082410868930066">"Cashisa ibhamuza"</string>
     <string name="bubbles_dont_bubble_conversation" msgid="1033040343437428822">"Ungayibhamuzi ingxoxo"</string>
     <string name="bubbles_user_education_title" msgid="5547017089271445797">"Xoxa usebenzisa amabhamuza"</string>
     <string name="bubbles_user_education_description" msgid="1160281719576715211">"Izingxoxo ezintsha zivela njengezithonjana ezintantayo, noma amabhamuza. Thepha ukuze uvule ibhamuza. Hudula ukuze ulihambise."</string>
@@ -1062,9 +1062,13 @@
     <string name="controls_structure_tooltip" msgid="4355922222944447867">"Swayipha ukuze ubone okuningi"</string>
     <string name="controls_seeding_in_progress" msgid="3033855341410264148">"Ilayisha izincomo"</string>
     <string name="controls_media_close_session" msgid="9023534788828414585">"Vala leseshini yemidiya"</string>
+    <string name="controls_media_resume" msgid="1933520684481586053">"Qalisa kabusha"</string>
     <string name="controls_error_timeout" msgid="794197289772728958">"Akusebenzi, hlola uhlelo lokusebenza"</string>
     <string name="controls_error_retryable" msgid="864025882878378470">"Iphutha, iyazama futhi…"</string>
-    <string name="controls_error_removed" msgid="6299213591234723805">"Idivayisi isusiwe"</string>
+    <string name="controls_error_removed" msgid="6675638069846014366">"Ayitholakali"</string>
+    <string name="controls_error_removed_title" msgid="1207794911208047818">"Ukulawula akutholakali"</string>
+    <string name="controls_error_removed_message" msgid="2885911717034750542">"Ayikwazanga ukufinyelela ku-<xliff:g id="DEVICE">%1$s</xliff:g>. Hlola uhlelo lokusebenza le-<xliff:g id="APPLICATION">%2$s</xliff:g> ukuqinisekisa ukuthi ukulawula kusatholakala nokuthi amasethingi wohlelo lokusebenza awakashintshi."</string>
+    <string name="controls_open_app" msgid="483650971094300141">"Vula uhlelo"</string>
     <string name="controls_error_generic" msgid="352500456918362905">"Ayikwazi ukulayisha isimo"</string>
     <string name="controls_error_failed" msgid="960228639198558525">"Iphutha, zama futhi"</string>
     <string name="controls_in_progress" msgid="4421080500238215939">"Iyaqhubeka"</string>
diff --git a/packages/SystemUI/res/values/colors.xml b/packages/SystemUI/res/values/colors.xml
index 837627c..40a4b50 100644
--- a/packages/SystemUI/res/values/colors.xml
+++ b/packages/SystemUI/res/values/colors.xml
@@ -202,6 +202,10 @@
     <color name="global_screenshot_dismiss_foreground">@color/GM2_grey_500</color>
     <color name="global_screenshot_background_protection_start">#40000000</color> <!-- 25% black -->
 
+    <!-- Bubbles -->
+    <color name="bubbles_light">#FFFFFF</color>
+    <color name="bubbles_dark">@color/GM2_grey_800</color>
+
     <!-- GM2 colors -->
     <color name="GM2_grey_50">#F8F9FA</color>
     <color name="GM2_grey_100">#F1F3F4</color>
diff --git a/packages/SystemUI/res/values/config.xml b/packages/SystemUI/res/values/config.xml
index 00537ff..848cdb1 100644
--- a/packages/SystemUI/res/values/config.xml
+++ b/packages/SystemUI/res/values/config.xml
@@ -95,9 +95,6 @@
     <!-- The maximum number of tiles in the QuickQSPanel -->
     <integer name="quick_qs_panel_max_columns">6</integer>
 
-    <!-- Whether QuickSettings is in a phone landscape -->
-    <bool name="quick_settings_wide">false</bool>
-
     <!-- The number of columns in the QuickSettings -->
     <integer name="quick_settings_num_columns">3</integer>
 
diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml
index 73d8e9a..d176fed 100644
--- a/packages/SystemUI/res/values/dimens.xml
+++ b/packages/SystemUI/res/values/dimens.xml
@@ -631,10 +631,10 @@
     <dimen name="notification_section_divider_height">@dimen/notification_side_paddings</dimen>
 
     <!-- Size of the face pile shown on one-line (children of a group) conversation notifications -->
-    <dimen name="conversation_single_line_face_pile_size">36dp</dimen>
+    <dimen name="conversation_single_line_face_pile_size">25dp</dimen>
 
     <!-- Size of an avatar shown on one-line (children of a group) conversation notifications -->
-    <dimen name="conversation_single_line_avatar_size">24dp</dimen>
+    <dimen name="conversation_single_line_avatar_size">20dp</dimen>
 
     <!-- Border width for avatars in the face pile shown on one-line (children of a group) conversation notifications -->
     <dimen name="conversation_single_line_face_pile_protection_width">1dp</dimen>
@@ -1075,8 +1075,7 @@
     <dimen name="edge_margin">8dp</dimen>
 
     <!-- The absolute side margins of quick settings -->
-    <dimen name="quick_settings_expanded_bottom_margin">16dp</dimen>
-    <dimen name="quick_settings_media_extra_bottom_margin">6dp</dimen>
+    <dimen name="quick_settings_bottom_margin_media">16dp</dimen>
     <dimen name="rounded_corner_content_padding">0dp</dimen>
     <dimen name="nav_content_padding">0dp</dimen>
     <dimen name="nav_quick_scrub_track_edge_padding">24dp</dimen>
@@ -1222,10 +1221,6 @@
     <dimen name="bubble_dismiss_slop">16dp</dimen>
     <!-- Height of button allowing users to adjust settings for bubbles. -->
     <dimen name="bubble_manage_button_height">48dp</dimen>
-    <!-- How far, horizontally, to animate the expanded view over when animating in/out. -->
-    <dimen name="bubble_expanded_animate_x_distance">100dp</dimen>
-    <!-- How far, vertically, to animate the expanded view over when animating in/out. -->
-    <dimen name="bubble_expanded_animate_y_distance">500dp</dimen>
     <!-- Max width of the message bubble-->
     <dimen name="bubble_message_max_width">144dp</dimen>
     <!-- Min width of the message bubble -->
@@ -1252,7 +1247,7 @@
     <!-- Bubbles user education views -->
     <dimen name="bubbles_manage_education_width">160dp</dimen>
     <!-- The inset from the top bound of the manage button to place the user education. -->
-    <dimen name="bubbles_manage_education_top_inset">10dp</dimen>
+    <dimen name="bubbles_manage_education_top_inset">65dp</dimen>
     <!-- Size of padding for the user education cling, this should at minimum be larger than
         individual_bubble_size + some padding. -->
     <dimen name="bubble_stack_user_education_side_inset">72dp</dimen>
@@ -1268,8 +1263,8 @@
     <dimen name="qs_media_panel_outer_padding">16dp</dimen>
     <dimen name="qs_media_album_size">52dp</dimen>
     <dimen name="qs_seamless_icon_size">20dp</dimen>
-    <dimen name="qqs_media_spacing">8dp</dimen>
-    <dimen name="qqs_horizonal_tile_padding_bottom">8dp</dimen>
+    <dimen name="qqs_media_spacing">16dp</dimen>
+    <dimen name="qs_footer_horizontal_margin">22dp</dimen>
 
     <dimen name="magnification_border_size">5dp</dimen>
     <dimen name="magnification_frame_move_short">5dp</dimen>
diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml
index 820615a6..f4141e2 100644
--- a/packages/SystemUI/res/values/strings.xml
+++ b/packages/SystemUI/res/values/strings.xml
@@ -1256,7 +1256,7 @@
     <string name="manage_notifications_history_text">History</string>
 
     <!-- Section title for notifications that have recently appeared. [CHAR LIMIT=40] -->
-    <string name="notification_section_header_incoming">Incoming</string>
+    <string name="notification_section_header_incoming">New</string>
 
     <!-- Section title for notifications that do not vibrate or make noise. [CHAR LIMIT=40] -->
     <string name="notification_section_header_gentle">Silent</string>
@@ -2640,7 +2640,7 @@
     <string name="bubble_accessibility_action_move_bottom_left">Move bottom left</string>
     <!-- Action in accessibility menu to move the stack of bubbles to the bottom right of the screen. [CHAR LIMIT=30]-->
     <string name="bubble_accessibility_action_move_bottom_right">Move bottom right</string>
-    <!-- Text used for the bubble dismiss area. Bubbles dragged to, or flung towards, this area will go away. [CHAR LIMIT=20] -->
+    <!-- Text used for the bubble dismiss area. Bubbles dragged to, or flung towards, this area will go away. [CHAR LIMIT=30] -->
     <string name="bubble_dismiss_text">Dismiss bubble</string>
     <!-- Button text to stop a conversation from bubbling [CHAR LIMIT=60]-->
     <string name="bubbles_dont_bubble_conversation">Don\u2019t bubble conversation</string>
diff --git a/packages/SystemUI/res/values/styles.xml b/packages/SystemUI/res/values/styles.xml
index 39f78bf..68c2a38 100644
--- a/packages/SystemUI/res/values/styles.xml
+++ b/packages/SystemUI/res/values/styles.xml
@@ -387,11 +387,6 @@
         <item name="android:homeAsUpIndicator">@drawable/ic_arrow_back</item>
     </style>
 
-    <style name="qs_security_footer" parent="@style/qs_theme">
-        <item name="android:textColor">?android:attr/textColorSecondary</item>
-        <item name="android:tint">?android:attr/textColorSecondary</item>
-    </style>
-
     <style name="systemui_theme_remote_input" parent="@android:style/Theme.DeviceDefault.Light">
         <item name="android:colorAccent">@color/remote_input_accent</item>
     </style>
@@ -549,6 +544,13 @@
     <style name="TextAppearance.NotificationImportanceChannelGroup">
         <item name="android:textSize">@dimen/notification_importance_channel_group_text</item>
         <item name="android:fontFamily">@*android:string/config_headlineFontFamily</item>
+        <item name="android:textColor">@color/notification_guts_header_text_color</item>
+        <item name="android:textSize">@dimen/notification_importance_channel_group_text</item>
+    </style>
+
+    <style name="TextAppearance.NotificationImportanceApp">
+        <item name="android:textSize">@dimen/notification_importance_channel_group_text</item>
+        <item name="android:fontFamily">@*android:string/config_headlineFontFamily</item>
         <item name="android:textColor">@color/notification_guts_sub_text_color</item>
         <item name="android:textSize">@dimen/notification_importance_channel_group_text</item>
     </style>
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/system/BlurUtils.java b/packages/SystemUI/shared/src/com/android/systemui/shared/system/BlurUtils.java
new file mode 100644
index 0000000..9f26d85
--- /dev/null
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/system/BlurUtils.java
@@ -0,0 +1,37 @@
+/*
+ * Copyright (C) 2020 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.shared.system;
+
+import android.app.ActivityManager;
+import android.os.SystemProperties;
+
+public abstract class BlurUtils {
+
+    private static boolean mBlurSupportedSysProp = SystemProperties
+            .getBoolean("ro.surface_flinger.supports_background_blur", false);
+    private static boolean mBlurDisabledSysProp = SystemProperties
+            .getBoolean("persist.sys.sf.disable_blurs", false);
+
+    /**
+     * If this device can render blurs.
+     *
+     * @return {@code true} when supported.
+     */
+    public static boolean supportsBlursOnWindows() {
+        return mBlurSupportedSysProp && !mBlurDisabledSysProp && ActivityManager.isHighEndGfx();
+    }
+}
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/system/InputConsumerController.java b/packages/SystemUI/shared/src/com/android/systemui/shared/system/InputConsumerController.java
index ebed1fc..27e4c85 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/system/InputConsumerController.java
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/system/InputConsumerController.java
@@ -63,8 +63,9 @@
      */
     private final class InputEventReceiver extends BatchedInputEventReceiver {
 
-        public InputEventReceiver(InputChannel inputChannel, Looper looper) {
-            super(inputChannel, looper, Choreographer.getInstance());
+        InputEventReceiver(InputChannel inputChannel, Looper looper,
+                Choreographer choreographer) {
+            super(inputChannel, looper, choreographer);
         }
 
         @Override
@@ -143,6 +144,14 @@
      * Registers the input consumer.
      */
     public void registerInputConsumer() {
+        registerInputConsumer(false);
+    }
+
+    /**
+     * Registers the input consumer.
+     * @param withSfVsync the flag set using sf vsync signal or no
+     */
+    public void registerInputConsumer(boolean withSfVsync) {
         if (mInputEventReceiver == null) {
             final InputChannel inputChannel = new InputChannel();
             try {
@@ -152,7 +161,8 @@
             } catch (RemoteException e) {
                 Log.e(TAG, "Failed to create input consumer", e);
             }
-            mInputEventReceiver = new InputEventReceiver(inputChannel, Looper.myLooper());
+            mInputEventReceiver = new InputEventReceiver(inputChannel, Looper.myLooper(),
+                    withSfVsync ? Choreographer.getSfInstance() : Choreographer.getInstance());
             if (mRegistrationListener != null) {
                 mRegistrationListener.onRegistrationChanged(true /* isRegistered */);
             }
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainer.java b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainer.java
index 1a4dd1e..1db2e32 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainer.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainer.java
@@ -25,12 +25,16 @@
 
 import static java.lang.Integer.max;
 
+import android.animation.Animator;
+import android.animation.AnimatorListenerAdapter;
+import android.animation.ValueAnimator;
 import android.app.Activity;
 import android.app.AlertDialog;
 import android.app.admin.DevicePolicyManager;
 import android.content.Context;
 import android.content.Intent;
 import android.content.res.ColorStateList;
+import android.graphics.Insets;
 import android.graphics.Rect;
 import android.metrics.LogMaker;
 import android.os.Handler;
@@ -48,9 +52,13 @@
 import android.view.ViewConfiguration;
 import android.view.WindowInsets;
 import android.view.WindowInsetsAnimation;
+import android.view.WindowInsetsAnimationControlListener;
+import android.view.WindowInsetsAnimationController;
 import android.view.WindowManager;
 import android.widget.FrameLayout;
 
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
 import androidx.annotation.VisibleForTesting;
 import androidx.dynamicanimation.animation.DynamicAnimation;
 import androidx.dynamicanimation.animation.SpringAnimation;
@@ -64,6 +72,7 @@
 import com.android.keyguard.KeyguardSecurityModel.SecurityMode;
 import com.android.settingslib.utils.ThreadUtils;
 import com.android.systemui.Dependency;
+import com.android.systemui.Interpolators;
 import com.android.systemui.R;
 import com.android.systemui.SystemUIFactory;
 import com.android.systemui.shared.system.SysUiStatsLog;
@@ -100,6 +109,8 @@
 
     private static final UiEventLogger sUiEventLogger = new UiEventLoggerImpl();
 
+    private static final long IME_DISAPPEAR_DURATION_MS = 125;
+
     private KeyguardSecurityModel mSecurityModel;
     private LockPatternUtils mLockPatternUtils;
 
@@ -125,6 +136,7 @@
     private int mActivePointerId = -1;
     private boolean mIsDragging;
     private float mStartTouchY = -1;
+    private boolean mDisappearAnimRunning;
 
     private final WindowInsetsAnimation.Callback mWindowInsetsAnimationCallback =
             new WindowInsetsAnimation.Callback(DISPATCH_MODE_STOP) {
@@ -148,22 +160,29 @@
                 public WindowInsets onProgress(WindowInsets windowInsets,
                         List<WindowInsetsAnimation> list) {
                     int translationY = 0;
-                    for (WindowInsetsAnimation animation : list) {
-                        if ((animation.getTypeMask() & WindowInsets.Type.ime()) == 0) {
-                            continue;
+                    if (mDisappearAnimRunning) {
+                        mSecurityViewFlipper.setTranslationY(
+                                mInitialBounds.bottom - mFinalBounds.bottom);
+                    } else {
+                        for (WindowInsetsAnimation animation : list) {
+                            if ((animation.getTypeMask() & WindowInsets.Type.ime()) == 0) {
+                                continue;
+                            }
+                            final int paddingBottom = (int) MathUtils.lerp(
+                                    mInitialBounds.bottom - mFinalBounds.bottom, 0,
+                                    animation.getInterpolatedFraction());
+                            translationY += paddingBottom;
                         }
-                        final int paddingBottom = (int) MathUtils.lerp(
-                                mInitialBounds.bottom - mFinalBounds.bottom, 0,
-                                animation.getInterpolatedFraction());
-                        translationY += paddingBottom;
+                        mSecurityViewFlipper.setTranslationY(translationY);
                     }
-                    mSecurityViewFlipper.setTranslationY(translationY);
                     return windowInsets;
                 }
 
                 @Override
                 public void onEnd(WindowInsetsAnimation animation) {
-                    mSecurityViewFlipper.setTranslationY(0);
+                    if (!mDisappearAnimRunning) {
+                        mSecurityViewFlipper.setTranslationY(0);
+                    }
                 }
             };
 
@@ -376,8 +395,51 @@
     }
 
     public boolean startDisappearAnimation(Runnable onFinishRunnable) {
+        mDisappearAnimRunning = true;
         if (mCurrentSecuritySelection == SecurityMode.Password) {
-            mSecurityViewFlipper.getWindowInsetsController().hide(WindowInsets.Type.ime());
+            mSecurityViewFlipper.getWindowInsetsController().controlWindowInsetsAnimation(ime(),
+                    IME_DISAPPEAR_DURATION_MS,
+                    Interpolators.LINEAR, null, new WindowInsetsAnimationControlListener() {
+
+
+                        @Override
+                        public void onReady(@NonNull WindowInsetsAnimationController controller,
+                                int types) {
+                            ValueAnimator anim = ValueAnimator.ofFloat(1f, 0f);
+                            anim.addUpdateListener(animation -> {
+                                if (controller.isCancelled()) {
+                                    return;
+                                }
+                                Insets shownInsets = controller.getShownStateInsets();
+                                Insets insets = Insets.add(shownInsets, Insets.of(0, 0, 0,
+                                        (int) (-shownInsets.bottom / 4
+                                                * anim.getAnimatedFraction())));
+                                controller.setInsetsAndAlpha(insets,
+                                        (float) animation.getAnimatedValue(),
+                                        anim.getAnimatedFraction());
+                            });
+                            anim.addListener(new AnimatorListenerAdapter() {
+                                @Override
+                                public void onAnimationEnd(Animator animation) {
+                                    controller.finish(false);
+                                }
+                            });
+                            anim.setDuration(IME_DISAPPEAR_DURATION_MS);
+                            anim.setInterpolator(Interpolators.FAST_OUT_LINEAR_IN);
+                            anim.start();
+                        }
+
+                        @Override
+                        public void onFinished(
+                                @NonNull WindowInsetsAnimationController controller) {
+                            mDisappearAnimRunning = false;
+                        }
+
+                        @Override
+                        public void onCancelled(
+                                @Nullable WindowInsetsAnimationController controller) {
+                        }
+                    });
         }
         if (mCurrentSecuritySelection != SecurityMode.None) {
             return getSecurityView(mCurrentSecuritySelection).startDisappearAnimation(
@@ -887,6 +949,7 @@
     @Override
     public void reset() {
         mSecurityViewFlipper.reset();
+        mDisappearAnimRunning = false;
     }
 
     @Override
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardSliceView.java b/packages/SystemUI/src/com/android/keyguard/KeyguardSliceView.java
index 9d8c545..f639c88 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardSliceView.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardSliceView.java
@@ -141,14 +141,6 @@
         mLayoutTransition.setAnimateParentHierarchy(false);
     }
 
-    // Temporary workaround to allow KeyguardStatusView to inflate a copy for Universal Smartspace.
-    // Eventually the existing copy will be reparented instead, and we won't need this.
-    public KeyguardSliceView(Context context, AttributeSet attributeSet) {
-        this(context, attributeSet, Dependency.get(ActivityStarter.class),
-                Dependency.get(ConfigurationController.class), Dependency.get(TunerService.class),
-                context.getResources());
-    }
-
     @Override
     protected void onFinishInflate() {
         super.onFinishInflate();
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardStatusView.java b/packages/SystemUI/src/com/android/keyguard/KeyguardStatusView.java
index a181ce4..5a1c997 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardStatusView.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardStatusView.java
@@ -18,10 +18,7 @@
 
 import android.app.ActivityManager;
 import android.app.IActivityManager;
-import android.content.BroadcastReceiver;
 import android.content.Context;
-import android.content.Intent;
-import android.content.IntentFilter;
 import android.content.res.Resources;
 import android.graphics.Color;
 import android.os.Handler;
@@ -43,8 +40,6 @@
 import com.android.internal.widget.LockPatternUtils;
 import com.android.systemui.Dependency;
 import com.android.systemui.R;
-import com.android.systemui.shared.system.SurfaceViewRequestReceiver;
-import com.android.systemui.shared.system.UniversalSmartspaceUtils;
 import com.android.systemui.statusbar.policy.ConfigurationController;
 
 import java.io.FileDescriptor;
@@ -127,21 +122,6 @@
         }
     };
 
-    private final BroadcastReceiver mUniversalSmartspaceBroadcastReceiver =
-            new BroadcastReceiver() {
-        private final SurfaceViewRequestReceiver mReceiver = new SurfaceViewRequestReceiver();
-
-        @Override
-        public void onReceive(Context context, Intent i) {
-            // TODO(b/148159743): Restrict to Pixel Launcher.
-            if (UniversalSmartspaceUtils.ACTION_REQUEST_SMARTSPACE_VIEW.equals(i.getAction())) {
-                mReceiver.onReceive(context,
-                        i.getBundleExtra(UniversalSmartspaceUtils.INTENT_BUNDLE_KEY),
-                        inflate(mContext, R.layout.keyguard_status_area, null));
-            }
-        }
-    };
-
     public KeyguardStatusView(Context context) {
         this(context, null, 0);
     }
@@ -336,8 +316,6 @@
         super.onAttachedToWindow();
         Dependency.get(KeyguardUpdateMonitor.class).registerCallback(mInfoCallback);
         Dependency.get(ConfigurationController.class).addCallback(this);
-        getContext().registerReceiver(mUniversalSmartspaceBroadcastReceiver,
-                new IntentFilter(UniversalSmartspaceUtils.ACTION_REQUEST_SMARTSPACE_VIEW));
     }
 
     @Override
@@ -345,7 +323,6 @@
         super.onDetachedFromWindow();
         Dependency.get(KeyguardUpdateMonitor.class).removeCallback(mInfoCallback);
         Dependency.get(ConfigurationController.class).removeCallback(this);
-        getContext().unregisterReceiver(mUniversalSmartspaceBroadcastReceiver);
     }
 
     @Override
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
index ee31706..7914d86 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
@@ -79,6 +79,7 @@
 import android.telephony.SubscriptionManager;
 import android.telephony.SubscriptionManager.OnSubscriptionsChangedListener;
 import android.telephony.TelephonyManager;
+import android.util.EventLog;
 import android.util.Log;
 import android.util.SparseArray;
 import android.util.SparseBooleanArray;
@@ -1074,6 +1075,17 @@
                 != LockPatternUtils.StrongAuthTracker.STRONG_AUTH_NOT_REQUIRED;
     }
 
+    private boolean isUserEncryptedOrLockdown(int userId) {
+        // Biometrics should not be started in this case. Think carefully before modifying this
+        // method, see b/79776455
+        final int strongAuth = mStrongAuthTracker.getStrongAuthForUser(userId);
+        final boolean isLockDown =
+                containsFlag(strongAuth, STRONG_AUTH_REQUIRED_AFTER_DPM_LOCK_NOW)
+                        || containsFlag(strongAuth, STRONG_AUTH_REQUIRED_AFTER_USER_LOCKDOWN);
+        final boolean isEncrypted = containsFlag(strongAuth, STRONG_AUTH_REQUIRED_AFTER_BOOT);
+        return isLockDown || isEncrypted;
+    }
+
     private boolean containsFlag(int haystack, int needle) {
         return (haystack & needle) != 0;
     }
@@ -1903,6 +1915,7 @@
     private boolean shouldListenForFingerprint() {
         final boolean allowedOnBouncer =
                 !(mFingerprintLockedOut && mBouncer && mCredentialAttempted);
+        final int user = getCurrentUser();
 
         // Only listen if this KeyguardUpdateMonitor belongs to the primary user. There is an
         // instance of KeyguardUpdateMonitor for each user but KeyguardUpdateMonitor is user-aware.
@@ -1911,7 +1924,7 @@
                 shouldListenForFingerprintAssistant() || (mKeyguardOccluded && mIsDreaming))
                 && !mSwitchingUser && !isFingerprintDisabled(getCurrentUser())
                 && (!mKeyguardGoingAway || !mDeviceInteractive) && mIsPrimaryUser
-                && allowedOnBouncer;
+                && allowedOnBouncer && !isUserEncryptedOrLockdown(user);
         return shouldListen;
     }
 
@@ -1925,12 +1938,8 @@
                 && !statusBarShadeLocked;
         final int user = getCurrentUser();
         final int strongAuth = mStrongAuthTracker.getStrongAuthForUser(user);
-        final boolean isLockDown =
-                containsFlag(strongAuth, STRONG_AUTH_REQUIRED_AFTER_DPM_LOCK_NOW)
-                        || containsFlag(strongAuth, STRONG_AUTH_REQUIRED_AFTER_USER_LOCKDOWN);
-        final boolean isEncryptedOrTimedOut =
-                containsFlag(strongAuth, STRONG_AUTH_REQUIRED_AFTER_BOOT)
-                        || containsFlag(strongAuth, STRONG_AUTH_REQUIRED_AFTER_TIMEOUT);
+        final boolean isTimedOut =
+                containsFlag(strongAuth, STRONG_AUTH_REQUIRED_AFTER_TIMEOUT);
 
         boolean canBypass = mKeyguardBypassController != null
                 && mKeyguardBypassController.canBypass();
@@ -1939,10 +1948,9 @@
         // TrustAgents or biometrics are keeping the device unlocked.
         boolean becauseCannotSkipBouncer = !getUserCanSkipBouncer(user) || canBypass;
 
-        // Scan even when encrypted or timeout to show a preemptive bouncer when bypassing.
+        // Scan even when timeout to show a preemptive bouncer when bypassing.
         // Lock-down mode shouldn't scan, since it is more explicit.
-        boolean strongAuthAllowsScanning = (!isEncryptedOrTimedOut || canBypass && !mBouncer)
-                && !isLockDown;
+        boolean strongAuthAllowsScanning = (!isTimedOut || canBypass && !mBouncer);
 
         // Only listen if this KeyguardUpdateMonitor belongs to the primary user. There is an
         // instance of KeyguardUpdateMonitor for each user but KeyguardUpdateMonitor is user-aware.
@@ -1952,7 +1960,7 @@
                 && !mSwitchingUser && !isFaceDisabled(user) && becauseCannotSkipBouncer
                 && !mKeyguardGoingAway && mFaceSettingEnabledForUser.get(user) && !mLockIconPressed
                 && strongAuthAllowsScanning && mIsPrimaryUser
-                && !mSecureCameraLaunched;
+                && !mSecureCameraLaunched && !isUserEncryptedOrLockdown(user);
 
         // Aggregate relevant fields for debug logging.
         if (DEBUG_FACE || DEBUG_SPEW) {
@@ -2025,6 +2033,11 @@
             if (mFingerprintCancelSignal != null) {
                 mFingerprintCancelSignal.cancel();
             }
+
+            if (isUserEncryptedOrLockdown(userId)) {
+                // If this happens, shouldListenForFingerprint() is wrong. SafetyNet for b/79776455
+                EventLog.writeEvent(0x534e4554, "79776455", "startListeningForFingerprint");
+            }
             mFingerprintCancelSignal = new CancellationSignal();
             mFpm.authenticate(null, mFingerprintCancelSignal, 0, mFingerprintAuthenticationCallback,
                     null, userId);
@@ -2043,6 +2056,11 @@
             if (mFaceCancelSignal != null) {
                 mFaceCancelSignal.cancel();
             }
+
+            if (isUserEncryptedOrLockdown(userId)) {
+                // If this happens, shouldListenForFace() is wrong. SafetyNet for b/79776455
+                EventLog.writeEvent(0x534e4554, "79776455", "startListeningForFace");
+            }
             mFaceCancelSignal = new CancellationSignal();
             mFaceManager.authenticate(null, mFaceCancelSignal, 0,
                     mFaceAuthenticationCallback, null, userId);
diff --git a/packages/SystemUI/src/com/android/systemui/Prefs.java b/packages/SystemUI/src/com/android/systemui/Prefs.java
index ccb506d..0218cd2 100644
--- a/packages/SystemUI/src/com/android/systemui/Prefs.java
+++ b/packages/SystemUI/src/com/android/systemui/Prefs.java
@@ -124,7 +124,7 @@
         String HAS_SEEN_BUBBLES_MANAGE_EDUCATION = "HasSeenBubblesManageOnboarding";
         String CONTROLS_STRUCTURE_SWIPE_TOOLTIP_COUNT = "ControlsStructureSwipeTooltipCount";
         /** Tracks whether the user has seen the onboarding screen for priority conversations */
-        String HAS_SEEN_PRIORITY_ONBOARDING = "HaveShownPriorityOnboarding";
+        String HAS_SEEN_PRIORITY_ONBOARDING = "HasUserSeenPriorityOnboarding";
     }
 
     public static boolean getBoolean(Context context, @Key String key, boolean defaultValue) {
diff --git a/packages/SystemUI/src/com/android/systemui/broadcast/BroadcastDispatcher.kt b/packages/SystemUI/src/com/android/systemui/broadcast/BroadcastDispatcher.kt
index 4269605..67c0c62 100644
--- a/packages/SystemUI/src/com/android/systemui/broadcast/BroadcastDispatcher.kt
+++ b/packages/SystemUI/src/com/android/systemui/broadcast/BroadcastDispatcher.kt
@@ -16,8 +16,10 @@
 
 package com.android.systemui.broadcast
 
+import android.app.ActivityManager
 import android.content.BroadcastReceiver
 import android.content.Context
+import android.content.Intent
 import android.content.IntentFilter
 import android.os.Handler
 import android.os.HandlerExecutor
@@ -28,15 +30,11 @@
 import android.util.SparseArray
 import com.android.internal.annotations.VisibleForTesting
 import com.android.systemui.Dumpable
-import com.android.systemui.dagger.qualifiers.Background
-import com.android.systemui.dagger.qualifiers.Main
+import com.android.systemui.broadcast.logging.BroadcastDispatcherLogger
 import com.android.systemui.dump.DumpManager
 import java.io.FileDescriptor
 import java.io.PrintWriter
-import java.lang.IllegalStateException
 import java.util.concurrent.Executor
-import javax.inject.Inject
-import javax.inject.Singleton
 
 data class ReceiverData(
     val receiver: BroadcastReceiver,
@@ -48,6 +46,8 @@
 private const val MSG_ADD_RECEIVER = 0
 private const val MSG_REMOVE_RECEIVER = 1
 private const val MSG_REMOVE_RECEIVER_FOR_USER = 2
+private const val MSG_USER_SWITCH = 3
+private const val MSG_SET_STARTING_USER = 99
 private const val TAG = "BroadcastDispatcher"
 private const val DEBUG = true
 
@@ -62,20 +62,27 @@
  * permissions, schemes, data types, data authorities or priority different than 0.
  * Cannot be used for getting sticky broadcasts (either as return of registering or as re-delivery).
  */
-@Singleton
-open class BroadcastDispatcher @Inject constructor (
+open class BroadcastDispatcher constructor (
     private val context: Context,
-    @Main private val mainHandler: Handler,
-    @Background private val bgLooper: Looper,
-    dumpManager: DumpManager
-) : Dumpable {
+    private val bgLooper: Looper,
+    private val dumpManager: DumpManager,
+    private val logger: BroadcastDispatcherLogger
+) : Dumpable, BroadcastReceiver() {
 
     // Only modify in BG thread
     private val receiversByUser = SparseArray<UserBroadcastDispatcher>(20)
 
-    init {
-        // TODO: Don't do this in the constructor
+    fun initialize() {
         dumpManager.registerDumpable(javaClass.name, this)
+        handler.sendEmptyMessage(MSG_SET_STARTING_USER)
+        registerReceiver(this, IntentFilter(Intent.ACTION_USER_SWITCHED), null, UserHandle.ALL)
+    }
+
+    override fun onReceive(context: Context, intent: Intent) {
+        if (intent.action == Intent.ACTION_USER_SWITCHED) {
+            val user = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, UserHandle.USER_NULL)
+            handler.obtainMessage(MSG_USER_SWITCH, user, 0).sendToTarget()
+        }
     }
 
     /**
@@ -87,7 +94,7 @@
      *               have at least one action.
      * @param handler A handler to dispatch [BroadcastReceiver.onReceive].
      * @param user A user handle to determine which broadcast should be dispatched to this receiver.
-     *             By default, it is the current user.
+     *             By default, it is the user of the context (system user in SystemUI).
      * @throws IllegalArgumentException if the filter has other constraints that are not actions or
      *                                  categories or the filter has no actions.
      */
@@ -113,7 +120,7 @@
      * @param executor An executor to dispatch [BroadcastReceiver.onReceive]. Pass null to use an
      *                 executor in the main thread (default).
      * @param user A user handle to determine which broadcast should be dispatched to this receiver.
-     *             By default, it is the current user.
+     *             By default, it is the user of the context (system user in SystemUI).
      * @throws IllegalArgumentException if the filter has other constraints that are not actions or
      *                                  categories or the filter has no actions.
      */
@@ -156,7 +163,7 @@
     /**
      * Unregister receiver for a particular user.
      *
-     * @param receiver The receiver to unregister. It will be unregistered for all users.
+     * @param receiver The receiver to unregister.
      * @param user The user associated to the registered [receiver]. It can be [UserHandle.ALL].
      */
     open fun unregisterReceiverForUser(receiver: BroadcastReceiver, user: UserHandle) {
@@ -166,10 +173,11 @@
 
     @VisibleForTesting
     protected open fun createUBRForUser(userId: Int) =
-            UserBroadcastDispatcher(context, userId, bgLooper)
+            UserBroadcastDispatcher(context, userId, bgLooper, logger)
 
     override fun dump(fd: FileDescriptor, pw: PrintWriter, args: Array<out String>) {
         pw.println("Broadcast dispatcher:")
+        pw.println("  Current user: ${handler.currentUser}")
         for (index in 0 until receiversByUser.size()) {
             pw.println("  User ${receiversByUser.keyAt(index)}")
             receiversByUser.valueAt(index).dump(fd, pw, args)
@@ -177,6 +185,8 @@
     }
 
     private val handler = object : Handler(bgLooper) {
+        var currentUser = UserHandle.USER_SYSTEM
+
         override fun handleMessage(msg: Message) {
             when (msg.what) {
                 MSG_ADD_RECEIVER -> {
@@ -184,7 +194,7 @@
                     // If the receiver asked to be registered under the current user, we register
                     // under the actual current user.
                     val userId = if (data.user.identifier == UserHandle.USER_CURRENT) {
-                        context.userId
+                        currentUser
                     } else {
                         data.user.identifier
                     }
@@ -207,6 +217,13 @@
                     receiversByUser.get(msg.arg1)?.unregisterReceiver(msg.obj as BroadcastReceiver)
                 }
 
+                MSG_USER_SWITCH -> {
+                    currentUser = msg.arg1
+                }
+                MSG_SET_STARTING_USER -> {
+                    currentUser = ActivityManager.getCurrentUser()
+                }
+
                 else -> super.handleMessage(msg)
             }
         }
diff --git a/packages/SystemUI/src/com/android/systemui/broadcast/UserBroadcastDispatcher.kt b/packages/SystemUI/src/com/android/systemui/broadcast/UserBroadcastDispatcher.kt
index 3272fb7..96f5a1f 100644
--- a/packages/SystemUI/src/com/android/systemui/broadcast/UserBroadcastDispatcher.kt
+++ b/packages/SystemUI/src/com/android/systemui/broadcast/UserBroadcastDispatcher.kt
@@ -30,6 +30,7 @@
 import androidx.annotation.VisibleForTesting
 import com.android.internal.util.Preconditions
 import com.android.systemui.Dumpable
+import com.android.systemui.broadcast.logging.BroadcastDispatcherLogger
 import java.io.FileDescriptor
 import java.io.PrintWriter
 import java.lang.IllegalArgumentException
@@ -54,7 +55,8 @@
 class UserBroadcastDispatcher(
     private val context: Context,
     private val userId: Int,
-    private val bgLooper: Looper
+    private val bgLooper: Looper,
+    private val logger: BroadcastDispatcherLogger
 ) : BroadcastReceiver(), Dumpable {
 
     companion object {
@@ -109,10 +111,12 @@
     }
 
     override fun onReceive(context: Context, intent: Intent) {
-        val id = if (DEBUG) index.getAndIncrement() else 0
+        val id = index.getAndIncrement()
         if (DEBUG) Log.w(TAG, "[$id] Received $intent")
+        logger.logBroadcastReceived(id, userId, intent)
         bgHandler.post(
-                HandleBroadcastRunnable(actionsToReceivers, context, intent, pendingResult, id))
+                HandleBroadcastRunnable(
+                        actionsToReceivers, context, intent, pendingResult, id, logger))
     }
 
     /**
@@ -143,6 +147,7 @@
                 ArraySet()
             }.add(receiverData)
         }
+        logger.logReceiverRegistered(userId, receiverData.receiver)
         if (changed) {
             createFilterAndRegisterReceiverBG()
         }
@@ -163,6 +168,7 @@
                 actionsToReceivers.remove(action)
             }
         }
+        logger.logReceiverUnregistered(userId, receiver)
         if (changed) {
             createFilterAndRegisterReceiverBG()
         }
@@ -187,7 +193,8 @@
         val context: Context,
         val intent: Intent,
         val pendingResult: PendingResult,
-        val index: Int
+        val index: Int,
+        val logger: BroadcastDispatcherLogger
     ) : Runnable {
         override fun run() {
             if (DEBUG) Log.w(TAG, "[$index] Dispatching $intent")
@@ -199,6 +206,7 @@
                         it.executor.execute {
                             if (DEBUG) Log.w(TAG,
                                     "[$index] Dispatching ${intent.action} to ${it.receiver}")
+                            logger.logBroadcastDispatched(index, intent.action, it.receiver)
                             it.receiver.pendingResult = pendingResult
                             it.receiver.onReceive(context, intent)
                         }
@@ -215,6 +223,7 @@
             if (registered.get()) {
                 try {
                     context.unregisterReceiver(this@UserBroadcastDispatcher)
+                    logger.logContextReceiverUnregistered(userId)
                 } catch (e: IllegalArgumentException) {
                     Log.e(TAG, "Trying to unregister unregistered receiver for user $userId",
                             IllegalStateException(e))
@@ -230,6 +239,7 @@
                         null,
                         bgHandler)
                 registered.set(true)
+                logger.logContextReceiverRegistered(userId, intentFilter)
             }
         }
     }
diff --git a/packages/SystemUI/src/com/android/systemui/broadcast/logging/BroadcastDispatcherLogger.kt b/packages/SystemUI/src/com/android/systemui/broadcast/logging/BroadcastDispatcherLogger.kt
new file mode 100644
index 0000000..123a8ae
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/broadcast/logging/BroadcastDispatcherLogger.kt
@@ -0,0 +1,117 @@
+/*
+ * Copyright (C) 2020 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.broadcast.logging
+
+import android.content.BroadcastReceiver
+import android.content.Intent
+import android.content.IntentFilter
+import com.android.systemui.log.LogBuffer
+import com.android.systemui.log.LogLevel
+import com.android.systemui.log.LogLevel.DEBUG
+import com.android.systemui.log.LogLevel.INFO
+import com.android.systemui.log.LogMessage
+import com.android.systemui.log.dagger.BroadcastDispatcherLog
+import javax.inject.Inject
+
+private const val TAG = "BroadcastDispatcherLog"
+
+class BroadcastDispatcherLogger @Inject constructor(
+    @BroadcastDispatcherLog private val buffer: LogBuffer
+) {
+
+    fun logBroadcastReceived(broadcastId: Int, user: Int, intent: Intent) {
+        val intentString = intent.toString()
+        log(INFO, {
+            int1 = broadcastId
+            int2 = user
+            str1 = intentString
+        }, {
+            "[$int1] Broadcast received for user $int2: $str1"
+        })
+    }
+
+    fun logBroadcastDispatched(broadcastId: Int, action: String?, receiver: BroadcastReceiver) {
+        val receiverString = receiver.toString()
+        log(DEBUG, {
+            int1 = broadcastId
+            str1 = action
+            str2 = receiverString
+        }, {
+            "Broadcast $int1 ($str1) dispatched to $str2"
+        })
+    }
+
+    fun logReceiverRegistered(user: Int, receiver: BroadcastReceiver) {
+        val receiverString = receiver.toString()
+        log(INFO, {
+            int1 = user
+            str1 = receiverString
+        }, {
+            "Receiver $str1 registered for user $int1"
+        })
+    }
+
+    fun logReceiverUnregistered(user: Int, receiver: BroadcastReceiver) {
+        val receiverString = receiver.toString()
+        log(INFO, {
+            int1 = user
+            str1 = receiverString
+        }, {
+            "Receiver $str1 unregistered for user $int1"
+        })
+    }
+
+    fun logContextReceiverRegistered(user: Int, filter: IntentFilter) {
+        val actions = filter.actionsIterator().asSequence()
+                .joinToString(separator = ",", prefix = "Actions(", postfix = ")")
+        val categories = if (filter.countCategories() != 0) {
+            filter.categoriesIterator().asSequence()
+                    .joinToString(separator = ",", prefix = "Categories(", postfix = ")")
+        } else {
+            ""
+        }
+        log(INFO, {
+            int1 = user
+            str1 = if (categories != "") {
+                "${actions}\n$categories"
+            } else {
+                actions
+            }
+        }, {
+            """
+                Receiver registered with Context for user $int1.
+                $str1
+            """.trimIndent()
+        })
+    }
+
+    fun logContextReceiverUnregistered(user: Int) {
+        log(INFO, {
+            int1 = user
+        }, {
+            "Receiver unregistered with Context for user $int1."
+        })
+    }
+
+    private inline fun log(
+        logLevel: LogLevel,
+        initializer: LogMessage.() -> Unit,
+        noinline printer: LogMessage.() -> String
+    ) {
+        buffer.log(TAG, logLevel, initializer, printer)
+    }
+}
\ No newline at end of file
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/Bubble.java b/packages/SystemUI/src/com/android/systemui/bubbles/Bubble.java
index 97a7304..7f78ddf 100644
--- a/packages/SystemUI/src/com/android/systemui/bubbles/Bubble.java
+++ b/packages/SystemUI/src/com/android/systemui/bubbles/Bubble.java
@@ -303,10 +303,10 @@
         mDotPath = info.dotPath;
 
         if (mExpandedView != null) {
-            mExpandedView.update(/* bubble */ this);
+            mExpandedView.update(this /* bubble */);
         }
         if (mIconView != null) {
-            mIconView.setRenderedBubble(/* bubble */ this);
+            mIconView.setRenderedBubble(this /* bubble */);
         }
     }
 
@@ -548,13 +548,13 @@
     }
 
     private boolean shouldSuppressNotification() {
-        if (mEntry == null) return false;
+        if (mEntry == null) return true;
         return mEntry.getBubbleMetadata() != null
                 && mEntry.getBubbleMetadata().isNotificationSuppressed();
     }
 
     boolean shouldAutoExpand() {
-        if (mEntry == null) return false;
+        if (mEntry == null) return mShouldAutoExpand;
         Notification.BubbleMetadata metadata = mEntry.getBubbleMetadata();
         return (metadata != null && metadata.getAutoExpandBubble()) ||  mShouldAutoExpand;
     }
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleController.java b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleController.java
index cf793f0..c4c5da4 100644
--- a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleController.java
+++ b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleController.java
@@ -55,7 +55,6 @@
 import android.content.pm.PackageManager;
 import android.content.res.Configuration;
 import android.graphics.PixelFormat;
-import android.graphics.Rect;
 import android.os.Binder;
 import android.os.Handler;
 import android.os.RemoteException;
@@ -156,6 +155,7 @@
     private final ShadeController mShadeController;
     private final FloatingContentCoordinator mFloatingContentCoordinator;
     private final BubbleDataRepository mDataRepository;
+    private BubbleLogger mLogger = new BubbleLoggerImpl();
 
     private BubbleData mBubbleData;
     private ScrimView mBubbleScrim;
@@ -179,6 +179,9 @@
     // Callback that updates BubbleOverflowActivity on data change.
     @Nullable private Runnable mOverflowCallback = null;
 
+    // Only load overflow data from disk once
+    private boolean mOverflowDataLoaded = false;
+
     private final NotificationInterruptStateProvider mNotificationInterruptStateProvider;
     private IStatusBarService mBarService;
     private WindowManager mWindowManager;
@@ -192,9 +195,6 @@
     /** Whether or not the BubbleStackView has been added to the WindowManager. */
     private boolean mAddedToWindowManager = false;
 
-    // Used for determining view rect for touch interaction
-    private Rect mTempRect = new Rect();
-
     // Listens to user switch so bubbles can be saved and restored.
     private final NotificationLockscreenUserManager mNotifUserManager;
 
@@ -317,6 +317,7 @@
             BubbleDataRepository dataRepository,
             SysUiState sysUiState,
             INotificationManager notificationManager,
+            @Nullable IStatusBarService statusBarService,
             WindowManager windowManager) {
         dumpManager.registerDumpable(TAG, this);
         mContext = context;
@@ -387,8 +388,10 @@
         mSurfaceSynchronizer = synchronizer;
 
         mWindowManager = windowManager;
-        mBarService = IStatusBarService.Stub.asInterface(
-                ServiceManager.getService(Context.STATUS_BAR_SERVICE));
+        mBarService = statusBarService == null
+                ? IStatusBarService.Stub.asInterface(
+                        ServiceManager.getService(Context.STATUS_BAR_SERVICE))
+                : statusBarService;
 
         mBubbleScrim = new ScrimView(mContext);
 
@@ -415,6 +418,16 @@
         mCallbacks.add(callback);
     }
 
+    /**
+     * Dispatches a back press into the expanded Bubble's ActivityView if its IME is visible,
+     * causing it to hide.
+     */
+    public void hideImeFromExpandedBubble() {
+        if (mStackView != null) {
+            mStackView.hideImeFromExpandedBubble();
+        }
+    }
+
     private void setupNEM() {
         mNotificationEntryManager.addNotificationEntryListener(
                 new NotificationEntryListener() {
@@ -617,7 +630,7 @@
         if (mStackView == null) {
             mStackView = new BubbleStackView(
                     mContext, mBubbleData, mSurfaceSynchronizer, mFloatingContentCoordinator,
-                    mSysUiState, mNotificationShadeWindowController, this::onAllBubblesAnimatedOut,
+                    mSysUiState, this::onAllBubblesAnimatedOut,
                     this::onImeVisibilityChanged);
             mStackView.addView(mBubbleScrim);
             if (mExpandListener != null) {
@@ -701,6 +714,9 @@
      * the new params if the stack has been added.
      */
     private void updateWmFlags() {
+        if (mStackView == null) {
+            return;
+        }
         if (isStackExpanded() && !mImeVisible) {
             // If we're expanded, and the IME isn't visible, we want to be focusable. This ensures
             // that any taps within Bubbles (including on the ActivityView) results in Bubbles
@@ -712,7 +728,7 @@
             mWmLayoutParams.flags |= WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;
         }
 
-        if (mStackView != null && mAddedToWindowManager) {
+        if (mAddedToWindowManager) {
             try {
                 mWindowManager.updateViewLayout(mStackView, mWmLayoutParams);
             } catch (IllegalArgumentException e) {
@@ -894,9 +910,11 @@
     }
 
     void promoteBubbleFromOverflow(Bubble bubble) {
+        mLogger.log(bubble, BubbleLogger.Event.BUBBLE_OVERFLOW_REMOVE_BACK_TO_STACK);
         bubble.setInflateSynchronously(mInflateSynchronously);
-        setIsBubble(bubble, /* isBubble */ true);
-        mBubbleData.promoteBubbleFromOverflow(bubble, mStackView, mBubbleIconFactory);
+        bubble.setShouldAutoExpand(true);
+        bubble.markAsAccessedAt(System.currentTimeMillis());
+        setIsBubble(bubble, true /* isBubble */);
     }
 
     /**
@@ -910,20 +928,17 @@
         Bubble bubble = mBubbleData.getBubbleInStackWithKey(key);
         if (bubble != null) {
             mBubbleData.setSelectedBubble(bubble);
+            mBubbleData.setExpanded(true);
         } else {
             bubble = mBubbleData.getOverflowBubbleWithKey(key);
             if (bubble != null) {
-                bubble.setShouldAutoExpand(true);
                 promoteBubbleFromOverflow(bubble);
             } else if (entry.canBubble()) {
                 // It can bubble but it's not -- it got aged out of the overflow before it
                 // was dismissed or opened, make it a bubble again.
-                setIsBubble(entry, true);
-                updateBubble(entry, true /* suppressFlyout */, false /* showInShade */);
+                setIsBubble(entry, true /* isBubble */, true /* autoExpand */);
             }
         }
-
-        mBubbleData.setExpanded(true);
     }
 
     /**
@@ -949,13 +964,14 @@
      * Fills the overflow bubbles by loading them from disk.
      */
     void loadOverflowBubblesFromDisk() {
-        if (!mBubbleData.getOverflowBubbles().isEmpty()) {
+        if (!mBubbleData.getOverflowBubbles().isEmpty() || mOverflowDataLoaded) {
             // we don't need to load overflow bubbles from disk if it is already in memory
             return;
         }
+        mOverflowDataLoaded = true;
         mDataRepository.loadBubbles((bubbles) -> {
             bubbles.forEach(bubble -> {
-                if (mBubbleData.getBubbles().contains(bubble)) {
+                if (mBubbleData.hasAnyBubbleWithKey(bubble.getKey())) {
                     // if the bubble is already active, there's no need to push it to overflow
                     return;
                 }
@@ -967,13 +983,17 @@
     }
 
     void updateBubble(NotificationEntry notif, boolean suppressFlyout, boolean showInShade) {
-        // Lazy init stack view when a bubble is created
-        ensureStackViewCreated();
         // If this is an interruptive notif, mark that it's interrupted
         if (notif.getImportance() >= NotificationManager.IMPORTANCE_HIGH) {
             notif.setInterruption();
         }
-        Bubble bubble = mBubbleData.getOrCreateBubble(notif);
+        Bubble bubble = mBubbleData.getOrCreateBubble(notif, null /* persistedBubble */);
+        inflateAndAdd(bubble, suppressFlyout, showInShade);
+    }
+
+    void inflateAndAdd(Bubble bubble, boolean suppressFlyout, boolean showInShade) {
+        // Lazy init stack view when a bubble is created
+        ensureStackViewCreated();
         bubble.setInflateSynchronously(mInflateSynchronously);
         bubble.inflate(
                 b -> {
@@ -1119,7 +1139,8 @@
         }
     }
 
-    private void setIsBubble(@NonNull final NotificationEntry entry, final boolean isBubble) {
+    private void setIsBubble(@NonNull final NotificationEntry entry, final boolean isBubble,
+            final boolean autoExpand) {
         Objects.requireNonNull(entry);
         if (isBubble) {
             entry.getSbn().getNotification().flags |= FLAG_BUBBLE;
@@ -1127,7 +1148,12 @@
             entry.getSbn().getNotification().flags &= ~FLAG_BUBBLE;
         }
         try {
-            mBarService.onNotificationBubbleChanged(entry.getKey(), isBubble, 0);
+            int flags = 0;
+            if (autoExpand) {
+                flags = Notification.BubbleMetadata.FLAG_SUPPRESS_NOTIFICATION;
+                flags |= Notification.BubbleMetadata.FLAG_AUTO_EXPAND_BUBBLE;
+            }
+            mBarService.onNotificationBubbleChanged(entry.getKey(), isBubble, flags);
         } catch (RemoteException e) {
             // Bad things have happened
         }
@@ -1141,13 +1167,15 @@
             b.disable(FLAG_BUBBLE);
         }
         if (b.getEntry() != null) {
-            setIsBubble(b.getEntry(), isBubble);
-        } else {
-            try {
-                mBarService.onNotificationBubbleChanged(b.getKey(), isBubble, 0);
-            } catch (RemoteException e) {
-                // Bad things have happened
-            }
+            // Updating the entry to be a bubble will trigger our normal update flow
+            setIsBubble(b.getEntry(), isBubble, b.shouldAutoExpand());
+        } else if (isBubble) {
+            // If we have no entry to update, it's a persisted bubble so
+            // we need to add it to the stack ourselves
+            Bubble bubble = mBubbleData.getOrCreateBubble(null, b /* persistedBubble */);
+            inflateAndAdd(bubble, bubble.shouldAutoExpand() /* suppressFlyout */,
+                    !bubble.shouldAutoExpand() /* showInShade */);
+
         }
     }
 
@@ -1199,7 +1227,7 @@
                             }
                         }
                     } else {
-                        if (bubble.isBubble() && bubble.showInShade()) {
+                        if (bubble.isBubble()) {
                             setIsBubble(bubble, false /* isBubble */);
                         }
                         if (bubble.getEntry() != null && bubble.getEntry().getRow() != null) {
@@ -1220,24 +1248,23 @@
             }
             mDataRepository.removeBubbles(mCurrentUserId, bubblesToBeRemovedFromRepository);
 
-            if (update.addedBubble != null) {
+            if (update.addedBubble != null && mStackView != null) {
                 mDataRepository.addBubble(mCurrentUserId, update.addedBubble);
                 mStackView.addBubble(update.addedBubble);
-
             }
 
-            if (update.updatedBubble != null) {
+            if (update.updatedBubble != null && mStackView != null) {
                 mStackView.updateBubble(update.updatedBubble);
             }
 
             // At this point, the correct bubbles are inflated in the stack.
             // Make sure the order in bubble data is reflected in bubble row.
-            if (update.orderChanged) {
+            if (update.orderChanged && mStackView != null) {
                 mDataRepository.addBubbles(mCurrentUserId, update.bubbles);
                 mStackView.updateBubbleOrder(update.bubbles);
             }
 
-            if (update.selectionChanged) {
+            if (update.selectionChanged && mStackView != null) {
                 mStackView.setSelectedBubble(update.selectedBubble);
                 if (update.selectedBubble != null && update.selectedBubble.getEntry() != null) {
                     mNotificationGroupManager.updateSuppression(
@@ -1247,7 +1274,9 @@
 
             // Expanding? Apply this last.
             if (update.expandedChanged && update.expanded) {
-                mStackView.setExpanded(true);
+                if (mStackView != null) {
+                    mStackView.setExpanded(true);
+                }
             }
 
             for (NotifCallback cb : mCallbacks) {
@@ -1353,7 +1382,6 @@
     }
 
     /**
-     * Lets any listeners know if bubble state has changed.
      * Updates the visibility of the bubbles based on current state.
      * Does not un-bubble, just hides or un-hides.
      * Updates stack description for TalkBack focus.
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleData.java b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleData.java
index 996a555..20a9a8c 100644
--- a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleData.java
+++ b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleData.java
@@ -115,7 +115,7 @@
     /** Bubbles that aged out to overflow. */
     private final List<Bubble> mOverflowBubbles;
     /** Bubbles that are being loaded but haven't been added to the stack just yet. */
-    private final List<Bubble> mPendingBubbles;
+    private final HashMap<String, Bubble> mPendingBubbles;
     private Bubble mSelectedBubble;
     private boolean mShowingOverflow;
     private boolean mExpanded;
@@ -151,7 +151,7 @@
         mContext = context;
         mBubbles = new ArrayList<>();
         mOverflowBubbles = new ArrayList<>();
-        mPendingBubbles = new ArrayList<>();
+        mPendingBubbles = new HashMap<>();
         mStateChange = new Update(mBubbles, mOverflowBubbles);
         mMaxBubbles = mContext.getResources().getInteger(R.integer.bubbles_max_rendered);
         mMaxOverflowBubbles = mContext.getResources().getInteger(R.integer.bubbles_max_overflow);
@@ -203,62 +203,46 @@
         dispatchPendingChanges();
     }
 
-    public void promoteBubbleFromOverflow(Bubble bubble, BubbleStackView stack,
-            BubbleIconFactory factory) {
-        if (DEBUG_BUBBLE_DATA) {
-            Log.d(TAG, "promoteBubbleFromOverflow: " + bubble);
-        }
-        mLogger.log(bubble, BubbleLogger.Event.BUBBLE_OVERFLOW_REMOVE_BACK_TO_STACK);
-        moveOverflowBubbleToPending(bubble);
-        // Preserve new order for next repack, which sorts by last updated time.
-        bubble.inflate(
-                b -> {
-                    b.setShouldAutoExpand(true);
-                    b.markUpdatedAt(mTimeSource.currentTimeMillis());
-                    notificationEntryUpdated(bubble, false /* suppressFlyout */,
-                            true /* showInShade */);
-                },
-                mContext, stack, factory, false /* skipInflation */);
-    }
-
     void setShowingOverflow(boolean showingOverflow) {
         mShowingOverflow = showingOverflow;
     }
 
-    private void moveOverflowBubbleToPending(Bubble b) {
-        mOverflowBubbles.remove(b);
-        mPendingBubbles.add(b);
-    }
-
     /**
      * Constructs a new bubble or returns an existing one. Does not add new bubbles to
      * bubble data, must go through {@link #notificationEntryUpdated(Bubble, boolean, boolean)}
      * for that.
+     *
+     * @param entry The notification entry to use, only null if it's a bubble being promoted from
+     *              the overflow that was persisted over reboot.
+     * @param persistedBubble The bubble to use, only non-null if it's a bubble being promoted from
+     *              the overflow that was persisted over reboot.
      */
-    Bubble getOrCreateBubble(NotificationEntry entry) {
-        String key = entry.getKey();
-        Bubble bubble = getBubbleInStackWithKey(entry.getKey());
-        if (bubble != null) {
-            bubble.setEntry(entry);
-        } else {
-            bubble = getOverflowBubbleWithKey(key);
-            if (bubble != null) {
-                moveOverflowBubbleToPending(bubble);
-                bubble.setEntry(entry);
-                return bubble;
+    Bubble getOrCreateBubble(NotificationEntry entry, Bubble persistedBubble) {
+        String key = entry != null ? entry.getKey() : persistedBubble.getKey();
+        Bubble bubbleToReturn = getBubbleInStackWithKey(key);
+
+        if (bubbleToReturn == null) {
+            bubbleToReturn = getOverflowBubbleWithKey(key);
+            if (bubbleToReturn != null) {
+                // Promoting from overflow
+                mOverflowBubbles.remove(bubbleToReturn);
+            } else if (mPendingBubbles.containsKey(key)) {
+                // Update while it was pending
+                bubbleToReturn = mPendingBubbles.get(key);
+            } else if (entry != null) {
+                // New bubble
+                bubbleToReturn = new Bubble(entry, mSuppressionListener);
+            } else {
+                // Persisted bubble being promoted
+                bubbleToReturn = persistedBubble;
             }
-            // Check for it in pending
-            for (int i = 0; i < mPendingBubbles.size(); i++) {
-                Bubble b = mPendingBubbles.get(i);
-                if (b.getKey().equals(entry.getKey())) {
-                    b.setEntry(entry);
-                    return b;
-                }
-            }
-            bubble = new Bubble(entry, mSuppressionListener);
-            mPendingBubbles.add(bubble);
         }
-        return bubble;
+
+        if (entry != null) {
+            bubbleToReturn.setEntry(entry);
+        }
+        mPendingBubbles.put(key, bubbleToReturn);
+        return bubbleToReturn;
     }
 
     /**
@@ -270,7 +254,7 @@
         if (DEBUG_BUBBLE_DATA) {
             Log.d(TAG, "notificationEntryUpdated: " + bubble);
         }
-        mPendingBubbles.remove(bubble); // No longer pending once we're here
+        mPendingBubbles.remove(bubble.getKey()); // No longer pending once we're here
         Bubble prevBubble = getBubbleInStackWithKey(bubble.getKey());
         suppressFlyout |= bubble.getEntry() == null
                 || !bubble.getEntry().getRanking().visuallyInterruptive();
@@ -408,10 +392,8 @@
             Log.d(TAG, "doRemove: " + key);
         }
         //  If it was pending remove it
-        for (int i = 0; i < mPendingBubbles.size(); i++) {
-            if (mPendingBubbles.get(i).getKey().equals(key)) {
-                mPendingBubbles.remove(mPendingBubbles.get(i));
-            }
+        if (mPendingBubbles.containsKey(key)) {
+            mPendingBubbles.remove(key);
         }
         int indexToRemove = indexForKey(key);
         if (indexToRemove == -1) {
@@ -435,7 +417,8 @@
         if (mBubbles.size() == 1) {
             // Going to become empty, handle specially.
             setExpandedInternal(false);
-            setSelectedBubbleInternal(null);
+            // Don't use setSelectedBubbleInternal because we don't want to trigger an applyUpdate
+            mSelectedBubble = null;
         }
         if (indexToRemove < mBubbles.size() - 1) {
             // Removing anything but the last bubble means positions will change.
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleExpandedView.java b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleExpandedView.java
index c3dcc0b..ca359b8 100644
--- a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleExpandedView.java
+++ b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleExpandedView.java
@@ -22,6 +22,7 @@
 import static android.graphics.PixelFormat.TRANSPARENT;
 import static android.view.Display.INVALID_DISPLAY;
 import static android.view.InsetsState.ITYPE_IME;
+import static android.view.ViewGroup.LayoutParams.WRAP_CONTENT;
 import static android.view.ViewRootImpl.NEW_INSETS_MODE_FULL;
 import static android.view.ViewRootImpl.sNewInsetsMode;
 import static android.view.WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS;
@@ -33,7 +34,6 @@
 import static com.android.systemui.bubbles.BubbleDebugConfig.TAG_BUBBLES;
 import static com.android.systemui.bubbles.BubbleDebugConfig.TAG_WITH_CLASS_NAME;
 
-import android.annotation.Nullable;
 import android.annotation.SuppressLint;
 import android.app.ActivityOptions;
 import android.app.ActivityTaskManager;
@@ -42,10 +42,12 @@
 import android.content.ComponentName;
 import android.content.Context;
 import android.content.Intent;
+import android.content.res.Configuration;
 import android.content.res.Resources;
 import android.content.res.TypedArray;
 import android.graphics.Color;
 import android.graphics.Insets;
+import android.graphics.Outline;
 import android.graphics.Point;
 import android.graphics.Rect;
 import android.graphics.drawable.ShapeDrawable;
@@ -55,12 +57,19 @@
 import android.util.AttributeSet;
 import android.util.Log;
 import android.view.Gravity;
+import android.view.SurfaceControl;
+import android.view.SurfaceView;
 import android.view.View;
+import android.view.ViewGroup;
+import android.view.ViewOutlineProvider;
 import android.view.WindowInsets;
 import android.view.WindowManager;
 import android.view.accessibility.AccessibilityNodeInfo;
+import android.widget.FrameLayout;
 import android.widget.LinearLayout;
 
+import androidx.annotation.Nullable;
+
 import com.android.internal.policy.ScreenDecorationsUtils;
 import com.android.systemui.Dependency;
 import com.android.systemui.R;
@@ -88,6 +97,7 @@
     // The triangle pointing to the expanded view
     private View mPointerView;
     private int mPointerMargin;
+    @Nullable private int[] mExpandedViewContainerLocation;
 
     private AlphaOptimizedButton mSettingsIcon;
 
@@ -121,6 +131,16 @@
     private View mVirtualImeView;
     private WindowManager mVirtualDisplayWindowManager;
     private boolean mImeShowing = false;
+    private float mCornerRadius = 0f;
+
+    /**
+     * Container for the ActivityView that has a solid, round-rect background that shows if the
+     * ActivityView hasn't loaded.
+     */
+    private FrameLayout mActivityViewContainer = new FrameLayout(getContext());
+
+    /** The SurfaceView that the ActivityView draws to. */
+    @Nullable private SurfaceView mActivitySurface;
 
     private ActivityView.StateCallback mStateCallback = new ActivityView.StateCallback() {
         @Override
@@ -143,6 +163,11 @@
                             Log.d(TAG, "onActivityViewReady: calling startActivity, "
                                     + "bubble=" + getBubbleKey());
                         }
+                        if (mActivityView == null) {
+                            mBubbleController.removeBubble(getBubbleKey(),
+                                    BubbleController.DISMISS_INVALID_INTENT);
+                            return;
+                        }
                         try {
                             if (!mIsOverflow && mBubble.usingShortcutInfo()) {
                                 options.setApplyActivityFlagsForBubbles(true);
@@ -255,8 +280,6 @@
 
         mPointerDrawable = new ShapeDrawable(TriangleShape.create(
                 mPointerWidth, mPointerHeight, true /* pointUp */));
-        mPointerDrawable.setTint(Color.WHITE);
-        mPointerView.setBackground(mPointerDrawable);
         mPointerView.setVisibility(INVISIBLE);
 
         mSettingsIconHeight = getContext().getResources().getDimensionPixelSize(
@@ -269,7 +292,28 @@
 
         // Set ActivityView's alpha value as zero, since there is no view content to be shown.
         setContentVisibility(false);
-        addView(mActivityView);
+
+        mActivityViewContainer.setBackgroundColor(Color.WHITE);
+        mActivityViewContainer.setOutlineProvider(new ViewOutlineProvider() {
+            @Override
+            public void getOutline(View view, Outline outline) {
+                outline.setRoundRect(0, 0, view.getWidth(), view.getHeight(), mCornerRadius);
+            }
+        });
+        mActivityViewContainer.setClipToOutline(true);
+        mActivityViewContainer.addView(mActivityView);
+        mActivityViewContainer.setLayoutParams(
+                new ViewGroup.LayoutParams(WRAP_CONTENT, WRAP_CONTENT));
+        addView(mActivityViewContainer);
+
+        if (mActivityView != null
+                && mActivityView.getChildCount() > 0
+                && mActivityView.getChildAt(0) instanceof SurfaceView) {
+            // Retrieve the surface from the ActivityView so we can screenshot it and change its
+            // z-ordering. This should always be possible, since ActivityView's constructor adds the
+            // SurfaceView as its first child.
+            mActivitySurface = (SurfaceView) mActivityView.getChildAt(0);
+        }
 
         // Expanded stack layout, top to bottom:
         // Expanded view container
@@ -311,7 +355,10 @@
             // ActivityView's vertical bounds. These events are part of a back gesture, and so they
             // should not collapse the stack (which all other touches on areas around the AV would
             // do).
-            if (motionEvent.getRawY() >= avBounds.top && motionEvent.getRawY() <= avBounds.bottom) {
+            if (motionEvent.getRawY() >= avBounds.top
+                            && motionEvent.getRawY() <= avBounds.bottom
+                            && (motionEvent.getRawX() < avBounds.left
+                                || motionEvent.getRawX() > avBounds.right)) {
                 return true;
             }
 
@@ -327,6 +374,39 @@
         return mBubble != null ? mBubble.getKey() : "null";
     }
 
+    /**
+     * Asks the ActivityView's surface to draw on top of all other views in the window. This is
+     * useful for ordering surfaces during animations, but should otherwise be set to false so that
+     * bubbles and menus can draw over the ActivityView.
+     */
+    void setSurfaceZOrderedOnTop(boolean onTop) {
+        if (mActivitySurface == null) {
+            return;
+        }
+
+        mActivitySurface.setZOrderedOnTop(onTop, true);
+    }
+
+    /** Return a GraphicBuffer with the contents of the ActivityView's underlying surface. */
+    @Nullable SurfaceControl.ScreenshotGraphicBuffer snapshotActivitySurface() {
+        if (mActivitySurface == null) {
+            return null;
+        }
+
+        return SurfaceControl.captureLayers(
+                mActivitySurface.getSurfaceControl(),
+                new Rect(0, 0, mActivityView.getWidth(), mActivityView.getHeight()),
+                1 /* scale */);
+    }
+
+    int[] getActivityViewLocationOnScreen() {
+        if (mActivityView != null) {
+            return mActivityView.getLocationOnScreen();
+        } else {
+            return new int[]{0, 0};
+        }
+    }
+
     void setManageClickListener(OnClickListener manageClickListener) {
         findViewById(R.id.settings_button).setOnClickListener(manageClickListener);
     }
@@ -345,13 +425,25 @@
     void applyThemeAttrs() {
         final TypedArray ta = mContext.obtainStyledAttributes(
                 new int[] {android.R.attr.dialogCornerRadius});
-        float cornerRadius = ta.getDimensionPixelSize(0, 0);
+        mCornerRadius = ta.getDimensionPixelSize(0, 0);
         ta.recycle();
 
         if (mActivityView != null && ScreenDecorationsUtils.supportsRoundedCornersOnWindows(
                 mContext.getResources())) {
-            mActivityView.setCornerRadius(cornerRadius);
+            mActivityView.setCornerRadius(mCornerRadius);
         }
+
+        final int mode =
+                getResources().getConfiguration().uiMode & Configuration.UI_MODE_NIGHT_MASK;
+        switch (mode) {
+            case Configuration.UI_MODE_NIGHT_NO:
+                mPointerDrawable.setTint(getResources().getColor(R.color.bubbles_light));
+                break;
+            case Configuration.UI_MODE_NIGHT_YES:
+                mPointerDrawable.setTint(getResources().getColor(R.color.bubbles_dark));
+                break;
+        }
+        mPointerView.setBackground(mPointerDrawable);
     }
 
     /**
@@ -398,6 +490,7 @@
         mPointerView.setAlpha(alpha);
         if (mActivityView != null) {
             mActivityView.setAlpha(alpha);
+            mActivityView.bringToFront();
         }
     }
 
@@ -490,7 +583,7 @@
         if (DEBUG_BUBBLE_EXPANDED_VIEW) {
             Log.d(TAG, "update: bubble=" + (bubble != null ? bubble.getKey() : "null"));
         }
-        boolean isNew = mBubble == null;
+        boolean isNew = mBubble == null || didBackingContentChange(bubble);
         if (isNew || bubble != null && bubble.getKey().equals(mBubble.getKey())) {
             mBubble = bubble;
             mSettingsIcon.setContentDescription(getResources().getString(
@@ -523,6 +616,12 @@
         }
     }
 
+    private boolean didBackingContentChange(Bubble newBubble) {
+        boolean prevWasIntentBased = mBubble != null && mPendingIntent != null;
+        boolean newIsIntentBased = newBubble.getBubbleIntent() != null;
+        return prevWasIntentBased != newIsIntentBased;
+    }
+
     /**
      * Lets activity view know it should be shown / populated with activity content.
      */
@@ -551,6 +650,11 @@
         if (DEBUG_BUBBLE_EXPANDED_VIEW) {
             Log.d(TAG, "updateHeight: bubble=" + getBubbleKey());
         }
+
+        if (mExpandedViewContainerLocation == null) {
+            return;
+        }
+
         if (usingActivityView()) {
             float desiredHeight = mOverflowHeight;
             if (!mIsOverflow) {
@@ -558,7 +662,7 @@
             }
             float height = Math.min(desiredHeight, getMaxExpandedHeight());
             height = Math.max(height, mIsOverflow? mOverflowHeight : mMinHeight);
-            LayoutParams lp = (LayoutParams) mActivityView.getLayoutParams();
+            ViewGroup.LayoutParams lp = mActivityView.getLayoutParams();
             mNeedsNewHeight = lp.height != height;
             if (!mKeyboardVisible) {
                 // If the keyboard is visible... don't adjust the height because that will cause
@@ -568,7 +672,8 @@
                 mNeedsNewHeight = false;
             }
             if (DEBUG_BUBBLE_EXPANDED_VIEW) {
-                Log.d(TAG, "updateHeight: bubble=" + getBubbleKey() + " height=" + height
+                Log.d(TAG, "updateHeight: bubble=" + getBubbleKey()
+                        + " height=" + height
                         + " mNeedsNewHeight=" + mNeedsNewHeight);
             }
         }
@@ -576,28 +681,40 @@
 
     private int getMaxExpandedHeight() {
         mWindowManager.getDefaultDisplay().getRealSize(mDisplaySize);
-        int[] windowLocation = mActivityView.getLocationOnScreen();
         int bottomInset = getRootWindowInsets() != null
                 ? getRootWindowInsets().getStableInsetBottom()
                 : 0;
-        return mDisplaySize.y - windowLocation[1] - mSettingsIconHeight - mPointerHeight
+
+        return mDisplaySize.y
+                - mExpandedViewContainerLocation[1]
+                - getPaddingTop()
+                - getPaddingBottom()
+                - mSettingsIconHeight
+                - mPointerHeight
                 - mPointerMargin - bottomInset;
     }
 
     /**
      * Update appearance of the expanded view being displayed.
+     *
+     * @param containerLocationOnScreen The location on-screen of the container the expanded view is
+     *                                  added to. This allows us to calculate max height without
+     *                                  waiting for layout.
      */
-    public void updateView() {
+    public void updateView(int[] containerLocationOnScreen) {
         if (DEBUG_BUBBLE_EXPANDED_VIEW) {
             Log.d(TAG, "updateView: bubble="
                     + getBubbleKey());
         }
+
+        mExpandedViewContainerLocation = containerLocationOnScreen;
+
         if (usingActivityView()
                 && mActivityView.getVisibility() == VISIBLE
                 && mActivityView.isAttachedToWindow()) {
             mActivityView.onLocationChanged();
+            updateHeight();
         }
-        updateHeight();
     }
 
     /**
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleManageEducationView.java b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleManageEducationView.java
index f4d6432..4712012 100644
--- a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleManageEducationView.java
+++ b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleManageEducationView.java
@@ -17,10 +17,8 @@
 package com.android.systemui.bubbles;
 
 import android.content.Context;
-import android.content.res.Resources;
 import android.content.res.TypedArray;
 import android.graphics.Color;
-import android.graphics.drawable.ShapeDrawable;
 import android.util.AttributeSet;
 import android.view.View;
 import android.widget.LinearLayout;
@@ -28,7 +26,6 @@
 
 import com.android.internal.util.ContrastColorUtil;
 import com.android.systemui.R;
-import com.android.systemui.recents.TriangleShape;
 
 /**
  * Educational view to highlight the manage button that allows a user to configure the settings
@@ -36,7 +33,6 @@
  */
 public class BubbleManageEducationView extends LinearLayout {
 
-    private View mPointerView;
     private View mManageView;
 
     public BubbleManageEducationView(Context context) {
@@ -70,26 +66,8 @@
         ta.recycle();
 
         textColor = ContrastColorUtil.ensureTextContrast(textColor, bgColor, true);
+        ((TextView) findViewById(R.id.user_education_title)).setTextColor(textColor);
         ((TextView) findViewById(R.id.user_education_description)).setTextColor(textColor);
-
-        final Resources res = getResources();
-        final int pointerWidth = res.getDimensionPixelSize(R.dimen.bubble_pointer_width);
-        final int pointerHeight = res.getDimensionPixelSize(R.dimen.bubble_pointer_height);
-
-        ShapeDrawable triangleShape =
-                new ShapeDrawable(TriangleShape.create(
-                        pointerWidth, pointerHeight, false /* isPointingUp */));
-        triangleShape.setTint(bgColor);
-
-        mPointerView = findViewById(R.id.user_education_pointer);
-        mPointerView.setBackground(triangleShape);
-    }
-
-    /**
-     * Specifies the x value this pointer should point to.
-     */
-    public void setPointerPosition(int x) {
-        mPointerView.setTranslationX(x - (mPointerView.getWidth() / 2));
     }
 
     /**
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleOverflow.java b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleOverflow.java
index b77e226..dadcb3a 100644
--- a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleOverflow.java
+++ b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleOverflow.java
@@ -22,9 +22,9 @@
 import static com.android.systemui.bubbles.BadgedImageView.DEFAULT_PATH_SIZE;
 
 import android.content.Context;
-import android.content.res.TypedArray;
+import android.content.res.Configuration;
+import android.content.res.Resources;
 import android.graphics.Bitmap;
-import android.graphics.Color;
 import android.graphics.Matrix;
 import android.graphics.Path;
 import android.graphics.drawable.AdaptiveIconDrawable;
@@ -62,13 +62,12 @@
 
     void setUpOverflow(ViewGroup parentViewGroup, BubbleStackView stackView) {
         updateDimensions();
-
         mExpandedView = (BubbleExpandedView) mInflater.inflate(
                 R.layout.bubble_expanded_view, parentViewGroup /* root */,
                 false /* attachToRoot */);
         mExpandedView.setOverflow(true);
         mExpandedView.setStackView(stackView);
-
+        mExpandedView.applyThemeAttrs();
         updateIcon(mContext, parentViewGroup);
     }
 
@@ -89,19 +88,23 @@
                 false /* attachToRoot */);
         mOverflowBtn.setContentDescription(mContext.getResources().getString(
                 R.string.bubble_overflow_button_content_description));
+        Resources res = mContext.getResources();
 
-        TypedArray ta = mContext.obtainStyledAttributes(
-                new int[]{android.R.attr.colorBackgroundFloating});
-        int bgColor = ta.getColor(0, Color.WHITE /* default */);
-        ta.recycle();
-
+        // Set color for button icon and dot
         TypedValue typedValue = new TypedValue();
         mContext.getTheme().resolveAttribute(android.R.attr.colorAccent, typedValue, true);
         int colorAccent = mContext.getColor(typedValue.resourceId);
         mOverflowBtn.getDrawable().setTint(colorAccent);
         mDotColor = colorAccent;
 
-        ColorDrawable bg = new ColorDrawable(bgColor);
+        // Set color for button and activity background
+        ColorDrawable bg = new ColorDrawable(res.getColor(R.color.bubbles_light));
+        final int mode = res.getConfiguration().uiMode & Configuration.UI_MODE_NIGHT_MASK;
+        if (mode == Configuration.UI_MODE_NIGHT_YES) {
+            bg = new ColorDrawable(res.getColor(R.color.bubbles_dark));
+        }
+
+        // Apply icon inset
         InsetDrawable fg = new InsetDrawable(mOverflowBtn.getDrawable(),
                 mBitmapSize - mIconBitmapSize /* inset */);
         AdaptiveIconDrawable adaptiveIconDrawable = new AdaptiveIconDrawable(bg, fg);
@@ -111,6 +114,7 @@
                 null /* user */,
                 true /* shrinkNonAdaptiveIcons */).icon;
 
+        // Get path with dot location
         float scale = iconFactory.getNormalizer().getScale(mOverflowBtn.getDrawable(),
                 null /* outBounds */, null /* path */, null /* outMaskShape */);
         float radius = DEFAULT_PATH_SIZE / 2f;
@@ -121,14 +125,9 @@
                 radius /* pivot y */);
         mPath.transform(matrix);
 
-        mOverflowBtn.setVisibility(GONE);
         mOverflowBtn.setRenderedBubble(this);
     }
 
-    ImageView getBtn() {
-        return mOverflowBtn;
-    }
-
     void setVisible(int visible) {
         mOverflowBtn.setVisibility(visible);
     }
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleOverflowActivity.java b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleOverflowActivity.java
index b4672c1..b644079 100644
--- a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleOverflowActivity.java
+++ b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleOverflowActivity.java
@@ -27,6 +27,7 @@
 import android.content.res.Resources;
 import android.content.res.TypedArray;
 import android.graphics.Color;
+import android.graphics.drawable.Drawable;
 import android.os.Bundle;
 import android.util.DisplayMetrics;
 import android.util.Log;
@@ -100,7 +101,6 @@
     public void onCreate(Bundle savedInstanceState) {
         super.onCreate(savedInstanceState);
         setContentView(R.layout.bubble_overflow_activity);
-        setBackgroundColor();
 
         mEmptyState = findViewById(R.id.bubble_overflow_empty_state);
         mRecyclerView = findViewById(R.id.bubble_overflow_recycler);
@@ -141,34 +141,25 @@
      * Handle theme changes.
      */
     void updateTheme() {
-        final int mode =
-                getResources().getConfiguration().uiMode & Configuration.UI_MODE_NIGHT_MASK;
+        Resources res = getResources();
+        final int mode = res.getConfiguration().uiMode & Configuration.UI_MODE_NIGHT_MASK;
         switch (mode) {
-            case Configuration.UI_MODE_NIGHT_NO:
-                if (DEBUG_OVERFLOW) {
-                    Log.d(TAG, "Set overflow UI to light mode");
-                }
-                mEmptyStateImage.setImageDrawable(
-                        getResources().getDrawable(R.drawable.ic_empty_bubble_overflow_light));
-                break;
             case Configuration.UI_MODE_NIGHT_YES:
-                if (DEBUG_OVERFLOW) {
-                    Log.d(TAG, "Set overflow UI to dark mode");
-                }
                 mEmptyStateImage.setImageDrawable(
-                        getResources().getDrawable(R.drawable.ic_empty_bubble_overflow_dark));
+                        res.getDrawable(R.drawable.ic_empty_bubble_overflow_dark));
+                findViewById(android.R.id.content)
+                        .setBackgroundColor(res.getColor(R.color.bubbles_dark));
+                break;
+
+            case Configuration.UI_MODE_NIGHT_NO:
+                mEmptyStateImage.setImageDrawable(
+                        res.getDrawable(R.drawable.ic_empty_bubble_overflow_light));
+                findViewById(android.R.id.content)
+                        .setBackgroundColor(res.getColor(R.color.bubbles_light));
                 break;
         }
     }
 
-    void setBackgroundColor() {
-        final TypedArray ta = getApplicationContext().obtainStyledAttributes(
-                new int[]{android.R.attr.colorBackgroundFloating});
-        int bgColor = ta.getColor(0, Color.WHITE);
-        ta.recycle();
-        findViewById(android.R.id.content).setBackgroundColor(bgColor);
-    }
-
     void onDataChanged(List<Bubble> bubbles) {
         mOverflowBubbles.clear();
         mOverflowBubbles.addAll(bubbles);
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleStackView.java b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleStackView.java
index 95c8d08..23bd174 100644
--- a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleStackView.java
+++ b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleStackView.java
@@ -49,6 +49,7 @@
 import android.graphics.Region;
 import android.graphics.drawable.TransitionDrawable;
 import android.os.Bundle;
+import android.os.Handler;
 import android.provider.Settings;
 import android.util.Log;
 import android.view.Choreographer;
@@ -56,6 +57,8 @@
 import android.view.Gravity;
 import android.view.LayoutInflater;
 import android.view.MotionEvent;
+import android.view.SurfaceControl;
+import android.view.SurfaceView;
 import android.view.View;
 import android.view.ViewGroup;
 import android.view.ViewOutlineProvider;
@@ -79,10 +82,10 @@
 
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.util.ContrastColorUtil;
-import com.android.internal.widget.ViewClippingUtil;
 import com.android.systemui.Interpolators;
 import com.android.systemui.Prefs;
 import com.android.systemui.R;
+import com.android.systemui.bubbles.animation.AnimatableScaleMatrix;
 import com.android.systemui.bubbles.animation.ExpandedAnimationController;
 import com.android.systemui.bubbles.animation.PhysicsAnimationLayout;
 import com.android.systemui.bubbles.animation.StackAnimationController;
@@ -91,7 +94,6 @@
 import com.android.systemui.shared.system.SysUiStatsLog;
 import com.android.systemui.statusbar.notification.collection.NotificationEntry;
 import com.android.systemui.statusbar.phone.CollapsedStatusBarFragment;
-import com.android.systemui.statusbar.phone.NotificationShadeWindowController;
 import com.android.systemui.util.DismissCircleView;
 import com.android.systemui.util.FloatingContentCoordinator;
 import com.android.systemui.util.RelativeTouchListener;
@@ -148,6 +150,22 @@
                     StackAnimationController.IME_ANIMATION_STIFFNESS,
                     StackAnimationController.DEFAULT_BOUNCINESS);
 
+    private final PhysicsAnimator.SpringConfig mScaleInSpringConfig =
+            new PhysicsAnimator.SpringConfig(300f, 0.9f);
+
+    private final PhysicsAnimator.SpringConfig mScaleOutSpringConfig =
+            new PhysicsAnimator.SpringConfig(900f, 1f);
+
+    private final PhysicsAnimator.SpringConfig mTranslateSpringConfig =
+            new PhysicsAnimator.SpringConfig(
+                    SpringForce.STIFFNESS_LOW, SpringForce.DAMPING_RATIO_NO_BOUNCY);
+
+    /**
+     * Handler to use for all delayed animations - this way, we can easily cancel them before
+     * starting a new animation.
+     */
+    private final Handler mDelayedAnimationHandler = new Handler();
+
     /**
      * Interface to synchronize {@link View} state and the screen.
      *
@@ -187,8 +205,6 @@
 
     private Point mDisplaySize;
 
-    private final SpringAnimation mExpandedViewXAnim;
-    private final SpringAnimation mExpandedViewYAnim;
     private final BubbleData mBubbleData;
 
     private final ValueAnimator mDesaturateAndDarkenAnimator;
@@ -200,6 +216,24 @@
 
     private FrameLayout mExpandedViewContainer;
 
+    /** Matrix used to scale the expanded view container with a given pivot point. */
+    private final AnimatableScaleMatrix mExpandedViewContainerMatrix = new AnimatableScaleMatrix();
+
+    /**
+     * SurfaceView that we draw screenshots of animating-out bubbles into. This allows us to animate
+     * between bubble activities without needing both to be alive at the same time.
+     */
+    private SurfaceView mAnimatingOutSurfaceView;
+
+    /** Container for the animating-out SurfaceView. */
+    private FrameLayout mAnimatingOutSurfaceContainer;
+
+    /**
+     * Buffer containing a screenshot of the animating-out bubble. This is drawn into the
+     * SurfaceView during animations.
+     */
+    private SurfaceControl.ScreenshotGraphicBuffer mAnimatingOutBubbleBuffer;
+
     private BubbleFlyoutView mFlyout;
     /** Runnable that fades out the flyout and then sets it to GONE. */
     private Runnable mHideFlyout = () -> animateFlyoutCollapsed(true, 0 /* velX */);
@@ -231,8 +265,7 @@
     private int mBubblePaddingTop;
     private int mBubbleTouchPadding;
     private int mExpandedViewPadding;
-    private int mExpandedAnimateXDistance;
-    private int mExpandedAnimateYDistance;
+    private int mCornerRadius;
     private int mPointerHeight;
     private int mStatusBarHeight;
     private int mImeOffset;
@@ -267,6 +300,7 @@
 
     private boolean mViewUpdatedRequested = false;
     private boolean mIsExpansionAnimating = false;
+    private boolean mIsBubbleSwitchAnimating = false;
     private boolean mShowingDismiss = false;
 
     /** The view to desaturate/darken when magneted to the dismiss target. */
@@ -292,20 +326,6 @@
     private ViewTreeObserver.OnDrawListener mSystemGestureExcludeUpdater =
             this::updateSystemGestureExcludeRects;
 
-    private ViewClippingUtil.ClippingParameters mClippingParameters =
-            new ViewClippingUtil.ClippingParameters() {
-
-                @Override
-                public boolean shouldFinish(View view) {
-                    return false;
-                }
-
-                @Override
-                public boolean isClippingEnablingAllowed(View view) {
-                    return !mIsExpanded;
-                }
-            };
-
     /** Float property that 'drags' the flyout. */
     private final FloatPropertyCompat mFlyoutCollapseProperty =
             new FloatPropertyCompat("FlyoutCollapseSpring") {
@@ -348,8 +368,6 @@
     @NonNull
     private final SurfaceSynchronizer mSurfaceSynchronizer;
 
-    private final NotificationShadeWindowController mNotificationShadeWindowController;
-
     /**
      * Callback to run when the IME visibility changes - BubbleController uses this to update the
      * Bubbles window focusability flags with the WindowManager.
@@ -460,6 +478,13 @@
     private OnClickListener mBubbleClickListener = new OnClickListener() {
         @Override
         public void onClick(View view) {
+            // Bubble clicks either trigger expansion/collapse or a bubble switch, both of which we
+            // shouldn't interrupt. These are quick transitions, so it's not worth trying to adjust
+            // the animations inflight.
+            if (mIsExpansionAnimating || mIsBubbleSwitchAnimating) {
+                return;
+            }
+
             final Bubble clickedBubble = mBubbleData.getBubbleWithView(view);
 
             // If the bubble has since left us, ignore the click.
@@ -524,6 +549,8 @@
                         mMagneticTarget,
                         mIndividualBubbleMagnetListener);
 
+                hideImeFromExpandedBubble();
+
                 // Save the magnetized individual bubble so we can dispatch touch events to it.
                 mMagnetizedObject = mExpandedAnimationController.getMagnetizedBubbleDraggingOut();
             } else {
@@ -682,7 +709,6 @@
             @Nullable SurfaceSynchronizer synchronizer,
             FloatingContentCoordinator floatingContentCoordinator,
             SysUiState sysUiState,
-            NotificationShadeWindowController notificationShadeWindowController,
             Runnable allBubblesAnimatedOutAction,
             Consumer<Boolean> onImeVisibilityChanged) {
         super(context);
@@ -691,7 +717,6 @@
         mInflater = LayoutInflater.from(context);
 
         mSysUiState = sysUiState;
-        mNotificationShadeWindowController = notificationShadeWindowController;
 
         Resources res = getResources();
         mMaxBubbles = res.getInteger(R.integer.bubbles_max_rendered);
@@ -699,10 +724,6 @@
         mBubbleElevation = res.getDimensionPixelSize(R.dimen.bubble_elevation);
         mBubblePaddingTop = res.getDimensionPixelSize(R.dimen.bubble_padding_top);
         mBubbleTouchPadding = res.getDimensionPixelSize(R.dimen.bubble_touch_padding);
-        mExpandedAnimateXDistance =
-                res.getDimensionPixelSize(R.dimen.bubble_expanded_animate_x_distance);
-        mExpandedAnimateYDistance =
-                res.getDimensionPixelSize(R.dimen.bubble_expanded_animate_y_distance);
         mPointerHeight = res.getDimensionPixelSize(R.dimen.bubble_pointer_height);
 
         mStatusBarHeight =
@@ -717,6 +738,11 @@
         mExpandedViewPadding = res.getDimensionPixelSize(R.dimen.bubble_expanded_view_padding);
         int elevation = res.getDimensionPixelSize(R.dimen.bubble_elevation);
 
+        final TypedArray ta = mContext.obtainStyledAttributes(
+                new int[] {android.R.attr.dialogCornerRadius});
+        mCornerRadius = ta.getDimensionPixelSize(0, 0);
+        ta.recycle();
+
         final Runnable onBubbleAnimatedOut = () -> {
             if (getBubbleCount() == 0) {
                 allBubblesAnimatedOutAction.run();
@@ -750,6 +776,24 @@
         mExpandedViewContainer.setClipChildren(false);
         addView(mExpandedViewContainer);
 
+        mAnimatingOutSurfaceContainer = new FrameLayout(getContext());
+        mAnimatingOutSurfaceContainer.setLayoutParams(
+                new ViewGroup.LayoutParams(WRAP_CONTENT, WRAP_CONTENT));
+        addView(mAnimatingOutSurfaceContainer);
+
+        mAnimatingOutSurfaceView = new SurfaceView(getContext());
+        mAnimatingOutSurfaceView.setUseAlpha();
+        mAnimatingOutSurfaceView.setZOrderOnTop(true);
+        mAnimatingOutSurfaceView.setCornerRadius(mCornerRadius);
+        mAnimatingOutSurfaceView.setLayoutParams(new ViewGroup.LayoutParams(0, 0));
+        mAnimatingOutSurfaceContainer.addView(mAnimatingOutSurfaceView);
+
+        mAnimatingOutSurfaceContainer.setPadding(
+                mExpandedViewPadding,
+                mExpandedViewPadding,
+                mExpandedViewPadding,
+                mExpandedViewPadding);
+
         setUpManageMenu();
 
         setUpFlyout();
@@ -795,26 +839,6 @@
         // MagnetizedObjects.
         mMagneticTarget = new MagnetizedObject.MagneticTarget(mDismissTargetCircle, dismissRadius);
 
-        mExpandedViewXAnim =
-                new SpringAnimation(mExpandedViewContainer, DynamicAnimation.TRANSLATION_X);
-        mExpandedViewXAnim.setSpring(
-                new SpringForce()
-                        .setStiffness(SpringForce.STIFFNESS_LOW)
-                        .setDampingRatio(SpringForce.DAMPING_RATIO_LOW_BOUNCY));
-
-        mExpandedViewYAnim =
-                new SpringAnimation(mExpandedViewContainer, DynamicAnimation.TRANSLATION_Y);
-        mExpandedViewYAnim.setSpring(
-                new SpringForce()
-                        .setStiffness(SpringForce.STIFFNESS_LOW)
-                        .setDampingRatio(SpringForce.DAMPING_RATIO_LOW_BOUNCY));
-        mExpandedViewYAnim.addEndListener((anim, cancelled, value, velocity) -> {
-            if (mIsExpanded && mExpandedBubble != null
-                    && mExpandedBubble.getExpandedView() != null) {
-                mExpandedBubble.getExpandedView().updateView();
-            }
-        });
-
         setClipChildren(false);
         setFocusable(true);
         mBubbleContainer.bringToFront();
@@ -849,7 +873,7 @@
                     if (mIsExpanded) {
                         mExpandedViewContainer.setTranslationY(getExpandedViewY());
                         if (mExpandedBubble != null && mExpandedBubble.getExpandedView() != null) {
-                            mExpandedBubble.getExpandedView().updateView();
+                            mExpandedBubble.getExpandedView().updateView(getLocationOnScreen());
                         }
                     }
 
@@ -973,15 +997,10 @@
 
         PhysicsAnimator.getInstance(mManageMenu).setDefaultSpringConfig(mManageSpringConfig);
 
-        final TypedArray ta = mContext.obtainStyledAttributes(
-                new int[] {android.R.attr.dialogCornerRadius});
-        final int menuCornerRadius = ta.getDimensionPixelSize(0, 0);
-        ta.recycle();
-
         mManageMenu.setOutlineProvider(new ViewOutlineProvider() {
             @Override
             public void getOutline(View view, Outline outline) {
-                outline.setRoundRect(0, 0, view.getWidth(), view.getHeight(), menuCornerRadius);
+                outline.setRoundRect(0, 0, view.getWidth(), view.getHeight(), mCornerRadius);
             }
         });
         mManageMenu.setClipToOutline(true);
@@ -1096,15 +1115,17 @@
             mBubbleOverflow = new BubbleOverflow(getContext());
             mBubbleOverflow.setUpOverflow(mBubbleContainer, this);
         } else {
-            mBubbleContainer.removeView(mBubbleOverflow.getBtn());
-            mBubbleOverflow.updateDimensions();
-            mBubbleOverflow.updateIcon(mContext,this);
+            mBubbleContainer.removeView(mBubbleOverflow.getIconView());
+            mBubbleOverflow.setUpOverflow(mBubbleContainer, this);
             overflowBtnIndex = mBubbleContainer.getChildCount();
         }
-        mBubbleContainer.addView(mBubbleOverflow.getBtn(), overflowBtnIndex,
+        mBubbleContainer.addView(mBubbleOverflow.getIconView(), overflowBtnIndex,
                 new FrameLayout.LayoutParams(WRAP_CONTENT, WRAP_CONTENT));
-
-        mBubbleOverflow.getBtn().setOnClickListener(v -> setSelectedBubble(mBubbleOverflow));
+        mBubbleOverflow.getIconView().setOnClickListener(v -> {
+            setSelectedBubble(mBubbleOverflow);
+            showManageMenu(false);
+        });
+        updateOverflowVisibility();
     }
     /**
      * Handle theme changes.
@@ -1114,6 +1135,7 @@
         setUpOverflow();
         setUpUserEducation();
         setUpManageMenu();
+        updateExpandedViewTheme();
     }
 
     /** Respond to the phone being rotated by repositioning the stack and hiding any flyouts. */
@@ -1215,6 +1237,18 @@
         setupLocalMenu(info);
     }
 
+    void updateExpandedViewTheme() {
+        final List<Bubble> bubbles = mBubbleData.getBubbles();
+        if (bubbles.isEmpty()) {
+            return;
+        }
+        bubbles.forEach(bubble -> {
+            if (bubble.getExpandedView() != null) {
+                bubble.getExpandedView().applyThemeAttrs();
+            }
+        });
+    }
+
     void setupLocalMenu(AccessibilityNodeInfo info) {
         Resources res = mContext.getResources();
 
@@ -1399,7 +1433,6 @@
 
         mBubbleContainer.addView(bubble.getIconView(), 0,
                 new FrameLayout.LayoutParams(WRAP_CONTENT, WRAP_CONTENT));
-        ViewClippingUtil.setClippingDeactivated(bubble.getIconView(), true, mClippingParameters);
         animateInFlyoutForBubble(bubble);
         requestUpdate();
         logBubbleEvent(bubble, SysUiStatsLog.BUBBLE_UICHANGED__ACTION__POSTED);
@@ -1467,6 +1500,31 @@
             mBubbleData.setShowingOverflow(true);
         }
 
+        // If we're expanded, screenshot the currently expanded bubble (before expanding the newly
+        // selected bubble) so we can animate it out.
+        if (mIsExpanded && mExpandedBubble != null && mExpandedBubble.getExpandedView() != null) {
+            if (mExpandedBubble != null && mExpandedBubble.getExpandedView() != null) {
+                // Before screenshotting, have the real ActivityView show on top of other surfaces
+                // so that the screenshot doesn't flicker on top of it.
+                mExpandedBubble.getExpandedView().setSurfaceZOrderedOnTop(true);
+            }
+
+            try {
+                screenshotAnimatingOutBubbleIntoSurface((success) -> {
+                    mAnimatingOutSurfaceContainer.setVisibility(
+                            success ? View.VISIBLE : View.INVISIBLE);
+                    showNewlySelectedBubble(bubbleToSelect);
+                });
+            } catch (Exception e) {
+                showNewlySelectedBubble(bubbleToSelect);
+                e.printStackTrace();
+            }
+        } else {
+            showNewlySelectedBubble(bubbleToSelect);
+        }
+    }
+
+    private void showNewlySelectedBubble(BubbleViewProvider bubbleToSelect) {
         final BubbleViewProvider previouslySelected = mExpandedBubble;
         mExpandedBubble = bubbleToSelect;
         updatePointerPosition();
@@ -1477,7 +1535,15 @@
             // expanded view becomes visible on the screen. See b/126856255
             mExpandedViewContainer.setAlpha(0.0f);
             mSurfaceSynchronizer.syncSurfaceAndRun(() -> {
-                previouslySelected.setContentVisibility(false);
+                if (previouslySelected != null) {
+                    previouslySelected.setContentVisibility(false);
+                }
+                if (previouslySelected != null && previouslySelected.getExpandedView() != null) {
+                    // Hide the currently expanded bubble's IME if it's visible before switching
+                    // to a new bubble.
+                    previouslySelected.getExpandedView().hideImeIfVisible();
+                }
+
                 updateExpandedBubble();
                 requestUpdate();
 
@@ -1594,12 +1660,19 @@
                 final int inset = getResources().getDimensionPixelSize(
                         R.dimen.bubbles_manage_education_top_inset);
                 mManageEducationView.bringToFront();
-                mManageEducationView.setManageViewPosition(mTempRect.left,
-                        mTempRect.top - viewHeight + inset);
-                mManageEducationView.setPointerPosition(mTempRect.centerX() - mTempRect.left);
+                mManageEducationView.setManageViewPosition(0, mTempRect.top - viewHeight + inset);
                 mManageEducationView.animate()
                         .setDuration(ANIMATE_STACK_USER_EDUCATION_DURATION)
                         .setInterpolator(FAST_OUT_SLOW_IN).alpha(1);
+                mManageEducationView.findViewById(R.id.manage).setOnClickListener(view -> {
+                            mExpandedBubble.getExpandedView().findViewById(R.id.settings_button)
+                                    .performClick();
+                            maybeShowManageEducation(false);
+                        });
+                mManageEducationView.findViewById(R.id.got_it).setOnClickListener(view ->
+                        maybeShowManageEducation(false));
+                mManageEducationView.setOnClickListener(view ->
+                        maybeShowManageEducation(false));
             });
             Prefs.putBoolean(getContext(), HAS_SEEN_BUBBLES_MANAGE_EDUCATION, true);
         } else if (!show
@@ -1656,84 +1729,262 @@
         }
     }
 
+    void hideImeFromExpandedBubble() {
+        if (mExpandedBubble != null && mExpandedBubble.getExpandedView() != null) {
+            // Hide the currently expanded bubble's IME if it's visible before switching to a new
+            // bubble.
+            mExpandedBubble.getExpandedView().hideImeIfVisible();
+        }
+    }
+
     private void beforeExpandedViewAnimation() {
+        mIsExpansionAnimating = true;
         hideFlyoutImmediate();
         updateExpandedBubble();
         updateExpandedView();
-        mIsExpansionAnimating = true;
     }
 
     private void afterExpandedViewAnimation() {
-        updateExpandedView();
         mIsExpansionAnimating = false;
+        updateExpandedView();
         requestUpdate();
     }
 
-    private void animateCollapse() {
-        // Hide the menu if it's visible.
-        showManageMenu(false);
-
-        mIsExpanded = false;
-        final BubbleViewProvider previouslySelected = mExpandedBubble;
-        beforeExpandedViewAnimation();
-        maybeShowManageEducation(false);
-
-        if (DEBUG_BUBBLE_STACK_VIEW) {
-            Log.d(TAG, "animateCollapse");
-            Log.d(TAG, BubbleDebugConfig.formatBubblesString(getBubblesOnScreen(),
-                    mExpandedBubble));
-        }
-        updateOverflowVisibility();
-        mBubbleContainer.cancelAllAnimations();
-        mExpandedAnimationController.collapseBackToStack(
-                mStackAnimationController.getStackPositionAlongNearestHorizontalEdge()
-                /* collapseTo */,
-                () -> {
-                    mBubbleContainer.setActiveController(mStackAnimationController);
-                    afterExpandedViewAnimation();
-                    previouslySelected.setContentVisibility(false);
-                });
-
-        mExpandedViewXAnim.animateToFinalPosition(getCollapsedX());
-        mExpandedViewYAnim.animateToFinalPosition(getCollapsedY());
-        mExpandedViewContainer.animate()
-                .setDuration(100)
-                .alpha(0f);
-    }
-
     private void animateExpansion() {
+        cancelDelayedExpandCollapseSwitchAnimations();
+
         mIsExpanded = true;
         hideStackUserEducation(true /* fromExpansion */);
         beforeExpandedViewAnimation();
 
         mBubbleContainer.setActiveController(mExpandedAnimationController);
         updateOverflowVisibility();
+        updatePointerPosition();
         mExpandedAnimationController.expandFromStack(() -> {
-            updatePointerPosition();
             afterExpandedViewAnimation();
             maybeShowManageEducation(true);
         } /* after */);
 
-        mExpandedViewContainer.setTranslationX(getCollapsedX());
-        mExpandedViewContainer.setTranslationY(getCollapsedY());
-        mExpandedViewContainer.setAlpha(0f);
+        mExpandedViewContainer.setTranslationX(0);
+        mExpandedViewContainer.setTranslationY(getExpandedViewY());
+        mExpandedViewContainer.setAlpha(1f);
 
-        mExpandedViewXAnim.animateToFinalPosition(0f);
-        mExpandedViewYAnim.animateToFinalPosition(getExpandedViewY());
-        mExpandedViewContainer.animate()
-                .setDuration(100)
-                .alpha(1f);
+        // X-value of the bubble we're expanding, once it's settled in its row.
+        final float bubbleWillBeAtX =
+                mExpandedAnimationController.getBubbleLeft(
+                        mBubbleData.getBubbles().indexOf(mExpandedBubble));
+
+        // How far horizontally the bubble will be animating. We'll wait a bit longer for bubbles
+        // that are animating farther, so that the expanded view doesn't move as much.
+        final float horizontalDistanceAnimated =
+                Math.abs(bubbleWillBeAtX
+                        - mStackAnimationController.getStackPosition().x);
+
+        // Wait for the path animation target to reach its end, and add a small amount of extra time
+        // if the bubble is moving a lot horizontally.
+        long startDelay = 0L;
+
+        // Should not happen since we lay out before expanding, but just in case...
+        if (getWidth() > 0) {
+            startDelay = (long)
+                    (ExpandedAnimationController.EXPAND_COLLAPSE_TARGET_ANIM_DURATION
+                            + (horizontalDistanceAnimated / getWidth()) * 30);
+        }
+
+        // Set the pivot point for the scale, so the expanded view animates out from the bubble.
+        mExpandedViewContainerMatrix.setScale(
+                0f, 0f,
+                bubbleWillBeAtX + mBubbleSize / 2f, getExpandedViewY());
+        mExpandedViewContainer.setAnimationMatrix(mExpandedViewContainerMatrix);
+
+        if (mExpandedBubble != null && mExpandedBubble.getExpandedView() != null) {
+            mExpandedBubble.getExpandedView().setSurfaceZOrderedOnTop(false);
+        }
+
+        mDelayedAnimationHandler.postDelayed(() ->
+                        PhysicsAnimator.getInstance(mExpandedViewContainerMatrix)
+                                .spring(AnimatableScaleMatrix.SCALE_X,
+                                        AnimatableScaleMatrix.getAnimatableValueForScaleFactor(1f),
+                                        mScaleInSpringConfig)
+                                .spring(AnimatableScaleMatrix.SCALE_Y,
+                                        AnimatableScaleMatrix.getAnimatableValueForScaleFactor(1f),
+                                        mScaleInSpringConfig)
+                                .addUpdateListener((target, values) -> {
+                                    if (mExpandedBubble.getIconView() == null) {
+                                        return;
+                                    }
+                                    mExpandedViewContainerMatrix.postTranslate(
+                                            mExpandedBubble.getIconView().getTranslationX()
+                                                    - bubbleWillBeAtX,
+                                            0);
+                                    mExpandedViewContainer.setAnimationMatrix(
+                                            mExpandedViewContainerMatrix);
+                                })
+                                .withEndActions(() -> {
+                                    if (mExpandedBubble != null
+                                            && mExpandedBubble.getExpandedView() != null) {
+                                        mExpandedBubble.getExpandedView()
+                                                .setSurfaceZOrderedOnTop(false);
+                                    }
+                                })
+                                .start(), startDelay);
     }
 
-    private float getCollapsedX() {
-        return mStackAnimationController.getStackPosition().x < getWidth() / 2
-                ? -mExpandedAnimateXDistance
-                : mExpandedAnimateXDistance;
+    private void animateCollapse() {
+        cancelDelayedExpandCollapseSwitchAnimations();
+
+        // Hide the menu if it's visible.
+        showManageMenu(false);
+
+        mIsExpanded = false;
+        mIsExpansionAnimating = true;
+
+        mBubbleContainer.cancelAllAnimations();
+
+        // If we were in the middle of swapping, the animating-out surface would have been scaling
+        // to zero - finish it off.
+        PhysicsAnimator.getInstance(mAnimatingOutSurfaceContainer).cancel();
+        mAnimatingOutSurfaceContainer.setScaleX(0f);
+        mAnimatingOutSurfaceContainer.setScaleY(0f);
+
+        if (mExpandedBubble != null && mExpandedBubble.getExpandedView() != null) {
+            mExpandedBubble.getExpandedView().hideImeIfVisible();
+        }
+
+        // Let the expanded animation controller know that it shouldn't animate child adds/reorders
+        // since we're about to animate collapsed.
+        mExpandedAnimationController.notifyPreparingToCollapse();
+
+        final long startDelay =
+                (long) (ExpandedAnimationController.EXPAND_COLLAPSE_TARGET_ANIM_DURATION * 0.6f);
+        mDelayedAnimationHandler.postDelayed(() -> mExpandedAnimationController.collapseBackToStack(
+                mStackAnimationController.getStackPositionAlongNearestHorizontalEdge()
+                /* collapseTo */,
+                () -> mBubbleContainer.setActiveController(mStackAnimationController)), startDelay);
+
+        // We want to visually collapse into this bubble during the animation.
+        final View expandingFromBubble = mExpandedBubble.getIconView();
+
+        // X-value the bubble is animating from (back into the stack).
+        final float expandingFromBubbleAtX =
+                mExpandedAnimationController.getBubbleLeft(
+                        mBubbleData.getBubbles().indexOf(mExpandedBubble));
+
+        // Set the pivot point.
+        mExpandedViewContainerMatrix.setScale(
+                1f, 1f,
+                expandingFromBubbleAtX + mBubbleSize / 2f,
+                getExpandedViewY());
+
+        PhysicsAnimator.getInstance(mExpandedViewContainerMatrix).cancel();
+        PhysicsAnimator.getInstance(mExpandedViewContainerMatrix)
+                .spring(AnimatableScaleMatrix.SCALE_X, 0f, mScaleOutSpringConfig)
+                .spring(AnimatableScaleMatrix.SCALE_Y, 0f, mScaleOutSpringConfig)
+                .addUpdateListener((target, values) -> {
+                    if (expandingFromBubble != null) {
+                        // Follow the bubble as it translates!
+                        mExpandedViewContainerMatrix.postTranslate(
+                                expandingFromBubble.getTranslationX()
+                                        - expandingFromBubbleAtX, 0f);
+                    }
+
+                    mExpandedViewContainer.setAnimationMatrix(mExpandedViewContainerMatrix);
+
+                    // Hide early so we don't have a tiny little expanded view still visible at the
+                    // end of the scale animation.
+                    if (mExpandedViewContainerMatrix.getScaleX() < 0.05f) {
+                        mExpandedViewContainer.setVisibility(View.INVISIBLE);
+                    }
+                })
+                .withEndActions(() -> {
+                    final BubbleViewProvider previouslySelected = mExpandedBubble;
+                    beforeExpandedViewAnimation();
+                    maybeShowManageEducation(false);
+
+                    if (DEBUG_BUBBLE_STACK_VIEW) {
+                        Log.d(TAG, "animateCollapse");
+                        Log.d(TAG, BubbleDebugConfig.formatBubblesString(getBubblesOnScreen(),
+                                mExpandedBubble));
+                    }
+                    updateOverflowVisibility();
+
+                    afterExpandedViewAnimation();
+                    if (previouslySelected != null) {
+                        previouslySelected.setContentVisibility(false);
+                    }
+                })
+                .start();
     }
 
-    private float getCollapsedY() {
-        return Math.min(mStackAnimationController.getStackPosition().y,
-                mExpandedAnimateYDistance);
+    private void animateSwitchBubbles() {
+        // If we're no longer expanded, this is meaningless.
+        if (!mIsExpanded) {
+            return;
+        }
+
+        mIsBubbleSwitchAnimating = true;
+
+        // The surface contains a screenshot of the animating out bubble, so we just need to animate
+        // it out (and then release the GraphicBuffer).
+        PhysicsAnimator.getInstance(mAnimatingOutSurfaceContainer).cancel();
+        PhysicsAnimator.getInstance(mAnimatingOutSurfaceContainer)
+                .spring(DynamicAnimation.SCALE_X, 0f, mScaleOutSpringConfig)
+                .spring(DynamicAnimation.SCALE_Y, 0f, mScaleOutSpringConfig)
+                .spring(DynamicAnimation.TRANSLATION_Y,
+                        mAnimatingOutSurfaceContainer.getTranslationY() - mBubbleSize * 2,
+                        mTranslateSpringConfig)
+                .withEndActions(this::releaseAnimatingOutBubbleBuffer)
+                .start();
+
+        boolean isOverflow = mExpandedBubble != null
+                && mExpandedBubble.getKey().equals(BubbleOverflow.KEY);
+        float expandingFromBubbleDestinationX =
+                mExpandedAnimationController.getBubbleLeft(isOverflow ? getBubbleCount()
+                        : mBubbleData.getBubbles().indexOf(mExpandedBubble));
+
+        mExpandedViewContainer.setAlpha(1f);
+        mExpandedViewContainer.setVisibility(View.VISIBLE);
+
+        mExpandedViewContainerMatrix.setScale(
+                0f, 0f, expandingFromBubbleDestinationX + mBubbleSize / 2f, getExpandedViewY());
+        mExpandedViewContainer.setAnimationMatrix(mExpandedViewContainerMatrix);
+
+        mDelayedAnimationHandler.postDelayed(() -> {
+            if (!mIsExpanded) {
+                mIsBubbleSwitchAnimating = false;
+                return;
+            }
+
+            PhysicsAnimator.getInstance(mExpandedViewContainerMatrix)
+                    .spring(AnimatableScaleMatrix.SCALE_X,
+                            AnimatableScaleMatrix.getAnimatableValueForScaleFactor(1f),
+                            mScaleInSpringConfig)
+                    .spring(AnimatableScaleMatrix.SCALE_Y,
+                            AnimatableScaleMatrix.getAnimatableValueForScaleFactor(1f),
+                            mScaleInSpringConfig)
+                    .addUpdateListener((target, values) -> {
+                        mExpandedViewContainer.setAnimationMatrix(mExpandedViewContainerMatrix);
+                    })
+                    .withEndActions(() -> {
+                        if (mExpandedBubble != null && mExpandedBubble.getExpandedView() != null) {
+                            mExpandedBubble.getExpandedView().setSurfaceZOrderedOnTop(false);
+                        }
+
+                        mIsBubbleSwitchAnimating = false;
+                    })
+                    .start();
+        }, 25);
+    }
+
+    /**
+     * Cancels any delayed steps for expand/collapse and bubble switch animations, and resets the is
+     * animating flags for those animations.
+     */
+    private void cancelDelayedExpandCollapseSwitchAnimations() {
+        mDelayedAnimationHandler.removeCallbacksAndMessages(null);
+
+        mIsExpansionAnimating = false;
+        mIsBubbleSwitchAnimating = false;
     }
 
     private void notifyExpansionChanged(BubbleViewProvider bubble, boolean expanded) {
@@ -1800,9 +2051,13 @@
      */
     @Override
     public void subtractObscuredTouchableRegion(Region touchableRegion, View view) {
-        // If the notification shade is expanded, or the manage menu is open, we shouldn't let the
-        // ActivityView steal any touch events from any location.
-        if (mNotificationShadeWindowController.getPanelExpanded() || mShowingManage) {
+        // If the notification shade is expanded, or the manage menu is open, or we are showing
+        // manage bubbles user education, we shouldn't let the ActivityView steal any touch events
+        // from any location.
+        if (!mIsExpanded
+                || mShowingManage
+                || (mManageEducationView != null
+                    && mManageEducationView.getVisibility() == VISIBLE)) {
             touchableRegion.setEmpty();
         }
     }
@@ -2238,21 +2493,118 @@
             Log.d(TAG, "updateExpandedBubble()");
         }
 
-        if (mExpandedBubble != null && mExpandedBubble.getExpandedView() != null) {
-            // Hide the currently expanded bubble's IME if it's visible before switching to a new
-            // bubble.
-            mExpandedBubble.getExpandedView().hideImeIfVisible();
-        }
-
         mExpandedViewContainer.removeAllViews();
         if (mIsExpanded && mExpandedBubble != null
                 && mExpandedBubble.getExpandedView() != null) {
             BubbleExpandedView bev = mExpandedBubble.getExpandedView();
+            bev.setContentVisibility(false);
+            mExpandedViewContainerMatrix.setScaleX(0f);
+            mExpandedViewContainerMatrix.setScaleY(0f);
+            mExpandedViewContainer.setVisibility(View.INVISIBLE);
+            mExpandedViewContainer.setAlpha(0f);
             mExpandedViewContainer.addView(bev);
             bev.setManageClickListener((view) -> showManageMenu(!mShowingManage));
             bev.populateExpandedView();
-            mExpandedViewContainer.setVisibility(VISIBLE);
-            mExpandedViewContainer.setAlpha(1.0f);
+
+            if (!mIsExpansionAnimating) {
+                mSurfaceSynchronizer.syncSurfaceAndRun(() -> {
+                    post(this::animateSwitchBubbles);
+                });
+            }
+        }
+    }
+
+    /**
+     * Requests a snapshot from the currently expanded bubble's ActivityView and displays it in a
+     * SurfaceView. This allows us to load a newly expanded bubble's Activity into the ActivityView,
+     * while animating the (screenshot of the) previously selected bubble's content away.
+     *
+     * @param onComplete Callback to run once we're done here - called with 'false' if something
+     *                   went wrong, or 'true' if the SurfaceView is now showing a screenshot of the
+     *                   expanded bubble.
+     */
+    private void screenshotAnimatingOutBubbleIntoSurface(Consumer<Boolean> onComplete) {
+        if (mExpandedBubble == null || mExpandedBubble.getExpandedView() == null) {
+            // You can't animate null.
+            onComplete.accept(false);
+            return;
+        }
+
+        final BubbleExpandedView animatingOutExpandedView = mExpandedBubble.getExpandedView();
+
+        // Release the previous screenshot if it hasn't been released already.
+        if (mAnimatingOutBubbleBuffer != null) {
+            releaseAnimatingOutBubbleBuffer();
+        }
+
+        try {
+            mAnimatingOutBubbleBuffer = animatingOutExpandedView.snapshotActivitySurface();
+        } catch (Exception e) {
+            // If we fail for any reason, print the stack trace and then notify the callback of our
+            // failure. This is not expected to occur, but it's not worth crashing over.
+            Log.wtf(TAG, e);
+            onComplete.accept(false);
+        }
+
+        if (mAnimatingOutBubbleBuffer == null
+                || mAnimatingOutBubbleBuffer.getGraphicBuffer() == null) {
+            // While no exception was thrown, we were unable to get a snapshot.
+            onComplete.accept(false);
+            return;
+        }
+
+        // Make sure the surface container's properties have been reset.
+        PhysicsAnimator.getInstance(mAnimatingOutSurfaceContainer).cancel();
+        mAnimatingOutSurfaceContainer.setScaleX(1f);
+        mAnimatingOutSurfaceContainer.setScaleY(1f);
+        mAnimatingOutSurfaceContainer.setTranslationX(0);
+        mAnimatingOutSurfaceContainer.setTranslationY(0);
+
+        final int[] activityViewLocation =
+                mExpandedBubble.getExpandedView().getActivityViewLocationOnScreen();
+        final int[] surfaceViewLocation = mAnimatingOutSurfaceView.getLocationOnScreen();
+
+        // Translate the surface to overlap the real ActivityView.
+        mAnimatingOutSurfaceContainer.setTranslationY(
+                activityViewLocation[1] - surfaceViewLocation[1]);
+
+        // Set the width/height of the SurfaceView to match the snapshot.
+        mAnimatingOutSurfaceView.getLayoutParams().width =
+                mAnimatingOutBubbleBuffer.getGraphicBuffer().getWidth();
+        mAnimatingOutSurfaceView.getLayoutParams().height =
+                mAnimatingOutBubbleBuffer.getGraphicBuffer().getHeight();
+        mAnimatingOutSurfaceView.requestLayout();
+
+        // Post to wait for layout.
+        post(() -> {
+            // The buffer might have been destroyed if the user is mashing on bubbles, that's okay.
+            if (mAnimatingOutBubbleBuffer.getGraphicBuffer().isDestroyed()) {
+                onComplete.accept(false);
+                return;
+            }
+
+            if (!mIsExpanded) {
+                onComplete.accept(false);
+                return;
+            }
+
+            // Attach the buffer! We're now displaying the snapshot.
+            mAnimatingOutSurfaceView.getHolder().getSurface().attachAndQueueBufferWithColorSpace(
+                    mAnimatingOutBubbleBuffer.getGraphicBuffer(),
+                    mAnimatingOutBubbleBuffer.getColorSpace());
+
+            mSurfaceSynchronizer.syncSurfaceAndRun(() -> post(() -> onComplete.accept(true)));
+        });
+    }
+
+    /**
+     * Releases the buffer containing the screenshot of the animating-out bubble, if it exists and
+     * isn't yet destroyed.
+     */
+    private void releaseAnimatingOutBubbleBuffer() {
+        if (mAnimatingOutBubbleBuffer != null
+                && !mAnimatingOutBubbleBuffer.getGraphicBuffer().isDestroyed()) {
+            mAnimatingOutBubbleBuffer.getGraphicBuffer().destroy();
         }
     }
 
@@ -2262,19 +2614,10 @@
         }
 
         mExpandedViewContainer.setVisibility(mIsExpanded ? VISIBLE : GONE);
-        if (mIsExpanded) {
-            final float y = getExpandedViewY();
-            if (!mExpandedViewYAnim.isRunning()) {
-                // We're not animating so set the value
-                mExpandedViewContainer.setTranslationY(y);
-                if (mExpandedBubble != null && mExpandedBubble.getExpandedView() != null) {
-                    mExpandedBubble.getExpandedView().updateView();
-                }
-            } else {
-                // We are animating so update the value; there is an end listener on the animator
-                // that will ensure expandedeView.updateView gets called.
-                mExpandedViewYAnim.animateToFinalPosition(y);
-            }
+        if (mExpandedBubble != null && mExpandedBubble.getExpandedView() != null) {
+            mExpandedViewContainer.setTranslationY(getExpandedViewY());
+            mExpandedBubble.getExpandedView().updateView(
+                    mExpandedViewContainer.getLocationOnScreen());
         }
 
         mStackOnLeftOrWillBe = mStackAnimationController.isStackOnLeftSide();
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/animation/AnimatableScaleMatrix.java b/packages/SystemUI/src/com/android/systemui/bubbles/animation/AnimatableScaleMatrix.java
new file mode 100644
index 0000000..ae78336
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/bubbles/animation/AnimatableScaleMatrix.java
@@ -0,0 +1,137 @@
+/*
+ * Copyright (C) 2020 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.bubbles.animation;
+
+import android.graphics.Matrix;
+
+import androidx.dynamicanimation.animation.DynamicAnimation;
+import androidx.dynamicanimation.animation.FloatPropertyCompat;
+
+/**
+ * Matrix whose scale properties can be animated using physics animations, via the {@link #SCALE_X}
+ * and {@link #SCALE_Y} FloatProperties.
+ *
+ * This is useful when you need to perform a scale animation with a pivot point, since pivot points
+ * are not supported by standard View scale operations but are supported by matrices.
+ *
+ * NOTE: DynamicAnimation assumes that all custom properties are denominated in pixels, and thus
+ * considers 1 to be the smallest user-visible change for custom properties. This means that if you
+ * animate {@link #SCALE_X} and {@link #SCALE_Y} to 3f, for example, the animation would have only
+ * three frames.
+ *
+ * To work around this, whenever animating to a desired scale value, animate to the value returned
+ * by {@link #getAnimatableValueForScaleFactor} instead. The SCALE_X and SCALE_Y properties will
+ * convert that (larger) value into the appropriate scale factor when scaling the matrix.
+ */
+public class AnimatableScaleMatrix extends Matrix {
+
+    /**
+     * The X value of the scale.
+     *
+     * NOTE: This must be set or animated to the value returned by
+     * {@link #getAnimatableValueForScaleFactor}, not the desired scale factor itself.
+     */
+    public static final FloatPropertyCompat<AnimatableScaleMatrix> SCALE_X =
+            new FloatPropertyCompat<AnimatableScaleMatrix>("matrixScaleX") {
+        @Override
+        public float getValue(AnimatableScaleMatrix object) {
+            return getAnimatableValueForScaleFactor(object.mScaleX);
+        }
+
+        @Override
+        public void setValue(AnimatableScaleMatrix object, float value) {
+            object.setScaleX(value * DynamicAnimation.MIN_VISIBLE_CHANGE_SCALE);
+        }
+    };
+
+    /**
+     * The Y value of the scale.
+     *
+     * NOTE: This must be set or animated to the value returned by
+     * {@link #getAnimatableValueForScaleFactor}, not the desired scale factor itself.
+     */
+    public static final FloatPropertyCompat<AnimatableScaleMatrix> SCALE_Y =
+            new FloatPropertyCompat<AnimatableScaleMatrix>("matrixScaleY") {
+                @Override
+                public float getValue(AnimatableScaleMatrix object) {
+                    return getAnimatableValueForScaleFactor(object.mScaleY);
+                }
+
+                @Override
+                public void setValue(AnimatableScaleMatrix object, float value) {
+                    object.setScaleY(value * DynamicAnimation.MIN_VISIBLE_CHANGE_SCALE);
+                }
+            };
+
+    private float mScaleX = 1f;
+    private float mScaleY = 1f;
+
+    private float mPivotX = 0f;
+    private float mPivotY = 0f;
+
+    /**
+     * Return the value to animate SCALE_X or SCALE_Y to in order to achieve the desired scale
+     * factor.
+     */
+    public static float getAnimatableValueForScaleFactor(float scale) {
+        return scale * (1f / DynamicAnimation.MIN_VISIBLE_CHANGE_SCALE);
+    }
+
+    @Override
+    public void setScale(float sx, float sy, float px, float py) {
+        mScaleX = sx;
+        mScaleY = sy;
+        mPivotX = px;
+        mPivotY = py;
+        super.setScale(mScaleX, mScaleY, mPivotX, mPivotY);
+    }
+
+    public void setScaleX(float scaleX) {
+        mScaleX = scaleX;
+        super.setScale(mScaleX, mScaleY, mPivotX, mPivotY);
+    }
+
+    public void setScaleY(float scaleY) {
+        mScaleY = scaleY;
+        super.setScale(mScaleX, mScaleY, mPivotX, mPivotY);
+    }
+
+    public void setPivotX(float pivotX) {
+        mPivotX = pivotX;
+        super.setScale(mScaleX, mScaleY, mPivotX, mPivotY);
+    }
+
+    public void setPivotY(float pivotY) {
+        mPivotY = pivotY;
+        super.setScale(mScaleX, mScaleY, mPivotX, mPivotY);
+    }
+
+    public float getScaleX() {
+        return mScaleX;
+    }
+
+    public float getScaleY() {
+        return mScaleY;
+    }
+
+    public float getPivotX() {
+        return mPivotX;
+    }
+
+    public float getPivotY() {
+        return mPivotY;
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/animation/ExpandedAnimationController.java b/packages/SystemUI/src/com/android/systemui/bubbles/animation/ExpandedAnimationController.java
index 76ff1af..cb8995a 100644
--- a/packages/SystemUI/src/com/android/systemui/bubbles/animation/ExpandedAnimationController.java
+++ b/packages/SystemUI/src/com/android/systemui/bubbles/animation/ExpandedAnimationController.java
@@ -56,7 +56,7 @@
     private static final int ANIMATE_TRANSLATION_FACTOR = 4;
 
     /** Duration of the expand/collapse target path animation. */
-    private static final int EXPAND_COLLAPSE_TARGET_ANIM_DURATION = 175;
+    public static final int EXPAND_COLLAPSE_TARGET_ANIM_DURATION = 175;
 
     /** Stiffness for the expand/collapse path-following animation. */
     private static final int EXPAND_COLLAPSE_ANIM_STIFFNESS = 1000;
@@ -92,6 +92,14 @@
     private int mScreenOrientation;
 
     private boolean mAnimatingExpand = false;
+
+    /**
+     * Whether we are animating other Bubbles UI elements out in preparation for a call to
+     * {@link #collapseBackToStack}. If true, we won't animate bubbles in response to adds or
+     * reorders.
+     */
+    private boolean mPreparingToCollapse = false;
+
     private boolean mAnimatingCollapse = false;
     private @Nullable Runnable mAfterExpand;
     private Runnable mAfterCollapse;
@@ -150,6 +158,7 @@
      */
     public void expandFromStack(
             @Nullable Runnable after, @Nullable Runnable leadBubbleEndAction) {
+        mPreparingToCollapse = false;
         mAnimatingCollapse = false;
         mAnimatingExpand = true;
         mAfterExpand = after;
@@ -165,9 +174,20 @@
         expandFromStack(after, null /* leadBubbleEndAction */);
     }
 
+    /**
+     * Sets that we're animating the stack collapsed, but haven't yet called
+     * {@link #collapseBackToStack}. This will temporarily suspend animations for bubbles that are
+     * added or re-ordered, since the upcoming collapse animation will handle positioning those
+     * bubbles in the collapsed stack.
+     */
+    public void notifyPreparingToCollapse() {
+        mPreparingToCollapse = true;
+    }
+
     /** Animate collapsing the bubbles back to their stacked position. */
     public void collapseBackToStack(PointF collapsePoint, Runnable after) {
         mAnimatingExpand = false;
+        mPreparingToCollapse = false;
         mAnimatingCollapse = true;
         mAfterCollapse = after;
         mCollapsePoint = collapsePoint;
@@ -501,12 +521,18 @@
             startOrUpdatePathAnimation(false /* expanding */);
         } else {
             child.setTranslationX(getBubbleLeft(index));
-            animationForChild(child)
-                    .translationY(
-                            getExpandedY() - mBubbleSizePx * ANIMATE_TRANSLATION_FACTOR, /* from */
-                            getExpandedY() /* to */)
-                    .start();
-            updateBubblePositions();
+
+            // If we're preparing to collapse, don't start animations since the collapse animation
+            // will take over and animate the new bubble into the correct (stacked) position.
+            if (!mPreparingToCollapse) {
+                animationForChild(child)
+                        .translationY(
+                                getExpandedY()
+                                        - mBubbleSizePx * ANIMATE_TRANSLATION_FACTOR, /* from */
+                                getExpandedY() /* to */)
+                        .start();
+                updateBubblePositions();
+            }
         }
     }
 
@@ -532,12 +558,20 @@
 
     @Override
     void onChildReordered(View child, int oldIndex, int newIndex) {
-        updateBubblePositions();
+        if (mPreparingToCollapse) {
+            // If a re-order is received while we're preparing to collapse, ignore it. Once started,
+            // the collapse animation will animate all of the bubbles to their correct (stacked)
+            // position.
+            return;
+        }
 
-        // We expect reordering during collapse, since we'll put the last selected bubble on top.
-        // Update the collapse animation so they end up in the right stacked positions.
         if (mAnimatingCollapse) {
+            // If a re-order is received during collapse, update the animation so that the bubbles
+            // end up in the correct (stacked) position.
             startOrUpdatePathAnimation(false /* expanding */);
+        } else {
+            // Otherwise, animate the bubbles around to reflect their new order.
+            updateBubblePositions();
         }
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/animation/StackAnimationController.java b/packages/SystemUI/src/com/android/systemui/bubbles/animation/StackAnimationController.java
index fd1f879..3ef2044 100644
--- a/packages/SystemUI/src/com/android/systemui/bubbles/animation/StackAnimationController.java
+++ b/packages/SystemUI/src/com/android/systemui/bubbles/animation/StackAnimationController.java
@@ -1034,13 +1034,13 @@
                 mMagnetizedStack.getFlingToTargetMinVelocity() /* default */);
         final float maxVelocity = Settings.Secure.getFloat(contentResolver,
                 "bubble_dismiss_stick_max_velocity",
-                mMagnetizedStack.getStickToTargetMaxVelocity() /* default */);
+                mMagnetizedStack.getStickToTargetMaxXVelocity() /* default */);
         final float targetWidth = Settings.Secure.getFloat(contentResolver,
                 "bubble_dismiss_target_width_percent",
                 mMagnetizedStack.getFlingToTargetWidthPercent() /* default */);
 
         mMagnetizedStack.setFlingToTargetMinVelocity(minVelocity);
-        mMagnetizedStack.setStickToTargetMaxVelocity(maxVelocity);
+        mMagnetizedStack.setStickToTargetMaxXVelocity(maxVelocity);
         mMagnetizedStack.setFlingToTargetWidthPercent(targetWidth);
 
         return mMagnetizedStack;
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/dagger/BubbleModule.java b/packages/SystemUI/src/com/android/systemui/bubbles/dagger/BubbleModule.java
index d1d07f6..097932e 100644
--- a/packages/SystemUI/src/com/android/systemui/bubbles/dagger/BubbleModule.java
+++ b/packages/SystemUI/src/com/android/systemui/bubbles/dagger/BubbleModule.java
@@ -20,6 +20,7 @@
 import android.content.Context;
 import android.view.WindowManager;
 
+import com.android.internal.statusbar.IStatusBarService;
 import com.android.systemui.bubbles.BubbleController;
 import com.android.systemui.bubbles.BubbleData;
 import com.android.systemui.bubbles.BubbleDataRepository;
@@ -70,6 +71,7 @@
             BubbleDataRepository bubbleDataRepository,
             SysUiState sysUiState,
             INotificationManager notifManager,
+            IStatusBarService statusBarService,
             WindowManager windowManager) {
         return new BubbleController(
                 context,
@@ -91,6 +93,7 @@
                 bubbleDataRepository,
                 sysUiState,
                 notifManager,
+                statusBarService,
                 windowManager);
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/controls/controller/ControlsController.kt b/packages/SystemUI/src/com/android/systemui/controls/controller/ControlsController.kt
index 0731920..45ba1e6 100644
--- a/packages/SystemUI/src/com/android/systemui/controls/controller/ControlsController.kt
+++ b/packages/SystemUI/src/com/android/systemui/controls/controller/ControlsController.kt
@@ -190,11 +190,6 @@
     fun countFavoritesForComponent(componentName: ComponentName): Int
 
     /**
-     * TEMPORARY for testing
-     */
-    fun resetFavorites()
-
-    /**
      * Interface for structure to pass data to [ControlsFavoritingActivity].
      */
     interface LoadData {
diff --git a/packages/SystemUI/src/com/android/systemui/controls/controller/ControlsControllerImpl.kt b/packages/SystemUI/src/com/android/systemui/controls/controller/ControlsControllerImpl.kt
index 93f0c7f..40c8c6b 100644
--- a/packages/SystemUI/src/com/android/systemui/controls/controller/ControlsControllerImpl.kt
+++ b/packages/SystemUI/src/com/android/systemui/controls/controller/ControlsControllerImpl.kt
@@ -200,9 +200,9 @@
                     GlobalActionsDialog.PREFS_CONTROLS_FILE, Context.MODE_PRIVATE)
                 val completedSeedingPackageSet = prefs.getStringSet(
                     GlobalActionsDialog.PREFS_CONTROLS_SEEDING_COMPLETED, mutableSetOf<String>())
-                val favoritePackageSet = favoriteComponentSet.map { it.packageName }
+                val servicePackageSet = serviceInfoSet.map { it.packageName }
                 prefs.edit().putStringSet(GlobalActionsDialog.PREFS_CONTROLS_SEEDING_COMPLETED,
-                    completedSeedingPackageSet.intersect(favoritePackageSet)).apply()
+                    completedSeedingPackageSet.intersect(servicePackageSet)).apply()
 
                 var changed = false
                 favoriteComponentSet.subtract(serviceInfoSet).forEach {
@@ -524,13 +524,6 @@
         }
     }
 
-    override fun resetFavorites() {
-        executor.execute {
-            Favorites.clear()
-            persistenceWrapper.storeFavorites(Favorites.getAllStructures())
-        }
-    }
-
     override fun refreshStatus(componentName: ComponentName, control: Control) {
         if (!confirmAvailability()) {
             Log.d(TAG, "Controls not available")
diff --git a/packages/SystemUI/src/com/android/systemui/controls/management/ControlAdapter.kt b/packages/SystemUI/src/com/android/systemui/controls/management/ControlAdapter.kt
index 26124f7..0543319 100644
--- a/packages/SystemUI/src/com/android/systemui/controls/management/ControlAdapter.kt
+++ b/packages/SystemUI/src/com/android/systemui/controls/management/ControlAdapter.kt
@@ -238,7 +238,7 @@
             updateFavorite(!favorite.isChecked)
             favoriteCallback(wrapper.controlId, favorite.isChecked)
         }
-        applyRenderInfo(renderInfo)
+        applyRenderInfo(renderInfo, wrapper.deviceType)
     }
 
     override fun updateFavorite(favorite: Boolean) {
@@ -254,12 +254,16 @@
         return RenderInfo.lookup(itemView.context, component, deviceType)
     }
 
-    private fun applyRenderInfo(ri: RenderInfo) {
+    private fun applyRenderInfo(ri: RenderInfo, @DeviceTypes.DeviceType deviceType: Int) {
         val context = itemView.context
         val fg = context.getResources().getColorStateList(ri.foreground, context.getTheme())
 
         icon.setImageDrawable(ri.icon)
-        icon.setImageTintList(fg)
+
+        // Do not color app icons
+        if (deviceType != DeviceTypes.TYPE_ROUTINE) {
+            icon.setImageTintList(fg)
+        }
     }
 }
 
diff --git a/packages/SystemUI/src/com/android/systemui/controls/ui/ControlViewHolder.kt b/packages/SystemUI/src/com/android/systemui/controls/ui/ControlViewHolder.kt
index 9e7cf1a..e853027 100644
--- a/packages/SystemUI/src/com/android/systemui/controls/ui/ControlViewHolder.kt
+++ b/packages/SystemUI/src/com/android/systemui/controls/ui/ControlViewHolder.kt
@@ -87,10 +87,9 @@
             deviceType: Int
         ): KClass<out Behavior> {
             return when {
-                status == Control.STATUS_UNKNOWN -> StatusBehavior::class
-                status == Control.STATUS_ERROR -> StatusBehavior::class
-                status == Control.STATUS_NOT_FOUND -> StatusBehavior::class
+                status != Control.STATUS_OK -> StatusBehavior::class
                 deviceType == DeviceTypes.TYPE_CAMERA -> TouchBehavior::class
+                template == ControlTemplate.NO_TEMPLATE -> TouchBehavior::class
                 template is ToggleTemplate -> ToggleBehavior::class
                 template is StatelessTemplate -> TouchBehavior::class
                 template is ToggleRangeTemplate -> ToggleRangeBehavior::class
@@ -123,7 +122,11 @@
     private val onDialogCancel: () -> Unit = { lastChallengeDialog = null }
 
     val deviceType: Int
-        get() = cws.control?.let { it.getDeviceType() } ?: cws.ci.deviceType
+        get() = cws.control?.let { it.deviceType } ?: cws.ci.deviceType
+    val controlStatus: Int
+        get() = cws.control?.let { it.status } ?: Control.STATUS_UNKNOWN
+    val controlTemplate: ControlTemplate
+        get() = cws.control?.let { it.controlTemplate } ?: ControlTemplate.NO_TEMPLATE
 
     init {
         val ld = layout.getBackground() as LayerDrawable
@@ -140,14 +143,16 @@
 
         cancelUpdate?.run()
 
-        val (controlStatus, template) = cws.control?.let {
-            title.setText(it.getTitle())
-            subtitle.setText(it.getSubtitle())
-            Pair(it.status, it.controlTemplate)
-        } ?: run {
+        // For the following statuses only, assume the title/subtitle could not be set properly
+        // by the app and instead use the last known information from favorites
+        if (controlStatus == Control.STATUS_UNKNOWN || controlStatus == Control.STATUS_NOT_FOUND) {
             title.setText(cws.ci.controlTitle)
             subtitle.setText(cws.ci.controlSubtitle)
-            Pair(Control.STATUS_UNKNOWN, ControlTemplate.NO_TEMPLATE)
+        } else {
+            cws.control?.let {
+                title.setText(it.title)
+                subtitle.setText(it.subtitle)
+            }
         }
 
         cws.control?.let {
@@ -161,7 +166,8 @@
         }
 
         isLoading = false
-        behavior = bindBehavior(behavior, findBehaviorClass(controlStatus, template, deviceType))
+        behavior = bindBehavior(behavior,
+            findBehaviorClass(controlStatus, controlTemplate, deviceType))
         updateContentDescription()
     }
 
@@ -230,7 +236,10 @@
         controlsController.action(cws.componentName, cws.ci, action)
     }
 
-    fun usePanel(): Boolean = deviceType in ControlViewHolder.FORCE_PANEL_DEVICES
+    fun usePanel(): Boolean {
+        return deviceType in ControlViewHolder.FORCE_PANEL_DEVICES ||
+            controlTemplate == ControlTemplate.NO_TEMPLATE
+    }
 
     fun bindBehavior(
         existingBehavior: Behavior?,
@@ -256,10 +265,15 @@
     }
 
     internal fun applyRenderInfo(enabled: Boolean, offset: Int, animated: Boolean = true) {
-        val ri = RenderInfo.lookup(context, cws.componentName, deviceType, offset)
+        val deviceTypeOrError = if (controlStatus == Control.STATUS_OK ||
+                controlStatus == Control.STATUS_UNKNOWN) {
+            deviceType
+        } else {
+            RenderInfo.ERROR_ICON
+        }
+        val ri = RenderInfo.lookup(context, cws.componentName, deviceTypeOrError, offset)
         val fg = context.resources.getColorStateList(ri.foreground, context.theme)
         val newText = nextStatusText
-        nextStatusText = ""
         val control = cws.control
 
         var shouldAnimate = animated
@@ -282,10 +296,8 @@
         if (immediately) {
             status.alpha = STATUS_ALPHA_ENABLED
             status.text = text
-            nextStatusText = ""
-        } else {
-            nextStatusText = text
         }
+        nextStatusText = text
     }
 
     private fun animateBackgroundChange(
diff --git a/packages/SystemUI/src/com/android/systemui/controls/ui/ControlsUiControllerImpl.kt b/packages/SystemUI/src/com/android/systemui/controls/ui/ControlsUiControllerImpl.kt
index d31b6eb..0f5aef7 100644
--- a/packages/SystemUI/src/com/android/systemui/controls/ui/ControlsUiControllerImpl.kt
+++ b/packages/SystemUI/src/com/android/systemui/controls/ui/ControlsUiControllerImpl.kt
@@ -19,16 +19,13 @@
 import android.animation.Animator
 import android.animation.AnimatorListenerAdapter
 import android.animation.ObjectAnimator
-import android.app.AlertDialog
 import android.content.ComponentName
 import android.content.Context
-import android.content.DialogInterface
 import android.content.Intent
 import android.content.SharedPreferences
 import android.content.res.Configuration
 import android.graphics.drawable.Drawable
 import android.graphics.drawable.LayerDrawable
-import android.os.Process
 import android.service.controls.Control
 import android.util.Log
 import android.util.TypedValue
@@ -36,7 +33,6 @@
 import android.view.LayoutInflater
 import android.view.View
 import android.view.ViewGroup
-import android.view.WindowManager
 import android.view.animation.AccelerateInterpolator
 import android.view.animation.DecelerateInterpolator
 import android.widget.AdapterView
@@ -272,8 +268,7 @@
     private fun createMenu() {
         val items = arrayOf(
             context.resources.getString(R.string.controls_menu_add),
-            context.resources.getString(R.string.controls_menu_edit),
-            "Reset"
+            context.resources.getString(R.string.controls_menu_edit)
         )
         var adapter = ArrayAdapter<String>(context, R.layout.controls_more_item, items)
 
@@ -298,10 +293,6 @@
                                 0 -> startFavoritingActivity(view.context, selectedStructure)
                                 // 1: Edit controls
                                 1 -> startEditingActivity(view.context, selectedStructure)
-                                // 2: TEMPORARY for reset controls
-                                2 -> showResetConfirmation()
-                                else -> Log.w(ControlsUiController.TAG,
-                                    "Unsupported index ($pos) on 'more' menu selection")
                             }
                             dismiss()
                         }
@@ -312,39 +303,6 @@
         })
     }
 
-    private fun showResetConfirmation() {
-        val builder = AlertDialog.Builder(
-            context,
-            android.R.style.Theme_DeviceDefault_Dialog_Alert
-        ).apply {
-            setMessage("For testing purposes: Would you like to " +
-                "reset your favorited device controls?")
-            setPositiveButton(
-                android.R.string.ok,
-                DialogInterface.OnClickListener { dialog, _ ->
-                    val userHandle = Process.myUserHandle()
-                    val userContext = context.createContextAsUser(userHandle, 0)
-                    val prefs = userContext.getSharedPreferences(
-                        "controls_prefs", Context.MODE_PRIVATE)
-                    prefs.edit().remove("SeedingCompleted").apply()
-                    controlsController.get().resetFavorites()
-                    dialog.dismiss()
-                    context.sendBroadcast(Intent(Intent.ACTION_CLOSE_SYSTEM_DIALOGS))
-            })
-            setNegativeButton(
-                android.R.string.cancel,
-                DialogInterface.OnClickListener {
-                    dialog, _ -> dialog.cancel()
-                }
-            )
-        }
-        builder.create().apply {
-            getWindow().apply {
-                setType(WindowManager.LayoutParams.TYPE_VOLUME_OVERLAY)
-            }
-        }.show()
-    }
-
     private fun createDropDown(items: List<SelectionItem>) {
         items.forEach {
             RenderInfo.registerComponentIcon(it.componentName, it.icon)
diff --git a/packages/SystemUI/src/com/android/systemui/controls/ui/RenderInfo.kt b/packages/SystemUI/src/com/android/systemui/controls/ui/RenderInfo.kt
index 09d41bd..3f17a4f 100644
--- a/packages/SystemUI/src/com/android/systemui/controls/ui/RenderInfo.kt
+++ b/packages/SystemUI/src/com/android/systemui/controls/ui/RenderInfo.kt
@@ -35,6 +35,7 @@
 ) {
     companion object {
         const val APP_ICON_ID = -1
+        const val ERROR_ICON = -1000
         private val iconMap = SparseArray<Drawable>()
         private val appIconMap = ArrayMap<ComponentName, Drawable>()
 
@@ -156,7 +157,8 @@
     DeviceTypes.TYPE_CURTAIN to R.drawable.ic_device_blinds,
     DeviceTypes.TYPE_DOOR to R.drawable.ic_device_door,
     DeviceTypes.TYPE_SHUTTER to R.drawable.ic_device_window,
-    DeviceTypes.TYPE_HEATER to R.drawable.ic_device_thermostat
+    DeviceTypes.TYPE_HEATER to R.drawable.ic_device_thermostat,
+    RenderInfo.ERROR_ICON to R.drawable.ic_error_outline
 ).withDefault {
     R.drawable.ic_device_unknown
 }
diff --git a/packages/SystemUI/src/com/android/systemui/controls/ui/TouchBehavior.kt b/packages/SystemUI/src/com/android/systemui/controls/ui/TouchBehavior.kt
index 48f9458..9dd0f53 100644
--- a/packages/SystemUI/src/com/android/systemui/controls/ui/TouchBehavior.kt
+++ b/packages/SystemUI/src/com/android/systemui/controls/ui/TouchBehavior.kt
@@ -21,6 +21,7 @@
 import android.view.View
 import android.service.controls.Control
 import android.service.controls.templates.ControlTemplate
+import android.service.controls.templates.StatelessTemplate
 
 import com.android.systemui.R
 import com.android.systemui.controls.ui.ControlViewHolder.Companion.MAX_LEVEL
@@ -35,24 +36,44 @@
     lateinit var template: ControlTemplate
     lateinit var control: Control
     lateinit var cvh: ControlViewHolder
+    private var statelessTouch = false
+    private var lastColorOffset = 0
+    private val enabled: Boolean
+        get() = if (lastColorOffset > 0 || statelessTouch) true else false
+
+    companion object {
+        const val STATELESS_ENABLE_TIMEOUT_IN_MILLIS = 3000L
+    }
 
     override fun initialize(cvh: ControlViewHolder) {
         this.cvh = cvh
 
         cvh.layout.setOnClickListener(View.OnClickListener() {
             cvh.controlActionCoordinator.touch(cvh, template.getTemplateId(), control)
+
+            // StatelessTemplates have no state, with no way to discern between enabled and
+            // disabled. Render an enabled state for a few moments to let the user know the
+            // action is in progress.
+            if (template is StatelessTemplate) {
+                statelessTouch = true
+                cvh.applyRenderInfo(enabled, lastColorOffset)
+                cvh.uiExecutor.executeDelayed({
+                    statelessTouch = false
+                    cvh.applyRenderInfo(enabled, lastColorOffset)
+                }, STATELESS_ENABLE_TIMEOUT_IN_MILLIS)
+            }
         })
     }
 
     override fun bind(cws: ControlWithState, colorOffset: Int) {
         this.control = cws.control!!
+        lastColorOffset = colorOffset
         cvh.setStatusText(control.getStatusText())
         template = control.getControlTemplate()
 
         val ld = cvh.layout.getBackground() as LayerDrawable
         clipLayer = ld.findDrawableByLayerId(R.id.clip_layer)
 
-        val enabled = if (colorOffset > 0) true else false
         clipLayer.setLevel(if (enabled) MAX_LEVEL else MIN_LEVEL)
         cvh.applyRenderInfo(enabled, colorOffset)
     }
diff --git a/packages/SystemUI/src/com/android/systemui/dagger/DefaultActivityBinder.java b/packages/SystemUI/src/com/android/systemui/dagger/DefaultActivityBinder.java
index 91f032d..28bcf3a 100644
--- a/packages/SystemUI/src/com/android/systemui/dagger/DefaultActivityBinder.java
+++ b/packages/SystemUI/src/com/android/systemui/dagger/DefaultActivityBinder.java
@@ -24,6 +24,8 @@
 import com.android.systemui.screenrecord.ScreenRecordDialog;
 import com.android.systemui.settings.BrightnessDialog;
 import com.android.systemui.tuner.TunerActivity;
+import com.android.systemui.usb.UsbDebuggingActivity;
+import com.android.systemui.usb.UsbDebuggingSecondaryUserActivity;
 
 import dagger.Binds;
 import dagger.Module;
@@ -70,4 +72,17 @@
     @IntoMap
     @ClassKey(BubbleOverflowActivity.class)
     public abstract Activity bindBubbleOverflowActivity(BubbleOverflowActivity activity);
+
+    /** Inject into UsbDebuggingActivity. */
+    @Binds
+    @IntoMap
+    @ClassKey(UsbDebuggingActivity.class)
+    public abstract Activity bindUsbDebuggingActivity(UsbDebuggingActivity activity);
+
+    /** Inject into UsbDebuggingSecondaryUserActivity. */
+    @Binds
+    @IntoMap
+    @ClassKey(UsbDebuggingSecondaryUserActivity.class)
+    public abstract Activity bindUsbDebuggingSecondaryUserActivity(
+            UsbDebuggingSecondaryUserActivity activity);
 }
diff --git a/packages/SystemUI/src/com/android/systemui/dagger/DependencyProvider.java b/packages/SystemUI/src/com/android/systemui/dagger/DependencyProvider.java
index 8368b2c..1f30305 100644
--- a/packages/SystemUI/src/com/android/systemui/dagger/DependencyProvider.java
+++ b/packages/SystemUI/src/com/android/systemui/dagger/DependencyProvider.java
@@ -25,6 +25,7 @@
 import android.hardware.display.NightDisplayListener;
 import android.os.Handler;
 import android.os.HandlerThread;
+import android.os.Looper;
 import android.os.ServiceManager;
 import android.util.DisplayMetrics;
 import android.view.Choreographer;
@@ -39,9 +40,12 @@
 import com.android.internal.widget.LockPatternUtils;
 import com.android.keyguard.ViewMediatorCallback;
 import com.android.systemui.Prefs;
+import com.android.systemui.broadcast.BroadcastDispatcher;
+import com.android.systemui.broadcast.logging.BroadcastDispatcherLogger;
 import com.android.systemui.dagger.qualifiers.Background;
 import com.android.systemui.dagger.qualifiers.Main;
 import com.android.systemui.doze.AlwaysOnDisplayPolicy;
+import com.android.systemui.dump.DumpManager;
 import com.android.systemui.keyguard.KeyguardViewMediator;
 import com.android.systemui.plugins.PluginInitializerImpl;
 import com.android.systemui.shared.plugins.PluginManager;
@@ -178,6 +182,21 @@
         return ActivityManagerWrapper.getInstance();
     }
 
+    /** Provides and initializes the {#link BroadcastDispatcher} for SystemUI */
+    @Singleton
+    @Provides
+    public BroadcastDispatcher providesBroadcastDispatcher(
+            Context context,
+            @Background Looper backgroundLooper,
+            DumpManager dumpManager,
+            BroadcastDispatcherLogger logger
+    ) {
+        BroadcastDispatcher bD =
+                new BroadcastDispatcher(context, backgroundLooper, dumpManager, logger);
+        bD.initialize();
+        return bD;
+    }
+
     @Singleton
     @Provides
     public DevicePolicyManagerWrapper provideDevicePolicyManagerWrapper() {
diff --git a/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialog.java b/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialog.java
index 5e5ebe9..9150921 100644
--- a/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialog.java
+++ b/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialog.java
@@ -247,7 +247,6 @@
     private final Executor mBackgroundExecutor;
     private List<ControlsServiceInfo> mControlsServiceInfos = new ArrayList<>();
     private Optional<ControlsController> mControlsControllerOptional;
-    private SharedPreferences mControlsPreferences;
     private final RingerModeTracker mRingerModeTracker;
     private int mDialogPressDelay = DIALOG_PRESS_DELAY; // ms
     private Handler mMainHandler;
@@ -405,12 +404,6 @@
                     });
         }
 
-        // Need to be user-specific with the context to make sure we read the correct prefs
-        Context userContext = context.createContextAsUser(
-                new UserHandle(mUserManager.getUserHandle()), 0);
-        mControlsPreferences = userContext.getSharedPreferences(PREFS_CONTROLS_FILE,
-            Context.MODE_PRIVATE);
-
         // Listen for changes to show controls on the power menu while locked
         onPowerMenuLockScreenSettingsChanged();
         mContext.getContentResolver().registerContentObserver(
@@ -444,19 +437,22 @@
                 Collections.emptySet());
 
         List<ComponentName> componentsToSeed = new ArrayList<>();
-        for (ControlsServiceInfo info : mControlsServiceInfos) {
-            String pkg = info.componentName.getPackageName();
-            if (seededPackages.contains(pkg)
-                    || mControlsControllerOptional.get().countFavoritesForComponent(
-                            info.componentName) > 0) {
-                continue;
-            }
-
-            for (int i = 0; i < Math.min(SEEDING_MAX, preferredControlsPackages.length); i++) {
-                if (pkg.equals(preferredControlsPackages[i])) {
-                    componentsToSeed.add(info.componentName);
+        for (int i = 0; i < Math.min(SEEDING_MAX, preferredControlsPackages.length); i++) {
+            String pkg = preferredControlsPackages[i];
+            for (ControlsServiceInfo info : mControlsServiceInfos) {
+                if (!pkg.equals(info.componentName.getPackageName())) continue;
+                if (seededPackages.contains(pkg)) {
+                    break;
+                } else if (mControlsControllerOptional.get()
+                        .countFavoritesForComponent(info.componentName) > 0) {
+                    // When there are existing controls but no saved preference, assume it
+                    // is out of sync, perhaps through a device restore, and update the
+                    // preference
+                    addPackageToSeededSet(prefs, pkg);
                     break;
                 }
+                componentsToSeed.add(info.componentName);
+                break;
             }
         }
 
@@ -466,16 +462,20 @@
                 componentsToSeed,
                 (response) -> {
                     Log.d(TAG, "Controls seeded: " + response);
-                    Set<String> completedPkgs = prefs.getStringSet(PREFS_CONTROLS_SEEDING_COMPLETED,
-                                                                   new HashSet<String>());
                     if (response.getAccepted()) {
-                        completedPkgs.add(response.getPackageName());
-                        prefs.edit().putStringSet(PREFS_CONTROLS_SEEDING_COMPLETED,
-                                                  completedPkgs).apply();
+                        addPackageToSeededSet(prefs, response.getPackageName());
                     }
                 });
     }
 
+    private void addPackageToSeededSet(SharedPreferences prefs, String pkg) {
+        Set<String> seededPackages = prefs.getStringSet(PREFS_CONTROLS_SEEDING_COMPLETED,
+                Collections.emptySet());
+        Set<String> updatedPkgs = new HashSet<>(seededPackages);
+        updatedPkgs.add(pkg);
+        prefs.edit().putStringSet(PREFS_CONTROLS_SEEDING_COMPLETED, updatedPkgs).apply();
+    }
+
     /**
      * Show the global actions dialog (creating if necessary)
      *
@@ -779,7 +779,8 @@
     @VisibleForTesting
     protected final class PowerOptionsAction extends SinglePressAction {
         private PowerOptionsAction() {
-            super(R.drawable.ic_lock_power_off, R.string.global_action_power_options);
+            super(com.android.systemui.R.drawable.ic_settings_power,
+                    R.string.global_action_power_options);
         }
 
         @Override
diff --git a/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsPopupMenu.java b/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsPopupMenu.java
index 6b71f1e..1dbbb4d 100644
--- a/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsPopupMenu.java
+++ b/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsPopupMenu.java
@@ -19,6 +19,7 @@
 import android.annotation.Nullable;
 import android.content.Context;
 import android.content.res.Resources;
+import android.util.LayoutDirection;
 import android.view.View;
 import android.view.View.MeasureSpec;
 import android.view.WindowManager;
@@ -106,7 +107,11 @@
             listView.setPadding(0, mMenuVerticalPadding, 0, mMenuVerticalPadding);
 
             setWidth(width);
-            setHorizontalOffset(getAnchorView().getWidth() - mGlobalActionsSidePadding - width);
+            if (getAnchorView().getLayoutDirection() == LayoutDirection.LTR) {
+                setHorizontalOffset(getAnchorView().getWidth() - mGlobalActionsSidePadding - width);
+            } else {
+                setHorizontalOffset(mGlobalActionsSidePadding);
+            }
         }
 
         super.show();
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
index b26dc5f..53251ed43 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
@@ -654,7 +654,7 @@
         @Override
         public void onBouncerVisiblityChanged(boolean shown) {
             synchronized (KeyguardViewMediator.this) {
-                adjustStatusBarLocked(shown);
+                adjustStatusBarLocked(shown, false);
             }
         }
 
@@ -2003,10 +2003,12 @@
     }
 
     private void adjustStatusBarLocked() {
-        adjustStatusBarLocked(false /* forceHideHomeRecentsButtons */);
+        adjustStatusBarLocked(false /* forceHideHomeRecentsButtons */,
+                false /* forceClearFlags */);
     }
 
-    private void adjustStatusBarLocked(boolean forceHideHomeRecentsButtons) {
+    private void adjustStatusBarLocked(boolean forceHideHomeRecentsButtons,
+            boolean forceClearFlags) {
         if (mStatusBarManager == null) {
             mStatusBarManager = (StatusBarManager)
                     mContext.getSystemService(Context.STATUS_BAR_SERVICE);
@@ -2018,6 +2020,13 @@
             // Disable aspects of the system/status/navigation bars that must not be re-enabled by
             // windows that appear on top, ever
             int flags = StatusBarManager.DISABLE_NONE;
+
+            // TODO (b/155663717) After restart, status bar will not properly hide home button
+            //  unless disable is called to show un-hide it once first
+            if (forceClearFlags) {
+                mStatusBarManager.disable(flags);
+            }
+
             if (forceHideHomeRecentsButtons || isShowingAndNotOccluded()) {
                 if (!mShowHomeOverLockscreen || !mInGestureNavigationMode) {
                     flags |= StatusBarManager.DISABLE_HOME;
@@ -2141,6 +2150,7 @@
     public void onBootCompleted() {
         synchronized (this) {
             mBootCompleted = true;
+            adjustStatusBarLocked(false, true);
             if (mBootSendUserPresent) {
                 sendUserPresentBroadcast();
             }
diff --git a/packages/SystemUI/src/com/android/systemui/log/dagger/BroadcastDispatcherLog.java b/packages/SystemUI/src/com/android/systemui/log/dagger/BroadcastDispatcherLog.java
new file mode 100644
index 0000000..7d1f1c2
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/log/dagger/BroadcastDispatcherLog.java
@@ -0,0 +1,33 @@
+/*
+ * Copyright (C) 2020 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.log.dagger;
+
+import static java.lang.annotation.RetentionPolicy.RUNTIME;
+
+import com.android.systemui.log.LogBuffer;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.Retention;
+
+import javax.inject.Qualifier;
+
+/** A {@link LogBuffer} for BroadcastDispatcher-related messages. */
+@Qualifier
+@Documented
+@Retention(RUNTIME)
+public @interface BroadcastDispatcherLog {
+}
diff --git a/packages/SystemUI/src/com/android/systemui/log/dagger/LogModule.java b/packages/SystemUI/src/com/android/systemui/log/dagger/LogModule.java
index 9c89fee..16f76de 100644
--- a/packages/SystemUI/src/com/android/systemui/log/dagger/LogModule.java
+++ b/packages/SystemUI/src/com/android/systemui/log/dagger/LogModule.java
@@ -68,7 +68,7 @@
     public static LogBuffer provideNotificationSectionLogBuffer(
             LogcatEchoTracker bufferFilter,
             DumpManager dumpManager) {
-        LogBuffer buffer = new LogBuffer("NotifSectionLog", 500, 10, bufferFilter);
+        LogBuffer buffer = new LogBuffer("NotifSectionLog", 1000, 10, bufferFilter);
         buffer.attach(dumpManager);
         return buffer;
     }
@@ -97,6 +97,18 @@
         return buffer;
     }
 
+    /** Provides a logging buffer for {@link com.android.systemui.broadcast.BroadcastDispatcher} */
+    @Provides
+    @Singleton
+    @BroadcastDispatcherLog
+    public static LogBuffer provideBroadcastDispatcherLogBuffer(
+            LogcatEchoTracker bufferFilter,
+            DumpManager dumpManager) {
+        LogBuffer buffer = new LogBuffer("BroadcastDispatcherLog", 500, 10, bufferFilter);
+        buffer.attach(dumpManager);
+        return buffer;
+    }
+
     /** Allows logging buffers to be tweaked via adb on debug builds but not on prod builds. */
     @Provides
     @Singleton
diff --git a/packages/SystemUI/src/com/android/systemui/media/MediaControlPanel.java b/packages/SystemUI/src/com/android/systemui/media/MediaControlPanel.java
index f039fc2..2df0507 100644
--- a/packages/SystemUI/src/com/android/systemui/media/MediaControlPanel.java
+++ b/packages/SystemUI/src/com/android/systemui/media/MediaControlPanel.java
@@ -35,7 +35,6 @@
 import android.view.View;
 import android.widget.ImageButton;
 import android.widget.ImageView;
-import android.widget.SeekBar;
 import android.widget.TextView;
 
 import androidx.annotation.NonNull;
@@ -97,13 +96,13 @@
      */
     @Inject
     public MediaControlPanel(Context context, @Background Executor backgroundExecutor,
-            ActivityStarter activityStarter, MediaHostStatesManager mediaHostStatesManager,
+            ActivityStarter activityStarter, MediaViewController mediaViewController,
             SeekBarViewModel seekBarViewModel) {
         mContext = context;
         mBackgroundExecutor = backgroundExecutor;
         mActivityStarter = activityStarter;
         mSeekBarViewModel = seekBarViewModel;
-        mMediaViewController = new MediaViewController(context, mediaHostStatesManager);
+        mMediaViewController = mediaViewController;
         loadDimens();
     }
 
@@ -165,9 +164,7 @@
         TransitionLayout player = vh.getPlayer();
         mSeekBarObserver = new SeekBarObserver(vh);
         mSeekBarViewModel.getProgress().observeForever(mSeekBarObserver);
-        SeekBar bar = vh.getSeekBar();
-        bar.setOnSeekBarChangeListener(mSeekBarViewModel.getSeekBarListener());
-        bar.setOnTouchListener(mSeekBarViewModel.getSeekBarTouchListener());
+        mSeekBarViewModel.attachTouchHandlers(vh.getSeekBar());
         mMediaViewController.attach(player);
     }
 
@@ -260,16 +257,18 @@
         rect.setColor(Color.TRANSPARENT);
 
         final MediaDeviceData device = data.getDevice();
+        int seamlessId = mViewHolder.getSeamless().getId();
         if (device != null && !device.getEnabled()) {
             mViewHolder.getSeamless().setEnabled(false);
-            // TODO(b/156875717): setEnabled should cause the alpha to change.
-            mViewHolder.getSeamless().setAlpha(0.38f);
+            expandedSet.setAlpha(seamlessId, 0.38f);
+            collapsedSet.setAlpha(seamlessId, 0.38f);
             iconView.setImageResource(R.drawable.ic_hardware_speaker);
             iconView.setVisibility(View.VISIBLE);
             deviceName.setText(R.string.media_seamless_remote_device);
         } else if (device != null) {
             mViewHolder.getSeamless().setEnabled(true);
-            mViewHolder.getSeamless().setAlpha(1f);
+            expandedSet.setAlpha(seamlessId, 1.0f);
+            collapsedSet.setAlpha(seamlessId, 1.0f);
             Drawable icon = device.getIcon();
             iconView.setVisibility(View.VISIBLE);
 
@@ -285,7 +284,8 @@
             // Reset to default
             Log.w(TAG, "device is null. Not binding output chip.");
             mViewHolder.getSeamless().setEnabled(true);
-            mViewHolder.getSeamless().setAlpha(1f);
+            expandedSet.setAlpha(seamlessId, 1.0f);
+            collapsedSet.setAlpha(seamlessId, 1.0f);
             iconView.setVisibility(View.GONE);
             deviceName.setText(com.android.internal.R.string.ext_media_seamless_action);
         }
@@ -302,11 +302,14 @@
             button.setContentDescription(mediaAction.getContentDescription());
             Runnable action = mediaAction.getAction();
 
-            button.setOnClickListener(v -> {
-                if (action != null) {
+            if (action == null) {
+                button.setEnabled(false);
+            } else {
+                button.setEnabled(true);
+                button.setOnClickListener(v -> {
                     action.run();
-                }
-            });
+                });
+            }
             boolean visibleInCompat = actionsWhenCollapsed.contains(i);
             setVisibleAndAlpha(collapsedSet, actionId, visibleInCompat);
             setVisibleAndAlpha(expandedSet, actionId, true /*visible */);
@@ -363,14 +366,6 @@
     }
 
     /**
-     * Return the token for the current media session
-     * @return the token
-     */
-    public MediaSession.Token getMediaSessionToken() {
-        return mToken;
-    }
-
-    /**
      * Get the current media controller
      * @return the controller
      */
@@ -379,25 +374,6 @@
     }
 
     /**
-     * Get the name of the package associated with the current media controller
-     * @return the package name, or null if no controller
-     */
-    public String getMediaPlayerPackage() {
-        if (mController == null) {
-            return null;
-        }
-        return mController.getPackageName();
-    }
-
-    /**
-     * Check whether this player has an attached media session.
-     * @return whether there is a controller with a current media session.
-     */
-    public boolean hasMediaSession() {
-        return mController != null && mController.getPlaybackState() != null;
-    }
-
-    /**
      * Check whether the media controlled by this player is currently playing
      * @return whether it is playing, or false if no controller information
      */
diff --git a/packages/SystemUI/src/com/android/systemui/media/MediaData.kt b/packages/SystemUI/src/com/android/systemui/media/MediaData.kt
index 5d28178..0b0ffce 100644
--- a/packages/SystemUI/src/com/android/systemui/media/MediaData.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/MediaData.kt
@@ -25,19 +25,65 @@
 data class MediaData(
     val initialized: Boolean = false,
     val backgroundColor: Int,
+    /**
+     * App name that will be displayed on the player.
+     */
     val app: String?,
+    /**
+     * Icon shown on player, close to app name.
+     */
     val appIcon: Drawable?,
+    /**
+     * Artist name.
+     */
     val artist: CharSequence?,
+    /**
+     * Song name.
+     */
     val song: CharSequence?,
+    /**
+     * Album artwork.
+     */
     val artwork: Icon?,
+    /**
+     * List of actions that can be performed on the player: prev, next, play, pause, etc.
+     */
     val actions: List<MediaAction>,
+    /**
+     * Same as above, but shown on smaller versions of the player, like in QQS or keyguard.
+     */
     val actionsToShowInCompact: List<Int>,
+    /**
+     * Package name of the app that's posting the media.
+     */
     val packageName: String,
+    /**
+     * Unique media session identifier.
+     */
     val token: MediaSession.Token?,
+    /**
+     * Action to perform when the player is tapped.
+     * This is unrelated to {@link #actions}.
+     */
     val clickIntent: PendingIntent?,
+    /**
+     * Where the media is playing: phone, headphones, ear buds, remote session.
+     */
     val device: MediaDeviceData?,
+    /**
+     * When active, a player will be displayed on keyguard and quick-quick settings.
+     * This is unrelated to the stream being playing or not, a player will not be active if
+     * timed out, or in resumption mode.
+     */
+    var active: Boolean,
+    /**
+     * Action that should be performed to restart a non active session.
+     */
     var resumeAction: Runnable?,
-    val notificationKey: String = "INVALID",
+    /**
+     * Notification key for cancelling a media player after a timeout (when not using resumption.)
+     */
+    val notificationKey: String? = null,
     var hasCheckedForResume: Boolean = false
 )
 
diff --git a/packages/SystemUI/src/com/android/systemui/media/MediaDataManager.kt b/packages/SystemUI/src/com/android/systemui/media/MediaDataManager.kt
index 094c5be..88bdaec 100644
--- a/packages/SystemUI/src/com/android/systemui/media/MediaDataManager.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/MediaDataManager.kt
@@ -18,8 +18,11 @@
 
 import android.app.Notification
 import android.app.PendingIntent
+import android.content.BroadcastReceiver
 import android.content.ContentResolver
 import android.content.Context
+import android.content.Intent
+import android.content.IntentFilter
 import android.graphics.Bitmap
 import android.graphics.Canvas
 import android.graphics.Color
@@ -30,11 +33,13 @@
 import android.media.MediaMetadata
 import android.media.session.MediaSession
 import android.net.Uri
+import android.os.UserHandle
 import android.service.notification.StatusBarNotification
 import android.text.TextUtils
 import android.util.Log
 import com.android.internal.graphics.ColorUtils
 import com.android.systemui.R
+import com.android.systemui.broadcast.BroadcastDispatcher
 import com.android.systemui.dagger.qualifiers.Background
 import com.android.systemui.dagger.qualifiers.Main
 import com.android.systemui.statusbar.NotificationMediaManager
@@ -62,7 +67,7 @@
 private const val SATURATION_MULTIPLIER = 0.8f
 
 private val LOADING = MediaData(false, 0, null, null, null, null, null,
-        emptyList(), emptyList(), "INVALID", null, null, null, null)
+        emptyList(), emptyList(), "INVALID", null, null, null, true, null)
 
 fun isMediaNotification(sbn: StatusBarNotification): Boolean {
     if (!sbn.notification.hasMediaSession()) {
@@ -83,22 +88,49 @@
 class MediaDataManager @Inject constructor(
     private val context: Context,
     private val mediaControllerFactory: MediaControllerFactory,
-    private val mediaTimeoutListener: MediaTimeoutListener,
     private val notificationEntryManager: NotificationEntryManager,
-    private val mediaResumeListener: MediaResumeListener,
     @Background private val backgroundExecutor: Executor,
-    @Main private val foregroundExecutor: Executor
+    @Main private val foregroundExecutor: Executor,
+    broadcastDispatcher: BroadcastDispatcher,
+    mediaTimeoutListener: MediaTimeoutListener,
+    mediaResumeListener: MediaResumeListener
 ) {
 
     private val listeners: MutableSet<Listener> = mutableSetOf()
     private val mediaEntries: LinkedHashMap<String, MediaData> = LinkedHashMap()
     private val useMediaResumption: Boolean = Utils.useMediaResumption(context)
 
+    private val userChangeReceiver = object : BroadcastReceiver() {
+        override fun onReceive(context: Context, intent: Intent) {
+            if (Intent.ACTION_USER_SWITCHED == intent.action) {
+                // Remove all controls, regardless of state
+                clearData()
+            }
+        }
+    }
+
+    private val appChangeReceiver = object : BroadcastReceiver() {
+        override fun onReceive(context: Context, intent: Intent) {
+            when (intent.action) {
+                Intent.ACTION_PACKAGES_SUSPENDED -> {
+                    val packages = intent.getStringArrayExtra(Intent.EXTRA_CHANGED_PACKAGE_LIST)
+                    packages?.forEach {
+                        removeAllForPackage(it)
+                    }
+                }
+                Intent.ACTION_PACKAGE_REMOVED, Intent.ACTION_PACKAGE_RESTARTED -> {
+                    intent.data?.encodedSchemeSpecificPart?.let {
+                        removeAllForPackage(it)
+                    }
+                }
+            }
+        }
+    }
+
     init {
         mediaTimeoutListener.timeoutCallback = { token: String, timedOut: Boolean ->
             setTimedOut(token, timedOut) }
         addListener(mediaTimeoutListener)
-
         if (useMediaResumption) {
             mediaResumeListener.addTrackToResumeCallback = { desc: MediaDescription,
                 resumeAction: Runnable, token: MediaSession.Token, appName: String,
@@ -111,6 +143,20 @@
             }
             addListener(mediaResumeListener)
         }
+
+        val userFilter = IntentFilter(Intent.ACTION_USER_SWITCHED)
+        broadcastDispatcher.registerReceiver(userChangeReceiver, userFilter, null, UserHandle.ALL)
+
+        val suspendFilter = IntentFilter(Intent.ACTION_PACKAGES_SUSPENDED)
+        broadcastDispatcher.registerReceiver(appChangeReceiver, suspendFilter, null, UserHandle.ALL)
+
+        val uninstallFilter = IntentFilter().apply {
+            addAction(Intent.ACTION_PACKAGE_REMOVED)
+            addAction(Intent.ACTION_PACKAGE_RESTARTED)
+            addDataScheme("package")
+        }
+        // BroadcastDispatcher does not allow filters with data schemes
+        context.registerReceiver(appChangeReceiver, uninstallFilter)
     }
 
     fun onNotificationAdded(key: String, sbn: StatusBarNotification) {
@@ -131,6 +177,29 @@
         }
     }
 
+    private fun clearData() {
+        // Called on user change. Remove all current MediaData objects and inform listeners
+        val listenersCopy = listeners.toSet()
+        mediaEntries.forEach {
+            listenersCopy.forEach { listener ->
+                listener.onMediaDataRemoved(it.key)
+            }
+        }
+        mediaEntries.clear()
+    }
+
+    private fun removeAllForPackage(packageName: String) {
+        Assert.isMainThread()
+        val listenersCopy = listeners.toSet()
+        val toRemove = mediaEntries.filter { it.value.packageName == packageName }
+        toRemove.forEach {
+            mediaEntries.remove(it.key)
+            listenersCopy.forEach { listener ->
+                listener.onMediaDataRemoved(it.key)
+            }
+        }
+    }
+
     private fun addResumptionControls(
         desc: MediaDescription,
         action: Runnable,
@@ -145,7 +214,7 @@
             mediaEntries.put(packageName, resumeData)
         }
         backgroundExecutor.execute {
-            loadMediaDataInBg(desc, action, token, appName, appIntent, packageName)
+            loadMediaDataInBgForResumption(desc, action, token, appName, appIntent, packageName)
         }
     }
 
@@ -185,16 +254,21 @@
     fun removeListener(listener: Listener) = listeners.remove(listener)
 
     private fun setTimedOut(token: String, timedOut: Boolean) {
-        if (!timedOut) {
-            return
-        }
         mediaEntries[token]?.let {
-            notificationEntryManager.removeNotification(it.notificationKey, null /* ranking */,
-                    UNDEFINED_DISMISS_REASON)
+            if (Utils.useMediaResumption(context)) {
+                if (it.active == !timedOut) {
+                    return
+                }
+                it.active = !timedOut
+                onMediaDataLoaded(token, token, it)
+            } else {
+                notificationEntryManager.removeNotification(it.notificationKey, null /* ranking */,
+                        UNDEFINED_DISMISS_REASON)
+            }
         }
     }
 
-    private fun loadMediaDataInBg(
+    private fun loadMediaDataInBgForResumption(
         desc: MediaDescription,
         resumeAction: Runnable,
         token: MediaSession.Token,
@@ -202,11 +276,6 @@
         appIntent: PendingIntent,
         packageName: String
     ) {
-        if (resumeAction == null) {
-            Log.e(TAG, "Resume action cannot be null")
-            return
-        }
-
         if (TextUtils.isEmpty(desc.title)) {
             Log.e(TAG, "Description incomplete")
             return
@@ -228,8 +297,9 @@
         val mediaAction = getResumeMediaAction(resumeAction)
         foregroundExecutor.execute {
             onMediaDataLoaded(packageName, null, MediaData(true, Color.DKGRAY, appName,
-                null, desc.subtitle, desc.title, artworkIcon, listOf(mediaAction), listOf(0),
-                packageName, token, appIntent, null, resumeAction, packageName))
+                    null, desc.subtitle, desc.title, artworkIcon, listOf(mediaAction), listOf(0),
+                    packageName, token, appIntent, device = null, active = false,
+                    resumeAction = resumeAction))
         }
     }
 
@@ -337,15 +407,20 @@
                     actionsToShowCollapsed.remove(index)
                     continue
                 }
+                val runnable = if (action.actionIntent != null) {
+                    Runnable {
+                        try {
+                            action.actionIntent.send()
+                        } catch (e: PendingIntent.CanceledException) {
+                            Log.d(TAG, "Intent canceled", e)
+                        }
+                    }
+                } else {
+                    null
+                }
                 val mediaAction = MediaAction(
                         action.getIcon().loadDrawable(packageContext),
-                        Runnable {
-                            try {
-                                action.actionIntent.send()
-                            } catch (e: PendingIntent.CanceledException) {
-                                Log.d(TAG, "Intent canceled", e)
-                            }
-                        },
+                        runnable,
                         action.title)
                 actionIcons.add(mediaAction)
             }
@@ -355,7 +430,8 @@
         foregroundExecutor.execute {
             onMediaDataLoaded(key, oldKey, MediaData(true, bgColor, app, smallIconDrawable, artist,
                     song, artWorkIcon, actionIcons, actionsToShowCollapsed, sbn.packageName, token,
-                    notif.contentIntent, null, resumeAction, key))
+                    notif.contentIntent, null, active = true, resumeAction = resumeAction,
+                    notificationKey = key))
         }
     }
 
@@ -453,13 +529,13 @@
     /**
      * Are there any media notifications active?
      */
-    fun hasActiveMedia() = mediaEntries.any({ isActive(it.value) })
+    fun hasActiveMedia() = mediaEntries.any { it.value.active }
 
-    fun isActive(data: MediaData): Boolean {
-        if (data.token == null) {
+    fun isActive(token: MediaSession.Token?): Boolean {
+        if (token == null) {
             return false
         }
-        val controller = mediaControllerFactory.create(data.token)
+        val controller = mediaControllerFactory.create(token)
         val state = controller?.playbackState?.state
         return state != null && NotificationMediaManager.isActiveState(state)
     }
@@ -467,7 +543,7 @@
     /**
      * Are there any media entries, including resume controls?
      */
-    fun hasAnyMedia() = mediaEntries.isNotEmpty()
+    fun hasAnyMedia() = if (useMediaResumption) mediaEntries.isNotEmpty() else hasActiveMedia()
 
     interface Listener {
 
diff --git a/packages/SystemUI/src/com/android/systemui/media/MediaDeviceManager.kt b/packages/SystemUI/src/com/android/systemui/media/MediaDeviceManager.kt
index 2f521ea..7ae2dc5 100644
--- a/packages/SystemUI/src/com/android/systemui/media/MediaDeviceManager.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/MediaDeviceManager.kt
@@ -22,6 +22,10 @@
 import com.android.settingslib.media.LocalMediaManager
 import com.android.settingslib.media.MediaDevice
 import com.android.systemui.dagger.qualifiers.Main
+import com.android.systemui.Dumpable
+import com.android.systemui.dump.DumpManager
+import java.io.FileDescriptor
+import java.io.PrintWriter
 import java.util.concurrent.Executor
 import javax.inject.Inject
 import javax.inject.Singleton
@@ -34,15 +38,16 @@
     private val context: Context,
     private val localMediaManagerFactory: LocalMediaManagerFactory,
     private val mr2manager: MediaRouter2Manager,
-    private val featureFlag: MediaFeatureFlag,
     @Main private val fgExecutor: Executor,
-    private val mediaDataManager: MediaDataManager
-) : MediaDataManager.Listener {
+    private val mediaDataManager: MediaDataManager,
+    private val dumpManager: DumpManager
+) : MediaDataManager.Listener, Dumpable {
     private val listeners: MutableSet<Listener> = mutableSetOf()
     private val entries: MutableMap<String, Token> = mutableMapOf()
 
     init {
         mediaDataManager.addListener(this)
+        dumpManager.registerDumpable(javaClass.name, this)
     }
 
     /**
@@ -56,20 +61,19 @@
     fun removeListener(listener: Listener) = listeners.remove(listener)
 
     override fun onMediaDataLoaded(key: String, oldKey: String?, data: MediaData) {
-        if (featureFlag.enabled) {
-            if (oldKey != null && oldKey != key) {
-                val oldToken = entries.remove(oldKey)
-                oldToken?.stop()
+        if (oldKey != null && oldKey != key) {
+            val oldEntry = entries.remove(oldKey)
+            oldEntry?.stop()
+        }
+        var entry = entries[key]
+        if (entry == null || entry?.token != data.token) {
+            entry?.stop()
+            val controller = data.token?.let {
+                MediaController(context, it)
             }
-            var tok = entries[key]
-            if (tok == null && data.token != null) {
-                val controller = MediaController(context, data.token!!)
-                tok = Token(key, controller, localMediaManagerFactory.create(data.packageName))
-                entries[key] = tok
-                tok.start()
-            }
-        } else {
-            onMediaDataRemoved(key)
+            entry = Token(key, controller, localMediaManagerFactory.create(data.packageName))
+            entries[key] = entry
+            entry.start()
         }
     }
 
@@ -83,6 +87,17 @@
         }
     }
 
+    override fun dump(fd: FileDescriptor, pw: PrintWriter, args: Array<String>) {
+        with(pw) {
+            println("MediaDeviceManager state:")
+            entries.forEach {
+                key, entry ->
+                println("  key=$key")
+                entry.dump(fd, pw, args)
+            }
+        }
+    }
+
     private fun processDevice(key: String, device: MediaDevice?) {
         val enabled = device != null
         val data = MediaDeviceData(enabled, device?.iconWithoutBackground, device?.name)
@@ -100,9 +115,11 @@
 
     private inner class Token(
         val key: String,
-        val controller: MediaController,
+        val controller: MediaController?,
         val localMediaManager: LocalMediaManager
     ) : LocalMediaManager.DeviceCallback {
+        val token
+            get() = controller?.sessionToken
         private var started = false
         private var current: MediaDevice? = null
             set(value) {
@@ -122,6 +139,17 @@
             localMediaManager.stopScan()
             localMediaManager.unregisterCallback(this)
         }
+        fun dump(fd: FileDescriptor, pw: PrintWriter, args: Array<String>) {
+            val route = controller?.let {
+                mr2manager.getRoutingSessionForMediaController(it)
+            }
+            with(pw) {
+                println("    current device is ${current?.name}")
+                val type = controller?.playbackInfo?.playbackType
+                println("    PlaybackType=$type (1 for local, 2 for remote)")
+                println("    route=$route")
+            }
+        }
         override fun onDeviceListUpdate(devices: List<MediaDevice>?) = fgExecutor.execute {
             updateCurrent()
         }
@@ -132,10 +160,14 @@
         }
         private fun updateCurrent() {
             val device = localMediaManager.getCurrentConnectedDevice()
-            val route = mr2manager.getRoutingSessionForMediaController(controller)
-            // If we get a null route, then don't trust the device. Just set to null to disable the
-            // output switcher chip.
-            current = if (route != null) device else null
+            controller?.let {
+                val route = mr2manager.getRoutingSessionForMediaController(it)
+                // If we get a null route, then don't trust the device. Just set to null to disable the
+                // output switcher chip.
+                current = if (route != null) device else null
+            } ?: run {
+                current = device
+            }
         }
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/media/MediaHierarchyManager.kt b/packages/SystemUI/src/com/android/systemui/media/MediaHierarchyManager.kt
index 775a1649..b86e1d0 100644
--- a/packages/SystemUI/src/com/android/systemui/media/MediaHierarchyManager.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/MediaHierarchyManager.kt
@@ -480,7 +480,17 @@
             if (inOverlay) {
                 rootOverlay!!.add(mediaFrame)
             } else {
+                // When adding back to the host, let's make sure to reset the bounds.
+                // Usually adding the view will trigger a layout that does this automatically,
+                // but we sometimes suppress this.
                 targetHost.addView(mediaFrame)
+                val left = targetHost.paddingLeft
+                val top = targetHost.paddingTop
+                mediaFrame.setLeftTopRightBottom(
+                        left,
+                        top,
+                        left + currentBounds.width(),
+                        top + currentBounds.height())
             }
         }
     }
diff --git a/packages/SystemUI/src/com/android/systemui/media/MediaHost.kt b/packages/SystemUI/src/com/android/systemui/media/MediaHost.kt
index 2bd8c0c..7c5f0d1 100644
--- a/packages/SystemUI/src/com/android/systemui/media/MediaHost.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/MediaHost.kt
@@ -1,5 +1,6 @@
 package com.android.systemui.media
 
+import android.graphics.PointF
 import android.graphics.Rect
 import android.view.View
 import android.view.View.OnAttachStateChangeListener
@@ -20,8 +21,6 @@
     var location: Int = -1
         private set
     var visibleChangedListener: ((Boolean) -> Unit)? = null
-    var visible: Boolean = false
-        private set
 
     private val tmpLocationOnScreen: IntArray = intArrayOf(0, 0)
 
@@ -109,16 +108,17 @@
     }
 
     private fun updateViewVisibility() {
-        if (showsOnlyActiveMedia) {
-            visible = mediaDataManager.hasActiveMedia()
+        visible = if (showsOnlyActiveMedia) {
+            mediaDataManager.hasActiveMedia()
         } else {
-            visible = mediaDataManager.hasAnyMedia()
+            mediaDataManager.hasAnyMedia()
         }
         hostView.visibility = if (visible) View.VISIBLE else View.GONE
         visibleChangedListener?.invoke(visible)
     }
 
     class MediaHostStateHolder @Inject constructor() : MediaHostState {
+        private var gonePivot: PointF = PointF()
 
         override var measurementInput: MeasurementInput? = null
             set(value) {
@@ -144,6 +144,25 @@
                 }
             }
 
+        override var visible: Boolean = true
+            set(value) {
+                if (field == value) {
+                    return
+                }
+                field = value
+                changedListener?.invoke()
+            }
+
+        override fun getPivotX(): Float = gonePivot.x
+        override fun getPivotY(): Float = gonePivot.y
+        override fun setGonePivot(x: Float, y: Float) {
+            if (gonePivot.equals(x, y)) {
+                return
+            }
+            gonePivot.set(x, y)
+            changedListener?.invoke()
+        }
+
         /**
          * A listener for all changes. This won't be copied over when invoking [copy]
          */
@@ -157,6 +176,8 @@
             mediaHostState.expansion = expansion
             mediaHostState.showsOnlyActiveMedia = showsOnlyActiveMedia
             mediaHostState.measurementInput = measurementInput?.copy()
+            mediaHostState.visible = visible
+            mediaHostState.gonePivot.set(gonePivot)
             return mediaHostState
         }
 
@@ -173,6 +194,12 @@
             if (showsOnlyActiveMedia != other.showsOnlyActiveMedia) {
                 return false
             }
+            if (visible != other.visible) {
+                return false
+            }
+            if (!gonePivot.equals(other.getPivotX(), other.getPivotY())) {
+                return false
+            }
             return true
         }
 
@@ -180,6 +207,8 @@
             var result = measurementInput?.hashCode() ?: 0
             result = 31 * result + expansion.hashCode()
             result = 31 * result + showsOnlyActiveMedia.hashCode()
+            result = 31 * result + if (visible) 1 else 2
+            result = 31 * result + gonePivot.hashCode()
             return result
         }
     }
@@ -194,7 +223,8 @@
     var measurementInput: MeasurementInput?
 
     /**
-     * The expansion of the player, 0 for fully collapsed, 1 for fully expanded
+     * The expansion of the player, 0 for fully collapsed (up to 3 actions), 1 for fully expanded
+     * (up to 5 actions.)
      */
     var expansion: Float
 
@@ -204,6 +234,30 @@
     var showsOnlyActiveMedia: Boolean
 
     /**
+     * If the view should be VISIBLE or GONE.
+     */
+    var visible: Boolean
+
+    /**
+     * Sets the pivot point when clipping the height or width.
+     * Clipping happens when animating visibility when we're visible in QS but not on QQS,
+     * for example.
+     */
+    fun setGonePivot(x: Float, y: Float)
+
+    /**
+     * x position of pivot, from 0 to 1
+     * @see [setGonePivot]
+     */
+    fun getPivotX(): Float
+
+    /**
+     * y position of pivot, from 0 to 1
+     * @see [setGonePivot]
+     */
+    fun getPivotY(): Float
+
+    /**
      * Get a copy of this view state, deepcopying all appropriate members
      */
     fun copy(): MediaHostState
diff --git a/packages/SystemUI/src/com/android/systemui/media/MediaResumeListener.kt b/packages/SystemUI/src/com/android/systemui/media/MediaResumeListener.kt
index 6bbe0d16..e8a4b1e 100644
--- a/packages/SystemUI/src/com/android/systemui/media/MediaResumeListener.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/MediaResumeListener.kt
@@ -40,7 +40,7 @@
 private const val TAG = "MediaResumeListener"
 
 private const val MEDIA_PREFERENCES = "media_control_prefs"
-private const val MEDIA_PREFERENCE_KEY = "browser_components"
+private const val MEDIA_PREFERENCE_KEY = "browser_components_"
 
 @Singleton
 class MediaResumeListener @Inject constructor(
@@ -63,11 +63,16 @@
     lateinit var resumeComponentFoundCallback: (String, Runnable?) -> Unit
 
     private var mediaBrowser: ResumeMediaBrowser? = null
+    private var currentUserId: Int
 
-    private val unlockReceiver = object : BroadcastReceiver() {
+    private val userChangeReceiver = object : BroadcastReceiver() {
         override fun onReceive(context: Context, intent: Intent) {
             if (Intent.ACTION_USER_UNLOCKED == intent.action) {
                 loadMediaResumptionControls()
+            } else if (Intent.ACTION_USER_SWITCHED == intent.action) {
+                currentUserId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, -1)
+                loadSavedComponents()
+                loadMediaResumptionControls()
             }
         }
     }
@@ -97,18 +102,22 @@
     }
 
     init {
+        currentUserId = context.userId
         if (useMediaResumption) {
             val unlockFilter = IntentFilter()
             unlockFilter.addAction(Intent.ACTION_USER_UNLOCKED)
-            broadcastDispatcher.registerReceiver(unlockReceiver, unlockFilter, null, UserHandle.ALL)
+            unlockFilter.addAction(Intent.ACTION_USER_SWITCHED)
+            broadcastDispatcher.registerReceiver(userChangeReceiver, unlockFilter, null,
+                UserHandle.ALL)
             loadSavedComponents()
         }
     }
 
     private fun loadSavedComponents() {
-        val userContext = context.createContextAsUser(context.getUser(), 0)
-        val prefs = userContext.getSharedPreferences(MEDIA_PREFERENCES, Context.MODE_PRIVATE)
-        val listString = prefs.getString(MEDIA_PREFERENCE_KEY, null)
+        // Make sure list is empty (if we switched users)
+        resumeComponents.clear()
+        val prefs = context.getSharedPreferences(MEDIA_PREFERENCES, Context.MODE_PRIVATE)
+        val listString = prefs.getString(MEDIA_PREFERENCE_KEY + currentUserId, null)
         val components = listString?.split(ResumeMediaBrowser.DELIMITER.toRegex())
             ?.dropLastWhile { it.isEmpty() }
         components?.forEach {
@@ -133,7 +142,6 @@
             val browser = ResumeMediaBrowser(context, mediaBrowserCallback, it)
             browser.findRecentMedia()
         }
-        broadcastDispatcher.unregisterReceiver(unlockReceiver) // only need to load once
     }
 
     override fun onMediaDataLoaded(key: String, oldKey: String?, data: MediaData) {
@@ -212,9 +220,8 @@
             sb.append(it.flattenToString())
             sb.append(ResumeMediaBrowser.DELIMITER)
         }
-        val userContext = context.createContextAsUser(context.getUser(), 0)
-        val prefs = userContext.getSharedPreferences(MEDIA_PREFERENCES, Context.MODE_PRIVATE)
-        prefs.edit().putString(MEDIA_PREFERENCE_KEY, sb.toString()).apply()
+        val prefs = context.getSharedPreferences(MEDIA_PREFERENCES, Context.MODE_PRIVATE)
+        prefs.edit().putString(MEDIA_PREFERENCE_KEY + currentUserId, sb.toString()).apply()
     }
 
     /**
diff --git a/packages/SystemUI/src/com/android/systemui/media/MediaTimeoutListener.kt b/packages/SystemUI/src/com/android/systemui/media/MediaTimeoutListener.kt
index 3c3f4a9..e0155a1 100644
--- a/packages/SystemUI/src/com/android/systemui/media/MediaTimeoutListener.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/MediaTimeoutListener.kt
@@ -43,6 +43,11 @@
 
     private val mediaListeners: MutableMap<String, PlaybackStateListener> = mutableMapOf()
 
+    /**
+     * Callback representing that a media object is now expired:
+     * @param token Media session unique identifier
+     * @param pauseTimeuot True when expired for {@code PAUSED_MEDIA_TIMEOUT}
+     */
     lateinit var timeoutCallback: (String, Boolean) -> Unit
 
     override fun onMediaDataLoaded(key: String, oldKey: String?, data: MediaData) {
@@ -112,11 +117,11 @@
             }
         }
 
-        private fun expireMediaTimeout(mediaNotificationKey: String, reason: String) {
+        private fun expireMediaTimeout(mediaKey: String, reason: String) {
             cancellation?.apply {
                 if (DEBUG) {
                     Log.v(TAG,
-                            "media timeout cancelled for  $mediaNotificationKey, reason: $reason")
+                            "media timeout cancelled for  $mediaKey, reason: $reason")
                 }
                 run()
             }
diff --git a/packages/SystemUI/src/com/android/systemui/media/MediaViewController.kt b/packages/SystemUI/src/com/android/systemui/media/MediaViewController.kt
index e82bb40..90ccfc6 100644
--- a/packages/SystemUI/src/com/android/systemui/media/MediaViewController.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/MediaViewController.kt
@@ -17,20 +17,22 @@
 package com.android.systemui.media
 
 import android.content.Context
+import android.graphics.PointF
 import androidx.constraintlayout.widget.ConstraintSet
 import com.android.systemui.R
+import com.android.systemui.util.animation.MeasurementOutput
 import com.android.systemui.util.animation.TransitionLayout
 import com.android.systemui.util.animation.TransitionLayoutController
 import com.android.systemui.util.animation.TransitionViewState
-import com.android.systemui.util.animation.MeasurementOutput
+import javax.inject.Inject
 
 /**
  * A class responsible for controlling a single instance of a media player handling interactions
  * with the view instance and keeping the media view states up to date.
  */
-class MediaViewController(
+class MediaViewController @Inject constructor(
     context: Context,
-    val mediaHostStatesManager: MediaHostStatesManager
+    private val mediaHostStatesManager: MediaHostStatesManager
 ) {
 
     private var firstRefresh: Boolean = true
@@ -44,7 +46,7 @@
     /**
      * A map containing all viewStates for all locations of this mediaState
      */
-    private val mViewStates: MutableMap<MediaHostState, TransitionViewState?> = mutableMapOf()
+    private val viewStates: MutableMap<MediaHostState, TransitionViewState?> = mutableMapOf()
 
     /**
      * The ending location of the view where it ends when all animations and transitions have
@@ -69,6 +71,11 @@
     private val tmpState = TransitionViewState()
 
     /**
+     * Temporary variable to avoid unnecessary allocations.
+     */
+    private val tmpPoint = PointF()
+
+    /**
      * A callback for media state changes
      */
     val stateCallback = object : MediaHostStatesManager.Callback {
@@ -125,7 +132,7 @@
      * it's not available, it will recreate one by measuring, which may be expensive.
      */
     private fun obtainViewState(state: MediaHostState): TransitionViewState? {
-        val viewState = mViewStates[state]
+        val viewState = viewStates[state]
         if (viewState != null) {
             // we already have cached this measurement, let's continue
             return viewState
@@ -143,7 +150,7 @@
                 // We don't want to cache interpolated or null states as this could quickly fill up
                 // our cache. We only cache the start and the end states since the interpolation
                 // is cheap
-                mViewStates[state.copy()] = result
+                viewStates[state.copy()] = result
             } else {
                 // This is an interpolated state
                 val startState = state.copy().also { it.expansion = 0.0f }
@@ -153,11 +160,13 @@
                 val startViewState = obtainViewState(startState) as TransitionViewState
                 val endState = state.copy().also { it.expansion = 1.0f }
                 val endViewState = obtainViewState(endState) as TransitionViewState
+                tmpPoint.set(startState.getPivotX(), startState.getPivotY())
                 result = TransitionViewState()
                 layoutController.getInterpolatedState(
                         startViewState,
                         endViewState,
                         state.expansion,
+                        tmpPoint,
                         result)
             }
         } else {
@@ -213,11 +222,35 @@
 
         val shouldAnimate = animateNextStateChange && !applyImmediately
 
+        var startHostState = mediaHostStatesManager.mediaHostStates[startLocation]
+        var endHostState = mediaHostStatesManager.mediaHostStates[endLocation]
+        var swappedStartState = false
+        var swappedEndState = false
+
+        // if we're going from or to a non visible state, let's grab the visible one and animate
+        // the view being clipped instead.
+        if (endHostState?.visible != true) {
+            endHostState = startHostState
+            swappedEndState = true
+        }
+        if (startHostState?.visible != true) {
+            startHostState = endHostState
+            swappedStartState = true
+        }
+        if (startHostState == null || endHostState == null) {
+            return
+        }
+
+        var endViewState = obtainViewState(endHostState) ?: return
+        if (swappedEndState) {
+            endViewState = endViewState.copy()
+            endViewState.height = 0
+        }
+
         // Obtain the view state that we'd want to be at the end
         // The view might not be bound yet or has never been measured and in that case will be
         // reset once the state is fully available
-        val endState = obtainViewStateForLocation(endLocation) ?: return
-        layoutController.setMeasureState(endState)
+        layoutController.setMeasureState(endViewState)
 
         // If the view isn't bound, we can drop the animation, otherwise we'll executute it
         animateNextStateChange = false
@@ -225,24 +258,43 @@
             return
         }
 
-        val startState = obtainViewStateForLocation(startLocation)
+        var startViewState = obtainViewState(startHostState)
+        if (swappedStartState) {
+            startViewState = startViewState?.copy()
+            startViewState?.height = 0
+        }
+
         val result: TransitionViewState?
-        if (transitionProgress == 1.0f || startState == null) {
-            result = endState
+        result = if (transitionProgress == 1.0f || startViewState == null) {
+            endViewState
         } else if (transitionProgress == 0.0f) {
-            result = startState
+            startViewState
         } else {
-            layoutController.getInterpolatedState(startState, endState, transitionProgress,
-                    tmpState)
-            result = tmpState
+            if (swappedEndState || swappedStartState) {
+                tmpPoint.set(startHostState.getPivotX(), startHostState.getPivotY())
+            } else {
+                tmpPoint.set(0.0f, 0.0f)
+            }
+            layoutController.getInterpolatedState(startViewState, endViewState, transitionProgress,
+                    tmpPoint, tmpState)
+            tmpState
         }
         layoutController.setState(result, applyImmediately, shouldAnimate, animationDuration,
                 animationDelay)
     }
 
-    private fun obtainViewStateForLocation(location: Int): TransitionViewState? {
-        val mediaState = mediaHostStatesManager.mediaHostStates[location] ?: return null
-        return obtainViewState(mediaState)
+    /**
+     * Retrieves the [TransitionViewState] and [MediaHostState] of a [@MediaLocation].
+     * In the event of [location] not being visible, [locationWhenHidden] will be used instead.
+     *
+     * @param location Target
+     * @param locationWhenHidden Location that will be used when the target is not
+     * [MediaHost.visible]
+     * @return State require for executing a transition, and also the respective [MediaHost].
+     */
+    private fun obtainViewStateForLocation(@MediaLocation location: Int): TransitionViewState? {
+        val mediaHostState = mediaHostStatesManager.mediaHostStates[location] ?: return null
+        return obtainViewState(mediaHostState)
     }
 
     /**
@@ -250,8 +302,7 @@
      * This updates the width the view will me measured with.
      */
     fun onLocationPreChange(@MediaLocation newLocation: Int) {
-        val viewState = obtainViewStateForLocation(newLocation)
-        viewState?.let {
+        obtainViewStateForLocation(newLocation)?.let {
             layoutController.setMeasureState(it)
         }
     }
@@ -271,7 +322,7 @@
     fun refreshState() {
         if (!firstRefresh) {
             // Let's clear all of our measurements and recreate them!
-            mViewStates.clear()
+            viewStates.clear()
             setCurrentState(currentStartLocation, currentEndLocation, currentTransitionProgress,
                     applyImmediately = false)
         }
diff --git a/packages/SystemUI/src/com/android/systemui/media/ResumeMediaBrowser.java b/packages/SystemUI/src/com/android/systemui/media/ResumeMediaBrowser.java
index 1e9a303..6462f07 100644
--- a/packages/SystemUI/src/com/android/systemui/media/ResumeMediaBrowser.java
+++ b/packages/SystemUI/src/com/android/systemui/media/ResumeMediaBrowser.java
@@ -135,12 +135,16 @@
          */
         @Override
         public void onConnected() {
+            Log.d(TAG, "Service connected for " + mComponentName);
             if (mMediaBrowser.isConnected()) {
-                mCallback.onConnected();
-                Log.d(TAG, "Service connected for " + mComponentName);
                 String root = mMediaBrowser.getRoot();
-                mMediaBrowser.subscribe(root, mSubscriptionCallback);
+                if (!TextUtils.isEmpty(root)) {
+                    mCallback.onConnected();
+                    mMediaBrowser.subscribe(root, mSubscriptionCallback);
+                    return;
+                }
             }
+            mCallback.onError();
         }
 
         /**
@@ -193,6 +197,10 @@
                     @Override
                     public void onConnected() {
                         Log.d(TAG, "Connected for restart " + mMediaBrowser.isConnected());
+                        if (!mMediaBrowser.isConnected()) {
+                            mCallback.onError();
+                            return;
+                        }
                         MediaSession.Token token = mMediaBrowser.getSessionToken();
                         MediaController controller = new MediaController(mContext, token);
                         controller.getTransportControls();
@@ -251,7 +259,8 @@
                     @Override
                     public void onConnected() {
                         Log.d(TAG, "connected");
-                        if (TextUtils.isEmpty(mMediaBrowser.getRoot())) {
+                        if (!mMediaBrowser.isConnected()
+                                || TextUtils.isEmpty(mMediaBrowser.getRoot())) {
                             mCallback.onError();
                         } else {
                             mCallback.onConnected();
diff --git a/packages/SystemUI/src/com/android/systemui/media/SeekBarViewModel.kt b/packages/SystemUI/src/com/android/systemui/media/SeekBarViewModel.kt
index efc476d..1dca3f1 100644
--- a/packages/SystemUI/src/com/android/systemui/media/SeekBarViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/SeekBarViewModel.kt
@@ -20,19 +20,22 @@
 import android.media.session.MediaController
 import android.media.session.PlaybackState
 import android.os.SystemClock
+import android.view.GestureDetector
 import android.view.MotionEvent
 import android.view.View
+import android.view.ViewConfiguration
 import android.widget.SeekBar
 import androidx.annotation.AnyThread
 import androidx.annotation.WorkerThread
+import androidx.core.view.GestureDetectorCompat
 import androidx.lifecycle.MutableLiveData
 import androidx.lifecycle.LiveData
 import com.android.systemui.dagger.qualifiers.Background
 import com.android.systemui.util.concurrency.RepeatableExecutor
-import java.util.concurrent.Executor
 import javax.inject.Inject
 
 private const val POSITION_UPDATE_INTERVAL_MILLIS = 100L
+private const val MIN_FLING_VELOCITY_SCALE_FACTOR = 10
 
 private fun PlaybackState.isInMotion(): Boolean {
     return this.state == PlaybackState.STATE_PLAYING ||
@@ -68,7 +71,6 @@
 
 /** ViewModel for seek bar in QS media player. */
 class SeekBarViewModel @Inject constructor(@Background private val bgExecutor: RepeatableExecutor) {
-
     private var _data = Progress(false, false, null, null)
         set(value) {
             field = value
@@ -104,6 +106,9 @@
     }
     private var cancel: Runnable? = null
 
+    /** Indicates if the seek interaction is considered a false guesture. */
+    private var isFalseSeek = false
+
     /** Listening state (QS open or closed) is used to control polling of progress. */
     var listening = true
         set(value) = bgExecutor.execute {
@@ -113,16 +118,61 @@
             }
         }
 
+    /** Set to true when the user is touching the seek bar to change the position. */
+    private var scrubbing = false
+        set(value) {
+            if (field != value) {
+                field = value
+                checkIfPollingNeeded()
+            }
+        }
+
+    /**
+     * Event indicating that the user has started interacting with the seek bar.
+     */
+    @AnyThread
+    fun onSeekStarting() = bgExecutor.execute {
+        scrubbing = true
+        isFalseSeek = false
+    }
+
+    /**
+     * Event indicating that the user has moved the seek bar but hasn't yet finished the gesture.
+     * @param position Current location in the track.
+     */
+    @AnyThread
+    fun onSeekProgress(position: Long) = bgExecutor.execute {
+        if (scrubbing) {
+            _data = _data.copy(elapsedTime = position.toInt())
+        }
+    }
+
+    /**
+     * Event indicating that the seek interaction is a false gesture and it should be ignored.
+     */
+    @AnyThread
+    fun onSeekFalse() = bgExecutor.execute {
+        if (scrubbing) {
+            isFalseSeek = true
+        }
+    }
+
     /**
      * Handle request to change the current position in the media track.
      * @param position Place to seek to in the track.
      */
-    @WorkerThread
-    fun onSeek(position: Long) {
-        controller?.transportControls?.seekTo(position)
-        // Invalidate the cached playbackState to avoid the thumb jumping back to the previous
-        // position.
-        playbackState = null
+    @AnyThread
+    fun onSeek(position: Long) = bgExecutor.execute {
+        if (isFalseSeek) {
+            scrubbing = false
+            checkPlaybackPosition()
+        } else {
+            controller?.transportControls?.seekTo(position)
+            // Invalidate the cached playbackState to avoid the thumb jumping back to the previous
+            // position.
+            playbackState = null
+            scrubbing = false
+        }
     }
 
     /**
@@ -180,7 +230,7 @@
 
     @WorkerThread
     private fun checkIfPollingNeeded() {
-        val needed = listening && playbackState?.isInMotion() ?: false
+        val needed = listening && !scrubbing && playbackState?.isInMotion() ?: false
         if (needed) {
             if (cancel == null) {
                 cancel = bgExecutor.executeRepeatedly(this::checkPlaybackPosition, 0L,
@@ -195,41 +245,162 @@
     /** Gets a listener to attach to the seek bar to handle seeking. */
     val seekBarListener: SeekBar.OnSeekBarChangeListener
         get() {
-            return SeekBarChangeListener(this, bgExecutor)
+            return SeekBarChangeListener(this)
         }
 
-    /** Gets a listener to attach to the seek bar to disable touch intercepting. */
-    val seekBarTouchListener: View.OnTouchListener
-        get() {
-            return SeekBarTouchListener()
-        }
+    /** Attach touch handlers to the seek bar view. */
+    fun attachTouchHandlers(bar: SeekBar) {
+        bar.setOnSeekBarChangeListener(seekBarListener)
+        bar.setOnTouchListener(SeekBarTouchListener(this, bar))
+    }
 
     private class SeekBarChangeListener(
-        val viewModel: SeekBarViewModel,
-        val bgExecutor: Executor
+        val viewModel: SeekBarViewModel
     ) : SeekBar.OnSeekBarChangeListener {
         override fun onProgressChanged(bar: SeekBar, progress: Int, fromUser: Boolean) {
             if (fromUser) {
-                bgExecutor.execute {
-                    viewModel.onSeek(progress.toLong())
-                }
+                viewModel.onSeekProgress(progress.toLong())
             }
         }
+
         override fun onStartTrackingTouch(bar: SeekBar) {
+            viewModel.onSeekStarting()
         }
+
         override fun onStopTrackingTouch(bar: SeekBar) {
-            val pos = bar.progress.toLong()
-            bgExecutor.execute {
-                viewModel.onSeek(pos)
-            }
+            viewModel.onSeek(bar.progress.toLong())
         }
     }
 
-    private class SeekBarTouchListener : View.OnTouchListener {
-        override fun onTouch(view: View, event: MotionEvent): Boolean {
-            view.parent.requestDisallowInterceptTouchEvent(true)
-            return view.onTouchEvent(event)
+    /**
+     * Responsible for intercepting touch events before they reach the seek bar.
+     *
+     * This reduces the gestures seen by the seek bar so that users don't accidentially seek when
+     * they intend to scroll the carousel.
+     */
+    private class SeekBarTouchListener(
+        private val viewModel: SeekBarViewModel,
+        private val bar: SeekBar
+    ) : View.OnTouchListener, GestureDetector.OnGestureListener {
+
+        // Gesture detector helps decide which touch events to intercept.
+        private val detector = GestureDetectorCompat(bar.context, this)
+        // Velocity threshold used to decide when a fling is considered a false gesture.
+        private val flingVelocity: Int = ViewConfiguration.get(bar.context).run {
+            getScaledMinimumFlingVelocity() * MIN_FLING_VELOCITY_SCALE_FACTOR
         }
+        // Indicates if the gesture should go to the seek bar or if it should be intercepted.
+        private var shouldGoToSeekBar = false
+
+        /**
+         * Decide which touch events to intercept before they reach the seek bar.
+         *
+         * Based on the gesture detected, we decide whether we want the event to reach the seek bar.
+         * If we want the seek bar to see the event, then we return false so that the event isn't
+         * handled here and it will be passed along. If, however, we don't want the seek bar to see
+         * the event, then return true so that the event is handled here.
+         *
+         * When the seek bar is contained in the carousel, the carousel still has the ability to
+         * intercept the touch event. So, even though we may handle the event here, the carousel can
+         * still intercept the event. This way, gestures that we consider falses on the seek bar can
+         * still be used by the carousel for paging.
+         *
+         * Returns true for events that we don't want dispatched to the seek bar.
+         */
+        override fun onTouch(view: View, event: MotionEvent): Boolean {
+            if (view != bar) {
+                return false
+            }
+            detector.onTouchEvent(event)
+            return !shouldGoToSeekBar
+        }
+
+        /**
+         * Handle down events that press down on the thumb.
+         *
+         * On the down action, determine a target box around the thumb to know when a scroll
+         * gesture starts by clicking on the thumb. The target box will be used by subsequent
+         * onScroll events.
+         *
+         * Returns true when the down event hits within the target box of the thumb.
+         */
+        override fun onDown(event: MotionEvent): Boolean {
+            val padL = bar.paddingLeft
+            val padR = bar.paddingRight
+            // Compute the X location of the thumb as a function of the seek bar progress.
+            // TODO: account for thumb offset
+            val progress = bar.getProgress()
+            val range = bar.max - bar.min
+            val widthFraction = if (range > 0) {
+                (progress - bar.min).toDouble() / range
+            } else {
+                0.0
+            }
+            val availableWidth = bar.width - padL - padR
+            val thumbX = if (bar.isLayoutRtl()) {
+                padL + availableWidth * (1 - widthFraction)
+            } else {
+                padL + availableWidth * widthFraction
+            }
+            // Set the min, max boundaries of the thumb box.
+            // I'm cheating by using the height of the seek bar as the width of the box.
+            val halfHeight: Int = bar.height / 2
+            val targetBoxMinX = (Math.round(thumbX) - halfHeight).toInt()
+            val targetBoxMaxX = (Math.round(thumbX) + halfHeight).toInt()
+            // If the x position of the down event is within the box, then request that the parent
+            // not intercept the event.
+            val x = Math.round(event.x)
+            shouldGoToSeekBar = x >= targetBoxMinX && x <= targetBoxMaxX
+            if (shouldGoToSeekBar) {
+                bar.parent?.requestDisallowInterceptTouchEvent(true)
+            }
+            return shouldGoToSeekBar
+        }
+
+        /**
+         * Always handle single tap up.
+         *
+         * This enables the user to single tap anywhere on the seek bar to seek to that position.
+         */
+        override fun onSingleTapUp(event: MotionEvent): Boolean {
+            shouldGoToSeekBar = true
+            return true
+        }
+
+        /**
+         * Handle scroll events when the down event is on the thumb.
+         *
+         * Returns true when the down event of the scroll hits within the target box of the thumb.
+         */
+        override fun onScroll(
+            eventStart: MotionEvent,
+            event: MotionEvent,
+            distanceX: Float,
+            distanceY: Float
+        ): Boolean {
+            return shouldGoToSeekBar
+        }
+
+        /**
+         * Handle fling events when the down event is on the thumb.
+         *
+         * Gestures that include a fling are considered a false gesture on the seek bar.
+         */
+        override fun onFling(
+            eventStart: MotionEvent,
+            event: MotionEvent,
+            velocityX: Float,
+            velocityY: Float
+        ): Boolean {
+            if (Math.abs(velocityX) > flingVelocity || Math.abs(velocityY) > flingVelocity) {
+                viewModel.onSeekFalse()
+            }
+            return shouldGoToSeekBar
+        }
+
+        override fun onShowPress(event: MotionEvent) {}
+
+        override fun onLongPress(event: MotionEvent) {}
     }
 
     /** State seen by seek bar UI. */
diff --git a/packages/SystemUI/src/com/android/systemui/pip/PipAnimationController.java b/packages/SystemUI/src/com/android/systemui/pip/PipAnimationController.java
index 03b1ddc..2980f11 100644
--- a/packages/SystemUI/src/com/android/systemui/pip/PipAnimationController.java
+++ b/packages/SystemUI/src/com/android/systemui/pip/PipAnimationController.java
@@ -16,8 +16,8 @@
 
 package com.android.systemui.pip;
 
+import android.animation.AnimationHandler;
 import android.animation.Animator;
-import android.animation.RectEvaluator;
 import android.animation.ValueAnimator;
 import android.annotation.IntDef;
 import android.content.Context;
@@ -27,7 +27,7 @@
 import android.view.animation.Interpolator;
 
 import com.android.internal.annotations.VisibleForTesting;
-import com.android.systemui.Interpolators;
+import com.android.internal.graphics.SfVsyncFrameCallbackProvider;
 
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
@@ -76,12 +76,22 @@
                 || direction == TRANSITION_DIRECTION_TO_SPLIT_SCREEN;
     }
 
+    private final Interpolator mFastOutSlowInInterpolator;
     private final PipSurfaceTransactionHelper mSurfaceTransactionHelper;
 
     private PipTransitionAnimator mCurrentAnimator;
 
+    private ThreadLocal<AnimationHandler> mSfAnimationHandlerThreadLocal =
+            ThreadLocal.withInitial(() -> {
+                AnimationHandler handler = new AnimationHandler();
+                handler.setProvider(new SfVsyncFrameCallbackProvider());
+                return handler;
+            });
+
     @Inject
     PipAnimationController(Context context, PipSurfaceTransactionHelper helper) {
+        mFastOutSlowInInterpolator = AnimationUtils.loadInterpolator(context,
+                com.android.internal.R.interpolator.fast_out_slow_in);
         mSurfaceTransactionHelper = helper;
     }
 
@@ -103,11 +113,10 @@
     }
 
     @SuppressWarnings("unchecked")
-    PipTransitionAnimator getAnimator(SurfaceControl leash, Rect startBounds, Rect endBounds,
-            Rect sourceHintRect) {
+    PipTransitionAnimator getAnimator(SurfaceControl leash, Rect startBounds, Rect endBounds) {
         if (mCurrentAnimator == null) {
             mCurrentAnimator = setupPipTransitionAnimator(
-                    PipTransitionAnimator.ofBounds(leash, startBounds, endBounds, sourceHintRect));
+                    PipTransitionAnimator.ofBounds(leash, startBounds, endBounds));
         } else if (mCurrentAnimator.getAnimationType() == ANIM_TYPE_ALPHA
                 && mCurrentAnimator.isRunning()) {
             // If we are still animating the fade into pip, then just move the surface and ensure
@@ -122,7 +131,7 @@
         } else {
             mCurrentAnimator.cancel();
             mCurrentAnimator = setupPipTransitionAnimator(
-                    PipTransitionAnimator.ofBounds(leash, startBounds, endBounds, sourceHintRect));
+                    PipTransitionAnimator.ofBounds(leash, startBounds, endBounds));
         }
         return mCurrentAnimator;
     }
@@ -133,8 +142,9 @@
 
     private PipTransitionAnimator setupPipTransitionAnimator(PipTransitionAnimator animator) {
         animator.setSurfaceTransactionHelper(mSurfaceTransactionHelper);
-        animator.setInterpolator(Interpolators.FAST_OUT_SLOW_IN);
+        animator.setInterpolator(mFastOutSlowInInterpolator);
         animator.setFloatValues(FRACTION_START, FRACTION_END);
+        animator.setAnimationHandler(mSfAnimationHandlerThreadLocal.get());
         return animator;
     }
 
@@ -331,7 +341,6 @@
                 @Override
                 void onStartTransaction(SurfaceControl leash, SurfaceControl.Transaction tx) {
                     getSurfaceTransactionHelper()
-                            .resetScale(tx, leash, getDestinationBounds())
                             .crop(tx, leash, getDestinationBounds())
                             .round(tx, leash, shouldApplyCornerRadius());
                     tx.show(leash);
@@ -347,46 +356,35 @@
         }
 
         static PipTransitionAnimator<Rect> ofBounds(SurfaceControl leash,
-                Rect startValue, Rect endValue, Rect sourceHintRect) {
-            // Just for simplicity we'll interpolate between the source rect hint insets and empty
-            // insets to calculate the window crop
-            final Rect initialStartValue = new Rect(startValue);
-            final Rect sourceHintRectInsets = sourceHintRect != null
-                    ? new Rect(sourceHintRect.left - startValue.left,
-                            sourceHintRect.top - startValue.top,
-                            startValue.right - sourceHintRect.right,
-                            startValue.bottom - sourceHintRect.bottom)
-                    : null;
-            final Rect sourceInsets = new Rect(0, 0, 0, 0);
-
+                Rect startValue, Rect endValue) {
             // construct new Rect instances in case they are recycled
             return new PipTransitionAnimator<Rect>(leash, ANIM_TYPE_BOUNDS,
                     endValue, new Rect(startValue), new Rect(endValue)) {
-                private final RectEvaluator mRectEvaluator = new RectEvaluator(new Rect());
-                private final RectEvaluator mInsetsEvaluator = new RectEvaluator(new Rect());
+                private final Rect mTmpRect = new Rect();
+
+                private int getCastedFractionValue(float start, float end, float fraction) {
+                    return (int) (start * (1 - fraction) + end * fraction + .5f);
+                }
 
                 @Override
                 void applySurfaceControlTransaction(SurfaceControl leash,
                         SurfaceControl.Transaction tx, float fraction) {
                     final Rect start = getStartValue();
                     final Rect end = getEndValue();
-                    Rect bounds = mRectEvaluator.evaluate(fraction, start, end);
-                    setCurrentValue(bounds);
+                    mTmpRect.set(
+                            getCastedFractionValue(start.left, end.left, fraction),
+                            getCastedFractionValue(start.top, end.top, fraction),
+                            getCastedFractionValue(start.right, end.right, fraction),
+                            getCastedFractionValue(start.bottom, end.bottom, fraction));
+                    setCurrentValue(mTmpRect);
                     if (inScaleTransition()) {
                         if (isOutPipDirection(getTransitionDirection())) {
-                            getSurfaceTransactionHelper().scale(tx, leash, end, bounds);
+                            getSurfaceTransactionHelper().scale(tx, leash, end, mTmpRect);
                         } else {
-                            getSurfaceTransactionHelper().scale(tx, leash, start, bounds);
+                            getSurfaceTransactionHelper().scale(tx, leash, start, mTmpRect);
                         }
                     } else {
-                        if (sourceHintRectInsets != null) {
-                            Rect insets = mInsetsEvaluator.evaluate(fraction, sourceInsets,
-                                    sourceHintRectInsets);
-                            getSurfaceTransactionHelper().scaleAndCrop(tx, leash, initialStartValue,
-                                    bounds, insets);
-                        } else {
-                            getSurfaceTransactionHelper().scale(tx, leash, start, bounds);
-                        }
+                        getSurfaceTransactionHelper().crop(tx, leash, mTmpRect);
                     }
                     tx.apply();
                 }
@@ -402,11 +400,11 @@
 
                 @Override
                 void onEndTransaction(SurfaceControl leash, SurfaceControl.Transaction tx) {
+                    if (!inScaleTransition()) return;
                     // NOTE: intentionally does not apply the transaction here.
                     // this end transaction should get executed synchronously with the final
                     // WindowContainerTransaction in task organizer
-                    getSurfaceTransactionHelper()
-                            .resetScale(tx, leash, getDestinationBounds())
+                    getSurfaceTransactionHelper().resetScale(tx, leash, getDestinationBounds())
                             .crop(tx, leash, getDestinationBounds());
                 }
 
diff --git a/packages/SystemUI/src/com/android/systemui/pip/PipBoundsHandler.java b/packages/SystemUI/src/com/android/systemui/pip/PipBoundsHandler.java
index 2657694..0d3a16e 100644
--- a/packages/SystemUI/src/com/android/systemui/pip/PipBoundsHandler.java
+++ b/packages/SystemUI/src/com/android/systemui/pip/PipBoundsHandler.java
@@ -296,14 +296,6 @@
      */
     public boolean onDisplayRotationChanged(Rect outBounds, Rect oldBounds, Rect outInsetBounds,
             int displayId, int fromRotation, int toRotation, WindowContainerTransaction t) {
-        // Calculate the snap fraction of the current stack along the old movement bounds
-        final Rect postChangeStackBounds = new Rect(oldBounds);
-        final float snapFraction = getSnapFraction(postChangeStackBounds);
-
-        // Update the display layout, note that we have to do this on every rotation even if we
-        // aren't in PIP since we need to update the display layout to get the right resources
-        mDisplayLayout.rotateTo(mContext.getResources(), toRotation);
-
         // Bail early if the event is not sent to current {@link #mDisplayInfo}
         if ((displayId != mDisplayInfo.displayId) || (fromRotation == toRotation)) {
             return false;
@@ -320,6 +312,13 @@
             return false;
         }
 
+        // Calculate the snap fraction of the current stack along the old movement bounds
+        final Rect postChangeStackBounds = new Rect(oldBounds);
+        final float snapFraction = getSnapFraction(postChangeStackBounds);
+
+        // Update the display layout
+        mDisplayLayout.rotateTo(mContext.getResources(), toRotation);
+
         // Populate the new {@link #mDisplayInfo}.
         // The {@link DisplayInfo} queried from DisplayManager would be the one before rotation,
         // therefore, the width/height may require a swap first.
diff --git a/packages/SystemUI/src/com/android/systemui/pip/PipSurfaceTransactionHelper.java b/packages/SystemUI/src/com/android/systemui/pip/PipSurfaceTransactionHelper.java
index 65ea887..fc41d2e 100644
--- a/packages/SystemUI/src/com/android/systemui/pip/PipSurfaceTransactionHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/pip/PipSurfaceTransactionHelper.java
@@ -44,7 +44,6 @@
     private final float[] mTmpFloat9 = new float[9];
     private final RectF mTmpSourceRectF = new RectF();
     private final RectF mTmpDestinationRectF = new RectF();
-    private final Rect mTmpDestinationRect = new Rect();
 
     @Inject
     public PipSurfaceTransactionHelper(Context context, ConfigurationController configController) {
@@ -91,30 +90,7 @@
         mTmpDestinationRectF.set(destinationBounds);
         mTmpTransform.setRectToRect(mTmpSourceRectF, mTmpDestinationRectF, Matrix.ScaleToFit.FILL);
         tx.setMatrix(leash, mTmpTransform, mTmpFloat9)
-                .setPosition(leash, mTmpDestinationRectF.left, mTmpDestinationRectF.top);
-        return this;
-    }
-
-    /**
-     * Operates the scale (setMatrix) on a given transaction and leash
-     * @return same {@link PipSurfaceTransactionHelper} instance for method chaining
-     */
-    PipSurfaceTransactionHelper scaleAndCrop(SurfaceControl.Transaction tx, SurfaceControl leash,
-            Rect sourceBounds, Rect destinationBounds, Rect insets) {
-        mTmpSourceRectF.set(sourceBounds);
-        mTmpDestinationRect.set(sourceBounds);
-        mTmpDestinationRect.inset(insets);
-        // Scale by the shortest edge and offset such that the top/left of the scaled inset source
-        // rect aligns with the top/left of the destination bounds
-        final float scale = sourceBounds.width() <= sourceBounds.height()
-                ? (float) destinationBounds.width() / sourceBounds.width()
-                : (float) destinationBounds.height() / sourceBounds.height();
-        final float left = destinationBounds.left - insets.left * scale;
-        final float top = destinationBounds.top - insets.top * scale;
-        mTmpTransform.setScale(scale, scale);
-        tx.setMatrix(leash, mTmpTransform, mTmpFloat9)
-                .setWindowCrop(leash, mTmpDestinationRect)
-                .setPosition(leash, left, top);
+                .setPosition(leash, destinationBounds.left, destinationBounds.top);
         return this;
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/pip/PipTaskOrganizer.java b/packages/SystemUI/src/com/android/systemui/pip/PipTaskOrganizer.java
index 42e0c56..b93e07e 100644
--- a/packages/SystemUI/src/com/android/systemui/pip/PipTaskOrganizer.java
+++ b/packages/SystemUI/src/com/android/systemui/pip/PipTaskOrganizer.java
@@ -143,10 +143,8 @@
             case MSG_RESIZE_ANIMATE: {
                 Rect currentBounds = (Rect) args.arg2;
                 Rect toBounds = (Rect) args.arg3;
-                Rect sourceHintRect = (Rect) args.arg4;
                 int duration = args.argi2;
-                animateResizePip(currentBounds, toBounds, sourceHintRect,
-                        args.argi1 /* direction */, duration);
+                animateResizePip(currentBounds, toBounds, args.argi1 /* direction */, duration);
                 if (updateBoundsCallback != null) {
                     updateBoundsCallback.accept(toBounds);
                 }
@@ -296,8 +294,7 @@
                 public void onTransactionReady(int id, SurfaceControl.Transaction t) {
                     t.apply();
                     scheduleAnimateResizePip(mLastReportedBounds, destinationBounds,
-                            null /* sourceHintRect */, direction, animationDurationMs,
-                            null /* updateBoundsCallback */);
+                            direction, animationDurationMs, null /* updateBoundsCallback */);
                     mInPip = false;
                 }
             });
@@ -360,8 +357,7 @@
         final Rect currentBounds = mTaskInfo.configuration.windowConfiguration.getBounds();
 
         if (mOneShotAnimationType == ANIM_TYPE_BOUNDS) {
-            final Rect sourceHintRect = getValidSourceHintRect(info, currentBounds);
-            scheduleAnimateResizePip(currentBounds, destinationBounds, sourceHintRect,
+            scheduleAnimateResizePip(currentBounds, destinationBounds,
                     TRANSITION_DIRECTION_TO_PIP, mEnterExitAnimationDuration,
                     null /* updateBoundsCallback */);
         } else if (mOneShotAnimationType == ANIM_TYPE_ALPHA) {
@@ -372,21 +368,6 @@
         }
     }
 
-    /**
-     * Returns the source hint rect if it is valid (if provided and is contained by the current
-     * task bounds).
-     */
-    private Rect getValidSourceHintRect(ActivityManager.RunningTaskInfo info, Rect sourceBounds) {
-        final Rect sourceHintRect = info.pictureInPictureParams != null
-                && info.pictureInPictureParams.hasSourceBoundsHint()
-                ? info.pictureInPictureParams.getSourceRectHint()
-                : null;
-        if (sourceHintRect != null && sourceBounds.contains(sourceHintRect)) {
-            return sourceHintRect;
-        }
-        return null;
-    }
-
     private void enterPipWithAlphaAnimation(Rect destinationBounds, long durationMs) {
         // If we are fading the PIP in, then we should move the pip to the final location as
         // soon as possible, but set the alpha immediately since the transaction can take a
@@ -523,8 +504,18 @@
                 // this could happen if rotation finishes before the animation
                 mLastReportedBounds.set(destinationBoundsOut);
                 scheduleFinishResizePip(mLastReportedBounds);
-            } else if (!mLastReportedBounds.isEmpty()) {
-                destinationBoundsOut.set(mLastReportedBounds);
+            } else  {
+                // There could be an animation on-going. If there is one on-going, last-reported
+                // bounds isn't yet updated. We'll use the animator's bounds instead.
+                if (animator != null && animator.isRunning()) {
+                    if (!animator.getDestinationBounds().isEmpty()) {
+                        destinationBoundsOut.set(animator.getDestinationBounds());
+                    }
+                } else {
+                    if (!mLastReportedBounds.isEmpty()) {
+                        destinationBoundsOut.set(mLastReportedBounds);
+                    }
+                }
             }
             return;
         }
@@ -571,13 +562,13 @@
             Log.d(TAG, "skip scheduleAnimateResizePip, entering pip deferred");
             return;
         }
-        scheduleAnimateResizePip(mLastReportedBounds, toBounds, null /* sourceHintRect */,
+        scheduleAnimateResizePip(mLastReportedBounds, toBounds,
                 TRANSITION_DIRECTION_NONE, duration, updateBoundsCallback);
     }
 
     private void scheduleAnimateResizePip(Rect currentBounds, Rect destinationBounds,
-            Rect sourceHintRect, @PipAnimationController.TransitionDirection int direction,
-            int durationMs, Consumer<Rect> updateBoundsCallback) {
+            @PipAnimationController.TransitionDirection int direction, int durationMs,
+            Consumer<Rect> updateBoundsCallback) {
         if (!mInPip) {
             // can be initiated in other component, ignore if we are no longer in PIP
             return;
@@ -587,7 +578,6 @@
         args.arg1 = updateBoundsCallback;
         args.arg2 = currentBounds;
         args.arg3 = destinationBounds;
-        args.arg4 = sourceHintRect;
         args.argi1 = direction;
         args.argi2 = durationMs;
         mUpdateHandler.sendMessage(mUpdateHandler.obtainMessage(MSG_RESIZE_ANIMATE, args));
@@ -687,8 +677,7 @@
         }
         final Rect destinationBounds = new Rect(originalBounds);
         destinationBounds.offset(xOffset, yOffset);
-        animateResizePip(originalBounds, destinationBounds, null /* sourceHintRect */,
-                TRANSITION_DIRECTION_SAME, durationMs);
+        animateResizePip(originalBounds, destinationBounds, TRANSITION_DIRECTION_SAME, durationMs);
     }
 
     private void resizePip(Rect destinationBounds) {
@@ -766,7 +755,7 @@
         WindowOrganizer.applyTransaction(wct);
     }
 
-    private void animateResizePip(Rect currentBounds, Rect destinationBounds, Rect sourceHintRect,
+    private void animateResizePip(Rect currentBounds, Rect destinationBounds,
             @PipAnimationController.TransitionDirection int direction, int durationMs) {
         if (Looper.myLooper() != mUpdateHandler.getLooper()) {
             throw new RuntimeException("Callers should call scheduleAnimateResizePip() instead of "
@@ -778,7 +767,7 @@
             return;
         }
         mPipAnimationController
-                .getAnimator(mLeash, currentBounds, destinationBounds, sourceHintRect)
+                .getAnimator(mLeash, currentBounds, destinationBounds)
                 .setTransitionDirection(direction)
                 .setPipAnimationCallback(mPipAnimationCallback)
                 .setDuration(durationMs)
diff --git a/packages/SystemUI/src/com/android/systemui/pip/phone/PipManager.java b/packages/SystemUI/src/com/android/systemui/pip/phone/PipManager.java
index b714bff..e38bfb4 100644
--- a/packages/SystemUI/src/com/android/systemui/pip/phone/PipManager.java
+++ b/packages/SystemUI/src/com/android/systemui/pip/phone/PipManager.java
@@ -269,7 +269,7 @@
             if (stackInfo != null) {
                 // If SystemUI restart, and it already existed a pinned stack,
                 // register the pip input consumer to ensure touch can send to it.
-                mInputConsumerController.registerInputConsumer();
+                mInputConsumerController.registerInputConsumer(true /* withSfVsync */);
             }
         } catch (RemoteException | UnsupportedOperationException e) {
             e.printStackTrace();
diff --git a/packages/SystemUI/src/com/android/systemui/pip/phone/PipMenuActivity.java b/packages/SystemUI/src/com/android/systemui/pip/phone/PipMenuActivity.java
index a3185a2..6ab73fc 100644
--- a/packages/SystemUI/src/com/android/systemui/pip/phone/PipMenuActivity.java
+++ b/packages/SystemUI/src/com/android/systemui/pip/phone/PipMenuActivity.java
@@ -295,6 +295,14 @@
     }
 
     @Override
+    public void onTopResumedActivityChanged(boolean isTopResumedActivity) {
+        super.onTopResumedActivityChanged(isTopResumedActivity);
+        if (!isTopResumedActivity && mMenuState != MENU_STATE_NONE) {
+            hideMenu();
+        }
+    }
+
+    @Override
     protected void onStop() {
         super.onStop();
 
diff --git a/packages/SystemUI/src/com/android/systemui/pip/phone/PipMenuActivityController.java b/packages/SystemUI/src/com/android/systemui/pip/phone/PipMenuActivityController.java
index 8b4d932..31d292f 100644
--- a/packages/SystemUI/src/com/android/systemui/pip/phone/PipMenuActivityController.java
+++ b/packages/SystemUI/src/com/android/systemui/pip/phone/PipMenuActivityController.java
@@ -197,7 +197,7 @@
     }
 
     public void onActivityPinned() {
-        mInputConsumerController.registerInputConsumer();
+        mInputConsumerController.registerInputConsumer(true /* withSfVsync */);
     }
 
     public void onActivityUnpinned() {
diff --git a/packages/SystemUI/src/com/android/systemui/pip/phone/PipMotionHelper.java b/packages/SystemUI/src/com/android/systemui/pip/phone/PipMotionHelper.java
index 2e75bab..856c192 100644
--- a/packages/SystemUI/src/com/android/systemui/pip/phone/PipMotionHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/pip/phone/PipMotionHelper.java
@@ -23,9 +23,11 @@
 import android.graphics.Rect;
 import android.os.Debug;
 import android.util.Log;
+import android.view.Choreographer;
 
 import androidx.dynamicanimation.animation.SpringForce;
 
+import com.android.internal.graphics.SfVsyncFrameCallbackProvider;
 import com.android.systemui.pip.PipSnapAlgorithm;
 import com.android.systemui.pip.PipTaskOrganizer;
 import com.android.systemui.util.FloatingContentCoordinator;
@@ -68,6 +70,9 @@
     /** The region that all of PIP must stay within. */
     private final Rect mFloatingAllowedArea = new Rect();
 
+    private final SfVsyncFrameCallbackProvider mSfVsyncFrameProvider =
+            new SfVsyncFrameCallbackProvider();
+
     /**
      * Bounds that are animated using the physics animator.
      */
@@ -79,6 +84,10 @@
     /** Coordinator instance for resolving conflicts with other floating content. */
     private FloatingContentCoordinator mFloatingContentCoordinator;
 
+    /** Callback that re-sizes PIP to the animated bounds. */
+    private final Choreographer.FrameCallback mResizePipVsyncCallback =
+            l -> resizePipUnchecked(mAnimatedBounds);
+
     /**
      * PhysicsAnimator instance for animating {@link #mAnimatedBounds} using physics animations.
      */
@@ -89,7 +98,7 @@
      * Update listener that resizes the PIP to {@link #mAnimatedBounds}.
      */
     final PhysicsAnimator.UpdateListener<Rect> mResizePipUpdateListener =
-            (target, values) -> resizePipUnchecked(mAnimatedBounds);
+            (target, values) -> mSfVsyncFrameProvider.postFrameCallback(mResizePipVsyncCallback);
 
     /** FlingConfig instances provided to PhysicsAnimator for fling gestures. */
     private PhysicsAnimator.FlingConfig mFlingConfigX;
@@ -482,10 +491,11 @@
             Log.d(TAG, "resizeAndAnimatePipUnchecked: toBounds=" + toBounds
                     + " duration=" + duration + " callers=\n" + Debug.getCallers(5, "    "));
         }
-        if (!toBounds.equals(mBounds)) {
-            mPipTaskOrganizer.scheduleAnimateResizePip(toBounds, duration, mUpdateBoundsCallback);
-            setAnimatingToBounds(toBounds);
-        }
+
+        // Intentionally resize here even if the current bounds match the destination bounds.
+        // This is so all the proper callbacks are performed.
+        mPipTaskOrganizer.scheduleAnimateResizePip(toBounds, duration, mUpdateBoundsCallback);
+        setAnimatingToBounds(toBounds);
     }
 
     /**
diff --git a/packages/SystemUI/src/com/android/systemui/pip/phone/PipResizeGestureHandler.java b/packages/SystemUI/src/com/android/systemui/pip/phone/PipResizeGestureHandler.java
index bafbd21..c151715 100644
--- a/packages/SystemUI/src/com/android/systemui/pip/phone/PipResizeGestureHandler.java
+++ b/packages/SystemUI/src/com/android/systemui/pip/phone/PipResizeGestureHandler.java
@@ -32,6 +32,8 @@
 import android.os.Handler;
 import android.os.Looper;
 import android.provider.DeviceConfig;
+import android.view.BatchedInputEventReceiver;
+import android.view.Choreographer;
 import android.view.InputChannel;
 import android.view.InputEvent;
 import android.view.InputEventReceiver;
@@ -258,12 +260,14 @@
 
     private void onMotionEvent(MotionEvent ev) {
         int action = ev.getActionMasked();
+        float x = ev.getX();
+        float y = ev.getY();
         if (action == MotionEvent.ACTION_DOWN) {
             mLastResizeBounds.setEmpty();
-            mAllowGesture = isWithinTouchRegion((int) ev.getX(), (int) ev.getY());
+            mAllowGesture = isWithinTouchRegion((int) x, (int) y);
             if (mAllowGesture) {
-                setCtrlType((int) ev.getX(), (int) ev.getY());
-                mDownPoint.set(ev.getX(), ev.getY());
+                setCtrlType((int) x, (int) y);
+                mDownPoint.set(x, y);
                 mLastDownBounds.set(mMotionHelper.getBounds());
             }
 
@@ -275,20 +279,23 @@
                     break;
                 case MotionEvent.ACTION_MOVE:
                     // Capture inputs
-                    float dx = Math.abs(ev.getX() - mDownPoint.x);
-                    float dy = Math.abs(ev.getY() - mDownPoint.y);
-                    if (!mThresholdCrossed && dx > mTouchSlop && dy > mTouchSlop) {
+                    if (!mThresholdCrossed
+                            && Math.hypot(x - mDownPoint.x, y - mDownPoint.y) > mTouchSlop) {
                         mThresholdCrossed = true;
+                        // Reset the down to begin resizing from this point
+                        mDownPoint.set(x, y);
                         mInputMonitor.pilferPointers();
                     }
-                    final Rect currentPipBounds = mMotionHelper.getBounds();
-                    mLastResizeBounds.set(TaskResizingAlgorithm.resizeDrag(ev.getX(), ev.getY(),
-                            mDownPoint.x, mDownPoint.y, currentPipBounds, mCtrlType, mMinSize.x,
-                            mMinSize.y, mMaxSize, true,
-                            mLastDownBounds.width() > mLastDownBounds.height()));
-                    mPipBoundsHandler.transformBoundsToAspectRatio(mLastResizeBounds);
-                    mPipTaskOrganizer.scheduleUserResizePip(mLastDownBounds, mLastResizeBounds,
-                            null);
+                    if (mThresholdCrossed) {
+                        final Rect currentPipBounds = mMotionHelper.getBounds();
+                        mLastResizeBounds.set(TaskResizingAlgorithm.resizeDrag(x, y,
+                                mDownPoint.x, mDownPoint.y, currentPipBounds, mCtrlType, mMinSize.x,
+                                mMinSize.y, mMaxSize, true,
+                                mLastDownBounds.width() > mLastDownBounds.height()));
+                        mPipBoundsHandler.transformBoundsToAspectRatio(mLastResizeBounds);
+                        mPipTaskOrganizer.scheduleUserResizePip(mLastDownBounds, mLastResizeBounds,
+                                null);
+                    }
                     break;
                 case MotionEvent.ACTION_UP:
                 case MotionEvent.ACTION_CANCEL:
@@ -323,9 +330,9 @@
         mMinSize.set(minX, minY);
     }
 
-    class SysUiInputEventReceiver extends InputEventReceiver {
+    class SysUiInputEventReceiver extends BatchedInputEventReceiver {
         SysUiInputEventReceiver(InputChannel channel, Looper looper) {
-            super(channel, looper);
+            super(channel, looper, Choreographer.getSfInstance());
         }
 
         public void onInputEvent(InputEvent event) {
diff --git a/packages/SystemUI/src/com/android/systemui/pip/phone/PipTouchHandler.java b/packages/SystemUI/src/com/android/systemui/pip/phone/PipTouchHandler.java
index 1ddb1f5..3cc9127 100644
--- a/packages/SystemUI/src/com/android/systemui/pip/phone/PipTouchHandler.java
+++ b/packages/SystemUI/src/com/android/systemui/pip/phone/PipTouchHandler.java
@@ -30,6 +30,7 @@
 import android.graphics.Point;
 import android.graphics.PointF;
 import android.graphics.Rect;
+import android.graphics.drawable.TransitionDrawable;
 import android.os.Handler;
 import android.os.RemoteException;
 import android.util.Log;
@@ -76,6 +77,9 @@
 public class PipTouchHandler {
     private static final String TAG = "PipTouchHandler";
 
+    /** Duration of the dismiss scrim fading in/out. */
+    private static final int DISMISS_TRANSITION_DURATION_MS = 200;
+
     // Allow dragging the PIP to a location to close it
     private final boolean mEnableDismissDragToEdge;
     // Allow PIP to resize to a slightly bigger state upon touch
@@ -249,6 +253,8 @@
 
         mTargetView = new DismissCircleView(context);
         mTargetViewContainer = new FrameLayout(context);
+        mTargetViewContainer.setBackgroundDrawable(
+                context.getDrawable(R.drawable.floating_dismiss_gradient_transition));
         mTargetViewContainer.setClipChildren(false);
         mTargetViewContainer.addView(mTargetView);
 
@@ -553,6 +559,9 @@
             mMagneticTargetAnimator
                     .spring(DynamicAnimation.TRANSLATION_Y, 0f, mTargetSpringConfig)
                     .start();
+
+            ((TransitionDrawable) mTargetViewContainer.getBackground()).startTransition(
+                    DISMISS_TRANSITION_DURATION_MS);
         }
     }
 
@@ -565,6 +574,9 @@
                         mTargetSpringConfig)
                 .withEndActions(() ->  mTargetViewContainer.setVisibility(View.GONE))
                 .start();
+
+        ((TransitionDrawable) mTargetViewContainer.getBackground()).reverseTransition(
+                DISMISS_TRANSITION_DURATION_MS);
     }
 
     /**
diff --git a/packages/SystemUI/src/com/android/systemui/qs/DoubleLineTileLayout.kt b/packages/SystemUI/src/com/android/systemui/qs/DoubleLineTileLayout.kt
index 40d317c..dc157a8 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/DoubleLineTileLayout.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/DoubleLineTileLayout.kt
@@ -139,12 +139,7 @@
         }
         tilesToShow = actualColumns * NUM_LINES
 
-        val interTileSpace = if (actualColumns <= 2) {
-            // Extra "column" of padding to be distributed on each end
-            (availableWidth - actualColumns * smallTileSize) / actualColumns
-        } else {
-            (availableWidth - actualColumns * smallTileSize) / (actualColumns - 1)
-        }
+        val spacePerTile = availableWidth / actualColumns
 
         for (index in 0 until mRecords.size) {
             val tileView = mRecords[index].tileView
@@ -154,15 +149,16 @@
                 tileView.visibility = View.VISIBLE
                 if (index > 0) tileView.updateAccessibilityOrder(mRecords[index - 1].tileView)
                 val column = index % actualColumns
-                val left = getLeftForColumn(column, interTileSpace, actualColumns <= 2)
+                val left = getLeftForColumn(column, spacePerTile)
                 val top = if (index < actualColumns) 0 else getTopBottomRow()
                 tileView.layout(left, top, left + smallTileSize, top + smallTileSize)
             }
         }
     }
 
-    private fun getLeftForColumn(column: Int, interSpace: Int, sideMargin: Boolean): Int {
-        return (if (sideMargin) interSpace / 2 else 0) + column * (smallTileSize + interSpace)
+    private fun getLeftForColumn(column: Int, spacePerTile: Int): Int {
+        // Distribute the space evenly among all tiles.
+        return (column * spacePerTile + spacePerTile / 2.0f - smallTileSize / 2.0f).toInt()
     }
 
     private fun getTopBottomRow() = smallTileSize + cellMarginVertical
diff --git a/packages/SystemUI/src/com/android/systemui/qs/NonInterceptingScrollView.java b/packages/SystemUI/src/com/android/systemui/qs/NonInterceptingScrollView.java
index c204d94..aa17c4a 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/NonInterceptingScrollView.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/NonInterceptingScrollView.java
@@ -17,6 +17,9 @@
 import android.content.Context;
 import android.util.AttributeSet;
 import android.view.MotionEvent;
+import android.view.View;
+import android.view.ViewConfiguration;
+import android.view.ViewParent;
 import android.widget.ScrollView;
 
 /**
@@ -24,8 +27,12 @@
  */
 public class NonInterceptingScrollView extends ScrollView {
 
+    private final int mTouchSlop;
+    private float mDownY;
+
     public NonInterceptingScrollView(Context context, AttributeSet attrs) {
         super(context, attrs);
+        mTouchSlop = ViewConfiguration.get(context).getScaledTouchSlop();
     }
 
     @Override
@@ -34,10 +41,52 @@
         switch (action) {
             case MotionEvent.ACTION_DOWN:
                 if (canScrollVertically(1)) {
-                    requestDisallowInterceptTouchEvent(true);
+                    // If we can scroll down, make sure we're not intercepted by the parent
+                    final ViewParent parent = getParent();
+                    if (parent != null) {
+                        parent.requestDisallowInterceptTouchEvent(true);
+                    }
                 }
                 break;
         }
         return super.onTouchEvent(ev);
     }
+
+    @Override
+    public boolean onInterceptTouchEvent(MotionEvent ev) {
+        // If there's a touch on this view and we can scroll down, we don't want to be intercepted
+        int action = ev.getActionMasked();
+        switch (action) {
+            case MotionEvent.ACTION_DOWN:
+                // If we can scroll down, make sure non of our parents intercepts us.
+                if (canScrollVertically(1)) {
+                    final ViewParent parent = getParent();
+                    if (parent != null) {
+                        parent.requestDisallowInterceptTouchEvent(true);
+                    }
+                }
+                mDownY = ev.getY();
+                break;
+            case MotionEvent.ACTION_MOVE: {
+                final int y = (int) ev.getY();
+                final float yDiff = y - mDownY;
+                if (yDiff < -mTouchSlop && !canScrollVertically(1)) {
+                    // Don't intercept touches that are overscrolling.
+                    return false;
+                }
+                break;
+            }
+        }
+        return super.onInterceptTouchEvent(ev);
+    }
+
+    public int getScrollRange() {
+        int scrollRange = 0;
+        if (getChildCount() > 0) {
+            View child = getChildAt(0);
+            scrollRange = Math.max(0,
+                    child.getHeight() - (getHeight() - mPaddingBottom - mPaddingTop));
+        }
+        return scrollRange;
+    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/qs/PagedTileLayout.java b/packages/SystemUI/src/com/android/systemui/qs/PagedTileLayout.java
index aaff9ac..3eed8ad 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/PagedTileLayout.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/PagedTileLayout.java
@@ -66,6 +66,10 @@
     private int mHorizontalClipBound;
     private final Rect mClippingRect;
     private final UiEventLogger mUiEventLogger = QSEvents.INSTANCE.getQsUiEventsLogger();
+    private int mExcessHeight;
+    private int mLastExcessHeight;
+    private int mMinRows = 1;
+    private int mMaxColumns = TileLayout.NO_MAX_COLUMNS;
 
     public PagedTileLayout(Context context, AttributeSet attrs) {
         super(context, attrs);
@@ -195,11 +199,18 @@
     @Override
     protected void onFinishInflate() {
         super.onFinishInflate();
-        mPages.add((TilePage) LayoutInflater.from(getContext())
-                .inflate(R.layout.qs_paged_page, this, false));
+        mPages.add(createTilePage());
         mAdapter.notifyDataSetChanged();
     }
 
+    private TilePage createTilePage() {
+        TilePage page = (TilePage) LayoutInflater.from(getContext())
+                .inflate(R.layout.qs_paged_page, this, false);
+        page.setMinRows(mMinRows);
+        page.setMaxColumns(mMaxColumns);
+        return page;
+    }
+
     public void setPageIndicator(PageIndicator indicator) {
         mPageIndicator = indicator;
         mPageIndicator.setNumPages(mPages.size());
@@ -280,15 +291,7 @@
     }
 
     private void emptyAndInflateOrRemovePages() {
-        final int nTiles = mTiles.size();
-        // We should always have at least one page, even if it's empty.
-        int numPages = Math.max(nTiles / mPages.get(0).maxTiles(), 1);
-
-        // Add one more not full page if needed
-        if (nTiles > numPages * mPages.get(0).maxTiles()) {
-            numPages++;
-        }
-
+        final int numPages = getNumPages();
         final int NP = mPages.size();
         for (int i = 0; i < NP; i++) {
             mPages.get(i).removeAllViews();
@@ -298,8 +301,7 @@
         }
         while (mPages.size() < numPages) {
             if (DEBUG) Log.d(TAG, "Adding page");
-            mPages.add((TilePage) LayoutInflater.from(getContext())
-                    .inflate(R.layout.qs_paged_page, this, false));
+            mPages.add(createTilePage());
         }
         while (mPages.size() > numPages) {
             if (DEBUG) Log.d(TAG, "Removing page");
@@ -342,17 +344,54 @@
     }
 
     @Override
+    public boolean setMinRows(int minRows) {
+        mMinRows = minRows;
+        boolean changed = false;
+        for (int i = 0; i < mPages.size(); i++) {
+            if (mPages.get(i).setMinRows(minRows)) {
+                changed = true;
+                mDistributeTiles = true;
+            }
+        }
+        return changed;
+    }
+
+    @Override
+    public boolean setMaxColumns(int maxColumns) {
+        mMaxColumns = maxColumns;
+        boolean changed = false;
+        for (int i = 0; i < mPages.size(); i++) {
+            if (mPages.get(i).setMaxColumns(maxColumns)) {
+                changed = true;
+                mDistributeTiles = true;
+            }
+        }
+        return changed;
+    }
+
+    /**
+     * Set the amount of excess space that we gave this view compared to the actual available
+     * height. This is because this view is in a scrollview.
+     */
+    public void setExcessHeight(int excessHeight) {
+        mExcessHeight = excessHeight;
+    }
+
+    @Override
     protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
 
         final int nTiles = mTiles.size();
         // If we have no reason to recalculate the number of rows, skip this step. In particular,
         // if the height passed by its parent is the same as the last time, we try not to remeasure.
-        if (mDistributeTiles || mLastMaxHeight != MeasureSpec.getSize(heightMeasureSpec)) {
+        if (mDistributeTiles || mLastMaxHeight != MeasureSpec.getSize(heightMeasureSpec)
+                || mLastExcessHeight != mExcessHeight) {
 
             mLastMaxHeight = MeasureSpec.getSize(heightMeasureSpec);
+            mLastExcessHeight = mExcessHeight;
             // Only change the pages if the number of rows or columns (from updateResources) has
             // changed or the tiles have changed
-            if (mPages.get(0).updateMaxRows(heightMeasureSpec, nTiles) || mDistributeTiles) {
+            int availableHeight = mLastMaxHeight - mExcessHeight;
+            if (mPages.get(0).updateMaxRows(availableHeight, nTiles) || mDistributeTiles) {
                 mDistributeTiles = false;
                 distributeTiles();
             }
@@ -384,6 +423,22 @@
         return mPages.get(0).mColumns;
     }
 
+    /**
+     * Gets the number of pages in this paged tile layout
+     */
+    public int getNumPages() {
+        final int nTiles = mTiles.size();
+        // We should always have at least one page, even if it's empty.
+        int numPages = Math.max(nTiles / mPages.get(0).maxTiles(), 1);
+
+        // Add one more not full page if needed
+        if (nTiles > numPages * mPages.get(0).maxTiles()) {
+            numPages++;
+        }
+
+        return numPages;
+    }
+
     public int getNumVisibleTiles() {
         if (mPages.size() == 0) return 0;
         TilePage currentPage = mPages.get(getCurrentPageNumber());
@@ -485,14 +540,6 @@
             // up.
             return Math.max(mColumns * mRows, 1);
         }
-
-        @Override
-        public boolean updateResources() {
-            final int sidePadding = getContext().getResources().getDimensionPixelSize(
-                    R.dimen.notification_side_paddings);
-            setPadding(sidePadding, 0, sidePadding, 0);
-            return super.updateResources();
-        }
     }
 
     private final PagerAdapter mAdapter = new PagerAdapter() {
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSAnimator.java b/packages/SystemUI/src/com/android/systemui/qs/QSAnimator.java
index ce00229..bc8f5a8 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSAnimator.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSAnimator.java
@@ -18,6 +18,7 @@
 import android.view.View;
 import android.view.View.OnAttachStateChangeListener;
 import android.view.View.OnLayoutChangeListener;
+import android.widget.ScrollView;
 
 import com.android.systemui.Dependency;
 import com.android.systemui.plugins.qs.QS;
@@ -30,7 +31,6 @@
 import com.android.systemui.qs.TouchAnimator.Listener;
 import com.android.systemui.tuner.TunerService;
 import com.android.systemui.tuner.TunerService.Tunable;
-import com.android.systemui.util.Utils;
 
 import java.util.ArrayList;
 import java.util.Collection;
@@ -66,6 +66,7 @@
     private TouchAnimator mNonfirstPageAnimator;
     private TouchAnimator mNonfirstPageDelayedAnimator;
     private TouchAnimator mBrightnessAnimator;
+    private boolean mNeedsAnimatorUpdate = false;
 
     private boolean mOnKeyguard;
 
@@ -98,6 +99,12 @@
         updateAnimators();
     }
 
+
+    public void onQsScrollingChanged() {
+        // Lazily update animators whenever the scrolling changes
+        mNeedsAnimatorUpdate = true;
+    }
+
     public void setOnKeyguard(boolean onKeyguard) {
         mOnKeyguard = onKeyguard;
         updateQQSVisibility();
@@ -172,6 +179,7 @@
     }
 
     private void updateAnimators() {
+        mNeedsAnimatorUpdate = false;
         TouchAnimator.Builder firstPageBuilder = new Builder();
         TouchAnimator.Builder translationXBuilder = new Builder();
         TouchAnimator.Builder translationYBuilder = new Builder();
@@ -286,13 +294,16 @@
                     .setListener(this)
                     .build();
             // Fade in the tiles/labels as we reach the final position.
-            mFirstPageDelayedAnimator = new TouchAnimator.Builder()
+            Builder builder = new Builder()
                     .setStartDelay(EXPANDED_TILE_DELAY)
-                    .addFloat(tileLayout, "alpha", 0, 1)
-                    .addFloat(mQsPanel.getDivider(), "alpha", 0, 1)
-                    .addFloat(mQsPanel.getFooter().getView(), "alpha", 0, 1).build();
-            mAllViews.add(mQsPanel.getDivider());
-            mAllViews.add(mQsPanel.getFooter().getView());
+                    .addFloat(tileLayout, "alpha", 0, 1);
+            if (mQsPanel.getSecurityFooter() != null) {
+                builder.addFloat(mQsPanel.getSecurityFooter().getView(), "alpha", 0, 1);
+            }
+            mFirstPageDelayedAnimator = builder.build();
+            if (mQsPanel.getSecurityFooter() != null) {
+                mAllViews.add(mQsPanel.getSecurityFooter().getView());
+            }
             float px = 0;
             float py = 1;
             if (tiles.size() <= 3) {
@@ -308,7 +319,6 @@
         }
         mNonfirstPageAnimator = new TouchAnimator.Builder()
                 .addFloat(mQuickQsPanel, "alpha", 1, 0)
-                .addFloat(mQsPanel.getDivider(), "alpha", 0, 1)
                 .setListener(mNonFirstPageListener)
                 .setEndDelay(.5f)
                 .build();
@@ -339,10 +349,18 @@
             loc1[0] += view.getLeft();
             loc1[1] += view.getTop();
         }
+        if (!(view instanceof PagedTileLayout)) {
+            // Remove the scrolling position of all scroll views other than the viewpager
+            loc1[0] -= view.getScrollX();
+            loc1[1] -= view.getScrollY();
+        }
         getRelativePositionInt(loc1, (View) view.getParent(), parent);
     }
 
     public void setPosition(float position) {
+        if (mNeedsAnimatorUpdate) {
+            updateAnimators();
+        }
         if (mFirstPageAnimator == null) return;
         if (mOnKeyguard) {
             if (mShowCollapsedOnKeyguard) {
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSContainerImpl.java b/packages/SystemUI/src/com/android/systemui/qs/QSContainerImpl.java
index 1c3b685..0332bc3 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSContainerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSContainerImpl.java
@@ -43,6 +43,7 @@
     private float mQsExpansion;
     private QSCustomizer mQSCustomizer;
     private View mDragHandle;
+    private View mQSPanelContainer;
 
     private View mBackground;
     private View mBackgroundGradient;
@@ -61,6 +62,7 @@
     protected void onFinishInflate() {
         super.onFinishInflate();
         mQSPanel = findViewById(R.id.quick_settings_panel);
+        mQSPanelContainer = findViewById(R.id.expanded_qs_scroll_view);
         mQSDetail = findViewById(R.id.qs_detail);
         mHeader = findViewById(R.id.header);
         mQSCustomizer = findViewById(R.id.qs_customize);
@@ -95,7 +97,7 @@
         Configuration config = getResources().getConfiguration();
         boolean navBelow = config.smallestScreenWidthDp >= 600
                 || config.orientation != Configuration.ORIENTATION_LANDSCAPE;
-        MarginLayoutParams layoutParams = (MarginLayoutParams) mQSPanel.getLayoutParams();
+        MarginLayoutParams layoutParams = (MarginLayoutParams) mQSPanelContainer.getLayoutParams();
 
         // The footer is pinned to the bottom of QSPanel (same bottoms), therefore we don't need to
         // subtract its height. We do not care if the collapsed notifications fit in the screen.
@@ -109,12 +111,11 @@
                 + layoutParams.rightMargin;
         final int qsPanelWidthSpec = getChildMeasureSpec(widthMeasureSpec, padding,
                 layoutParams.width);
-        // Measure with EXACTLY. That way, PagedTileLayout will only use excess height and will be
-        // measured last, after other views and padding is accounted for.
-        mQSPanel.measure(qsPanelWidthSpec, MeasureSpec.makeMeasureSpec(maxQs, MeasureSpec.EXACTLY));
-        int width = mQSPanel.getMeasuredWidth() + padding;
+        mQSPanelContainer.measure(qsPanelWidthSpec,
+                MeasureSpec.makeMeasureSpec(maxQs, MeasureSpec.AT_MOST));
+        int width = mQSPanelContainer.getMeasuredWidth() + padding;
         int height = layoutParams.topMargin + layoutParams.bottomMargin
-                + mQSPanel.getMeasuredHeight() + getPaddingBottom();
+                + mQSPanelContainer.getMeasuredHeight() + getPaddingBottom();
         super.onMeasure(MeasureSpec.makeMeasureSpec(width, MeasureSpec.EXACTLY),
                 MeasureSpec.makeMeasureSpec(height, MeasureSpec.EXACTLY));
         // QSCustomizer will always be the height of the screen, but do this after
@@ -130,7 +131,7 @@
         // Do not measure QSPanel again when doing super.onMeasure.
         // This prevents the pages in PagedTileLayout to be remeasured with a different (incorrect)
         // size to the one used for determining the number of rows and then the number of pages.
-        if (child != mQSPanel) {
+        if (child != mQSPanelContainer) {
             super.measureChildWithMargins(child, parentWidthMeasureSpec, widthUsed,
                     parentHeightMeasureSpec, heightUsed);
         }
@@ -151,10 +152,10 @@
     }
 
     private void updateResources() {
-        LayoutParams layoutParams = (LayoutParams) mQSPanel.getLayoutParams();
+        LayoutParams layoutParams = (LayoutParams) mQSPanelContainer.getLayoutParams();
         layoutParams.topMargin = mContext.getResources().getDimensionPixelSize(
                 com.android.internal.R.dimen.quick_qs_offset_height);
-        mQSPanel.setLayoutParams(layoutParams);
+        mQSPanelContainer.setLayoutParams(layoutParams);
 
         mSideMargins = getResources().getDimensionPixelSize(R.dimen.notification_side_paddings);
         mContentPaddingStart = getResources().getDimensionPixelSize(
@@ -185,7 +186,7 @@
         mQSDetail.setBottom(getTop() + height);
         // Pin the drag handle to the bottom of the panel.
         mDragHandle.setTranslationY(height - mDragHandle.getHeight());
-        mBackground.setTop(mQSPanel.getTop());
+        mBackground.setTop(mQSPanelContainer.getTop());
         mBackground.setBottom(height);
     }
 
@@ -223,7 +224,7 @@
             LayoutParams lp = (LayoutParams) view.getLayoutParams();
             lp.rightMargin = mSideMargins;
             lp.leftMargin = mSideMargins;
-            if (view == mQSPanel) {
+            if (view == mQSPanelContainer) {
                 // QS panel lays out some of its content full width
                 mQSPanel.setContentMargins(mContentPaddingStart, mContentPaddingEnd);
             } else if (view == mHeader) {
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSFooterImpl.java b/packages/SystemUI/src/com/android/systemui/qs/QSFooterImpl.java
index fc8e36f..c4bb4e8 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSFooterImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSFooterImpl.java
@@ -218,7 +218,7 @@
                 .addFloat(mActionsContainer, "alpha", 0, 1)
                 .addFloat(mEditContainer, "alpha", 0, 1)
                 .addFloat(mPageIndicator, "alpha", 0, 1)
-                .setStartDelay(0.15f)
+                .setStartDelay(0.9f)
                 .build();
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSFragment.java b/packages/SystemUI/src/com/android/systemui/qs/QSFragment.java
index 6af9e1e..f1bb899 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSFragment.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSFragment.java
@@ -24,7 +24,6 @@
 import android.util.Log;
 import android.view.ContextThemeWrapper;
 import android.view.LayoutInflater;
-import android.view.MotionEvent;
 import android.view.View;
 import android.view.View.OnClickListener;
 import android.view.ViewGroup;
@@ -72,6 +71,7 @@
     protected QuickStatusBarHeader mHeader;
     private QSCustomizer mQSCustomizer;
     protected QSPanel mQSPanel;
+    protected NonInterceptingScrollView mQSPanelScrollView;
     private QSDetail mQSDetail;
     private boolean mListening;
     private QSContainerImpl mContainer;
@@ -122,8 +122,20 @@
     public void onViewCreated(View view, @Nullable Bundle savedInstanceState) {
         super.onViewCreated(view, savedInstanceState);
         mQSPanel = view.findViewById(R.id.quick_settings_panel);
+        mQSPanelScrollView = view.findViewById(R.id.expanded_qs_scroll_view);
+        mQSPanelScrollView.addOnLayoutChangeListener(
+                (v, left, top, right, bottom, oldLeft, oldTop, oldRight, oldBottom) -> {
+                    updateQsBounds();
+                });
+        mQSPanelScrollView.setOnScrollChangeListener(
+                (v, scrollX, scrollY, oldScrollX, oldScrollY) -> {
+            // Lazily update animators whenever the scrolling changes
+            mQSAnimator.onQsScrollingChanged();
+            mHeader.setExpandedScrollAmount(scrollY);
+        });
         mQSDetail = view.findViewById(R.id.qs_detail);
         mHeader = view.findViewById(R.id.header);
+        mQSPanel.setHeaderContainer(view.findViewById(R.id.header_text_container));
         mFooter = view.findViewById(R.id.qs_footer);
         mContainer = view.findViewById(id.quick_settings_container);
 
@@ -133,8 +145,8 @@
 
 
         mQSDetail.setQsPanel(mQSPanel, mHeader, (View) mFooter);
-        mQSAnimator = new QSAnimator(this,
-                mHeader.findViewById(R.id.quick_qs_panel), mQSPanel);
+        mQSAnimator = new QSAnimator(this, mHeader.findViewById(R.id.quick_qs_panel), mQSPanel);
+
 
         mQSCustomizer = view.findViewById(R.id.qs_customize);
         mQSCustomizer.setQs(this);
@@ -319,11 +331,6 @@
     }
 
     @Override
-    public boolean onInterceptTouchEvent(MotionEvent event) {
-        return isCustomizing();
-    }
-
-    @Override
     public void setHeaderClickable(boolean clickable) {
         if (DEBUG) Log.d(TAG, "setHeaderClickable " + clickable);
     }
@@ -394,7 +401,9 @@
         mLastViewHeight = currentHeight;
 
         boolean fullyExpanded = expansion == 1;
-        int heightDiff = mQSPanel.getBottom() - mHeader.getBottom() + mHeader.getPaddingBottom();
+        boolean fullyCollapsed = expansion == 0.0f;
+        int heightDiff = mQSPanelScrollView.getBottom() - mHeader.getBottom()
+                + mHeader.getPaddingBottom();
         float panelTranslationY = translationScaleY * heightDiff;
 
         // Let the views animate their contents correctly by giving them the necessary context.
@@ -403,19 +412,19 @@
         mFooter.setExpansion(onKeyguardAndExpanded ? 1 : expansion);
         mQSPanel.getQsTileRevealController().setExpansion(expansion);
         mQSPanel.getTileLayout().setExpansion(expansion);
-        mQSPanel.setTranslationY(translationScaleY * heightDiff);
+        mQSPanelScrollView.setTranslationY(translationScaleY * heightDiff);
+        if (fullyCollapsed) {
+            mQSPanelScrollView.setScrollY(0);
+        }
         mQSDetail.setFullyExpanded(fullyExpanded);
 
-        if (fullyExpanded) {
-            // Always draw within the bounds of the view when fully expanded.
-            mQSPanel.setClipBounds(null);
-        } else {
+        if (!fullyExpanded) {
             // Set bounds on the QS panel so it doesn't run over the header when animating.
-            mQsBounds.top = (int) -mQSPanel.getTranslationY();
-            mQsBounds.right = mQSPanel.getWidth();
-            mQsBounds.bottom = mQSPanel.getHeight();
-            mQSPanel.setClipBounds(mQsBounds);
+            mQsBounds.top = (int) -mQSPanelScrollView.getTranslationY();
+            mQsBounds.right = mQSPanelScrollView.getWidth();
+            mQsBounds.bottom = mQSPanelScrollView.getHeight();
         }
+        updateQsBounds();
 
         if (mQSAnimator != null) {
             mQSAnimator.setPosition(expansion);
@@ -423,31 +432,63 @@
         updateMediaPositions();
     }
 
+    private void updateQsBounds() {
+        if (mLastQSExpansion == 1.0f) {
+            // Fully expanded, let's set the layout bounds as clip bounds. This is necessary because
+            // it's a scrollview and otherwise wouldn't be clipped.
+            mQsBounds.set(0, 0, mQSPanelScrollView.getWidth(), mQSPanelScrollView.getHeight());
+        }
+        mQSPanelScrollView.setClipBounds(mQsBounds);
+    }
+
     private void updateMediaPositions() {
         if (Utils.useQsMediaPlayer(getContext())) {
             mContainer.getLocationOnScreen(mTmpLocation);
             float absoluteBottomPosition = mTmpLocation[1] + mContainer.getHeight();
-            pinToBottom(absoluteBottomPosition, mQSPanel.getMediaHost());
-            pinToBottom(absoluteBottomPosition - mHeader.getPaddingBottom(),
-                    mHeader.getHeaderQsPanel().getMediaHost());
+            // The Media can be scrolled off screen by default, let's offset it
+            float expandedMediaPosition = absoluteBottomPosition - mQSPanelScrollView.getScrollY()
+                    + mQSPanelScrollView.getScrollRange();
+            // The expanded media host should never move below the laid out position
+            pinToBottom(expandedMediaPosition, mQSPanel.getMediaHost(), true /* expanded */);
+            // The expanded media host should never move above the laid out position
+            pinToBottom(absoluteBottomPosition, mHeader.getHeaderQsPanel().getMediaHost(),
+                    false /* expanded */);
         }
     }
 
-    private void pinToBottom(float absoluteBottomPosition, MediaHost mediaHost) {
+    private void pinToBottom(float absoluteBottomPosition, MediaHost mediaHost, boolean expanded) {
         View hostView = mediaHost.getHostView();
         if (mLastQSExpansion > 0) {
-            ViewGroup.MarginLayoutParams params =
-                    (ViewGroup.MarginLayoutParams) hostView.getLayoutParams();
-            float targetPosition = absoluteBottomPosition - params.bottomMargin
+            float targetPosition = absoluteBottomPosition - getTotalBottomMargin(hostView)
                     - hostView.getHeight();
             float currentPosition = mediaHost.getCurrentBounds().top
                     - hostView.getTranslationY();
-            hostView.setTranslationY(targetPosition - currentPosition);
+            float translationY = targetPosition - currentPosition;
+            if (expanded) {
+                // Never go below the laid out position. This is necessary since the qs panel can
+                // change in height and we don't want to ever go below it's position
+                translationY = Math.min(translationY, 0);
+            } else {
+                translationY = Math.max(translationY, 0);
+            }
+            hostView.setTranslationY(translationY);
         } else {
             hostView.setTranslationY(0);
         }
     }
 
+    private float getTotalBottomMargin(View startView) {
+        int result = 0;
+        View child = startView;
+        View parent = (View) startView.getParent();
+        while (!(parent instanceof QSContainerImpl) && parent != null) {
+            result += parent.getHeight() - child.getBottom();
+            child = parent;
+            parent = (View) parent.getParent();
+        }
+        return result;
+    }
+
     private boolean headerWillBeAnimating() {
         return mState == StatusBarState.KEYGUARD && mShowCollapsedOnKeyguard
                 && !isKeyguardShowing();
@@ -504,7 +545,8 @@
     public void notifyCustomizeChanged() {
         // The customize state changed, so our height changed.
         mContainer.updateExpansion();
-        mQSPanel.setVisibility(!mQSCustomizer.isCustomizing() ? View.VISIBLE : View.INVISIBLE);
+        mQSPanelScrollView.setVisibility(!mQSCustomizer.isCustomizing() ? View.VISIBLE
+                : View.INVISIBLE);
         mFooter.setVisibility(!mQSCustomizer.isCustomizing() ? View.VISIBLE : View.INVISIBLE);
         // Let the panel know the position changed and it needs to update where notifications
         // and whatnot are.
@@ -521,9 +563,9 @@
             return getView().getHeight();
         }
         if (mQSDetail.isClosingDetail()) {
-            LayoutParams layoutParams = (LayoutParams) mQSPanel.getLayoutParams();
+            LayoutParams layoutParams = (LayoutParams) mQSPanelScrollView.getLayoutParams();
             int panelHeight = layoutParams.topMargin + layoutParams.bottomMargin +
-                    + mQSPanel.getMeasuredHeight();
+                    + mQSPanelScrollView.getMeasuredHeight();
             return panelHeight + getView().getPaddingBottom();
         } else {
             return getView().getMeasuredHeight();
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java b/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java
index 7844878..5021e00 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java
@@ -16,10 +16,10 @@
 
 package com.android.systemui.qs;
 
-import static com.android.systemui.qs.tileimpl.QSTileImpl.getColorForState;
 import static com.android.systemui.util.InjectionInflationController.VIEW_CONTEXT;
 import static com.android.systemui.util.Utils.useQsMediaPlayer;
 
+import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.content.ComponentName;
 import android.content.Context;
@@ -29,8 +29,8 @@
 import android.os.Bundle;
 import android.os.Handler;
 import android.os.Message;
-import android.service.quicksettings.Tile;
 import android.util.AttributeSet;
+import android.view.Gravity;
 import android.view.LayoutInflater;
 import android.view.View;
 import android.view.ViewGroup;
@@ -39,7 +39,7 @@
 import com.android.internal.logging.MetricsLogger;
 import com.android.internal.logging.UiEventLogger;
 import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
-import com.android.settingslib.Utils;
+import com.android.internal.widget.RemeasuringLinearLayout;
 import com.android.systemui.Dependency;
 import com.android.systemui.Dumpable;
 import com.android.systemui.R;
@@ -83,38 +83,65 @@
     protected final ArrayList<TileRecord> mRecords = new ArrayList<>();
     private final BroadcastDispatcher mBroadcastDispatcher;
     protected final MediaHost mMediaHost;
+
+    /**
+     * The index where the content starts that needs to be moved between parents
+     */
+    private final int mMovableContentStartIndex;
     private String mCachedSpecs = "";
-    protected final View mBrightnessView;
+
+    @Nullable
+    protected View mBrightnessView;
+    @Nullable
+    private BrightnessController mBrightnessController;
+
     private final H mHandler = new H();
     private final MetricsLogger mMetricsLogger = Dependency.get(MetricsLogger.class);
-    private final QSTileRevealController mQsTileRevealController;
+    private QSTileRevealController mQsTileRevealController;
     /** Whether or not the QS media player feature is enabled. */
     protected boolean mUsingMediaPlayer;
+    private int mVisualMarginStart;
+    private int mVisualMarginEnd;
 
     protected boolean mExpanded;
     protected boolean mListening;
 
     private QSDetail.Callback mCallback;
-    private BrightnessController mBrightnessController;
     private final DumpManager mDumpManager;
     private final QSLogger mQSLogger;
     protected final UiEventLogger mUiEventLogger;
     protected QSTileHost mHost;
 
-    protected QSSecurityFooter mFooter;
+    @Nullable
+    protected QSSecurityFooter mSecurityFooter;
+
+    @Nullable
+    protected View mFooter;
+
+    @Nullable
+    private ViewGroup mHeaderContainer;
     private PageIndicator mFooterPageIndicator;
     private boolean mGridContentVisible = true;
     private int mContentMarginStart;
     private int mContentMarginEnd;
     private int mVisualTilePadding;
-
-    protected QSTileLayout mTileLayout;
+    private boolean mUsingHorizontalLayout;
 
     private QSCustomizer mCustomizePanel;
     private Record mDetailRecord;
 
     private BrightnessMirrorController mBrightnessMirrorController;
-    private View mDivider;
+    private LinearLayout mHorizontalLinearLayout;
+    private LinearLayout mHorizontalContentContainer;
+
+    // Only used with media
+    private QSTileLayout mHorizontalTileLayout;
+    protected QSTileLayout mRegularTileLayout;
+    protected QSTileLayout mTileLayout;
+    private int mLastOrientation = -1;
+    private int mMediaTotalBottomMargin;
+    private int mFooterMarginStartHorizontal;
+
 
     @Inject
     public QSPanel(
@@ -128,7 +155,13 @@
     ) {
         super(context, attrs);
         mUsingMediaPlayer = useQsMediaPlayer(context);
+        mMediaTotalBottomMargin = getResources().getDimensionPixelSize(
+                R.dimen.quick_settings_bottom_margin_media);
         mMediaHost = mediaHost;
+        mMediaHost.setVisibleChangedListener((visible) -> {
+            switchTileLayout();
+            return null;
+        });
         mContext = context;
         mQSLogger = qsLogger;
         mDumpManager = dumpManager;
@@ -137,71 +170,104 @@
 
         setOrientation(VERTICAL);
 
+        addViewsAboveTiles();
+        mMovableContentStartIndex = getChildCount();
+        mRegularTileLayout = createRegularTileLayout();
+
+        if (mUsingMediaPlayer) {
+            mHorizontalLinearLayout = new RemeasuringLinearLayout(mContext);
+            mHorizontalLinearLayout.setOrientation(LinearLayout.HORIZONTAL);
+            mHorizontalLinearLayout.setClipChildren(false);
+            mHorizontalLinearLayout.setClipToPadding(false);
+
+            mHorizontalContentContainer = new RemeasuringLinearLayout(mContext);
+            mHorizontalContentContainer.setOrientation(LinearLayout.VERTICAL);
+            mHorizontalContentContainer.setClipChildren(false);
+            mHorizontalContentContainer.setClipToPadding(false);
+
+            mHorizontalTileLayout = createHorizontalTileLayout();
+            LayoutParams lp = new LayoutParams(0, LayoutParams.WRAP_CONTENT, 1);
+            int marginSize = (int) mContext.getResources().getDimension(R.dimen.qqs_media_spacing);
+            lp.setMarginStart(0);
+            lp.setMarginEnd(marginSize);
+            lp.gravity = Gravity.CENTER_VERTICAL;
+            mHorizontalLinearLayout.addView(mHorizontalContentContainer, lp);
+
+            lp = new LayoutParams(LayoutParams.MATCH_PARENT, 0, 1);
+            addView(mHorizontalLinearLayout, lp);
+
+            initMediaHostState();
+        }
+        addSecurityFooter();
+        if (mRegularTileLayout instanceof PagedTileLayout) {
+            mQsTileRevealController = new QSTileRevealController(mContext, this,
+                    (PagedTileLayout) mRegularTileLayout);
+        }
+        mQSLogger.logAllTilesChangeListening(mListening, getDumpableTag(), mCachedSpecs);
+        updateResources();
+    }
+
+    protected void addSecurityFooter() {
+        mSecurityFooter = new QSSecurityFooter(this, mContext);
+    }
+
+    protected void addViewsAboveTiles() {
         mBrightnessView = LayoutInflater.from(mContext).inflate(
             R.layout.quick_settings_brightness_dialog, this, false);
         addView(mBrightnessView);
-
-        mTileLayout = (QSTileLayout) LayoutInflater.from(mContext).inflate(
-                R.layout.qs_paged_tile_layout, this, false);
-        mQSLogger.logAllTilesChangeListening(mListening, getDumpableTag(), mCachedSpecs);
-        mTileLayout.setListening(mListening);
-        addView((View) mTileLayout);
-
-        mQsTileRevealController = new QSTileRevealController(mContext, this,
-                (PagedTileLayout) mTileLayout);
-
-        addDivider();
-
-        mFooter = new QSSecurityFooter(this, context);
-        addView(mFooter.getView());
-
-        updateResources();
-
         mBrightnessController = new BrightnessController(getContext(),
                 findViewById(R.id.brightness_slider), mBroadcastDispatcher);
     }
 
-    @Override
-    protected void onFinishInflate() {
-        super.onFinishInflate();
-        // Add media carousel at the end
-        if (useQsMediaPlayer(getContext())) {
-            addMediaHostView();
+    protected QSTileLayout createRegularTileLayout() {
+        if (mRegularTileLayout == null) {
+            mRegularTileLayout = (QSTileLayout) LayoutInflater.from(mContext).inflate(
+                    R.layout.qs_paged_tile_layout, this, false);
         }
+        return mRegularTileLayout;
     }
 
-    protected void addMediaHostView() {
+
+    protected QSTileLayout createHorizontalTileLayout() {
+        return createRegularTileLayout();
+    }
+
+    protected void initMediaHostState() {
         mMediaHost.setExpansion(1.0f);
         mMediaHost.setShowsOnlyActiveMedia(false);
+        // Reveal player with some parallax (1.0f would also work)
+        mMediaHost.setGonePivot(0.0f, 0.8f);
         mMediaHost.init(MediaHierarchyManager.LOCATION_QS);
-        ViewGroup hostView = mMediaHost.getHostView();
-        addView(hostView);
-        int bottomPadding = getResources().getDimensionPixelSize(
-                R.dimen.quick_settings_expanded_bottom_margin);
-        MarginLayoutParams layoutParams = (MarginLayoutParams) hostView.getLayoutParams();
-        layoutParams.height = ViewGroup.LayoutParams.WRAP_CONTENT;
-        layoutParams.width = ViewGroup.LayoutParams.MATCH_PARENT;
-        layoutParams.bottomMargin = bottomPadding;
-        hostView.setLayoutParams(layoutParams);
-        updateMediaHostContentMargins();
-    }
-
-    protected void addDivider() {
-        mDivider = LayoutInflater.from(mContext).inflate(R.layout.qs_divider, this, false);
-        mDivider.setBackgroundColor(Utils.applyAlpha(mDivider.getAlpha(),
-                getColorForState(mContext, Tile.STATE_ACTIVE)));
-        addView(mDivider);
     }
 
     @Override
     protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
+        if (mTileLayout instanceof PagedTileLayout) {
+            // Since PageIndicator gets measured before PagedTileLayout, we preemptively set the
+            // # of pages before the measurement pass so PageIndicator is measured appropriately
+            if (mFooterPageIndicator != null) {
+                mFooterPageIndicator.setNumPages(((PagedTileLayout) mTileLayout).getNumPages());
+            }
+
+            // Allow the UI to be as big as it want's to, we're in a scroll view
+            int newHeight = 10000;
+            int availableHeight = MeasureSpec.getSize(heightMeasureSpec);
+            int excessHeight = newHeight - availableHeight;
+            // Measure with EXACTLY. That way, The content will only use excess height and will
+            // be measured last, after other views and padding is accounted for. This only
+            // works because our Layouts in here remeasure themselves with the exact content
+            // height.
+            heightMeasureSpec = MeasureSpec.makeMeasureSpec(newHeight, MeasureSpec.EXACTLY);
+            ((PagedTileLayout) mTileLayout).setExcessHeight(excessHeight);
+        }
+        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
+
         // We want all the logic of LinearLayout#onMeasure, and for it to assign the excess space
         // not used by the other children to PagedTileLayout. However, in this case, LinearLayout
         // assumes that PagedTileLayout would use all the excess space. This is not the case as
         // PagedTileLayout height is quantized (because it shows a certain number of rows).
         // Therefore, after everything is measured, we need to make sure that we add up the correct
         // total height
-        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
         int height = getPaddingBottom() + getPaddingTop();
         int numChildren = getChildCount();
         for (int i = 0; i < numChildren; i++) {
@@ -215,10 +281,6 @@
         setMeasuredDimension(getMeasuredWidth(), height);
     }
 
-    public View getDivider() {
-        return mDivider;
-    }
-
     public QSTileRevealController getQsTileRevealController() {
         return mQsTileRevealController;
     }
@@ -273,7 +335,7 @@
 
     @Override
     public void onTuningChanged(String key, String newValue) {
-        if (QS_SHOW_BRIGHTNESS.equals(key)) {
+        if (QS_SHOW_BRIGHTNESS.equals(key) && mBrightnessView != null) {
             updateViewVisibilityForTuningValue(mBrightnessView, newValue);
         }
     }
@@ -316,6 +378,7 @@
         updateBrightnessMirror();
     }
 
+    @Nullable
     View getBrightnessView() {
         return mBrightnessView;
     }
@@ -328,7 +391,9 @@
         mHost = host;
         mHost.addCallback(this);
         setTiles(mHost.getTiles());
-        mFooter.setHostEnvironment(host);
+        if (mSecurityFooter != null) {
+            mSecurityFooter.setHostEnvironment(host);
+        }
         mCustomizePanel = customizer;
         if (mCustomizePanel != null) {
             mCustomizePanel.setHost(mHost);
@@ -341,18 +406,18 @@
      * @param pageIndicator indicator to use for page scrolling
      */
     public void setFooterPageIndicator(PageIndicator pageIndicator) {
-        if (mTileLayout instanceof PagedTileLayout) {
+        if (mRegularTileLayout instanceof PagedTileLayout) {
             mFooterPageIndicator = pageIndicator;
             updatePageIndicator();
         }
     }
 
     private void updatePageIndicator() {
-        if (mTileLayout instanceof PagedTileLayout) {
+        if (mRegularTileLayout instanceof PagedTileLayout) {
             if (mFooterPageIndicator != null) {
                 mFooterPageIndicator.setVisibility(View.GONE);
 
-                ((PagedTileLayout) mTileLayout).setPageIndicator(mFooterPageIndicator);
+                ((PagedTileLayout) mRegularTileLayout).setPageIndicator(mFooterPageIndicator);
             }
         }
     }
@@ -364,6 +429,8 @@
     public void updateResources() {
         int tileSize = getResources().getDimensionPixelSize(R.dimen.qs_quick_tile_size);
         int tileBg = getResources().getDimensionPixelSize(R.dimen.qs_tile_background_size);
+        mFooterMarginStartHorizontal = getResources().getDimensionPixelSize(
+                R.dimen.qs_footer_horizontal_margin);
         mVisualTilePadding = (int) ((tileSize - tileBg) / 2.0f);
         updatePadding();
 
@@ -379,8 +446,15 @@
 
     protected void updatePadding() {
         final Resources res = mContext.getResources();
+        int padding = res.getDimensionPixelSize(R.dimen.qs_panel_padding_top);
+        if (mUsingHorizontalLayout) {
+            // When using the horizontal layout, our space is quite constrained. We therefore
+            // reduce some of the padding on the top, which makes the brightness bar overlapp,
+            // but since that has naturally quite a bit of built in padding, that's fine.
+            padding = (int) (padding * 0.6f);
+        }
         setPaddingRelative(getPaddingStart(),
-                res.getDimensionPixelSize(R.dimen.qs_panel_padding_top),
+                padding,
                 getPaddingEnd(),
                 res.getDimensionPixelSize(R.dimen.qs_panel_padding_bottom));
     }
@@ -388,10 +462,165 @@
     @Override
     protected void onConfigurationChanged(Configuration newConfig) {
         super.onConfigurationChanged(newConfig);
-        mFooter.onConfigurationChanged();
+        if (mSecurityFooter != null) {
+            mSecurityFooter.onConfigurationChanged();
+        }
         updateResources();
 
         updateBrightnessMirror();
+
+        if (newConfig.orientation != mLastOrientation) {
+            mLastOrientation = newConfig.orientation;
+            switchTileLayout();
+        }
+    }
+
+    @Override
+    protected void onFinishInflate() {
+        super.onFinishInflate();
+        mFooter = findViewById(R.id.qs_footer);
+        switchTileLayout(true /* force */);
+    }
+
+    boolean switchTileLayout() {
+        return switchTileLayout(false /* force */);
+    }
+
+    private boolean switchTileLayout(boolean force) {
+        /** Whether or not the QuickQSPanel currently contains a media player. */
+        boolean horizontal = shouldUseHorizontalLayout();
+        if (horizontal != mUsingHorizontalLayout || force) {
+            mUsingHorizontalLayout = horizontal;
+            View visibleView = horizontal ? mHorizontalLinearLayout : (View) mRegularTileLayout;
+            View hiddenView = horizontal ? (View) mRegularTileLayout : mHorizontalLinearLayout;
+            ViewGroup newParent = horizontal ? mHorizontalContentContainer : this;
+            QSTileLayout newLayout = horizontal ? mHorizontalTileLayout : mRegularTileLayout;
+            if (hiddenView != null &&
+                    (mRegularTileLayout != mHorizontalTileLayout ||
+                            hiddenView != mRegularTileLayout)) {
+                // Only hide the view if the horizontal and the regular view are different,
+                // otherwise its reattached.
+                hiddenView.setVisibility(View.GONE);
+            }
+            visibleView.setVisibility(View.VISIBLE);
+            switchAllContentToParent(newParent, newLayout);
+            reAttachMediaHost();
+            if (mTileLayout != null) {
+                mTileLayout.setListening(false);
+                for (TileRecord record : mRecords) {
+                    mTileLayout.removeTile(record);
+                    record.tile.removeCallback(record.callback);
+                }
+            }
+            mTileLayout = newLayout;
+            if (mHost != null) setTiles(mHost.getTiles());
+            newLayout.setListening(mListening);
+            if (needsDynamicRowsAndColumns()) {
+                newLayout.setMinRows(horizontal ? 2 : 1);
+                // Let's use 3 columns to match the current layout
+                newLayout.setMaxColumns(horizontal ? 3 : TileLayout.NO_MAX_COLUMNS);
+            }
+            updateTileLayoutMargins();
+            updateFooterMargin();
+            updateMediaHostContentMargins();
+            updateHorizontalLinearLayoutMargins();
+            updatePadding();
+            return true;
+        }
+        return false;
+    }
+
+    private void updateHorizontalLinearLayoutMargins() {
+        if (mHorizontalLinearLayout != null && !displayMediaMarginsOnMedia()) {
+            LayoutParams lp = (LayoutParams) mHorizontalLinearLayout.getLayoutParams();
+            lp.bottomMargin = mMediaTotalBottomMargin - getPaddingBottom();
+            mHorizontalLinearLayout.setLayoutParams(lp);
+        }
+    }
+
+    /**
+     * @return true if the margin bottom of the media view should be on the media host or false
+     *         if they should be on the HorizontalLinearLayout. Returning {@code false} is useful
+     *         to visually center the tiles in the Media view, which doesn't work when the
+     *         expanded panel actually scrolls.
+     */
+    protected boolean displayMediaMarginsOnMedia() {
+        return true;
+    }
+
+    protected boolean needsDynamicRowsAndColumns() {
+        return true;
+    }
+
+    private void switchAllContentToParent(ViewGroup parent, QSTileLayout newLayout) {
+        int index = parent == this ? mMovableContentStartIndex : 0;
+
+        // Let's first move the tileLayout to the new parent, since that should come first.
+        switchToParent((View) newLayout, parent, index);
+        index++;
+
+        if (mSecurityFooter != null) {
+            View view = mSecurityFooter.getView();
+            LinearLayout.LayoutParams layoutParams = (LayoutParams) view.getLayoutParams();
+            if (mUsingHorizontalLayout && mHeaderContainer != null) {
+                // Adding the security view to the header, that enables us to avoid scrolling
+                layoutParams.width = 0;
+                layoutParams.weight = 1.6f;
+                switchToParent(view, mHeaderContainer, 1 /* always in second place */);
+            } else {
+                layoutParams.width = LayoutParams.WRAP_CONTENT;
+                layoutParams.weight = 0;
+                switchToParent(view, parent, index);
+                index++;
+            }
+            view.setLayoutParams(layoutParams);
+        }
+
+        if (mFooter != null) {
+            // Then the footer with the settings
+            switchToParent(mFooter, parent, index);
+        }
+    }
+
+    private void switchToParent(View child, ViewGroup parent, int index) {
+        ViewGroup currentParent = (ViewGroup) child.getParent();
+        if (currentParent != parent || currentParent.indexOfChild(child) != index) {
+            if (currentParent != null) {
+                currentParent.removeView(child);
+            }
+            parent.addView(child, index);
+        }
+    }
+
+    private boolean shouldUseHorizontalLayout() {
+        return mUsingMediaPlayer && mMediaHost.getVisible()
+                && getResources().getConfiguration().orientation
+                == Configuration.ORIENTATION_LANDSCAPE;
+    }
+
+    protected void reAttachMediaHost() {
+        if (!mUsingMediaPlayer) {
+            return;
+        }
+        boolean horizontal = shouldUseHorizontalLayout();
+        ViewGroup host = mMediaHost.getHostView();
+        ViewGroup newParent = horizontal ? mHorizontalLinearLayout : this;
+        ViewGroup currentParent = (ViewGroup) host.getParent();
+        if (currentParent != newParent) {
+            if (currentParent != null) {
+                currentParent.removeView(host);
+            }
+            newParent.addView(host);
+            LinearLayout.LayoutParams layoutParams = (LayoutParams) host.getLayoutParams();
+            layoutParams.height = ViewGroup.LayoutParams.WRAP_CONTENT;
+            layoutParams.width = horizontal ? 0 : ViewGroup.LayoutParams.MATCH_PARENT;
+            layoutParams.weight = horizontal ? 1.2f : 0;
+            // Add any bottom margin, such that the total spacing is correct. This is only
+            // necessary if the view isn't horizontal, since otherwise the padding is
+            // carried in the parent of this view (to ensure correct vertical alignment)
+            layoutParams.bottomMargin = !horizontal || displayMediaMarginsOnMedia()
+                    ? mMediaTotalBottomMargin - getPaddingBottom() : 0;
+        }
     }
 
     public void updateBrightnessMirror() {
@@ -457,13 +686,18 @@
 
     public void setListening(boolean listening, boolean expanded) {
         setListening(listening && expanded);
-        getFooter().setListening(listening);
+        if (mSecurityFooter != null) {
+            mSecurityFooter.setListening(listening);
+        }
         // Set the listening as soon as the QS fragment starts listening regardless of the expansion,
         // so it will update the current brightness before the slider is visible.
         setBrightnessListening(listening);
     }
 
     public void setBrightnessListening(boolean listening) {
+        if (mBrightnessController == null) {
+            return;
+        }
         if (listening) {
             mBrightnessController.registerCallbacks();
         } else {
@@ -472,11 +706,15 @@
     }
 
     public void refreshAllTiles() {
-        mBrightnessController.checkRestrictionAndSetEnabled();
+        if (mBrightnessController != null) {
+            mBrightnessController.checkRestrictionAndSetEnabled();
+        }
         for (TileRecord r : mRecords) {
             r.tile.refreshState();
         }
-        mFooter.refreshState();
+        if (mSecurityFooter != null) {
+            mSecurityFooter.refreshState();
+        }
     }
 
     public void showDetailAdapter(boolean show, DetailAdapter adapter, int[] locationInWindow) {
@@ -728,12 +966,15 @@
         return null;
     }
 
-    public QSSecurityFooter getFooter() {
-        return mFooter;
+    @Nullable
+    public QSSecurityFooter getSecurityFooter() {
+        return mSecurityFooter;
     }
 
     public void showDeviceMonitoringDialog() {
-        mFooter.showDeviceMonitoringDialog();
+        if (mSecurityFooter != null) {
+            mSecurityFooter.showDeviceMonitoringDialog();
+        }
     }
 
     public void setContentMargins(int startMargin, int endMargin) {
@@ -744,6 +985,24 @@
         updateTileLayoutMargins(mContentMarginStart - mVisualTilePadding,
                 mContentMarginEnd - mVisualTilePadding);
         updateMediaHostContentMargins();
+        updateFooterMargin();
+    }
+
+    private void updateFooterMargin() {
+        if (mFooter != null) {
+            int footerMargin = 0;
+            int indicatorMargin = 0;
+            if (mUsingHorizontalLayout) {
+                footerMargin = mFooterMarginStartHorizontal;
+                indicatorMargin = footerMargin - mVisualMarginEnd;
+            }
+            updateMargins(mFooter, footerMargin, 0);
+            // The page indicator isn't centered anymore because of the visual positioning.
+            // Let's fix it by adding some margin
+            if (mFooterPageIndicator != null) {
+                updateMargins(mFooterPageIndicator, 0, indicatorMargin);
+            }
+        }
     }
 
     /**
@@ -754,16 +1013,30 @@
      * @param visualMarginEnd the visual end margin of the tile, adjusted for local insets
      *                        to the tile. This can be set on a tileLayout
      */
-    protected void updateTileLayoutMargins(int visualMarginStart, int visualMarginEnd) {
-        updateMargins((View) mTileLayout, visualMarginStart, visualMarginEnd);
+    private void updateTileLayoutMargins(int visualMarginStart, int visualMarginEnd) {
+        mVisualMarginStart = visualMarginStart;
+        mVisualMarginEnd = visualMarginEnd;
+        updateTileLayoutMargins();
+    }
+
+    private void updateTileLayoutMargins() {
+        int marginEnd = mVisualMarginEnd;
+        if (mUsingHorizontalLayout) {
+            marginEnd = 0;
+        }
+        updateMargins((View) mTileLayout, mVisualMarginStart, marginEnd);
     }
 
     /**
      * Update the margins of the media hosts
      */
     protected void updateMediaHostContentMargins() {
-        if (mUsingMediaPlayer && mMediaHost != null) {
-            updateMargins(mMediaHost.getHostView(), mContentMarginStart, mContentMarginEnd);
+        if (mUsingMediaPlayer) {
+            int marginStart = mContentMarginStart;
+            if (mUsingHorizontalLayout) {
+                marginStart = 0;
+            }
+            updateMargins(mMediaHost.getHostView(), marginStart, mContentMarginEnd);
         }
     }
 
@@ -785,6 +1058,13 @@
         return mMediaHost;
     }
 
+    /**
+     * Set the header container of quick settings.
+     */
+    public void setHeaderContainer(@NonNull ViewGroup headerContainer) {
+        mHeaderContainer = headerContainer;
+    }
+
     private class H extends Handler {
         private static final int SHOW_DETAIL = 1;
         private static final int SET_TILE_VISIBILITY = 2;
@@ -812,6 +1092,7 @@
         }
     }
 
+
     protected static class Record {
         DetailAdapter detailAdapter;
         int x;
@@ -841,6 +1122,26 @@
 
         void setListening(boolean listening);
 
+        /**
+         * Set the minimum number of rows to show
+         *
+         * @param minRows the minimum.
+         */
+        default boolean setMinRows(int minRows) {
+            return false;
+        }
+
+        /**
+         * Set the max number of collums to show
+         *
+         * @param maxColumns the maximum
+         *
+         * @return true if the number of visible columns has changed.
+         */
+        default boolean setMaxColumns(int maxColumns) {
+            return false;
+        }
+
         default void setExpansion(float expansion) {}
 
         int getNumVisibleTiles();
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSSecurityFooter.java b/packages/SystemUI/src/com/android/systemui/qs/QSSecurityFooter.java
index 476af20..7bcaa72 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSSecurityFooter.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSSecurityFooter.java
@@ -51,6 +51,7 @@
 public class QSSecurityFooter implements OnClickListener, DialogInterface.OnClickListener {
     protected static final String TAG = "QSSecurityFooter";
     protected static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
+    private static final boolean DEBUG_FORCE_VISIBLE = false;
 
     private final View mRootView;
     private final TextView mFooterText;
@@ -60,7 +61,6 @@
     private final SecurityController mSecurityController;
     private final ActivityStarter mActivityStarter;
     private final Handler mMainHandler;
-    private final View mDivider;
 
     private final UserManager mUm;
 
@@ -85,7 +85,6 @@
         mActivityStarter = Dependency.get(ActivityStarter.class);
         mSecurityController = Dependency.get(SecurityController.class);
         mHandler = new H(Dependency.get(Dependency.BG_LOOPER));
-        mDivider = qsPanel == null ? null : qsPanel.getDivider();
         mUm = (UserManager) mContext.getSystemService(Context.USER_SERVICE);
     }
 
@@ -177,7 +176,7 @@
             boolean hasCACerts, boolean hasCACertsInWorkProfile, boolean isNetworkLoggingEnabled,
             String vpnName, String vpnNameWorkProfile, CharSequence organizationName,
             CharSequence workProfileName) {
-        if (isDeviceManaged) {
+        if (isDeviceManaged || DEBUG_FORCE_VISIBLE) {
             if (hasCACerts || hasCACertsInWorkProfile || isNetworkLoggingEnabled) {
                 if (organizationName == null) {
                     return mContext.getString(
@@ -451,8 +450,7 @@
             if (mFooterTextContent != null) {
                 mFooterText.setText(mFooterTextContent);
             }
-            mRootView.setVisibility(mIsVisible ? View.VISIBLE : View.GONE);
-            if (mDivider != null) mDivider.setVisibility(mIsVisible ? View.GONE : View.VISIBLE);
+            mRootView.setVisibility(mIsVisible || DEBUG_FORCE_VISIBLE ? View.VISIBLE : View.GONE);
         }
     };
 
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QuickQSPanel.java b/packages/SystemUI/src/com/android/systemui/qs/QuickQSPanel.java
index 94b4cee..affb7b9 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QuickQSPanel.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QuickQSPanel.java
@@ -24,7 +24,6 @@
 import android.util.AttributeSet;
 import android.view.Gravity;
 import android.view.View;
-import android.view.ViewGroup;
 import android.widget.LinearLayout;
 
 import com.android.internal.logging.UiEventLogger;
@@ -61,15 +60,7 @@
     private boolean mDisabledByPolicy;
     private int mMaxTiles;
     protected QSPanel mFullPanel;
-    /** Whether or not the QuickQSPanel currently contains a media player. */
-    private boolean mShowHorizontalTileLayout;
-    private LinearLayout mHorizontalLinearLayout;
 
-    // Only used with media
-    private QSTileLayout mHorizontalTileLayout;
-    private QSTileLayout mRegularTileLayout;
-    private int mLastOrientation = -1;
-    private int mMediaBottomMargin;
 
     @Inject
     public QuickQSPanel(
@@ -82,59 +73,8 @@
             UiEventLogger uiEventLogger
     ) {
         super(context, attrs, dumpManager, broadcastDispatcher, qsLogger, mediaHost, uiEventLogger);
-        if (mFooter != null) {
-            removeView(mFooter.getView());
-        }
-        if (mTileLayout != null) {
-            for (int i = 0; i < mRecords.size(); i++) {
-                mTileLayout.removeTile(mRecords.get(i));
-            }
-            removeView((View) mTileLayout);
-        }
-        mMediaBottomMargin = getResources().getDimensionPixelSize(
-                R.dimen.quick_settings_media_extra_bottom_margin);
-        if (mUsingMediaPlayer) {
-            mHorizontalLinearLayout = new LinearLayout(mContext);
-            mHorizontalLinearLayout.setOrientation(LinearLayout.HORIZONTAL);
-            mHorizontalLinearLayout.setClipChildren(false);
-            mHorizontalLinearLayout.setClipToPadding(false);
-
-            DoubleLineTileLayout horizontalTileLayout = new DoubleLineTileLayout(context,
-                    mUiEventLogger);
-            horizontalTileLayout.setPaddingRelative(
-                    horizontalTileLayout.getPaddingStart(),
-                    horizontalTileLayout.getPaddingTop(),
-                    horizontalTileLayout.getPaddingEnd(),
-                    mContext.getResources().getDimensionPixelSize(
-                            R.dimen.qqs_horizonal_tile_padding_bottom));
-            mHorizontalTileLayout = horizontalTileLayout;
-            mRegularTileLayout = new HeaderTileLayout(context, mUiEventLogger);
-            LayoutParams lp = new LayoutParams(0, LayoutParams.WRAP_CONTENT, 1);
-            int marginSize = (int) mContext.getResources().getDimension(R.dimen.qqs_media_spacing);
-            lp.setMarginStart(0);
-            lp.setMarginEnd(marginSize);
-            lp.gravity = Gravity.CENTER_VERTICAL;
-            mHorizontalLinearLayout.addView((View) mHorizontalTileLayout, lp);
-
-            sDefaultMaxTiles = getResources().getInteger(R.integer.quick_qs_panel_max_columns);
-
-            boolean useHorizontal = shouldUseHorizontalTileLayout();
-            mTileLayout = useHorizontal ? mHorizontalTileLayout : mRegularTileLayout;
-            mTileLayout.setListening(mListening);
-            addView(mHorizontalLinearLayout, 0 /* Between brightness and footer */);
-            ((View) mRegularTileLayout).setVisibility(!useHorizontal ? View.VISIBLE : View.GONE);
-            mHorizontalLinearLayout.setVisibility(useHorizontal ? View.VISIBLE : View.GONE);
-            addView((View) mRegularTileLayout, 0);
-            super.setPadding(0, 0, 0, 0);
-            applyBottomMargin((View) mRegularTileLayout);
-        } else {
-            sDefaultMaxTiles = getResources().getInteger(R.integer.quick_qs_panel_max_columns);
-            mTileLayout = new HeaderTileLayout(context, mUiEventLogger);
-            mTileLayout.setListening(mListening);
-            addView((View) mTileLayout, 0 /* Between brightness and footer */);
-            super.setPadding(0, 0, 0, 0);
-            applyBottomMargin((View) mTileLayout);
-        }
+        sDefaultMaxTiles = getResources().getInteger(R.integer.quick_qs_panel_max_columns);
+        applyBottomMargin((View) mRegularTileLayout);
     }
 
     private void applyBottomMargin(View view) {
@@ -144,48 +84,42 @@
         view.setLayoutParams(layoutParams);
     }
 
-    private void reAttachMediaHost() {
-        if (mMediaHost == null) {
-            return;
-        }
-        boolean horizontal = shouldUseHorizontalTileLayout();
-        ViewGroup host = mMediaHost.getHostView();
-        ViewGroup newParent = horizontal ? mHorizontalLinearLayout : this;
-        ViewGroup currentParent = (ViewGroup) host.getParent();
-        if (currentParent != newParent) {
-            if (currentParent != null) {
-                currentParent.removeView(host);
-            }
-            newParent.addView(host);
-            LinearLayout.LayoutParams layoutParams = (LayoutParams) host.getLayoutParams();
-            layoutParams.height = ViewGroup.LayoutParams.WRAP_CONTENT;
-            layoutParams.width = horizontal ? 0 : ViewGroup.LayoutParams.MATCH_PARENT;
-            layoutParams.weight = horizontal ? 1.5f : 0;
-            layoutParams.bottomMargin = mMediaBottomMargin;
-        }
+    @Override
+    protected void addSecurityFooter() {
+        // No footer needed
     }
 
     @Override
-    protected void addMediaHostView() {
-        mMediaHost.setVisibleChangedListener((visible) -> {
-            switchTileLayout();
-            return null;
-        });
+    protected void addViewsAboveTiles() {
+        // Nothing to add above the tiles
+    }
+
+    @Override
+    protected TileLayout createRegularTileLayout() {
+        return new QuickQSPanel.HeaderTileLayout(mContext, mUiEventLogger);
+    }
+
+    @Override
+    protected QSTileLayout createHorizontalTileLayout() {
+        return new DoubleLineTileLayout(mContext, mUiEventLogger);
+    }
+
+    @Override
+    protected void initMediaHostState() {
         mMediaHost.setExpansion(0.0f);
         mMediaHost.setShowsOnlyActiveMedia(true);
         mMediaHost.init(MediaHierarchyManager.LOCATION_QQS);
-        reAttachMediaHost();
-        updateMediaHostContentMargins();
     }
 
     @Override
-    protected void updateTileLayoutMargins(int visualMarginStart, int visualMarginEnd) {
-        if (mUsingMediaPlayer) {
-            updateMargins((View) mRegularTileLayout, visualMarginStart, visualMarginEnd);
-            updateMargins((View) mHorizontalTileLayout, visualMarginStart, 0);
-        } else {
-            updateMargins((View) mTileLayout, visualMarginStart, visualMarginEnd);
-        }
+    protected boolean needsDynamicRowsAndColumns() {
+        return false; // QQS always have the same layout
+    }
+
+    @Override
+    protected boolean displayMediaMarginsOnMedia() {
+        // Margins should be on the container to visually center the view
+        return false;
     }
 
     @Override
@@ -194,10 +128,6 @@
     }
 
     @Override
-    protected void addDivider() {
-    }
-
-    @Override
     protected void onAttachedToWindow() {
         super.onAttachedToWindow();
         Dependency.get(TunerService.class).addTunable(mNumTiles, NUM_QUICK_TILES);
@@ -237,60 +167,6 @@
     }
 
     @Override
-    protected void onConfigurationChanged(Configuration newConfig) {
-        super.onConfigurationChanged(newConfig);
-        if (newConfig.orientation != mLastOrientation) {
-            mLastOrientation = newConfig.orientation;
-            switchTileLayout();
-        }
-    }
-
-    boolean switchTileLayout() {
-        if (!mUsingMediaPlayer) return false;
-        mShowHorizontalTileLayout = shouldUseHorizontalTileLayout();
-        if (mShowHorizontalTileLayout && mHorizontalLinearLayout.getVisibility() == View.GONE) {
-            mHorizontalLinearLayout.setVisibility(View.VISIBLE);
-            ((View) mRegularTileLayout).setVisibility(View.GONE);
-            mTileLayout.setListening(false);
-            for (TileRecord record : mRecords) {
-                mTileLayout.removeTile(record);
-                record.tile.removeCallback(record.callback);
-            }
-            mTileLayout = mHorizontalTileLayout;
-            if (mHost != null) setTiles(mHost.getTiles());
-            mTileLayout.setListening(mListening);
-            reAttachMediaHost();
-            return true;
-        } else if (!mShowHorizontalTileLayout
-                && mHorizontalLinearLayout.getVisibility() == View.VISIBLE) {
-            mHorizontalLinearLayout.setVisibility(View.GONE);
-            ((View) mRegularTileLayout).setVisibility(View.VISIBLE);
-            mTileLayout.setListening(false);
-            for (TileRecord record : mRecords) {
-                mTileLayout.removeTile(record);
-                record.tile.removeCallback(record.callback);
-            }
-            mTileLayout = mRegularTileLayout;
-            if (mHost != null) setTiles(mHost.getTiles());
-            mTileLayout.setListening(mListening);
-            reAttachMediaHost();
-            return true;
-        }
-        return false;
-    }
-
-    private boolean shouldUseHorizontalTileLayout() {
-        return mMediaHost.getVisible()
-                && getResources().getConfiguration().orientation
-                        == Configuration.ORIENTATION_LANDSCAPE;
-    }
-
-    /** Returns true if this panel currently uses a horizontal tile layout. */
-    public boolean usesHorizontalLayout() {
-        return mShowHorizontalTileLayout;
-    }
-
-    @Override
     public void setHost(QSTileHost host, QSCustomizer customizer) {
         super.setHost(host, customizer);
         setTiles(mHost.getTiles());
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeader.java b/packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeader.java
index 20e47b2..b5afe77 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeader.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeader.java
@@ -15,6 +15,7 @@
 package com.android.systemui.qs;
 
 import static android.app.StatusBarManager.DISABLE2_QUICK_SETTINGS;
+import static android.view.ViewGroup.LayoutParams.WRAP_CONTENT;
 
 import static com.android.systemui.util.InjectionInflationController.VIEW_CONTEXT;
 
@@ -36,13 +37,14 @@
 import android.text.format.DateUtils;
 import android.util.AttributeSet;
 import android.util.Log;
+import android.util.MathUtils;
 import android.util.Pair;
 import android.view.ContextThemeWrapper;
 import android.view.DisplayCutout;
 import android.view.View;
+import android.view.ViewGroup;
 import android.view.WindowInsets;
 import android.widget.ImageView;
-import android.widget.LinearLayout;
 import android.widget.RelativeLayout;
 import android.widget.TextView;
 
@@ -55,6 +57,7 @@
 import com.android.settingslib.Utils;
 import com.android.systemui.BatteryMeterView;
 import com.android.systemui.DualToneHandler;
+import com.android.systemui.Interpolators;
 import com.android.systemui.R;
 import com.android.systemui.plugins.ActivityStarter;
 import com.android.systemui.plugins.DarkIconDispatcher;
@@ -149,6 +152,8 @@
     private int mWaterfallTopInset;
     private int mCutOutPaddingLeft;
     private int mCutOutPaddingRight;
+    private float mExpandedHeaderAlpha = 1.0f;
+    private float mKeyguardExpansionFraction;
 
     @Inject
     public QuickStatusBarHeader(@Named(VIEW_CONTEXT) Context context, AttributeSet attrs,
@@ -344,6 +349,15 @@
                 com.android.internal.R.dimen.quick_qs_offset_height);
         mSystemIconsView.setLayoutParams(mSystemIconsView.getLayoutParams());
 
+        ViewGroup.LayoutParams lp = getLayoutParams();
+        if (mQsDisabled) {
+            lp.height = resources.getDimensionPixelSize(
+                    com.android.internal.R.dimen.quick_qs_offset_height);
+        } else {
+            lp.height = WRAP_CONTENT;
+        }
+        setLayoutParams(lp);
+
         updateStatusIconAlphaAnimator();
         updateHeaderTextContainerAlphaAnimator();
     }
@@ -356,7 +370,7 @@
 
     private void updateHeaderTextContainerAlphaAnimator() {
         mHeaderTextContainerAlphaAnimator = new TouchAnimator.Builder()
-                .addFloat(mHeaderTextContainerView, "alpha", 0, 0, 1)
+                .addFloat(mHeaderTextContainerView, "alpha", 0, 0, mExpandedHeaderAlpha)
                 .build();
     }
 
@@ -403,6 +417,7 @@
                 updateResources();
             }
         }
+        mKeyguardExpansionFraction = keyguardExpansionFraction;
     }
 
     public void disable(int state1, int state2, boolean animate) {
@@ -596,4 +611,22 @@
         }
         updateClockPadding();
     }
+
+    public void setExpandedScrollAmount(int scrollY) {
+        // The scrolling of the expanded qs has changed. Since the header text isn't part of it,
+        // but would overlap content, we're fading it out.
+        float newAlpha = 1.0f;
+        if (mHeaderTextContainerView.getHeight() > 0) {
+            newAlpha = MathUtils.map(0, mHeaderTextContainerView.getHeight() / 2.0f, 1.0f, 0.0f,
+                    scrollY);
+            newAlpha = Interpolators.ALPHA_OUT.getInterpolation(newAlpha);
+        }
+        mHeaderTextContainerView.setScrollY(scrollY);
+        if (newAlpha != mExpandedHeaderAlpha) {
+            mExpandedHeaderAlpha = newAlpha;
+            mHeaderTextContainerView.setAlpha(MathUtils.lerp(0.0f, mExpandedHeaderAlpha,
+                    mKeyguardExpansionFraction));
+            updateHeaderTextContainerAlphaAnimator();
+        }
+    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/qs/TileLayout.java b/packages/SystemUI/src/com/android/systemui/qs/TileLayout.java
index 383c29d..694492a 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/TileLayout.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/TileLayout.java
@@ -17,6 +17,7 @@
 
 public class TileLayout extends ViewGroup implements QSTileLayout {
 
+    public static final int NO_MAX_COLUMNS = 100;
     private static final float TILE_ASPECT = 1.2f;
 
     private static final String TAG = "TileLayout";
@@ -36,6 +37,9 @@
 
     // Prototyping with less rows
     private final boolean mLessRows;
+    private int mMinRows = 1;
+    private int mMaxColumns = NO_MAX_COLUMNS;
+    private int mResourceColumns;
 
     public TileLayout(Context context) {
         this(context, null);
@@ -64,6 +68,22 @@
         }
     }
 
+    @Override
+    public boolean setMinRows(int minRows) {
+        if (mMinRows != minRows) {
+            mMinRows = minRows;
+            updateResources();
+            return true;
+        }
+        return false;
+    }
+
+    @Override
+    public boolean setMaxColumns(int maxColumns) {
+        mMaxColumns = maxColumns;
+        return updateColumns();
+    }
+
     public void addTile(TileRecord tile) {
         mRecords.add(tile);
         tile.tile.setListening(this, mListening);
@@ -91,21 +111,26 @@
 
     public boolean updateResources() {
         final Resources res = mContext.getResources();
-        final int columns = Math.max(1, res.getInteger(R.integer.quick_settings_num_columns));
+        mResourceColumns = Math.max(1, res.getInteger(R.integer.quick_settings_num_columns));
         mCellHeight = mContext.getResources().getDimensionPixelSize(R.dimen.qs_tile_height);
         mCellMarginHorizontal = res.getDimensionPixelSize(R.dimen.qs_tile_margin_horizontal);
         mCellMarginVertical= res.getDimensionPixelSize(R.dimen.qs_tile_margin_vertical);
         mCellMarginTop = res.getDimensionPixelSize(R.dimen.qs_tile_margin_top);
         mMaxAllowedRows = Math.max(1, getResources().getInteger(R.integer.quick_settings_max_rows));
-        if (mLessRows) mMaxAllowedRows = Math.max(1, mMaxAllowedRows - 1);
-        if (mColumns != columns) {
-            mColumns = columns;
+        if (mLessRows) mMaxAllowedRows = Math.max(mMinRows, mMaxAllowedRows - 1);
+        if (updateColumns()) {
             requestLayout();
             return true;
         }
         return false;
     }
 
+    private boolean updateColumns() {
+        int oldColumns = mColumns;
+        mColumns = Math.min(mResourceColumns, mMaxColumns);
+        return oldColumns != mColumns;
+    }
+
     @Override
     protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
         // If called with AT_MOST, it will limit the number of rows. If called with UNSPECIFIED
@@ -142,18 +167,19 @@
      * Determines the maximum number of rows that can be shown based on height. Clips at a minimum
      * of 1 and a maximum of mMaxAllowedRows.
      *
-     * @param heightMeasureSpec Available height.
+     * @param allowedHeight The height this view has visually available
      * @param tilesCount Upper limit on the number of tiles to show. to prevent empty rows.
      */
-    public boolean updateMaxRows(int heightMeasureSpec, int tilesCount) {
-        final int availableHeight = MeasureSpec.getSize(heightMeasureSpec) - mCellMarginTop
+    public boolean updateMaxRows(int allowedHeight, int tilesCount) {
+        final int availableHeight =  allowedHeight - mCellMarginTop
+                // Add the cell margin in order to divide easily by the height + the margin below
                 + mCellMarginVertical;
         final int previousRows = mRows;
         mRows = availableHeight / (mCellHeight + mCellMarginVertical);
-        if (mRows >= mMaxAllowedRows) {
+        if (mRows < mMinRows) {
+            mRows = mMinRows;
+        } else if (mRows >= mMaxAllowedRows) {
             mRows = mMaxAllowedRows;
-        } else if (mRows <= 1) {
-            mRows = 1;
         }
         if (mRows > (tilesCount + mColumns - 1) / mColumns) {
             mRows = (tilesCount + mColumns - 1) / mColumns;
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/ScreenRecordTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/ScreenRecordTile.java
index d7dd6f2..32ef063 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/ScreenRecordTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/ScreenRecordTile.java
@@ -22,6 +22,7 @@
 import android.util.Log;
 import android.widget.Switch;
 
+import com.android.internal.logging.UiEventLogger;
 import com.android.systemui.R;
 import com.android.systemui.plugins.ActivityStarter;
 import com.android.systemui.plugins.qs.QSTile;
@@ -41,14 +42,16 @@
     private ActivityStarter mActivityStarter;
     private long mMillisUntilFinished = 0;
     private Callback mCallback = new Callback();
+    private UiEventLogger mUiEventLogger;
 
     @Inject
     public ScreenRecordTile(QSHost host, RecordingController controller,
-            ActivityStarter activityStarter) {
+            ActivityStarter activityStarter, UiEventLogger uiEventLogger) {
         super(host);
         mController = controller;
         mController.observe(this, mCallback);
         mActivityStarter = activityStarter;
+        mUiEventLogger = uiEventLogger;
     }
 
     @Override
@@ -112,7 +115,6 @@
     }
 
     private void startCountdown() {
-        Log.d(TAG, "Starting countdown");
         // Close QS, otherwise the permission dialog appears beneath it
         getHost().collapsePanels();
         Intent intent = mController.getPromptIntent();
@@ -125,7 +127,6 @@
     }
 
     private void stopRecording() {
-        Log.d(TAG, "Stopping recording from tile");
         mController.stopRecording();
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/UserDetailItemView.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/UserDetailItemView.java
index aa63b40..6a8c6149 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/UserDetailItemView.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/UserDetailItemView.java
@@ -95,14 +95,11 @@
         mAvatar.setDrawableWithBadge(picture, userId);
     }
 
-    public void setAvatarEnabled(boolean enabled) {
-        mAvatar.setEnabled(enabled);
-    }
-
     public void setDisabledByAdmin(boolean disabled) {
-        mRestrictedPadlock.setVisibility(disabled ? View.VISIBLE : View.GONE);
-        mName.setEnabled(!disabled);
-        mAvatar.setEnabled(!disabled);
+        if (mRestrictedPadlock != null) {
+            mRestrictedPadlock.setVisibility(disabled ? View.VISIBLE : View.GONE);
+        }
+        setEnabled(!disabled);
     }
 
     public void setEnabled(boolean enabled) {
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/UserDetailView.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/UserDetailView.java
index 89ce125..fba7a22 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/UserDetailView.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/UserDetailView.java
@@ -16,8 +16,12 @@
 
 package com.android.systemui.qs.tiles;
 
+import static com.android.systemui.statusbar.policy.UserSwitcherController.USER_SWITCH_DISABLED_ALPHA;
+import static com.android.systemui.statusbar.policy.UserSwitcherController.USER_SWITCH_ENABLED_ALPHA;
+
 import android.content.Context;
 import android.content.Intent;
+import android.graphics.drawable.BitmapDrawable;
 import android.graphics.drawable.Drawable;
 import android.graphics.drawable.LayerDrawable;
 import android.util.AttributeSet;
@@ -94,18 +98,21 @@
             }
             String name = getName(mContext, item);
             if (item.picture == null) {
-                v.bind(name, getDrawable(mContext, item), item.resolveId());
+                v.bind(name, getDrawable(mContext, item).mutate(), item.resolveId());
             } else {
-                v.bind(name, item.picture, item.info.id);
+                Drawable drawable = new BitmapDrawable(v.getResources(), item.picture);
+                drawable.setColorFilter(
+                        item.isSwitchToEnabled ? null : getDisabledUserAvatarColorFilter());
+                v.bind(name, drawable, item.info.id);
             }
             v.setActivated(item.isCurrent);
+            v.setDisabledByAdmin(item.isDisabledByAdmin);
+            v.setEnabled(item.isSwitchToEnabled);
+            v.setAlpha(v.isEnabled() ? USER_SWITCH_ENABLED_ALPHA : USER_SWITCH_DISABLED_ALPHA);
+
             if (item.isCurrent) {
                 mCurrentUserView = v;
             }
-            v.setDisabledByAdmin(item.isDisabledByAdmin);
-            if (!item.isSwitchToEnabled) {
-                v.setEnabled(false);
-            }
             v.setTag(item);
             return v;
         }
@@ -113,8 +120,14 @@
         private static Drawable getDrawable(Context context,
                 UserSwitcherController.UserRecord item) {
             Drawable icon = getIconDrawable(context, item);
-            int iconColorRes = item.isCurrent ? R.color.qs_user_switcher_selected_avatar_icon_color
-                    : R.color.qs_user_switcher_avatar_icon_color;
+            int iconColorRes;
+            if (item.isCurrent) {
+                iconColorRes = R.color.qs_user_switcher_selected_avatar_icon_color;
+            } else if (!item.isSwitchToEnabled) {
+                iconColorRes = R.color.GM2_grey_600;
+            } else {
+                iconColorRes = R.color.qs_user_switcher_avatar_icon_color;
+            }
             icon.setTint(context.getResources().getColor(iconColorRes, context.getTheme()));
 
             int bgRes = item.isCurrent ? R.drawable.bg_avatar_selected : R.drawable.qs_bg_avatar;
diff --git a/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyRecentsImpl.java b/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyRecentsImpl.java
index f3e2f10..f89185e 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyRecentsImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyRecentsImpl.java
@@ -118,6 +118,7 @@
                 try {
                     if (mOverviewProxyService.getProxy() != null) {
                         mOverviewProxyService.getProxy().onOverviewToggle();
+                        mOverviewProxyService.notifyToggleRecentApps();
                     }
                 } catch (RemoteException e) {
                     Log.e(TAG, "Cannot send toggle recents through proxy service.", e);
diff --git a/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java b/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java
index baa2dfd..790b2585 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java
@@ -200,11 +200,13 @@
                             mInputFocusTransferStartY = event.getY();
                             mInputFocusTransferStartMillis = event.getEventTime();
                             statusBar.onInputFocusTransfer(
-                                    mInputFocusTransferStarted, 0 /* velocity */);
+                                    mInputFocusTransferStarted, false /* cancel */,
+                                    0 /* velocity */);
                         }
                         if (action == ACTION_UP || action == ACTION_CANCEL) {
                             mInputFocusTransferStarted = false;
                             statusBar.onInputFocusTransfer(mInputFocusTransferStarted,
+                                    action == ACTION_CANCEL,
                                     (event.getY() - mInputFocusTransferStartY)
                                     / (event.getEventTime() - mInputFocusTransferStartMillis));
                         }
@@ -577,10 +579,6 @@
         // Listen for nav bar mode changes
         mNavBarMode = navModeController.addListener(this);
 
-        // Listen for device provisioned/user setup
-        updateEnabledState();
-        startTracking();
-
         // Listen for launcher package changes
         IntentFilter filter = new IntentFilter(Intent.ACTION_PACKAGE_ADDED);
         filter.addDataScheme("package");
@@ -601,6 +599,13 @@
                         .commitUpdate(mContext.getDisplayId());
             }
         });
+
+        // Listen for user setup
+        startTracking();
+
+        // Connect to the service
+        updateEnabledState();
+        startConnectionToCurrentUser();
     }
 
     @Override
@@ -689,7 +694,8 @@
             mHandler.post(()-> {
                 mStatusBarOptionalLazy.ifPresent(statusBarLazy -> {
                     mInputFocusTransferStarted = false;
-                    statusBarLazy.get().onInputFocusTransfer(false, 0 /* velocity */);
+                    statusBarLazy.get().onInputFocusTransfer(false, true /* cancel */,
+                            0 /* velocity */);
                 });
             });
         }
@@ -868,6 +874,12 @@
         }
     }
 
+    void notifyToggleRecentApps() {
+        for (int i = mConnectionCallbacks.size() - 1; i >= 0; --i) {
+            mConnectionCallbacks.get(i).onToggleRecentApps();
+        }
+    }
+
     private void updateEnabledState() {
         mIsEnabled = mContext.getPackageManager().resolveServiceAsUser(mQuickStepIntent,
                 MATCH_SYSTEM_ONLY,
@@ -898,6 +910,8 @@
         default void onQuickSwitchToNewTask(@Surface.Rotation int rotation) {}
         default void onOverviewShown(boolean fromHome) {}
         default void onQuickScrubStarted() {}
+        /** Notify the recents app (overview) is started by 3-button navigation. */
+        default void onToggleRecentApps() {}
         /** Notify changes in the nav bar button alpha */
         default void onNavBarButtonAlphaChanged(float alpha, boolean animate) {}
         default void onSystemUiStateChanged(int sysuiStateFlags) {}
diff --git a/packages/SystemUI/src/com/android/systemui/screenrecord/Events.java b/packages/SystemUI/src/com/android/systemui/screenrecord/Events.java
new file mode 100644
index 0000000..9dede48
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/screenrecord/Events.java
@@ -0,0 +1,45 @@
+/*
+ * Copyright (C) 2020 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.screenrecord;
+
+import com.android.internal.logging.UiEvent;
+import com.android.internal.logging.UiEventLogger;
+
+/**
+ * Events related to the SystemUI screen recorder
+ */
+public class Events {
+
+    public enum ScreenRecordEvent implements UiEventLogger.UiEventEnum {
+        @UiEvent(doc = "Screen recording was started")
+        SCREEN_RECORD_START(299),
+        @UiEvent(doc = "Screen recording was stopped from the quick settings tile")
+        SCREEN_RECORD_END_QS_TILE(300),
+        @UiEvent(doc = "Screen recording was stopped from the notification")
+        SCREEN_RECORD_END_NOTIFICATION(301);
+
+        private final int mId;
+        ScreenRecordEvent(int id) {
+            mId = id;
+        }
+
+        @Override
+        public int getId() {
+            return mId;
+        }
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/screenrecord/RecordingService.java b/packages/SystemUI/src/com/android/systemui/screenrecord/RecordingService.java
index 2ddd6aa..f2e8599 100644
--- a/packages/SystemUI/src/com/android/systemui/screenrecord/RecordingService.java
+++ b/packages/SystemUI/src/com/android/systemui/screenrecord/RecordingService.java
@@ -36,6 +36,8 @@
 import android.util.Log;
 import android.widget.Toast;
 
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.logging.UiEventLogger;
 import com.android.systemui.R;
 import com.android.systemui.dagger.qualifiers.LongRunning;
 
@@ -63,22 +65,28 @@
 
     private static final String ACTION_START = "com.android.systemui.screenrecord.START";
     private static final String ACTION_STOP = "com.android.systemui.screenrecord.STOP";
+    private static final String ACTION_STOP_NOTIF =
+            "com.android.systemui.screenrecord.STOP_FROM_NOTIF";
     private static final String ACTION_SHARE = "com.android.systemui.screenrecord.SHARE";
     private static final String ACTION_DELETE = "com.android.systemui.screenrecord.DELETE";
 
     private final RecordingController mController;
-    private Notification.Builder mRecordingNotificationBuilder;
 
     private ScreenRecordingAudioSource mAudioSource;
     private boolean mShowTaps;
     private boolean mOriginalShowTaps;
     private ScreenMediaRecorder mRecorder;
     private final Executor mLongExecutor;
+    private final UiEventLogger mUiEventLogger;
+    private final NotificationManager mNotificationManager;
 
     @Inject
-    public RecordingService(RecordingController controller, @LongRunning Executor executor) {
+    public RecordingService(RecordingController controller, @LongRunning Executor executor,
+            UiEventLogger uiEventLogger, NotificationManager notificationManager) {
         mController = controller;
         mLongExecutor = executor;
+        mUiEventLogger = uiEventLogger;
+        mNotificationManager = notificationManager;
     }
 
     /**
@@ -110,9 +118,6 @@
         String action = intent.getAction();
         Log.d(TAG, "onStartCommand " + action);
 
-        NotificationManager notificationManager =
-                (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
-
         switch (action) {
             case ACTION_START:
                 mAudioSource = ScreenRecordingAudioSource
@@ -135,10 +140,16 @@
                 startRecording();
                 break;
 
+            case ACTION_STOP_NOTIF:
             case ACTION_STOP:
+                // only difference for actions is the log event
+                if (ACTION_STOP_NOTIF.equals(action)) {
+                    mUiEventLogger.log(Events.ScreenRecordEvent.SCREEN_RECORD_END_NOTIFICATION);
+                } else {
+                    mUiEventLogger.log(Events.ScreenRecordEvent.SCREEN_RECORD_END_QS_TILE);
+                }
                 stopRecording();
-                notificationManager.cancel(NOTIFICATION_RECORDING_ID);
-                saveRecording(notificationManager);
+                mNotificationManager.cancel(NOTIFICATION_RECORDING_ID);
                 stopSelf();
                 break;
 
@@ -154,7 +165,7 @@
                 sendBroadcast(new Intent(Intent.ACTION_CLOSE_SYSTEM_DIALOGS));
 
                 // Remove notification
-                notificationManager.cancel(NOTIFICATION_VIEW_ID);
+                mNotificationManager.cancel(NOTIFICATION_VIEW_ID);
 
                 startActivity(Intent.createChooser(shareIntent, shareLabel)
                         .setFlags(Intent.FLAG_ACTIVITY_NEW_TASK));
@@ -173,7 +184,7 @@
                         Toast.LENGTH_LONG).show();
 
                 // Remove notification
-                notificationManager.cancel(NOTIFICATION_VIEW_ID);
+                mNotificationManager.cancel(NOTIFICATION_VIEW_ID);
                 Log.d(TAG, "Deleted recording " + uri);
                 break;
         }
@@ -190,14 +201,20 @@
         super.onCreate();
     }
 
+    @VisibleForTesting
+    protected ScreenMediaRecorder getRecorder() {
+        return mRecorder;
+    }
+
     /**
      * Begin the recording session
      */
     private void startRecording() {
         try {
-            mRecorder.start();
+            getRecorder().start();
             mController.updateState(true);
             createRecordingNotification();
+            mUiEventLogger.log(Events.ScreenRecordEvent.SCREEN_RECORD_START);
         } catch (IOException | RemoteException e) {
             Toast.makeText(this,
                     R.string.screenrecord_start_error, Toast.LENGTH_LONG)
@@ -206,7 +223,8 @@
         }
     }
 
-    private void createRecordingNotification() {
+    @VisibleForTesting
+    protected void createRecordingNotification() {
         Resources res = getResources();
         NotificationChannel channel = new NotificationChannel(
                 CHANNEL_ID,
@@ -214,9 +232,7 @@
                 NotificationManager.IMPORTANCE_DEFAULT);
         channel.setDescription(getString(R.string.screenrecord_channel_description));
         channel.enableVibration(true);
-        NotificationManager notificationManager =
-                (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
-        notificationManager.createNotificationChannel(channel);
+        mNotificationManager.createNotificationChannel(channel);
 
         Bundle extras = new Bundle();
         extras.putString(Notification.EXTRA_SUBSTITUTE_APP_NAME,
@@ -226,7 +242,9 @@
                 ? res.getString(R.string.screenrecord_ongoing_screen_only)
                 : res.getString(R.string.screenrecord_ongoing_screen_and_audio);
 
-        mRecordingNotificationBuilder = new Notification.Builder(this, CHANNEL_ID)
+
+        Intent stopIntent = getNotificationIntent(this);
+        Notification.Builder builder = new Notification.Builder(this, CHANNEL_ID)
                 .setSmallIcon(R.drawable.ic_screenrecord)
                 .setContentTitle(notificationTitle)
                 .setContentText(getResources().getString(R.string.screenrecord_stop_text))
@@ -235,17 +253,28 @@
                 .setColor(getResources().getColor(R.color.GM2_red_700))
                 .setOngoing(true)
                 .setContentIntent(
-                        PendingIntent.getService(
-                                this, REQUEST_CODE, getStopIntent(this),
+                        PendingIntent.getService(this, REQUEST_CODE, stopIntent,
                                 PendingIntent.FLAG_UPDATE_CURRENT))
                 .addExtras(extras);
-        notificationManager.notify(NOTIFICATION_RECORDING_ID,
-                mRecordingNotificationBuilder.build());
-        Notification notification = mRecordingNotificationBuilder.build();
-        startForeground(NOTIFICATION_RECORDING_ID, notification);
+        startForeground(NOTIFICATION_RECORDING_ID, builder.build());
     }
 
-    private Notification createSaveNotification(ScreenMediaRecorder.SavedRecording recording) {
+    @VisibleForTesting
+    protected Notification createProcessingNotification() {
+        Resources res = getApplicationContext().getResources();
+        String notificationTitle = mAudioSource == ScreenRecordingAudioSource.NONE
+                ? res.getString(R.string.screenrecord_ongoing_screen_only)
+                : res.getString(R.string.screenrecord_ongoing_screen_and_audio);
+        Notification.Builder builder = new Notification.Builder(getApplicationContext(), CHANNEL_ID)
+                .setContentTitle(notificationTitle)
+                .setContentText(
+                        getResources().getString(R.string.screenrecord_background_processing_label))
+                .setSmallIcon(R.drawable.ic_screenrecord);
+        return builder.build();
+    }
+
+    @VisibleForTesting
+    protected Notification createSaveNotification(ScreenMediaRecorder.SavedRecording recording) {
         Uri uri = recording.getUri();
         Intent viewIntent = new Intent(Intent.ACTION_VIEW)
                 .setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_GRANT_READ_URI_PERMISSION)
@@ -301,44 +330,39 @@
 
     private void stopRecording() {
         setTapsVisible(mOriginalShowTaps);
-        mRecorder.end();
+        if (getRecorder() != null) {
+            getRecorder().end();
+            saveRecording();
+        } else {
+            Log.e(TAG, "stopRecording called, but recorder was null");
+        }
         mController.updateState(false);
     }
 
-    private void saveRecording(NotificationManager notificationManager) {
-        Resources res = getApplicationContext().getResources();
-        String notificationTitle = mAudioSource == ScreenRecordingAudioSource.NONE
-                ? res.getString(R.string.screenrecord_ongoing_screen_only)
-                : res.getString(R.string.screenrecord_ongoing_screen_and_audio);
-        Notification.Builder builder = new Notification.Builder(getApplicationContext(), CHANNEL_ID)
-                .setContentTitle(notificationTitle)
-                .setContentText(
-                        getResources().getString(R.string.screenrecord_background_processing_label))
-                .setSmallIcon(R.drawable.ic_screenrecord);
-        notificationManager.notify(NOTIFICATION_PROCESSING_ID, builder.build());
+    private void saveRecording() {
+        mNotificationManager.notify(NOTIFICATION_PROCESSING_ID, createProcessingNotification());
 
         mLongExecutor.execute(() -> {
             try {
                 Log.d(TAG, "saving recording");
-                Notification notification = createSaveNotification(mRecorder.save());
+                Notification notification = createSaveNotification(getRecorder().save());
                 if (!mController.isRecording()) {
                     Log.d(TAG, "showing saved notification");
-                    notificationManager.notify(NOTIFICATION_VIEW_ID, notification);
+                    mNotificationManager.notify(NOTIFICATION_VIEW_ID, notification);
                 }
             } catch (IOException e) {
                 Log.e(TAG, "Error saving screen recording: " + e.getMessage());
                 Toast.makeText(this, R.string.screenrecord_delete_error, Toast.LENGTH_LONG)
                         .show();
             } finally {
-                notificationManager.cancel(NOTIFICATION_PROCESSING_ID);
+                mNotificationManager.cancel(NOTIFICATION_PROCESSING_ID);
             }
         });
     }
 
     private void setTapsVisible(boolean turnOn) {
         int value = turnOn ? 1 : 0;
-        Settings.System.putInt(getApplicationContext().getContentResolver(),
-                Settings.System.SHOW_TOUCHES, value);
+        Settings.System.putInt(getContentResolver(), Settings.System.SHOW_TOUCHES, value);
     }
 
     /**
@@ -350,6 +374,15 @@
         return new Intent(context, RecordingService.class).setAction(ACTION_STOP);
     }
 
+    /**
+     * Get the recording notification content intent
+     * @param context
+     * @return
+     */
+    protected static Intent getNotificationIntent(Context context) {
+        return new Intent(context, RecordingService.class).setAction(ACTION_STOP_NOTIF);
+    }
+
     private static Intent getShareIntent(Context context, String path) {
         return new Intent(context, RecordingService.class).setAction(ACTION_SHARE)
                 .putExtra(EXTRA_PATH, path);
diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/GlobalScreenshot.java b/packages/SystemUI/src/com/android/systemui/screenshot/GlobalScreenshot.java
index a624479..ca37532 100644
--- a/packages/SystemUI/src/com/android/systemui/screenshot/GlobalScreenshot.java
+++ b/packages/SystemUI/src/com/android/systemui/screenshot/GlobalScreenshot.java
@@ -41,13 +41,19 @@
 import android.content.res.Configuration;
 import android.content.res.Resources;
 import android.graphics.Bitmap;
+import android.graphics.Color;
 import android.graphics.Insets;
 import android.graphics.Outline;
 import android.graphics.PixelFormat;
 import android.graphics.PointF;
 import android.graphics.Rect;
 import android.graphics.Region;
+import android.graphics.drawable.BitmapDrawable;
+import android.graphics.drawable.ColorDrawable;
+import android.graphics.drawable.Drawable;
 import android.graphics.drawable.Icon;
+import android.graphics.drawable.InsetDrawable;
+import android.graphics.drawable.LayerDrawable;
 import android.media.MediaActionSound;
 import android.net.Uri;
 import android.os.Handler;
@@ -114,7 +120,6 @@
         public Consumer<Uri> finisher;
         public GlobalScreenshot.ActionsReadyListener mActionsReadyListener;
         public int errorMsgResId;
-        public boolean createDeleteAction;
 
         void clearImage() {
             image = null;
@@ -168,6 +173,8 @@
 
     private static final long SCREENSHOT_FLASH_IN_DURATION_MS = 133;
     private static final long SCREENSHOT_FLASH_OUT_DURATION_MS = 217;
+    // delay before starting to fade in dismiss button
+    private static final long SCREENSHOT_TO_CORNER_DISMISS_DELAY_MS = 200;
     private static final long SCREENSHOT_TO_CORNER_X_DURATION_MS = 234;
     private static final long SCREENSHOT_TO_CORNER_Y_DURATION_MS = 500;
     private static final long SCREENSHOT_TO_CORNER_SCALE_DURATION_MS = 234;
@@ -261,7 +268,8 @@
                         | WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN
                         | WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL
                         | WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH
-                        | WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED,
+                        | WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED
+                        | WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM,
                 PixelFormat.TRANSLUCENT);
         mWindowLayoutParams.setTitle("ScreenshotAnimation");
         mWindowLayoutParams.layoutInDisplayCutoutMode = LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS;
@@ -424,7 +432,6 @@
         data.image = mScreenBitmap;
         data.finisher = finisher;
         data.mActionsReadyListener = actionsReadyListener;
-        data.createDeleteAction = false;
 
         if (mSaveInBgTask != null) {
             // just log success/failure for the pre-existing screenshot
@@ -449,10 +456,12 @@
         int rot = mDisplay.getRotation();
         int width = crop.width();
         int height = crop.height();
-        takeScreenshot(SurfaceControl.screenshot(crop, width, height, rot), finisher, screenRect);
+        takeScreenshot(SurfaceControl.screenshot(crop, width, height, rot), finisher, screenRect,
+                Insets.NONE, true);
     }
 
-    private void takeScreenshot(Bitmap screenshot, Consumer<Uri> finisher, Rect screenRect) {
+    private void takeScreenshot(Bitmap screenshot, Consumer<Uri> finisher, Rect screenRect,
+            Insets screenInsets, boolean showFlash) {
         dismissScreenshot("new screenshot requested", true);
 
         mScreenBitmap = screenshot;
@@ -482,7 +491,7 @@
             mDismissAnimation.cancel();
         }
         // Start the post-screenshot animation
-        startAnimation(finisher, mScreenBitmap.getWidth(), mScreenBitmap.getHeight(), screenRect);
+        startAnimation(finisher, screenRect, screenInsets, showFlash);
     }
 
     void takeScreenshot(Consumer<Uri> finisher, Runnable onComplete) {
@@ -498,9 +507,15 @@
             Insets visibleInsets, int taskId, int userId, ComponentName topComponent,
             Consumer<Uri> finisher, Runnable onComplete) {
         // TODO: use task Id, userId, topComponent for smart handler
-        // TODO: use visibleInsets for animation
+
         mOnCompleteRunnable = onComplete;
-        takeScreenshot(screenshot, finisher, screenshotScreenBounds);
+        if (aspectRatiosMatch(screenshot, visibleInsets, screenshotScreenBounds)) {
+            takeScreenshot(screenshot, finisher, screenshotScreenBounds, visibleInsets, false);
+        } else {
+            takeScreenshot(screenshot, finisher,
+                    new Rect(0, 0, screenshot.getWidth(), screenshot.getHeight()), Insets.NONE,
+                    true);
+        }
     }
 
     /**
@@ -621,8 +636,9 @@
         }
 
         // Clear any references to the bitmap
-        mScreenshotPreview.setImageBitmap(null);
-        mScreenshotAnimatedView.setImageBitmap(null);
+        mScreenshotPreview.setImageDrawable(null);
+        mScreenshotAnimatedView.setImageDrawable(null);
+        mScreenshotAnimatedView.setVisibility(View.GONE);
         mActionsContainerBackground.setVisibility(View.GONE);
         mActionsContainer.setVisibility(View.GONE);
         mBackgroundProtection.setAlpha(0f);
@@ -688,8 +704,9 @@
     /**
      * Starts the animation after taking the screenshot
      */
-    private void startAnimation(
-            final Consumer<Uri> finisher, int bitmapWidth, int bitmapHeight, Rect screenRect) {
+    private void startAnimation(final Consumer<Uri> finisher, Rect screenRect, Insets screenInsets,
+            boolean showFlash) {
+
         // If power save is on, show a toast so there is some visual indication that a
         // screenshot has been taken.
         PowerManager powerManager = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE);
@@ -701,9 +718,13 @@
             if (!mScreenshotLayout.isAttachedToWindow()) {
                 mWindowManager.addView(mScreenshotLayout, mWindowLayoutParams);
             }
-            mScreenshotAnimatedView.setImageBitmap(mScreenBitmap);
-            mScreenshotPreview.setImageBitmap(mScreenBitmap);
+            mScreenshotAnimatedView.setImageDrawable(
+                    createScreenDrawable(mScreenBitmap, screenInsets));
+            setAnimatedViewSize(screenRect.width(), screenRect.height());
+            // Show when the animation starts
+            mScreenshotAnimatedView.setVisibility(View.GONE);
 
+            mScreenshotPreview.setImageDrawable(createScreenDrawable(mScreenBitmap, screenInsets));
             // make static preview invisible (from gone) so we can query its location on screen
             mScreenshotPreview.setVisibility(View.INVISIBLE);
 
@@ -711,14 +732,14 @@
                 mScreenshotLayout.getViewTreeObserver().addOnComputeInternalInsetsListener(this);
 
                 mScreenshotAnimation =
-                        createScreenshotDropInAnimation(bitmapWidth, bitmapHeight, screenRect);
+                        createScreenshotDropInAnimation(screenRect, showFlash);
 
                 saveScreenshotInWorkerThread(finisher, new ActionsReadyListener() {
-                            @Override
-                            void onActionsReady(SavedImageData imageData) {
-                                showUiOnActionsReady(imageData);
-                            }
-                        });
+                    @Override
+                    void onActionsReady(SavedImageData imageData) {
+                        showUiOnActionsReady(imageData);
+                    }
+                });
 
                 // Play the shutter sound to notify that we've taken a screenshot
                 mCameraSound.play(MediaActionSound.SHUTTER_CLICK);
@@ -730,19 +751,19 @@
         });
     }
 
-    private AnimatorSet createScreenshotDropInAnimation(
-            int bitmapWidth, int bitmapHeight, Rect bounds) {
+    private AnimatorSet createScreenshotDropInAnimation(Rect bounds, boolean showFlash) {
         Rect previewBounds = new Rect();
         mScreenshotPreview.getBoundsOnScreen(previewBounds);
 
-        float cornerScale = mCornerSizeX / (mOrientationPortrait ? bitmapWidth : bitmapHeight);
-        float currentScale = bounds.height() / (float) bitmapHeight;
+        float cornerScale =
+                mCornerSizeX / (mOrientationPortrait ? bounds.width() : bounds.height());
+        final float currentScale = 1f;
 
         mScreenshotAnimatedView.setScaleX(currentScale);
         mScreenshotAnimatedView.setScaleY(currentScale);
 
-        mScreenshotAnimatedView.setPivotX(0);
-        mScreenshotAnimatedView.setPivotY(0);
+        mDismissButton.setAlpha(0);
+        mDismissButton.setVisibility(View.VISIBLE);
 
         AnimatorSet dropInAnimation = new AnimatorSet();
         ValueAnimator flashInAnimator = ValueAnimator.ofFloat(0, 1);
@@ -765,6 +786,8 @@
         toCorner.setDuration(SCREENSHOT_TO_CORNER_Y_DURATION_MS);
         float xPositionPct =
                 SCREENSHOT_TO_CORNER_X_DURATION_MS / (float) SCREENSHOT_TO_CORNER_Y_DURATION_MS;
+        float dismissPct =
+                SCREENSHOT_TO_CORNER_DISMISS_DELAY_MS / (float) SCREENSHOT_TO_CORNER_Y_DURATION_MS;
         float scalePct =
                 SCREENSHOT_TO_CORNER_SCALE_DURATION_MS / (float) SCREENSHOT_TO_CORNER_Y_DURATION_MS;
         toCorner.addUpdateListener(animation -> {
@@ -785,13 +808,26 @@
             if (t < xPositionPct) {
                 float xCenter = MathUtils.lerp(startPos.x, finalPos.x,
                         mFastOutSlowIn.getInterpolation(t / xPositionPct));
-                mScreenshotAnimatedView.setX(xCenter - bitmapWidth * currentScaleX / 2f);
+                mScreenshotAnimatedView.setX(xCenter - bounds.width() * currentScaleX / 2f);
             } else {
-                mScreenshotAnimatedView.setX(finalPos.x - bitmapWidth * currentScaleX / 2f);
+                mScreenshotAnimatedView.setX(finalPos.x - bounds.width() * currentScaleX / 2f);
             }
             float yCenter = MathUtils.lerp(
                     startPos.y, finalPos.y, mFastOutSlowIn.getInterpolation(t));
-            mScreenshotAnimatedView.setY(yCenter - bitmapHeight * currentScaleY / 2f);
+            mScreenshotAnimatedView.setY(yCenter - bounds.height() * currentScaleY / 2f);
+
+            if (t >= dismissPct) {
+                mDismissButton.setAlpha((t - dismissPct) / (1 - dismissPct));
+                float currentX = mScreenshotAnimatedView.getX();
+                float currentY = mScreenshotAnimatedView.getY();
+                mDismissButton.setY(currentY - mDismissButton.getHeight() / 2f);
+                if (mDirectionLTR) {
+                    mDismissButton.setX(currentX
+                            + bounds.width() * currentScaleX - mDismissButton.getWidth() / 2f);
+                } else {
+                    mDismissButton.setX(currentX - mDismissButton.getWidth() / 2f);
+                }
+            }
         });
 
         toCorner.addListener(new AnimatorListenerAdapter() {
@@ -805,20 +841,31 @@
         mScreenshotFlash.setAlpha(0f);
         mScreenshotFlash.setVisibility(View.VISIBLE);
 
-        dropInAnimation.play(flashOutAnimator).after(flashInAnimator);
-        dropInAnimation.play(flashOutAnimator).with(toCorner);
+        if (showFlash) {
+            dropInAnimation.play(flashOutAnimator).after(flashInAnimator);
+            dropInAnimation.play(flashOutAnimator).with(toCorner);
+        } else {
+            dropInAnimation.play(toCorner);
+        }
 
         dropInAnimation.addListener(new AnimatorListenerAdapter() {
             @Override
             public void onAnimationEnd(Animator animation) {
                 super.onAnimationEnd(animation);
+                mDismissButton.setAlpha(1);
+                float dismissOffset = mDismissButton.getWidth() / 2f;
+                float finalDismissX = mDirectionLTR
+                        ? finalPos.x - dismissOffset + bounds.width() * cornerScale / 2f
+                        : finalPos.x - dismissOffset - bounds.width() * cornerScale / 2f;
+                mDismissButton.setX(finalDismissX);
+                mDismissButton.setY(
+                        finalPos.y - dismissOffset - bounds.height() * cornerScale / 2f);
                 mScreenshotAnimatedView.setScaleX(1);
                 mScreenshotAnimatedView.setScaleY(1);
                 mScreenshotAnimatedView.setX(finalPos.x - bounds.width() * cornerScale / 2f);
                 mScreenshotAnimatedView.setY(finalPos.y - bounds.height() * cornerScale / 2f);
                 mScreenshotAnimatedView.setVisibility(View.GONE);
                 mScreenshotPreview.setVisibility(View.VISIBLE);
-                mDismissButton.setVisibility(View.VISIBLE);
                 mScreenshotLayout.forceLayout();
             }
         });
@@ -972,6 +1019,71 @@
         return animSet;
     }
 
+    private void setAnimatedViewSize(int width, int height) {
+        ViewGroup.LayoutParams layoutParams = mScreenshotAnimatedView.getLayoutParams();
+        layoutParams.width = width;
+        layoutParams.height = height;
+        mScreenshotAnimatedView.setLayoutParams(layoutParams);
+    }
+
+    /** Does the aspect ratio of the bitmap with insets removed match the bounds. */
+    private boolean aspectRatiosMatch(Bitmap bitmap, Insets bitmapInsets, Rect screenBounds) {
+        int insettedWidth = bitmap.getWidth() - bitmapInsets.left - bitmapInsets.right;
+        int insettedHeight = bitmap.getHeight() - bitmapInsets.top - bitmapInsets.bottom;
+
+        if (insettedHeight == 0 || insettedWidth == 0 || bitmap.getWidth() == 0
+                || bitmap.getHeight() == 0) {
+            Log.e(TAG, String.format(
+                    "Provided bitmap and insets create degenerate region: %dx%d %s",
+                    bitmap.getWidth(), bitmap.getHeight(), bitmapInsets));
+            return false;
+        }
+
+        float insettedBitmapAspect = ((float) insettedWidth) / insettedHeight;
+        float boundsAspect = ((float) screenBounds.width()) / screenBounds.height();
+
+        boolean matchWithinTolerance = Math.abs(insettedBitmapAspect - boundsAspect) < 0.1f;
+        if (!matchWithinTolerance) {
+            Log.d(TAG, String.format("aspectRatiosMatch: don't match bitmap: %f, bounds: %f",
+                    insettedBitmapAspect, boundsAspect));
+        }
+
+        return matchWithinTolerance;
+    }
+
+    /**
+     * Create a drawable using the size of the bitmap and insets as the fractional inset parameters.
+     */
+    private Drawable createScreenDrawable(Bitmap bitmap, Insets insets) {
+        int insettedWidth = bitmap.getWidth() - insets.left - insets.right;
+        int insettedHeight = bitmap.getHeight() - insets.top - insets.bottom;
+
+        BitmapDrawable bitmapDrawable = new BitmapDrawable(mContext.getResources(), bitmap);
+        if (insettedHeight == 0 || insettedWidth == 0 || bitmap.getWidth() == 0
+                || bitmap.getHeight() == 0) {
+            Log.e(TAG, String.format(
+                    "Can't create insetted drawable, using 0 insets "
+                            + "bitmap and insets create degenerate region: %dx%d %s",
+                    bitmap.getWidth(), bitmap.getHeight(), insets));
+            return bitmapDrawable;
+        }
+
+        InsetDrawable insetDrawable = new InsetDrawable(bitmapDrawable,
+                -1f * insets.left / insettedWidth,
+                -1f * insets.top / insettedHeight,
+                -1f * insets.right / insettedWidth,
+                -1f * insets.bottom / insettedHeight);
+
+        if (insets.left < 0 || insets.top < 0 || insets.right < 0 || insets.bottom < 0) {
+            // Are any of the insets negative, meaning the bitmap is smaller than the bounds so need
+            // to fill in the background of the drawable.
+            return new LayerDrawable(new Drawable[] {
+                    new ColorDrawable(Color.BLACK), insetDrawable});
+        } else {
+            return insetDrawable;
+        }
+    }
+
     /**
      * Receiver to proxy the share or edit intent, used to clean up the notification and send
      * appropriate signals to the system (ie. to dismiss the keyguard if necessary).
diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/GlobalScreenshotLegacy.java b/packages/SystemUI/src/com/android/systemui/screenshot/GlobalScreenshotLegacy.java
deleted file mode 100644
index 0017b1f..0000000
--- a/packages/SystemUI/src/com/android/systemui/screenshot/GlobalScreenshotLegacy.java
+++ /dev/null
@@ -1,567 +0,0 @@
-/*
- * Copyright (C) 2011 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.screenshot;
-
-import static android.view.WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS;
-
-import android.animation.Animator;
-import android.animation.AnimatorListenerAdapter;
-import android.animation.AnimatorSet;
-import android.animation.ValueAnimator;
-import android.animation.ValueAnimator.AnimatorUpdateListener;
-import android.annotation.Nullable;
-import android.content.ComponentName;
-import android.content.Context;
-import android.content.res.Configuration;
-import android.content.res.Resources;
-import android.graphics.Bitmap;
-import android.graphics.Color;
-import android.graphics.Insets;
-import android.graphics.PixelFormat;
-import android.graphics.PointF;
-import android.graphics.Rect;
-import android.media.MediaActionSound;
-import android.net.Uri;
-import android.os.AsyncTask;
-import android.os.PowerManager;
-import android.util.DisplayMetrics;
-import android.view.Display;
-import android.view.LayoutInflater;
-import android.view.MotionEvent;
-import android.view.SurfaceControl;
-import android.view.View;
-import android.view.ViewGroup;
-import android.view.WindowManager;
-import android.view.animation.Interpolator;
-import android.widget.ImageView;
-import android.widget.Toast;
-
-import com.android.systemui.R;
-import com.android.systemui.dagger.qualifiers.Main;
-
-import java.util.function.Consumer;
-
-import javax.inject.Inject;
-import javax.inject.Singleton;
-
-/**
- * Class for handling device screen shots
- *
- * @deprecated will be removed when corner flow is complete and tested
- */
-@Singleton
-@Deprecated
-public class GlobalScreenshotLegacy {
-
-    // These strings are used for communicating the action invoked to
-    // ScreenshotNotificationSmartActionsProvider.
-    static final String EXTRA_ACTION_TYPE = "android:screenshot_action_type";
-    static final String EXTRA_ID = "android:screenshot_id";
-    static final String ACTION_TYPE_DELETE = "Delete";
-    static final String ACTION_TYPE_SHARE = "Share";
-    static final String ACTION_TYPE_EDIT = "Edit";
-    static final String EXTRA_SMART_ACTIONS_ENABLED = "android:smart_actions_enabled";
-    static final String EXTRA_ACTION_INTENT = "android:screenshot_action_intent";
-
-    static final String SCREENSHOT_URI_ID = "android:screenshot_uri_id";
-    static final String EXTRA_CANCEL_NOTIFICATION = "android:screenshot_cancel_notification";
-    static final String EXTRA_DISALLOW_ENTER_PIP = "android:screenshot_disallow_enter_pip";
-
-    private static final String TAG = "GlobalScreenshot";
-
-    private static final int SCREENSHOT_FLASH_TO_PEAK_DURATION = 130;
-    private static final int SCREENSHOT_DROP_IN_DURATION = 430;
-    private static final int SCREENSHOT_DROP_OUT_DELAY = 500;
-    private static final int SCREENSHOT_DROP_OUT_DURATION = 430;
-    private static final int SCREENSHOT_DROP_OUT_SCALE_DURATION = 370;
-    private static final int SCREENSHOT_FAST_DROP_OUT_DURATION = 320;
-    private static final float BACKGROUND_ALPHA = 0.5f;
-    private static final float SCREENSHOT_SCALE = 1f;
-    private static final float SCREENSHOT_DROP_IN_MIN_SCALE = SCREENSHOT_SCALE * 0.725f;
-    private static final float SCREENSHOT_DROP_OUT_MIN_SCALE = SCREENSHOT_SCALE * 0.45f;
-    private static final float SCREENSHOT_FAST_DROP_OUT_MIN_SCALE = SCREENSHOT_SCALE * 0.6f;
-    private static final float SCREENSHOT_DROP_OUT_MIN_SCALE_OFFSET = 0f;
-
-    private final ScreenshotNotificationsController mNotificationsController;
-
-    private Context mContext;
-    private WindowManager mWindowManager;
-    private WindowManager.LayoutParams mWindowLayoutParams;
-    private Display mDisplay;
-    private DisplayMetrics mDisplayMetrics;
-
-    private Bitmap mScreenBitmap;
-    private View mScreenshotLayout;
-    private ScreenshotSelectorView mScreenshotSelectorView;
-    private ImageView mBackgroundView;
-    private ImageView mScreenshotView;
-    private ImageView mScreenshotFlash;
-
-    private AnimatorSet mScreenshotAnimation;
-
-    private float mBgPadding;
-    private float mBgPaddingScale;
-
-    private AsyncTask<Void, Void, Void> mSaveInBgTask;
-
-    private MediaActionSound mCameraSound;
-
-    /**
-     * @param context everything needs a context :(
-     */
-    @Inject
-    public GlobalScreenshotLegacy(
-            Context context, @Main Resources resources, LayoutInflater layoutInflater,
-            ScreenshotNotificationsController screenshotNotificationsController) {
-        mContext = context;
-        mNotificationsController = screenshotNotificationsController;
-
-        // Inflate the screenshot layout
-        mScreenshotLayout = layoutInflater.inflate(R.layout.global_screenshot_legacy, null);
-        mBackgroundView = mScreenshotLayout.findViewById(R.id.global_screenshot_legacy_background);
-        mScreenshotView = mScreenshotLayout.findViewById(R.id.global_screenshot_legacy);
-
-        mScreenshotFlash = mScreenshotLayout.findViewById(R.id.global_screenshot_legacy_flash);
-        mScreenshotSelectorView = mScreenshotLayout.findViewById(
-                R.id.global_screenshot_legacy_selector);
-        mScreenshotLayout.setFocusable(true);
-        mScreenshotSelectorView.setFocusable(true);
-        mScreenshotSelectorView.setFocusableInTouchMode(true);
-        mScreenshotLayout.setOnTouchListener((v, event) -> {
-            // Intercept and ignore all touch events
-            return true;
-        });
-
-        // Setup the window that we are going to use
-        mWindowLayoutParams = new WindowManager.LayoutParams(
-                ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT, 0, 0,
-                WindowManager.LayoutParams.TYPE_SCREENSHOT,
-                WindowManager.LayoutParams.FLAG_FULLSCREEN
-                        | WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN
-                        | WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED,
-                PixelFormat.TRANSLUCENT);
-        mWindowLayoutParams.setTitle("ScreenshotAnimation");
-        mWindowLayoutParams.layoutInDisplayCutoutMode = LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS;
-        mWindowLayoutParams.setFitInsetsTypes(0 /* types */);
-        mWindowManager = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
-        mDisplay = mWindowManager.getDefaultDisplay();
-        mDisplayMetrics = new DisplayMetrics();
-        mDisplay.getRealMetrics(mDisplayMetrics);
-
-        // Scale has to account for both sides of the bg
-        mBgPadding = (float) resources.getDimensionPixelSize(
-                R.dimen.global_screenshot_legacy_bg_padding);
-        mBgPaddingScale = mBgPadding / mDisplayMetrics.widthPixels;
-
-
-        // Setup the Camera shutter sound
-        mCameraSound = new MediaActionSound();
-        mCameraSound.load(MediaActionSound.SHUTTER_CLICK);
-    }
-
-    /**
-     * Creates a new worker thread and saves the screenshot to the media store.
-     */
-    private void saveScreenshotInWorkerThread(
-            Consumer<Uri> finisher,
-            @Nullable GlobalScreenshot.ActionsReadyListener actionsReadyListener) {
-        GlobalScreenshot.SaveImageInBackgroundData data =
-                new GlobalScreenshot.SaveImageInBackgroundData();
-        data.image = mScreenBitmap;
-        data.finisher = finisher;
-        data.mActionsReadyListener = actionsReadyListener;
-        data.createDeleteAction = true;
-        if (mSaveInBgTask != null) {
-            mSaveInBgTask.cancel(false);
-        }
-
-        mNotificationsController.reset();
-        mNotificationsController.setImage(mScreenBitmap);
-        mNotificationsController.showSavingScreenshotNotification();
-
-        mSaveInBgTask = new SaveImageInBackgroundTask(mContext, data).execute();
-    }
-
-    /**
-     * Takes a screenshot of the current display and shows an animation.
-     */
-    private void takeScreenshot(Consumer<Uri> finisher, boolean statusBarVisible,
-            boolean navBarVisible, Rect crop) {
-        int rot = mDisplay.getRotation();
-        int width = crop.width();
-        int height = crop.height();
-
-        takeScreenshot(SurfaceControl.screenshot(crop, width, height, rot), finisher,
-                statusBarVisible, navBarVisible, null);
-    }
-
-    private void takeScreenshot(Bitmap screenshot, Consumer<Uri> finisher, boolean statusBarVisible,
-            boolean navBarVisible, Rect screenboundsOfBitmap) {
-        mScreenBitmap = screenshot;
-        if (mScreenBitmap == null) {
-            mNotificationsController.notifyScreenshotError(
-                    R.string.screenshot_failed_to_capture_text);
-            finisher.accept(null);
-            return;
-        }
-
-        // Optimizations
-        mScreenBitmap.setHasAlpha(false);
-        mScreenBitmap.prepareToDraw();
-
-        // Start the post-screenshot animation
-        startAnimation(finisher, mDisplayMetrics.widthPixels, mDisplayMetrics.heightPixels,
-                statusBarVisible, navBarVisible, screenboundsOfBitmap);
-    }
-
-    void takeScreenshot(Consumer<Uri> finisher, boolean statusBarVisible, boolean navBarVisible) {
-        mDisplay.getRealMetrics(mDisplayMetrics);
-        takeScreenshot(finisher, statusBarVisible, navBarVisible,
-                new Rect(0, 0, mDisplayMetrics.widthPixels, mDisplayMetrics.heightPixels));
-    }
-
-    void handleImageAsScreenshot(Bitmap screenshot, Rect screenshotScreenBounds,
-            Insets visibleInsets, int taskId, int userId, ComponentName topComponent,
-            Consumer<Uri> finisher) {
-        // TODO: use task Id, userId, topComponent for smart handler
-        // TODO: use visibleInsets for animation
-        takeScreenshot(screenshot, finisher, false, false, screenshotScreenBounds);
-    }
-
-    /**
-     * Displays a screenshot selector
-     */
-    void takeScreenshotPartial(final Consumer<Uri> finisher, final boolean statusBarVisible,
-            final boolean navBarVisible) {
-        mWindowManager.addView(mScreenshotLayout, mWindowLayoutParams);
-        mScreenshotSelectorView.setOnTouchListener(new View.OnTouchListener() {
-            @Override
-            public boolean onTouch(View v, MotionEvent event) {
-                ScreenshotSelectorView view = (ScreenshotSelectorView) v;
-                switch (event.getAction()) {
-                    case MotionEvent.ACTION_DOWN:
-                        view.startSelection((int) event.getX(), (int) event.getY());
-                        return true;
-                    case MotionEvent.ACTION_MOVE:
-                        view.updateSelection((int) event.getX(), (int) event.getY());
-                        return true;
-                    case MotionEvent.ACTION_UP:
-                        view.setVisibility(View.GONE);
-                        mWindowManager.removeView(mScreenshotLayout);
-                        final Rect rect = view.getSelectionRect();
-                        if (rect != null) {
-                            if (rect.width() != 0 && rect.height() != 0) {
-                                // Need mScreenshotLayout to handle it after the view disappears
-                                mScreenshotLayout.post(() -> takeScreenshot(
-                                        finisher, statusBarVisible, navBarVisible, rect));
-                            }
-                        }
-
-                        view.stopSelection();
-                        return true;
-                }
-
-                return false;
-            }
-        });
-        mScreenshotLayout.post(() -> {
-            mScreenshotSelectorView.setVisibility(View.VISIBLE);
-            mScreenshotSelectorView.requestFocus();
-        });
-    }
-
-    /**
-     * Cancels screenshot request
-     */
-    void stopScreenshot() {
-        // If the selector layer still presents on screen, we remove it and resets its state.
-        if (mScreenshotSelectorView.getSelectionRect() != null) {
-            mWindowManager.removeView(mScreenshotLayout);
-            mScreenshotSelectorView.stopSelection();
-        }
-    }
-
-    /**
-     * Clears current screenshot
-     */
-    private void clearScreenshot() {
-        if (mScreenshotLayout.isAttachedToWindow()) {
-            mWindowManager.removeView(mScreenshotLayout);
-        }
-
-        // Clear any references to the bitmap
-        mScreenBitmap = null;
-        mScreenshotView.setImageBitmap(null);
-        mBackgroundView.setVisibility(View.GONE);
-        mScreenshotView.setVisibility(View.GONE);
-        mScreenshotView.setLayerType(View.LAYER_TYPE_NONE, null);
-    }
-
-    /**
-     * Starts the animation after taking the screenshot
-     */
-    private void startAnimation(final Consumer<Uri> finisher, int w, int h,
-            boolean statusBarVisible, boolean navBarVisible, @Nullable Rect screenBoundsOfBitmap) {
-        // If power save is on, show a toast so there is some visual indication that a screenshot
-        // has been taken.
-        PowerManager powerManager = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE);
-        if (powerManager.isPowerSaveMode()) {
-            Toast.makeText(mContext, R.string.screenshot_saved_title, Toast.LENGTH_SHORT).show();
-        }
-
-        // Add the view for the animation
-        mScreenshotView.setImageBitmap(mScreenBitmap);
-        mScreenshotLayout.requestFocus();
-
-        // Setup the animation with the screenshot just taken
-        if (mScreenshotAnimation != null) {
-            if (mScreenshotAnimation.isStarted()) {
-                mScreenshotAnimation.end();
-            }
-            mScreenshotAnimation.removeAllListeners();
-        }
-
-        mWindowManager.addView(mScreenshotLayout, mWindowLayoutParams);
-        ValueAnimator screenshotDropInAnim = screenBoundsOfBitmap != null
-                ? createRectAnimation(screenBoundsOfBitmap) : createScreenshotDropInAnimation();
-        ValueAnimator screenshotFadeOutAnim =
-                createScreenshotDropOutAnimation(w, h, statusBarVisible, navBarVisible);
-        mScreenshotAnimation = new AnimatorSet();
-        mScreenshotAnimation.playSequentially(screenshotDropInAnim, screenshotFadeOutAnim);
-        mScreenshotAnimation.addListener(new AnimatorListenerAdapter() {
-            @Override
-            public void onAnimationEnd(Animator animation) {
-                // Save the screenshot once we have a bit of time now
-                saveScreenshotInWorkerThread(finisher, new GlobalScreenshot.ActionsReadyListener() {
-                    @Override
-                    void onActionsReady(GlobalScreenshot.SavedImageData actionData) {
-                        if (actionData.uri == null) {
-                            mNotificationsController.notifyScreenshotError(
-                                    R.string.screenshot_failed_to_capture_text);
-                        } else {
-                            mNotificationsController
-                                    .showScreenshotActionsNotification(actionData);
-                        }
-                    }
-                });
-                clearScreenshot();
-            }
-        });
-        mScreenshotLayout.post(() -> {
-            // Play the shutter sound to notify that we've taken a screenshot
-            mCameraSound.play(MediaActionSound.SHUTTER_CLICK);
-
-            mScreenshotView.setLayerType(View.LAYER_TYPE_HARDWARE, null);
-            mScreenshotView.buildLayer();
-            mScreenshotAnimation.start();
-        });
-    }
-
-    private ValueAnimator createScreenshotDropInAnimation() {
-        final float flashPeakDurationPct = ((float) (SCREENSHOT_FLASH_TO_PEAK_DURATION)
-                / SCREENSHOT_DROP_IN_DURATION);
-        final float flashDurationPct = 2f * flashPeakDurationPct;
-        final Interpolator flashAlphaInterpolator = new Interpolator() {
-            @Override
-            public float getInterpolation(float x) {
-                // Flash the flash view in and out quickly
-                if (x <= flashDurationPct) {
-                    return (float) Math.sin(Math.PI * (x / flashDurationPct));
-                }
-                return 0;
-            }
-        };
-        final Interpolator scaleInterpolator = new Interpolator() {
-            @Override
-            public float getInterpolation(float x) {
-                // We start scaling when the flash is at it's peak
-                if (x < flashPeakDurationPct) {
-                    return 0;
-                }
-                return (x - flashDurationPct) / (1f - flashDurationPct);
-            }
-        };
-
-        Resources r = mContext.getResources();
-        if ((r.getConfiguration().uiMode & Configuration.UI_MODE_NIGHT_MASK)
-                == Configuration.UI_MODE_NIGHT_YES) {
-            mScreenshotView.getBackground().setTint(Color.BLACK);
-        } else {
-            mScreenshotView.getBackground().setTintList(null);
-        }
-
-        ValueAnimator anim = ValueAnimator.ofFloat(0f, 1f);
-        anim.setDuration(SCREENSHOT_DROP_IN_DURATION);
-        anim.addListener(new AnimatorListenerAdapter() {
-            @Override
-            public void onAnimationStart(Animator animation) {
-                mBackgroundView.setAlpha(0f);
-                mBackgroundView.setVisibility(View.VISIBLE);
-                mScreenshotView.setAlpha(0f);
-                mScreenshotView.setTranslationX(0f);
-                mScreenshotView.setTranslationY(0f);
-                mScreenshotView.setScaleX(SCREENSHOT_SCALE + mBgPaddingScale);
-                mScreenshotView.setScaleY(SCREENSHOT_SCALE + mBgPaddingScale);
-                mScreenshotView.setVisibility(View.VISIBLE);
-                mScreenshotFlash.setAlpha(0f);
-                mScreenshotFlash.setVisibility(View.VISIBLE);
-            }
-
-            @Override
-            public void onAnimationEnd(android.animation.Animator animation) {
-                mScreenshotFlash.setVisibility(View.GONE);
-            }
-        });
-        anim.addUpdateListener(new AnimatorUpdateListener() {
-            @Override
-            public void onAnimationUpdate(ValueAnimator animation) {
-                float t = (Float) animation.getAnimatedValue();
-                float scaleT = (SCREENSHOT_SCALE + mBgPaddingScale)
-                        - scaleInterpolator.getInterpolation(t)
-                        * (SCREENSHOT_SCALE - SCREENSHOT_DROP_IN_MIN_SCALE);
-                mBackgroundView.setAlpha(scaleInterpolator.getInterpolation(t) * BACKGROUND_ALPHA);
-                mScreenshotView.setAlpha(t);
-                mScreenshotView.setScaleX(scaleT);
-                mScreenshotView.setScaleY(scaleT);
-                mScreenshotFlash.setAlpha(flashAlphaInterpolator.getInterpolation(t));
-            }
-        });
-        return anim;
-    }
-
-    /**
-     * If a bitmap was supplied to be used as the screenshot, animated from where that bitmap was
-     * on screen, rather than using the whole screen.
-     */
-    private ValueAnimator createRectAnimation(Rect rect) {
-        mScreenshotView.setAdjustViewBounds(true);
-        mScreenshotView.setMaxHeight(rect.height());
-        mScreenshotView.setMaxWidth(rect.width());
-
-        final float flashPeakDurationPct = ((float) (SCREENSHOT_FLASH_TO_PEAK_DURATION)
-                / SCREENSHOT_DROP_IN_DURATION);
-        final float flashDurationPct = 2f * flashPeakDurationPct;
-        final Interpolator scaleInterpolator = x -> {
-            // We start scaling when the flash is at it's peak
-            if (x < flashPeakDurationPct) {
-                return 0;
-            }
-            return (x - flashDurationPct) / (1f - flashDurationPct);
-        };
-
-        ValueAnimator anim = ValueAnimator.ofFloat(0f, 1f);
-        anim.setDuration(SCREENSHOT_DROP_IN_DURATION);
-        anim.addListener(new AnimatorListenerAdapter() {
-            @Override
-            public void onAnimationStart(Animator animation) {
-                mBackgroundView.setAlpha(0f);
-                mBackgroundView.setVisibility(View.VISIBLE);
-                mScreenshotView.setAlpha(0f);
-                mScreenshotView.setElevation(0f);
-                mScreenshotView.setTranslationX(0f);
-                mScreenshotView.setTranslationY(0f);
-                mScreenshotView.setScaleX(SCREENSHOT_SCALE + mBgPaddingScale);
-                mScreenshotView.setScaleY(SCREENSHOT_SCALE + mBgPaddingScale);
-                mScreenshotView.setVisibility(View.VISIBLE);
-            }
-        });
-        anim.addUpdateListener(animation -> {
-            float t = (Float) animation.getAnimatedValue();
-            float scaleT = (SCREENSHOT_SCALE + mBgPaddingScale)
-                    - scaleInterpolator.getInterpolation(t)
-                    * (SCREENSHOT_SCALE - SCREENSHOT_DROP_IN_MIN_SCALE);
-            mBackgroundView.setAlpha(scaleInterpolator.getInterpolation(t) * BACKGROUND_ALPHA);
-            mScreenshotView.setAlpha(t);
-        });
-        return anim;
-    }
-
-    private ValueAnimator createScreenshotDropOutAnimation(int w, int h, boolean statusBarVisible,
-            boolean navBarVisible) {
-        ValueAnimator anim = ValueAnimator.ofFloat(0f, 1f);
-        anim.setStartDelay(SCREENSHOT_DROP_OUT_DELAY);
-        anim.addListener(new AnimatorListenerAdapter() {
-            @Override
-            public void onAnimationEnd(Animator animation) {
-                mBackgroundView.setVisibility(View.GONE);
-                mScreenshotView.setVisibility(View.GONE);
-                mScreenshotView.setLayerType(View.LAYER_TYPE_NONE, null);
-            }
-        });
-
-        if (!statusBarVisible || !navBarVisible) {
-            // There is no status bar/nav bar, so just fade the screenshot away in place
-            anim.setDuration(SCREENSHOT_FAST_DROP_OUT_DURATION);
-            anim.addUpdateListener(new AnimatorUpdateListener() {
-                @Override
-                public void onAnimationUpdate(ValueAnimator animation) {
-                    float t = (Float) animation.getAnimatedValue();
-                    float scaleT = (SCREENSHOT_DROP_IN_MIN_SCALE + mBgPaddingScale)
-                            - t * (SCREENSHOT_DROP_IN_MIN_SCALE
-                            - SCREENSHOT_FAST_DROP_OUT_MIN_SCALE);
-                    mBackgroundView.setAlpha((1f - t) * BACKGROUND_ALPHA);
-                    mScreenshotView.setAlpha(1f - t);
-                    mScreenshotView.setScaleX(scaleT);
-                    mScreenshotView.setScaleY(scaleT);
-                }
-            });
-        } else {
-            // In the case where there is a status bar, animate to the origin of the bar (top-left)
-            final float scaleDurationPct = (float) SCREENSHOT_DROP_OUT_SCALE_DURATION
-                    / SCREENSHOT_DROP_OUT_DURATION;
-            final Interpolator scaleInterpolator = new Interpolator() {
-                @Override
-                public float getInterpolation(float x) {
-                    if (x < scaleDurationPct) {
-                        // Decelerate, and scale the input accordingly
-                        return (float) (1f - Math.pow(1f - (x / scaleDurationPct), 2f));
-                    }
-                    return 1f;
-                }
-            };
-
-            // Determine the bounds of how to scale
-            float halfScreenWidth = (w - 2f * mBgPadding) / 2f;
-            float halfScreenHeight = (h - 2f * mBgPadding) / 2f;
-            final float offsetPct = SCREENSHOT_DROP_OUT_MIN_SCALE_OFFSET;
-            final PointF finalPos = new PointF(
-                    -halfScreenWidth
-                            + (SCREENSHOT_DROP_OUT_MIN_SCALE + offsetPct) * halfScreenWidth,
-                    -halfScreenHeight
-                            + (SCREENSHOT_DROP_OUT_MIN_SCALE + offsetPct) * halfScreenHeight);
-
-            // Animate the screenshot to the status bar
-            anim.setDuration(SCREENSHOT_DROP_OUT_DURATION);
-            anim.addUpdateListener(new AnimatorUpdateListener() {
-                @Override
-                public void onAnimationUpdate(ValueAnimator animation) {
-                    float t = (Float) animation.getAnimatedValue();
-                    float scaleT = (SCREENSHOT_DROP_IN_MIN_SCALE + mBgPaddingScale)
-                            - scaleInterpolator.getInterpolation(t)
-                            * (SCREENSHOT_DROP_IN_MIN_SCALE - SCREENSHOT_DROP_OUT_MIN_SCALE);
-                    mBackgroundView.setAlpha((1f - t) * BACKGROUND_ALPHA);
-                    mScreenshotView.setAlpha(1f - scaleInterpolator.getInterpolation(t));
-                    mScreenshotView.setScaleX(scaleT);
-                    mScreenshotView.setScaleY(scaleT);
-                    mScreenshotView.setTranslationX(t * finalPos.x);
-                    mScreenshotView.setTranslationY(t * finalPos.y);
-                }
-            });
-        }
-        return anim;
-    }
-}
diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/SaveImageInBackgroundTask.java b/packages/SystemUI/src/com/android/systemui/screenshot/SaveImageInBackgroundTask.java
index 221174f..10e6902 100644
--- a/packages/SystemUI/src/com/android/systemui/screenshot/SaveImageInBackgroundTask.java
+++ b/packages/SystemUI/src/com/android/systemui/screenshot/SaveImageInBackgroundTask.java
@@ -88,7 +88,6 @@
     private final ScreenshotNotificationSmartActionsProvider mSmartActionsProvider;
     private final String mScreenshotId;
     private final boolean mSmartActionsEnabled;
-    private final boolean mCreateDeleteAction;
     private final Random mRandom = new Random();
 
     SaveImageInBackgroundTask(Context context, GlobalScreenshot.SaveImageInBackgroundData data) {
@@ -102,8 +101,6 @@
         mImageFileName = String.format(SCREENSHOT_FILE_NAME_TEMPLATE, imageDate);
         mScreenshotId = String.format(SCREENSHOT_ID_TEMPLATE, UUID.randomUUID());
 
-        mCreateDeleteAction = data.createDeleteAction;
-
         // Initialize screenshot notification smart actions provider.
         mSmartActionsEnabled = DeviceConfig.getBoolean(DeviceConfig.NAMESPACE_SYSTEMUI,
                 SystemUiDeviceConfigFlags.ENABLE_SCREENSHOT_NOTIFICATION_SMART_ACTIONS, true);
diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/TakeScreenshotService.java b/packages/SystemUI/src/com/android/systemui/screenshot/TakeScreenshotService.java
index 8322fe0..c05c823 100644
--- a/packages/SystemUI/src/com/android/systemui/screenshot/TakeScreenshotService.java
+++ b/packages/SystemUI/src/com/android/systemui/screenshot/TakeScreenshotService.java
@@ -48,7 +48,6 @@
     private static final String TAG = "TakeScreenshotService";
 
     private final GlobalScreenshot mScreenshot;
-    private final GlobalScreenshotLegacy mScreenshotLegacy;
     private final UserManager mUserManager;
     private final UiEventLogger mUiEventLogger;
 
@@ -81,9 +80,6 @@
                 return;
             }
 
-            // TODO: clean up once notifications flow is fully deprecated
-            boolean useCornerFlow = true;
-
             ScreenshotHelper.ScreenshotRequest screenshotRequest =
                     (ScreenshotHelper.ScreenshotRequest) msg.obj;
 
@@ -91,22 +87,10 @@
 
             switch (msg.what) {
                 case WindowManager.TAKE_SCREENSHOT_FULLSCREEN:
-                    if (useCornerFlow) {
-                        mScreenshot.takeScreenshot(uriConsumer, onComplete);
-                    } else {
-                        mScreenshotLegacy.takeScreenshot(
-                                uriConsumer, screenshotRequest.getHasStatusBar(),
-                                screenshotRequest.getHasNavBar());
-                    }
+                    mScreenshot.takeScreenshot(uriConsumer, onComplete);
                     break;
                 case WindowManager.TAKE_SCREENSHOT_SELECTED_REGION:
-                    if (useCornerFlow) {
-                        mScreenshot.takeScreenshotPartial(uriConsumer, onComplete);
-                    } else {
-                        mScreenshotLegacy.takeScreenshotPartial(
-                                uriConsumer, screenshotRequest.getHasStatusBar(),
-                                screenshotRequest.getHasNavBar());
-                    }
+                    mScreenshot.takeScreenshotPartial(uriConsumer, onComplete);
                     break;
                 case WindowManager.TAKE_SCREENSHOT_PROVIDED_IMAGE:
                     Bitmap screenshot = BitmapUtil.bundleToHardwareBitmap(
@@ -116,13 +100,8 @@
                     int taskId = screenshotRequest.getTaskId();
                     int userId = screenshotRequest.getUserId();
                     ComponentName topComponent = screenshotRequest.getTopComponent();
-                    if (useCornerFlow) {
-                        mScreenshot.handleImageAsScreenshot(screenshot, screenBounds, insets,
-                                taskId, userId, topComponent, uriConsumer, onComplete);
-                    } else {
-                        mScreenshotLegacy.handleImageAsScreenshot(screenshot, screenBounds, insets,
-                                taskId, userId, topComponent, uriConsumer);
-                    }
+                    mScreenshot.handleImageAsScreenshot(screenshot, screenBounds, insets,
+                            taskId, userId, topComponent, uriConsumer, onComplete);
                     break;
                 default:
                     Log.d(TAG, "Invalid screenshot option: " + msg.what);
@@ -131,11 +110,9 @@
     };
 
     @Inject
-    public TakeScreenshotService(GlobalScreenshot globalScreenshot,
-            GlobalScreenshotLegacy globalScreenshotLegacy, UserManager userManager,
+    public TakeScreenshotService(GlobalScreenshot globalScreenshot, UserManager userManager,
             UiEventLogger uiEventLogger) {
         mScreenshot = globalScreenshot;
-        mScreenshotLegacy = globalScreenshotLegacy;
         mUserManager = userManager;
         mUiEventLogger = uiEventLogger;
     }
@@ -148,8 +125,6 @@
     @Override
     public boolean onUnbind(Intent intent) {
         if (mScreenshot != null) mScreenshot.stopScreenshot();
-        // TODO remove once notifications flow is fully deprecated
-        if (mScreenshotLegacy != null) mScreenshotLegacy.stopScreenshot();
         return true;
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/stackdivider/WindowManagerProxy.java b/packages/SystemUI/src/com/android/systemui/stackdivider/WindowManagerProxy.java
index c8361c6..853a225 100644
--- a/packages/SystemUI/src/com/android/systemui/stackdivider/WindowManagerProxy.java
+++ b/packages/SystemUI/src/com/android/systemui/stackdivider/WindowManagerProxy.java
@@ -229,7 +229,11 @@
         // as a result, the above will not capture any tasks; yet, we need to clean-up the
         // home task bounds.
         List<ActivityManager.RunningTaskInfo> freeHomeAndRecents =
-                TaskOrganizer.getRootTasks(Display.DEFAULT_DISPLAY, HOME_AND_RECENTS);
+                TaskOrganizer.getRootTasks(DEFAULT_DISPLAY, HOME_AND_RECENTS);
+        // Filter out the root split tasks
+        freeHomeAndRecents.removeIf(p -> p.token.equals(tiles.mSecondary.token)
+                || p.token.equals(tiles.mPrimary.token));
+
         if (primaryChildren.isEmpty() && secondaryChildren.isEmpty()
                 && freeHomeAndRecents.isEmpty()) {
             return;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationListener.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationListener.java
index 72d9d0e..4d09071 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationListener.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationListener.java
@@ -104,6 +104,9 @@
                     listener.onNotificationPosted(sbn, completeMap);
                 }
             }
+            for (NotificationHandler listener : mNotificationHandlers) {
+                listener.onNotificationsInitialized();
+            }
         });
         onSilentStatusBarIconsVisibilityChanged(
                 mNotificationManager.shouldHideSilentStatusBarIcons());
@@ -224,5 +227,10 @@
         void onNotificationRemoved(StatusBarNotification sbn, RankingMap rankingMap);
         void onNotificationRemoved(StatusBarNotification sbn, RankingMap rankingMap, int reason);
         void onNotificationRankingUpdate(RankingMap rankingMap);
+
+        /**
+         * Called after the listener has connected to NoMan and posted any current notifications.
+         */
+        void onNotificationsInitialized();
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationViewHierarchyManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationViewHierarchyManager.java
index a8c0324..5bee9a7 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationViewHierarchyManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationViewHierarchyManager.java
@@ -60,7 +60,11 @@
 
     private final Handler mHandler;
 
-    /** Re-usable map of top-level notifications to their sorted children if any.*/
+    /**
+     * Re-usable map of top-level notifications to their sorted children if any.
+     * If the top-level notification doesn't have children, its key will still exist in this map
+     * with its value explicitly set to null.
+     */
     private final HashMap<NotificationEntry, List<NotificationEntry>> mTmpChildOrderMap =
             new HashMap<>();
 
@@ -212,10 +216,19 @@
                 }
                 orderedChildren.add(ent);
             } else {
-                // Top-level notif
-                mTmpChildOrderMap.put(ent, null);
+                // Top-level notif (either a summary or single notification)
+
+                // A child may have already added its summary to mTmpChildOrderMap with a
+                // list of children. This can happen since there's no guarantee summaries are
+                // sorted before its children.
+                if (!mTmpChildOrderMap.containsKey(ent)) {
+                    // mTmpChildOrderMap's keyset is used to iterate through all entries, so it's
+                    // necessary to add each top-level notif as a key
+                    mTmpChildOrderMap.put(ent, null);
+                }
                 toShow.add(ent.getRow());
             }
+
         }
 
         ArrayList<ExpandableNotificationRow> viewsToRemove = new ArrayList<>();
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/ActivityLaunchAnimator.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/ActivityLaunchAnimator.java
index 6aef6b4..6a33024 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/ActivityLaunchAnimator.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/ActivityLaunchAnimator.java
@@ -41,6 +41,8 @@
 import com.android.systemui.statusbar.phone.NotificationPanelViewController;
 import com.android.systemui.statusbar.phone.NotificationShadeWindowViewController;
 
+import java.util.concurrent.Executor;
+
 /**
  * A class that allows activities to be launched in a seamless way where the notification
  * transforms nicely into the starting window.
@@ -59,6 +61,7 @@
     private final float mWindowCornerRadius;
     private final NotificationShadeWindowViewController mNotificationShadeWindowViewController;
     private final NotificationShadeDepthController mDepthController;
+    private final Executor mMainExecutor;
     private Callback mCallback;
     private final Runnable mTimeoutRunnable = () -> {
         setAnimationPending(false);
@@ -73,12 +76,14 @@
             Callback callback,
             NotificationPanelViewController notificationPanel,
             NotificationShadeDepthController depthController,
-            NotificationListContainer container) {
+            NotificationListContainer container,
+            Executor mainExecutor) {
         mNotificationPanel = notificationPanel;
         mNotificationContainer = container;
         mDepthController = depthController;
         mNotificationShadeWindowViewController = notificationShadeWindowViewController;
         mCallback = callback;
+        mMainExecutor = mainExecutor;
         mWindowCornerRadius = ScreenDecorationsUtils
                 .getWindowCornerRadius(mNotificationShadeWindowViewController.getView()
                         .getResources());
@@ -155,7 +160,7 @@
                 RemoteAnimationTarget[] remoteAnimationWallpaperTargets,
                 IRemoteAnimationFinishedCallback iRemoteAnimationFinishedCallback)
                     throws RemoteException {
-            mSourceNotification.post(() -> {
+            mMainExecutor.execute(() -> {
                 RemoteAnimationTarget primary = getPrimaryRemoteAnimationTarget(
                         remoteAnimationTargets);
                 if (primary == null) {
@@ -191,8 +196,9 @@
                     }
                 }
                 int targetWidth = primary.sourceContainerBounds.width();
-                int notificationHeight = mSourceNotification.getActualHeight()
-                        - mSourceNotification.getClipBottomAmount();
+                // If the notification panel is collapsed, the clip may be larger than the height.
+                int notificationHeight = Math.max(mSourceNotification.getActualHeight()
+                        - mSourceNotification.getClipBottomAmount(), 0);
                 int notificationWidth = mSourceNotification.getWidth();
                 anim.setDuration(ANIMATION_DURATION);
                 anim.setInterpolator(Interpolators.LINEAR);
@@ -292,7 +298,7 @@
 
         @Override
         public void onAnimationCancelled() throws RemoteException {
-            mSourceNotification.post(() -> {
+            mMainExecutor.execute(() -> {
                 setAnimationPending(false);
                 mCallback.onLaunchAnimationCancelled();
             });
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/ConversationNotifications.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/ConversationNotifications.kt
index fc6c2be..1972b86 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/ConversationNotifications.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/ConversationNotifications.kt
@@ -19,13 +19,16 @@
 import android.app.Notification
 import android.content.Context
 import android.content.pm.LauncherApps
+import android.os.Handler
 import android.service.notification.NotificationListenerService.Ranking
 import android.service.notification.NotificationListenerService.RankingMap
 import com.android.internal.statusbar.NotificationVisibility
 import com.android.internal.widget.ConversationLayout
+import com.android.systemui.dagger.qualifiers.Main
 import com.android.systemui.statusbar.notification.collection.NotificationEntry
 import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow
 import com.android.systemui.statusbar.notification.row.NotificationContentView
+import com.android.systemui.statusbar.notification.stack.StackStateAnimator
 import com.android.systemui.statusbar.phone.NotificationGroupManager
 import java.util.concurrent.ConcurrentHashMap
 import javax.inject.Inject
@@ -62,7 +65,8 @@
 class ConversationNotificationManager @Inject constructor(
     private val notificationEntryManager: NotificationEntryManager,
     private val notificationGroupManager: NotificationGroupManager,
-    private val context: Context
+    private val context: Context,
+    @Main private val mainHandler: Handler
 ) {
     // Need this state to be thread safe, since it's accessed from the ui thread
     // (NotificationEntryListener) and a bg thread (NotificationContentInflater)
@@ -72,32 +76,41 @@
 
     init {
         notificationEntryManager.addNotificationEntryListener(object : NotificationEntryListener {
-
             override fun onNotificationRankingUpdated(rankingMap: RankingMap) {
                 fun getLayouts(view: NotificationContentView) =
                         sequenceOf(view.contractedChild, view.expandedChild, view.headsUpChild)
                 val ranking = Ranking()
-                states.keys.asSequence()
+                val activeConversationEntries = states.keys.asSequence()
                         .mapNotNull { notificationEntryManager.getActiveNotificationUnfiltered(it) }
-                        .forEach { entry ->
-                            if (rankingMap.getRanking(entry.sbn.key, ranking) &&
-                                    ranking.isConversation) {
-                                val important = ranking.channel.isImportantConversation
-                                var changed = false
-                                entry.row?.layouts?.asSequence()
-                                        ?.flatMap(::getLayouts)
-                                        ?.mapNotNull { it as? ConversationLayout }
-                                        ?.forEach {
-                                            if (important != it.isImportantConversation) {
-                                                it.setIsImportantConversation(important)
-                                                changed = true
-                                            }
-                                        }
-                                if (changed) {
-                                    notificationGroupManager.updateIsolation(entry)
-                                }
+                for (entry in activeConversationEntries) {
+                    if (rankingMap.getRanking(entry.sbn.key, ranking) && ranking.isConversation) {
+                        val important = ranking.channel.isImportantConversation
+                        val layouts = entry.row?.layouts?.asSequence()
+                                ?.flatMap(::getLayouts)
+                                ?.mapNotNull { it as? ConversationLayout }
+                                ?: emptySequence()
+                        var changed = false
+                        for (layout in layouts) {
+                            if (important == layout.isImportantConversation) {
+                                continue
+                            }
+                            changed = true
+                            if (important && entry.isMarkedForUserTriggeredMovement) {
+                                // delay this so that it doesn't animate in until after
+                                // the notif has been moved in the shade
+                                mainHandler.postDelayed({
+                                    layout.setIsImportantConversation(
+                                            important, true /* animate */)
+                                }, IMPORTANCE_ANIMATION_DELAY.toLong())
+                            } else {
+                                layout.setIsImportantConversation(important)
                             }
                         }
+                        if (changed) {
+                            notificationGroupManager.updateIsolation(entry)
+                        }
+                    }
+                }
             }
 
             override fun onEntryInflated(entry: NotificationEntry) {
@@ -177,9 +190,16 @@
 
     private fun resetBadgeUi(row: ExpandableNotificationRow): Unit =
             (row.layouts?.asSequence() ?: emptySequence())
-                    .flatMap { layout -> layout.allViews.asSequence()}
+                    .flatMap { layout -> layout.allViews.asSequence() }
                     .mapNotNull { view -> view as? ConversationLayout }
                     .forEach { convoLayout -> convoLayout.setUnreadCount(0) }
 
     private data class ConversationState(val unreadCount: Int, val notification: Notification)
+
+    companion object {
+        private const val IMPORTANCE_ANIMATION_DELAY =
+                StackStateAnimator.ANIMATION_DURATION_STANDARD +
+                StackStateAnimator.ANIMATION_DURATION_PRIORITY_CHANGE +
+                100
+    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationEntryManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationEntryManager.java
index adb51a5..9abc660 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationEntryManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationEntryManager.java
@@ -385,6 +385,10 @@
         public void onNotificationRankingUpdate(RankingMap rankingMap) {
             updateNotificationRanking(rankingMap);
         }
+
+        @Override
+        public void onNotificationsInitialized() {
+        }
     };
 
     /**
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotifCollection.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotifCollection.java
index 45987b6..c1acfbad 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotifCollection.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotifCollection.java
@@ -47,7 +47,6 @@
 import android.annotation.UserIdInt;
 import android.app.Notification;
 import android.os.RemoteException;
-import android.os.SystemClock;
 import android.os.UserHandle;
 import android.service.notification.NotificationListenerService;
 import android.service.notification.NotificationListenerService.Ranking;
@@ -82,6 +81,7 @@
 import com.android.systemui.statusbar.notification.collection.notifcollection.RankingAppliedEvent;
 import com.android.systemui.statusbar.notification.collection.notifcollection.RankingUpdatedEvent;
 import com.android.systemui.util.Assert;
+import com.android.systemui.util.time.SystemClock;
 
 import java.io.FileDescriptor;
 import java.io.PrintWriter;
@@ -95,6 +95,7 @@
 import java.util.Map;
 import java.util.Objects;
 import java.util.Queue;
+import java.util.concurrent.TimeUnit;
 
 import javax.inject.Inject;
 import javax.inject.Singleton;
@@ -125,6 +126,7 @@
 @Singleton
 public class NotifCollection implements Dumpable {
     private final IStatusBarService mStatusBarService;
+    private final SystemClock mClock;
     private final FeatureFlags mFeatureFlags;
     private final NotifCollectionLogger mLogger;
     private final LogBufferEulogizer mEulogizer;
@@ -142,20 +144,24 @@
 
     private boolean mAttached = false;
     private boolean mAmDispatchingToOtherCode;
+    private long mInitializedTimestamp = 0;
 
     @Inject
     public NotifCollection(
             IStatusBarService statusBarService,
-            DumpManager dumpManager,
+            SystemClock clock,
             FeatureFlags featureFlags,
             NotifCollectionLogger logger,
-            LogBufferEulogizer logBufferEulogizer) {
+            LogBufferEulogizer logBufferEulogizer,
+            DumpManager dumpManager) {
         Assert.isMainThread();
         mStatusBarService = statusBarService;
+        mClock = clock;
+        mFeatureFlags = featureFlags;
         mLogger = logger;
         mEulogizer = logBufferEulogizer;
+
         dumpManager.registerDumpable(TAG, this);
-        mFeatureFlags = featureFlags;
     }
 
     /** Initializes the NotifCollection and registers it to receive notification events. */
@@ -376,9 +382,10 @@
 
         final NotificationEntry entry = mNotificationSet.get(sbn.getKey());
         if (entry == null) {
-            throw mEulogizer.record(
+            crashIfNotInitializing(
                     new IllegalStateException("No notification to remove with key "
                             + sbn.getKey()));
+            return;
         }
 
         entry.mCancellationReason = reason;
@@ -394,6 +401,10 @@
         dispatchEventsAndRebuildList();
     }
 
+    private void onNotificationsInitialized() {
+        mInitializedTimestamp = mClock.uptimeMillis();
+    }
+
     private void postNotification(
             StatusBarNotification sbn,
             Ranking ranking) {
@@ -401,7 +412,7 @@
 
         if (entry == null) {
             // A new notification!
-            entry = new NotificationEntry(sbn, ranking, SystemClock.uptimeMillis());
+            entry = new NotificationEntry(sbn, ranking, mClock.uptimeMillis());
             mEventQueue.add(new InitEntryEvent(entry));
             mEventQueue.add(new BindEntryEvent(entry, sbn));
             mNotificationSet.put(sbn.getKey(), entry);
@@ -628,6 +639,23 @@
         }
     }
 
+    // While the NotificationListener is connecting to NotificationManager, there is a short period
+    // during which it's possible for us to receive events about notifications we don't yet know
+    // about (or that otherwise don't make sense). Until that race condition is fixed, we create a
+    // "forgiveness window" of five seconds during which we won't crash if we receive nonsensical
+    // messages from system server.
+    private void crashIfNotInitializing(RuntimeException exception) {
+        final boolean isRecentlyInitialized = mInitializedTimestamp == 0
+                || mClock.uptimeMillis() - mInitializedTimestamp
+                        < INITIALIZATION_FORGIVENESS_WINDOW;
+
+        if (isRecentlyInitialized) {
+            mLogger.logIgnoredError(exception.getMessage());
+        } else {
+            throw mEulogizer.record(exception);
+        }
+    }
+
     private static Ranking requireRanking(RankingMap rankingMap, String key) {
         // TODO: Modify RankingMap so that we don't have to make a copy here
         Ranking ranking = new Ranking();
@@ -742,6 +770,11 @@
         public void onNotificationRankingUpdate(RankingMap rankingMap) {
             NotifCollection.this.onNotificationRankingUpdate(rankingMap);
         }
+
+        @Override
+        public void onNotificationsInitialized() {
+            NotifCollection.this.onNotificationsInitialized();
+        }
     };
 
     private static final String TAG = "NotifCollection";
@@ -773,4 +806,6 @@
 
     static final int REASON_NOT_CANCELED = -1;
     public static final int REASON_UNKNOWN = 0;
+
+    private static final long INITIALIZATION_FORGIVENESS_WINDOW = TimeUnit.SECONDS.toMillis(5);
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coalescer/GroupCoalescer.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coalescer/GroupCoalescer.java
index 596235c..1710daa 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coalescer/GroupCoalescer.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coalescer/GroupCoalescer.java
@@ -153,6 +153,11 @@
             applyRanking(rankingMap);
             mHandler.onNotificationRankingUpdate(rankingMap);
         }
+
+        @Override
+        public void onNotificationsInitialized() {
+            mHandler.onNotificationsInitialized();
+        }
     };
 
     private void maybeEmitBatch(StatusBarNotification sbn) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/notifcollection/NotifCollectionLogger.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/notifcollection/NotifCollectionLogger.kt
index 0eb2d64..76751ea 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/notifcollection/NotifCollectionLogger.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/notifcollection/NotifCollectionLogger.kt
@@ -20,6 +20,7 @@
 import android.service.notification.NotificationListenerService.RankingMap
 import com.android.systemui.log.LogBuffer
 import com.android.systemui.log.LogLevel.DEBUG
+import com.android.systemui.log.LogLevel.ERROR
 import com.android.systemui.log.LogLevel.INFO
 import com.android.systemui.log.LogLevel.WARNING
 import com.android.systemui.log.LogLevel.WTF
@@ -167,6 +168,14 @@
             "LIFETIME EXTENSION ENDED for $str1 by '$str2'; $int1 remaining extensions"
         })
     }
+
+    fun logIgnoredError(message: String?) {
+        buffer.log(TAG, ERROR, {
+            str1 = message
+        }, {
+            "ERROR suppressed due to initialization forgiveness: $str1"
+        })
+    }
 }
 
 private const val TAG = "NotifCollection"
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/provider/HighPriorityProvider.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/provider/HighPriorityProvider.java
index df3609b..1c076c4 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/provider/HighPriorityProvider.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/provider/HighPriorityProvider.java
@@ -23,6 +23,9 @@
 import com.android.systemui.statusbar.notification.collection.ListEntry;
 import com.android.systemui.statusbar.notification.collection.NotificationEntry;
 import com.android.systemui.statusbar.notification.people.PeopleNotificationIdentifier;
+import com.android.systemui.statusbar.phone.NotificationGroupManager;
+
+import java.util.List;
 
 import javax.inject.Inject;
 import javax.inject.Singleton;
@@ -36,10 +39,14 @@
 @Singleton
 public class HighPriorityProvider {
     private final PeopleNotificationIdentifier mPeopleNotificationIdentifier;
+    private final NotificationGroupManager mGroupManager;
 
     @Inject
-    public HighPriorityProvider(PeopleNotificationIdentifier peopleNotificationIdentifier) {
+    public HighPriorityProvider(
+            PeopleNotificationIdentifier peopleNotificationIdentifier,
+            NotificationGroupManager groupManager) {
         mPeopleNotificationIdentifier = peopleNotificationIdentifier;
+        mGroupManager = groupManager;
     }
 
     /**
@@ -74,13 +81,25 @@
 
 
     private boolean hasHighPriorityChild(ListEntry entry) {
+        List<NotificationEntry> children = null;
+
         if (entry instanceof GroupEntry) {
-            for (NotificationEntry child : ((GroupEntry) entry).getChildren()) {
+            // New notification pipeline
+            children = ((GroupEntry) entry).getChildren();
+        } else if (entry.getRepresentativeEntry() != null
+                && mGroupManager.isGroupSummary(entry.getRepresentativeEntry().getSbn())) {
+            // Old notification pipeline
+            children = mGroupManager.getChildren(entry.getRepresentativeEntry().getSbn());
+        }
+
+        if (children != null) {
+            for (NotificationEntry child : children) {
                 if (isHighPriority(child)) {
                     return true;
                 }
             }
         }
+
         return false;
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/icon/IconManager.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/icon/IconManager.kt
index 08be4f8..011ad19 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/icon/IconManager.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/icon/IconManager.kt
@@ -255,23 +255,11 @@
 
     @Throws(InflationException::class)
     private fun createPeopleAvatar(entry: NotificationEntry): Icon? {
-        // Attempt to extract form shortcut.
-        val conversationId = entry.ranking.channel.conversationId
-        val query = LauncherApps.ShortcutQuery()
-                .setPackage(entry.sbn.packageName)
-                .setQueryFlags(
-                        LauncherApps.ShortcutQuery.FLAG_MATCH_DYNAMIC
-                                or LauncherApps.ShortcutQuery.FLAG_MATCH_PINNED)
-                .setShortcutIds(listOf(conversationId))
-        val shortcuts = launcherApps.getShortcuts(query, entry.sbn.user)
         var ic: Icon? = null
-        if (shortcuts != null && shortcuts.isNotEmpty()) {
-            ic = shortcuts[0].icon
-        }
 
-        // Fall back to notification large icon if available
-        if (ic == null) {
-            ic = entry.sbn.notification.getLargeIcon()
+        val shortcut = entry.ranking.shortcutInfo
+        if (shortcut != null) {
+            ic = launcherApps.getShortcutIcon(shortcut)
         }
 
         // Fall back to extract from message
@@ -290,6 +278,11 @@
             }
         }
 
+        // Fall back to notification large icon if available
+        if (ic == null) {
+            ic = entry.sbn.notification.getLargeIcon()
+        }
+
         // Revert to small icon if still not available
         if (ic == null) {
             ic = entry.sbn.notification.smallIcon
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/logging/NotificationLogger.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/logging/NotificationLogger.java
index ad04788..bd0d0b3 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/logging/NotificationLogger.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/logging/NotificationLogger.java
@@ -29,6 +29,7 @@
 
 import androidx.annotation.Nullable;
 
+import com.android.internal.annotations.GuardedBy;
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.statusbar.IStatusBarService;
 import com.android.internal.statusbar.NotificationVisibility;
@@ -36,6 +37,7 @@
 import com.android.systemui.plugins.statusbar.StatusBarStateController;
 import com.android.systemui.plugins.statusbar.StatusBarStateController.StateListener;
 import com.android.systemui.statusbar.NotificationListener;
+import com.android.systemui.statusbar.StatusBarState;
 import com.android.systemui.statusbar.notification.NotificationEntryListener;
 import com.android.systemui.statusbar.notification.NotificationEntryManager;
 import com.android.systemui.statusbar.notification.collection.NotificationEntry;
@@ -58,6 +60,7 @@
  */
 public class NotificationLogger implements StateListener {
     private static final String TAG = "NotificationLogger";
+    private static final boolean DEBUG = false;
 
     /** The minimum delay in ms between reports of notification visibility. */
     private static final int VISIBILITY_REPORT_MIN_DELAY_MS = 500;
@@ -79,7 +82,12 @@
     private long mLastVisibilityReportUptimeMs;
     private NotificationListContainer mListContainer;
     private final Object mDozingLock = new Object();
-    private boolean mDozing;
+    @GuardedBy("mDozingLock")
+    private Boolean mDozing = null;  // Use null to indicate state is not yet known
+    @GuardedBy("mDozingLock")
+    private Boolean mLockscreen = null;  // Use null to indicate state is not yet known
+    private Boolean mPanelExpanded = null;  // Use null to indicate state is not yet known
+    private boolean mLogging = false;
 
     protected final OnChildLocationsChangedListener mNotificationLocationsChangedListener =
             new OnChildLocationsChangedListener() {
@@ -247,33 +255,44 @@
     }
 
     public void stopNotificationLogging() {
-        // Report all notifications as invisible and turn down the
-        // reporter.
-        if (!mCurrentlyVisibleNotifications.isEmpty()) {
-            logNotificationVisibilityChanges(
-                    Collections.emptyList(), mCurrentlyVisibleNotifications);
-            recycleAllVisibilityObjects(mCurrentlyVisibleNotifications);
+        if (mLogging) {
+            mLogging = false;
+            if (DEBUG) {
+                Log.i(TAG, "stopNotificationLogging: log notifications invisible");
+            }
+            // Report all notifications as invisible and turn down the
+            // reporter.
+            if (!mCurrentlyVisibleNotifications.isEmpty()) {
+                logNotificationVisibilityChanges(
+                        Collections.emptyList(), mCurrentlyVisibleNotifications);
+                recycleAllVisibilityObjects(mCurrentlyVisibleNotifications);
+            }
+            mHandler.removeCallbacks(mVisibilityReporter);
+            mListContainer.setChildLocationsChangedListener(null);
         }
-        mHandler.removeCallbacks(mVisibilityReporter);
-        mListContainer.setChildLocationsChangedListener(null);
     }
 
     public void startNotificationLogging() {
-        mListContainer.setChildLocationsChangedListener(mNotificationLocationsChangedListener);
-        // Some transitions like mVisibleToUser=false -> mVisibleToUser=true don't
-        // cause the scroller to emit child location events. Hence generate
-        // one ourselves to guarantee that we're reporting visible
-        // notifications.
-        // (Note that in cases where the scroller does emit events, this
-        // additional event doesn't break anything.)
-        mNotificationLocationsChangedListener.onChildLocationsChanged();
-        mNotificationPanelLogger.logPanelShown(mListContainer.hasPulsingNotifications(),
-                mEntryManager.getVisibleNotifications());
+        if (!mLogging) {
+            mLogging = true;
+            if (DEBUG) {
+                Log.i(TAG, "startNotificationLogging");
+            }
+            mListContainer.setChildLocationsChangedListener(mNotificationLocationsChangedListener);
+            // Some transitions like mVisibleToUser=false -> mVisibleToUser=true don't
+            // cause the scroller to emit child location events. Hence generate
+            // one ourselves to guarantee that we're reporting visible
+            // notifications.
+            // (Note that in cases where the scroller does emit events, this
+            // additional event doesn't break anything.)
+            mNotificationLocationsChangedListener.onChildLocationsChanged();
+        }
     }
 
     private void setDozing(boolean dozing) {
         synchronized (mDozingLock) {
             mDozing = dozing;
+            maybeUpdateLoggingStatus();
         }
     }
 
@@ -343,19 +362,12 @@
                 for (int i = 0; i < N; i++) {
                     newlyVisibleKeyAr[i] = newlyVisibleAr[i].key;
                 }
-
-                synchronized (mDozingLock) {
-                    // setNotificationsShown should only be called if we are confident that
-                    // the user has seen the notification, aka not when ambient display is on
-                    if (!mDozing) {
-                        // TODO: Call NotificationEntryManager to do this, once it exists.
-                        // TODO: Consider not catching all runtime exceptions here.
-                        try {
-                            mNotificationListener.setNotificationsShown(newlyVisibleKeyAr);
-                        } catch (RuntimeException e) {
-                            Log.d(TAG, "failed setNotificationsShown: ", e);
-                        }
-                    }
+                // TODO: Call NotificationEntryManager to do this, once it exists.
+                // TODO: Consider not catching all runtime exceptions here.
+                try {
+                    mNotificationListener.setNotificationsShown(newlyVisibleKeyAr);
+                } catch (RuntimeException e) {
+                    Log.d(TAG, "failed setNotificationsShown: ", e);
                 }
             }
             recycleAllVisibilityObjects(newlyVisibleAr);
@@ -400,14 +412,64 @@
 
     @Override
     public void onStateChanged(int newState) {
-        // don't care about state change
+        if (DEBUG) {
+            Log.i(TAG, "onStateChanged: new=" + newState);
+        }
+        synchronized (mDozingLock) {
+            mLockscreen = (newState == StatusBarState.KEYGUARD
+                    || newState == StatusBarState.SHADE_LOCKED);
+        }
     }
 
     @Override
     public void onDozingChanged(boolean isDozing) {
+        if (DEBUG) {
+            Log.i(TAG, "onDozingChanged: new=" + isDozing);
+        }
         setDozing(isDozing);
     }
 
+    @GuardedBy("mDozingLock")
+    private void maybeUpdateLoggingStatus() {
+        if (mPanelExpanded == null || mDozing == null) {
+            if (DEBUG) {
+                Log.i(TAG, "Panel status unclear: panelExpandedKnown="
+                        + (mPanelExpanded == null) + " dozingKnown=" + (mDozing == null));
+            }
+            return;
+        }
+        // Once we know panelExpanded and Dozing, turn logging on & off when appropriate
+        boolean lockscreen = mLockscreen == null ? false : mLockscreen;
+        if (mPanelExpanded && !mDozing) {
+            mNotificationPanelLogger.logPanelShown(lockscreen,
+                    mEntryManager.getVisibleNotifications());
+            if (DEBUG) {
+                Log.i(TAG, "Notification panel shown, lockscreen=" + lockscreen);
+            }
+            startNotificationLogging();
+        } else {
+            if (DEBUG) {
+                Log.i(TAG, "Notification panel hidden, lockscreen=" + lockscreen);
+            }
+            stopNotificationLogging();
+        }
+    }
+
+    /**
+     * Called by StatusBar to notify the logger that the panel expansion has changed.
+     * The panel may be showing any of the normal notification panel, the AOD, or the bouncer.
+     * @param isExpanded True if the panel is expanded.
+     */
+    public void onPanelExpandedChanged(boolean isExpanded) {
+        if (DEBUG) {
+            Log.i(TAG, "onPanelExpandedChanged: new=" + isExpanded);
+        }
+        mPanelExpanded = isExpanded;
+        synchronized (mDozingLock) {
+            maybeUpdateLoggingStatus();
+        }
+    }
+
     /**
      * Called when the notification is expanded / collapsed.
      */
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/AppOpsInfo.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/AppOpsInfo.java
index 87612f1..e445c9d 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/AppOpsInfo.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/AppOpsInfo.java
@@ -188,7 +188,9 @@
 
     @Override
     public boolean handleCloseControls(boolean save, boolean force) {
-        mMetricsLogger.visibility(MetricsEvent.APP_OPS_GUTS, false);
+        if (mMetricsLogger != null) {
+            mMetricsLogger.visibility(MetricsEvent.APP_OPS_GUTS, false);
+        }
         return false;
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationConversationInfo.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationConversationInfo.java
index e9d8958..bee2f70 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationConversationInfo.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationConversationInfo.java
@@ -44,6 +44,7 @@
 import android.content.pm.ShortcutManager;
 import android.os.Handler;
 import android.os.RemoteException;
+import android.os.UserHandle;
 import android.provider.Settings;
 import android.service.notification.StatusBarNotification;
 import android.text.TextUtils;
@@ -53,7 +54,6 @@
 import android.transition.TransitionSet;
 import android.util.AttributeSet;
 import android.util.Log;
-import android.util.Slog;
 import android.view.LayoutInflater;
 import android.view.View;
 import android.view.accessibility.AccessibilityEvent;
@@ -508,10 +508,10 @@
         mBgHandler.post(
                 new UpdateChannelRunnable(mINotificationManager, mPackageName,
                         mAppUid, mSelectedAction, mNotificationChannel));
-        mMainHandler.postDelayed(() -> {
-            mEntry.markForUserTriggeredMovement(true);
-            mVisualStabilityManager.temporarilyAllowReordering();
-        }, StackStateAnimator.ANIMATION_DURATION_STANDARD);
+        mEntry.markForUserTriggeredMovement(true);
+        mMainHandler.postDelayed(
+                mVisualStabilityManager::temporarilyAllowReordering,
+                StackStateAnimator.ANIMATION_DURATION_STANDARD);
     }
 
     private boolean shouldShowPriorityOnboarding() {
@@ -541,7 +541,9 @@
                 .setView(onboardingView)
                 .setIgnoresDnd(ignoreDnd)
                 .setShowsAsBubble(showAsBubble)
-                .setIcon(((ImageView) findViewById(R.id.conversation_icon)).getDrawable())
+                .setIcon(mIconFactory.getBaseIconDrawable(mShortcutInfo))
+                .setBadge(mIconFactory.getAppBadge(
+                        mPackageName, UserHandle.getUserId(mSbn.getUid())))
                 .setOnSettingsClick(mOnConversationSettingsClickListener)
                 .build();
 
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/PartialConversationInfo.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/PartialConversationInfo.java
index f1fe54a..186ffa6 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/PartialConversationInfo.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/PartialConversationInfo.java
@@ -148,8 +148,7 @@
     }
 
     private void bindHeader() {
-        bindConversationDetails();
-
+        bindPackage();
         // Delegate
         bindDelegate();
     }
@@ -180,51 +179,6 @@
         });
     }
 
-    private void bindConversationDetails() {
-        final TextView channelName = findViewById(R.id.parent_channel_name);
-        channelName.setText(mNotificationChannel.getName());
-
-        bindGroup();
-        bindName();
-        bindPackage();
-        bindIcon();
-    }
-
-    private void bindName() {
-        TextView name = findViewById(R.id.name);
-        Bundle extras = mSbn.getNotification().extras;
-        CharSequence nameString = extras.getCharSequence(Notification.EXTRA_CONVERSATION_TITLE, "");
-        if (TextUtils.isEmpty(nameString)) {
-            nameString = extras.getCharSequence(Notification.EXTRA_TITLE, "");
-        }
-        name.setText(nameString);
-    }
-
-    private void bindIcon() {
-        ImageView image = findViewById(R.id.conversation_icon);
-        if (mSbn.getNotification().extras.getBoolean(EXTRA_IS_GROUP_CONVERSATION, false)) {
-            // TODO: maybe use a generic group icon, or a composite of recent senders
-            image.setImageDrawable(mPkgIcon);
-        } else {
-            final List<Notification.MessagingStyle.Message> messages =
-                    Notification.MessagingStyle.Message.getMessagesFromBundleArray(
-                            (Parcelable[]) mSbn.getNotification().extras.get(
-                                    Notification.EXTRA_MESSAGES));
-
-            final Notification.MessagingStyle.Message latestMessage =
-                    Notification.MessagingStyle.findLatestIncomingMessage(messages);
-            Icon personIcon = null;
-            if (latestMessage != null && latestMessage.getSenderPerson() != null) {
-                personIcon = latestMessage.getSenderPerson().getIcon();
-            }
-            if (personIcon != null) {
-                image.setImageIcon(latestMessage.getSenderPerson().getIcon());
-            } else {
-                image.setImageDrawable(mPkgIcon);
-            }
-        }
-    }
-
     private void bindPackage() {
         ApplicationInfo info;
         try {
@@ -241,6 +195,10 @@
         } catch (PackageManager.NameNotFoundException e) {
             mPkgIcon = mPm.getDefaultActivityIcon();
         }
+        TextView name = findViewById(R.id.name);
+        name.setText(mAppName);
+        ImageView image = findViewById(R.id.icon);
+        image.setImageDrawable(mPkgIcon);
     }
 
     private void bindDelegate() {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/PriorityOnboardingDialogController.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/PriorityOnboardingDialogController.kt
index c88f0bd..fab367d 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/PriorityOnboardingDialogController.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/PriorityOnboardingDialogController.kt
@@ -16,41 +16,57 @@
 
 package com.android.systemui.statusbar.notification.row
 
+import android.animation.Animator
+import android.animation.AnimatorListenerAdapter
+import android.animation.AnimatorSet
+import android.animation.ValueAnimator
 import android.app.Dialog
 import android.content.Context
 import android.graphics.Color
 import android.graphics.PixelFormat
 import android.graphics.drawable.ColorDrawable
 import android.graphics.drawable.Drawable
+import android.graphics.drawable.GradientDrawable
 import android.text.SpannableStringBuilder
 import android.text.style.BulletSpan
 import android.view.Gravity
 import android.view.View
+import android.view.ViewGroup
 import android.view.ViewGroup.LayoutParams.MATCH_PARENT
 import android.view.ViewGroup.LayoutParams.WRAP_CONTENT
 import android.view.Window
 import android.view.WindowInsets.Type.statusBars
 import android.view.WindowManager
+import android.view.animation.Interpolator
+import android.view.animation.PathInterpolator
 import android.widget.ImageView
 import android.widget.TextView
+import com.android.systemui.Interpolators.LINEAR_OUT_SLOW_IN
 import com.android.systemui.Prefs
 import com.android.systemui.R
 import com.android.systemui.statusbar.notification.row.NotificationConversationInfo.OnConversationSettingsClickListener
 import javax.inject.Inject
 
+
 /**
  * Controller to handle presenting the priority conversations onboarding dialog
  */
 class PriorityOnboardingDialogController @Inject constructor(
-    val view: View,
-    val context: Context,
-    val ignoresDnd: Boolean,
-    val showsAsBubble: Boolean,
-    val icon : Drawable,
-    val onConversationSettingsClickListener : OnConversationSettingsClickListener
+        val view: View,
+        val context: Context,
+        private val ignoresDnd: Boolean,
+        private val showsAsBubble: Boolean,
+        val icon : Drawable,
+        private val onConversationSettingsClickListener : OnConversationSettingsClickListener,
+        val badge : Drawable
 ) {
 
     private lateinit var dialog: Dialog
+    private val OVERSHOOT: Interpolator = PathInterpolator(0.4f, 0f, 0.2f, 1.4f)
+    private val IMPORTANCE_ANIM_DELAY = 150L
+    private val IMPORTANCE_ANIM_GROW_DURATION = 250L
+    private val IMPORTANCE_ANIM_SHRINK_DURATION = 200L
+    private val IMPORTANCE_ANIM_SHRINK_DELAY = 25L
 
     fun init() {
         initDialog()
@@ -81,6 +97,7 @@
         private lateinit var icon: Drawable
         private lateinit var onConversationSettingsClickListener
                 : OnConversationSettingsClickListener
+        private lateinit var badge : Drawable
 
         fun setView(v: View): Builder {
             view = v
@@ -106,6 +123,10 @@
             icon = draw
             return this
         }
+        fun setBadge(badge : Drawable) : Builder {
+            this.badge = badge
+            return this
+        }
 
         fun setOnSettingsClick(onClick : OnConversationSettingsClickListener) : Builder {
             onConversationSettingsClickListener = onClick
@@ -115,7 +136,7 @@
         fun build(): PriorityOnboardingDialogController {
             val controller = PriorityOnboardingDialogController(
                     view, context, ignoresDnd, showAsBubble, icon,
-                    onConversationSettingsClickListener)
+                    onConversationSettingsClickListener, badge)
             return controller
         }
     }
@@ -143,6 +164,65 @@
             }
 
             findViewById<ImageView>(R.id.conversation_icon)?.setImageDrawable(icon)
+            findViewById<ImageView>(R.id.icon)?.setImageDrawable(badge)
+            val mImportanceRingView = findViewById<ImageView>(R.id.conversation_icon_badge_ring)
+            val conversationIconBadgeBg = findViewById<ImageView>(R.id.conversation_icon_badge_bg)
+
+            val ring: GradientDrawable = mImportanceRingView.drawable as GradientDrawable
+            ring.mutate()
+            val bg = conversationIconBadgeBg.drawable as GradientDrawable
+            bg.mutate()
+            val ringColor = context.getResources()
+                    .getColor(com.android.internal.R.color.conversation_important_highlight)
+            val standardThickness = context.resources.getDimensionPixelSize(
+                    com.android.internal.R.dimen.importance_ring_stroke_width)
+            val largeThickness = context.resources.getDimensionPixelSize(
+                    com.android.internal.R.dimen.importance_ring_anim_max_stroke_width)
+            val standardSize = context.resources.getDimensionPixelSize(
+                    com.android.internal.R.dimen.importance_ring_size)
+            val baseSize = standardSize - standardThickness * 2
+            val largeSize = baseSize + largeThickness * 2
+            val bgSize = context.resources.getDimensionPixelSize(
+                    com.android.internal.R.dimen.conversation_icon_size_badged)
+
+            val animatorUpdateListener: ValueAnimator.AnimatorUpdateListener
+                    = ValueAnimator.AnimatorUpdateListener { animation ->
+                val strokeWidth = animation.animatedValue as Int
+                ring.setStroke(strokeWidth, ringColor)
+                val newSize = baseSize + strokeWidth * 2
+                ring.setSize(newSize, newSize)
+                mImportanceRingView.invalidate()
+            }
+
+            val growAnimation: ValueAnimator = ValueAnimator.ofInt(0, largeThickness)
+            growAnimation.interpolator = LINEAR_OUT_SLOW_IN
+            growAnimation.duration = IMPORTANCE_ANIM_GROW_DURATION
+            growAnimation.addUpdateListener(animatorUpdateListener)
+
+            val shrinkAnimation: ValueAnimator
+                    = ValueAnimator.ofInt(largeThickness, standardThickness)
+            shrinkAnimation.duration = IMPORTANCE_ANIM_SHRINK_DURATION
+            shrinkAnimation.startDelay = IMPORTANCE_ANIM_SHRINK_DELAY
+            shrinkAnimation.interpolator = OVERSHOOT
+            shrinkAnimation.addUpdateListener(animatorUpdateListener)
+            shrinkAnimation.addListener(object : AnimatorListenerAdapter() {
+                override fun onAnimationStart(animation: Animator?) {
+                    // Shrink the badge bg so that it doesn't peek behind the animation
+                    bg.setSize(baseSize, baseSize);
+                    conversationIconBadgeBg.invalidate();
+                }
+
+                override fun onAnimationEnd(animation: Animator?) {
+                    // Reset bg back to normal size
+                    bg.setSize(bgSize, bgSize);
+                    conversationIconBadgeBg.invalidate();
+
+                }
+            })
+
+            val anims = AnimatorSet()
+            anims.startDelay = IMPORTANCE_ANIM_DELAY
+            anims.playSequentially(growAnimation, shrinkAnimation)
 
             val gapWidth = dialog.context.getResources().getDimensionPixelSize(
                     R.dimen.conversation_onboarding_bullet_gap_width)
@@ -180,6 +260,7 @@
                     height = WRAP_CONTENT
                 }
             }
+            anims.start()
         }
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationHeaderViewWrapper.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationHeaderViewWrapper.java
index 4c9cb20..c747a7c 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationHeaderViewWrapper.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationHeaderViewWrapper.java
@@ -262,7 +262,10 @@
         stack.push(mView);
         while (!stack.isEmpty()) {
             View child = stack.pop();
-            if (child instanceof ImageView) {
+            if (child instanceof ImageView
+                    // Skip the importance ring for conversations, disabled cropping is needed for
+                    // its animation
+                    && child.getId() != com.android.internal.R.id.conversation_icon_badge_ring) {
                 ((ImageView) child).setCropToPadding(true);
             } else if (child instanceof ViewGroup){
                 ViewGroup group = (ViewGroup) child;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationSectionsManager.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationSectionsManager.kt
index 0bdac39..c87b998 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationSectionsManager.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationSectionsManager.kt
@@ -41,6 +41,7 @@
 import com.android.systemui.statusbar.notification.stack.StackScrollAlgorithm.SectionProvider
 import com.android.systemui.statusbar.policy.ConfigurationController
 import com.android.systemui.util.children
+import com.android.systemui.util.takeUntil
 import com.android.systemui.util.foldToSparseArray
 import javax.inject.Inject
 
@@ -197,7 +198,7 @@
         else -> null
     }
 
-    private fun logShadeContents() = parent.children.forEachIndexed { i, child ->
+    private fun logShadeChild(i: Int, child: View) {
         when {
             child === incomingHeaderView -> logger.logIncomingHeader(i)
             child === mediaControlsView -> logger.logMediaControls(i)
@@ -216,6 +217,7 @@
             }
         }
     }
+    private fun logShadeContents() = parent.children.forEachIndexed(::logShadeChild)
 
     private val isUsingMultipleSections: Boolean
         get() = sectionsFeatureManager.getNumberOfBuckets() > 1
@@ -223,6 +225,57 @@
     @VisibleForTesting
     fun updateSectionBoundaries() = updateSectionBoundaries("test")
 
+    private interface SectionUpdateState<out T : ExpandableView> {
+        val header: T
+        var currentPosition: Int?
+        var targetPosition: Int?
+        fun adjustViewPosition()
+    }
+
+    private fun <T : ExpandableView> expandableViewHeaderState(header: T): SectionUpdateState<T> =
+            object : SectionUpdateState<T> {
+                override val header = header
+                override var currentPosition: Int? = null
+                override var targetPosition: Int? = null
+
+                override fun adjustViewPosition() {
+                    val target = targetPosition
+                    val current = currentPosition
+                    if (target == null) {
+                        if (current != null) {
+                            parent.removeView(header)
+                        }
+                    } else {
+                        if (current == null) {
+                            // If the header is animating away, it will still have a parent, so
+                            // detach it first
+                            // TODO: We should really cancel the active animations here. This will
+                            //  happen automatically when the view's intro animation starts, but
+                            //  it's a fragile link.
+                            header.transientContainer?.removeTransientView(header)
+                            header.transientContainer = null
+                            parent.addView(header, target)
+                        } else {
+                            parent.changeViewPosition(header, target)
+                        }
+                    }
+                }
+    }
+
+    private fun <T : StackScrollerDecorView> decorViewHeaderState(
+        header: T
+    ): SectionUpdateState<T> {
+        val inner = expandableViewHeaderState(header)
+        return object : SectionUpdateState<T> by inner {
+            override fun adjustViewPosition() {
+                inner.adjustViewPosition()
+                if (targetPosition != null && currentPosition == null) {
+                    header.isContentVisible = true
+                }
+            }
+        }
+    }
+
     /**
      * Should be called whenever notifs are added, removed, or updated. Updates section boundary
      * bookkeeping and adds/moves/removes section headers if appropriate.
@@ -238,233 +291,136 @@
         // Then, once we find the start of a new section, we track that position as the "target" for
         // the section header, adjusted for the case where existing headers are in front of that
         // target, but won't be once they are moved / removed after the pass has completed.
+
         val showHeaders = statusBarStateController.state != StatusBarState.KEYGUARD
         val usingPeopleFiltering = sectionsFeatureManager.isFilteringEnabled()
         val usingMediaControls = sectionsFeatureManager.isMediaControlsEnabled()
 
+        val mediaState = mediaControlsView?.let(::expandableViewHeaderState)
+        val incomingState = incomingHeaderView?.let(::decorViewHeaderState)
+        val peopleState = peopleHeaderView?.let(::decorViewHeaderState)
+        val alertingState = alertingHeaderView?.let(::decorViewHeaderState)
+        val gentleState = silentHeaderView?.let(::decorViewHeaderState)
+
+        fun getSectionState(view: View): SectionUpdateState<ExpandableView>? = when {
+            view === mediaControlsView -> mediaState
+            view === incomingHeaderView -> incomingState
+            view === peopleHeaderView -> peopleState
+            view === alertingHeaderView -> alertingState
+            view === silentHeaderView -> gentleState
+            else -> null
+        }
+
+        val headersOrdered = sequenceOf(
+                mediaState, incomingState, peopleState, alertingState, gentleState
+        ).filterNotNull()
+
         var peopleNotifsPresent = false
-        var currentMediaControlsIdx = -1
-        val mediaControlsTarget = if (usingMediaControls) 0 else -1
-        var currentIncomingHeaderIdx = -1
-        var incomingHeaderTarget = -1
-        var currentPeopleHeaderIdx = -1
-        var peopleHeaderTarget = -1
-        var currentAlertingHeaderIdx = -1
-        var alertingHeaderTarget = -1
-        var currentGentleHeaderIdx = -1
-        var gentleHeaderTarget = -1
-
         var lastNotifIndex = 0
-        var lastIncomingIndex = -1
-        var prev: ExpandableNotificationRow? = null
+        var nextBucket: Int? = null
+        var inIncomingSection = false
 
-        for ((i, child) in parent.children.withIndex()) {
-            when {
-                // Track the existing positions of the headers
-                child === incomingHeaderView -> {
-                    logger.logIncomingHeader(i)
-                    currentIncomingHeaderIdx = i
-                }
-                child === mediaControlsView -> {
-                    logger.logMediaControls(i)
-                    currentMediaControlsIdx = i
-                }
-                child === peopleHeaderView -> {
-                    logger.logConversationsHeader(i)
-                    currentPeopleHeaderIdx = i
-                }
-                child === alertingHeaderView -> {
-                    logger.logAlertingHeader(i)
-                    currentAlertingHeaderIdx = i
-                }
-                child === silentHeaderView -> {
-                    logger.logSilentHeader(i)
-                    currentGentleHeaderIdx = i
-                }
-                child !is ExpandableNotificationRow -> logger.logOther(i, child.javaClass)
-                else -> {
-                    lastNotifIndex = i
-                    // Is there a section discontinuity? This usually occurs due to HUNs
-                    if (prev?.entry?.bucket?.let { it > child.entry.bucket } == true) {
-                        // Remove existing headers, and move the Incoming header if necessary
-                        incomingHeaderTarget = when {
-                            !showHeaders -> -1
-                            incomingHeaderTarget != -1 -> incomingHeaderTarget
-                            peopleHeaderTarget != -1 -> peopleHeaderTarget
-                            alertingHeaderTarget != -1 -> alertingHeaderTarget
-                            gentleHeaderTarget != -1 -> gentleHeaderTarget
-                            else -> 0
-                        }
-                        peopleHeaderTarget = -1
-                        alertingHeaderTarget = -1
-                        gentleHeaderTarget = -1
-                        // Walk backwards changing all previous notifications to the Incoming
-                        // section
-                        for (j in i - 1 downTo lastIncomingIndex + 1) {
-                            val prevChild = parent.getChildAt(j)
-                            if (prevChild is ExpandableNotificationRow) {
-                                prevChild.entry.bucket = BUCKET_HEADS_UP
-                            }
-                        }
-                        // Track the new bottom of the Incoming section
-                        lastIncomingIndex = i - 1
-                    }
-                    val isHeadsUp = child.isHeadsUp
-                    when (child.entry.bucket) {
-                        BUCKET_FOREGROUND_SERVICE -> logger.logForegroundService(i, isHeadsUp)
-                        BUCKET_PEOPLE -> {
-                            logger.logConversation(i, isHeadsUp)
-                            peopleNotifsPresent = true
-                            if (showHeaders && peopleHeaderTarget == -1) {
-                                peopleHeaderTarget = i
-                                // Offset the target if there are other headers before this that
-                                // will be moved.
-                                if (currentIncomingHeaderIdx != -1 && incomingHeaderTarget == -1) {
-                                    peopleHeaderTarget--
-                                }
-                                if (currentPeopleHeaderIdx != -1) {
-                                    peopleHeaderTarget--
-                                }
-                                if (currentAlertingHeaderIdx != -1) {
-                                    peopleHeaderTarget--
-                                }
-                                if (currentGentleHeaderIdx != -1) {
-                                    peopleHeaderTarget--
-                                }
-                            }
-                        }
-                        BUCKET_ALERTING -> {
-                            logger.logAlerting(i, isHeadsUp)
-                            if (showHeaders && usingPeopleFiltering && alertingHeaderTarget == -1) {
-                                alertingHeaderTarget = i
-                                // Offset the target if there are other headers before this that
-                                // will be moved.
-                                if (currentIncomingHeaderIdx != -1 && incomingHeaderTarget == -1) {
-                                    alertingHeaderTarget--
-                                }
-                                if (currentPeopleHeaderIdx != -1 && peopleHeaderTarget == -1) {
-                                    // People header will be removed
-                                    alertingHeaderTarget--
-                                }
-                                if (currentAlertingHeaderIdx != -1) {
-                                    alertingHeaderTarget--
-                                }
-                                if (currentGentleHeaderIdx != -1) {
-                                    alertingHeaderTarget--
-                                }
-                            }
-                        }
-                        BUCKET_SILENT -> {
-                            logger.logSilent(i, isHeadsUp)
-                            if (showHeaders && gentleHeaderTarget == -1) {
-                                gentleHeaderTarget = i
-                                // Offset the target if there are other headers before this that
-                                // will be moved.
-                                if (currentIncomingHeaderIdx != -1 && incomingHeaderTarget == -1) {
-                                    gentleHeaderTarget--
-                                }
-                                if (currentPeopleHeaderIdx != -1 && peopleHeaderTarget == -1) {
-                                    // People header will be removed
-                                    gentleHeaderTarget--
-                                }
-                                if (currentAlertingHeaderIdx != -1 && alertingHeaderTarget == -1) {
-                                    // Alerting header will be removed
-                                    gentleHeaderTarget--
-                                }
-                                if (currentGentleHeaderIdx != -1) {
-                                    gentleHeaderTarget--
-                                }
-                            }
-                        }
-                    }
-
-                    prev = child
+        // Iterating backwards allows for easier construction of the Incoming section, as opposed
+        // to backtracking when a discontinuity in the sections is discovered.
+        // Iterating to -1 in order to support the case where a header is at the very top of the
+        // shade.
+        for (i in parent.childCount - 1 downTo -1) {
+            val child: View? = parent.getChildAt(i)
+            child?.let {
+                logShadeChild(i, child)
+                // If this child is a header, update the tracked positions
+                getSectionState(child)?.let { state ->
+                    state.currentPosition = i
+                    // If headers that should appear above this one in the shade already have a
+                    // target index, then we need to decrement them in order to account for this one
+                    // being either removed, or moved below them.
+                    headersOrdered.takeUntil { it === state }
+                            .forEach { it.targetPosition = it.targetPosition?.minus(1) }
                 }
             }
+
+            val row = child as? ExpandableNotificationRow
+
+            // Is there a section discontinuity? This usually occurs due to HUNs
+            inIncomingSection = inIncomingSection || nextBucket?.let { next ->
+                row?.entry?.bucket?.let { curr -> next < curr }
+            } == true
+
+            if (inIncomingSection) {
+                // Update the bucket to reflect that it's being placed in the Incoming section
+                row?.entry?.bucket = BUCKET_HEADS_UP
+            }
+
+            // Insert a header in front of the next row, if there's a boundary between it and this
+            // row, or if it is the topmost row.
+            val isSectionBoundary = nextBucket != null &&
+                    (child == null || row != null && nextBucket != row.entry.bucket)
+            if (isSectionBoundary && showHeaders) {
+                when (nextBucket) {
+                    BUCKET_HEADS_UP -> incomingState?.targetPosition = i + 1
+                    BUCKET_PEOPLE -> peopleState?.targetPosition = i + 1
+                    BUCKET_ALERTING -> alertingState?.targetPosition = i + 1
+                    BUCKET_SILENT -> gentleState?.targetPosition = i + 1
+                }
+            }
+
+            row ?: continue
+
+            // Check if there are any people notifications
+            peopleNotifsPresent = peopleNotifsPresent || row.entry.bucket == BUCKET_PEOPLE
+
+            if (nextBucket == null) {
+                lastNotifIndex = i
+            }
+            nextBucket = row.entry.bucket
         }
 
-        if (showHeaders && usingPeopleFiltering && peopleHubVisible && peopleHeaderTarget == -1) {
-            // Insert the people header even if there are no people visible, in order to show
-            // the hub. Put it directly above the next header.
-            peopleHeaderTarget = when {
-                alertingHeaderTarget != -1 -> alertingHeaderTarget
-                gentleHeaderTarget != -1 -> gentleHeaderTarget
-                else -> lastNotifIndex // Put it at the end of the list.
-            }
+        if (showHeaders && usingPeopleFiltering && peopleHubVisible) {
+            peopleState?.targetPosition = peopleState?.targetPosition
+                    // Insert the people header even if there are no people visible, in order to
+                    // show the hub. Put it directly above the next header.
+                    ?: alertingState?.targetPosition
+                    ?: gentleState?.targetPosition
+                    // Put it at the end of the list.
+                    ?: lastNotifIndex
+
             // Offset the target to account for the current position of the people header.
-            if (currentPeopleHeaderIdx != -1 && currentPeopleHeaderIdx < peopleHeaderTarget) {
-                peopleHeaderTarget--
+            peopleState?.targetPosition = peopleState?.currentPosition?.let { current ->
+                peopleState?.targetPosition?.let { target ->
+                    if (current < target) target - 1 else target
+                }
             }
         }
 
+        mediaState?.targetPosition = if (usingMediaControls) 0 else null
+
         logger.logStr("New header target positions:")
-        logger.logIncomingHeader(incomingHeaderTarget)
-        logger.logMediaControls(mediaControlsTarget)
-        logger.logConversationsHeader(peopleHeaderTarget)
-        logger.logAlertingHeader(alertingHeaderTarget)
-        logger.logSilentHeader(gentleHeaderTarget)
+        logger.logMediaControls(mediaState?.targetPosition ?: -1)
+        logger.logIncomingHeader(incomingState?.targetPosition ?: -1)
+        logger.logConversationsHeader(peopleState?.targetPosition ?: -1)
+        logger.logAlertingHeader(alertingState?.targetPosition ?: -1)
+        logger.logSilentHeader(gentleState?.targetPosition ?: -1)
 
-        // Add headers in reverse order to preserve indices
-        silentHeaderView?.let {
-            adjustHeaderVisibilityAndPosition(gentleHeaderTarget, it, currentGentleHeaderIdx)
-        }
-        alertingHeaderView?.let {
-            adjustHeaderVisibilityAndPosition(alertingHeaderTarget, it, currentAlertingHeaderIdx)
-        }
-        peopleHeaderView?.let {
-            adjustHeaderVisibilityAndPosition(peopleHeaderTarget, it, currentPeopleHeaderIdx)
-        }
-        incomingHeaderView?.let {
-            adjustHeaderVisibilityAndPosition(incomingHeaderTarget, it, currentIncomingHeaderIdx)
-        }
-        mediaControlsView?.let {
-            adjustViewPosition(mediaControlsTarget, it, currentMediaControlsIdx)
-        }
+        // Update headers in reverse order to preserve indices, otherwise movements earlier in the
+        // list will affect the target indices of the headers later in the list.
+        headersOrdered.asIterable().reversed().forEach { it.adjustViewPosition() }
 
         logger.logStr("Final order:")
         logShadeContents()
         logger.logStr("Section boundary update complete")
 
         // Update headers to reflect state of section contents
-        silentHeaderView?.setAreThereDismissableGentleNotifs(
-                parent.hasActiveClearableNotifications(NotificationStackScrollLayout.ROWS_GENTLE)
-        )
-        peopleHeaderView?.canSwipe = showHeaders && peopleHubVisible && !peopleNotifsPresent
-        if (peopleHeaderTarget != currentPeopleHeaderIdx) {
-            peopleHeaderView?.resetTranslation()
+        silentHeaderView?.run {
+            val hasActiveClearableNotifications = this@NotificationSectionsManager.parent
+                    .hasActiveClearableNotifications(NotificationStackScrollLayout.ROWS_GENTLE)
+            setAreThereDismissableGentleNotifs(hasActiveClearableNotifications)
         }
-    }
-
-    private fun adjustHeaderVisibilityAndPosition(
-        targetPosition: Int,
-        header: StackScrollerDecorView,
-        currentPosition: Int
-    ) {
-        adjustViewPosition(targetPosition, header, currentPosition)
-        if (targetPosition != -1 && currentPosition == -1) {
-            header.isContentVisible = true
-        }
-    }
-
-    private fun adjustViewPosition(
-        targetPosition: Int,
-        view: ExpandableView,
-        currentPosition: Int
-    ) {
-        if (targetPosition == -1) {
-            if (currentPosition != -1) {
-                parent.removeView(view)
-            }
-        } else {
-            if (currentPosition == -1) {
-                // If the header is animating away, it will still have a parent, so detach it first
-                // TODO: We should really cancel the active animations here. This will happen
-                // automatically when the view's intro animation starts, but it's a fragile link.
-                view.transientContainer?.removeTransientView(view)
-                view.transientContainer = null
-                parent.addView(view, targetPosition)
-            } else {
-                parent.changeViewPosition(view, targetPosition)
+        peopleHeaderView?.run {
+            canSwipe = showHeaders && peopleHubVisible && !peopleNotifsPresent
+            peopleState?.targetPosition?.let { targetPosition ->
+                if (targetPosition != peopleState.currentPosition) {
+                    resetTranslation()
+                }
             }
         }
     }
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 325c8c0..684bf19 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
@@ -146,6 +146,7 @@
 import com.android.systemui.statusbar.phone.HeadsUpTouchHelper;
 import com.android.systemui.statusbar.phone.KeyguardBypassController;
 import com.android.systemui.statusbar.phone.LockscreenGestureLogger;
+import com.android.systemui.statusbar.phone.LockscreenGestureLogger.LockscreenUiEvent;
 import com.android.systemui.statusbar.phone.NotificationGroupManager;
 import com.android.systemui.statusbar.phone.NotificationGroupManager.OnGroupChangeListener;
 import com.android.systemui.statusbar.phone.NotificationIconAreaController;
@@ -6538,7 +6539,7 @@
             return row.canViewBeDismissed();
         }
         if (v instanceof PeopleHubView) {
-            return true;
+            return ((PeopleHubView) v).getCanSwipe();
         }
         return false;
     }
@@ -6633,6 +6634,7 @@
                         MetricsEvent.ACTION_LS_SHADE,
                         (int) (dragLengthY / mDisplayMetrics.density),
                         0 /* velocityDp - N/A */);
+                mLockscreenGestureLogger.log(LockscreenUiEvent.LOCKSCREEN_PULL_SHADE_OPEN);
 
                 if (!mAmbientState.isDozing() || startingChild != null) {
                     // We have notifications, go to locked shade.
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/PeopleHubView.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/PeopleHubView.kt
index a1d898f..8f77a1d 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/PeopleHubView.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/PeopleHubView.kt
@@ -72,7 +72,7 @@
         }
     }
 
-    var canSwipe: Boolean = true
+    var canSwipe: Boolean = false
         set(value) {
             if (field != value) {
                 if (field) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/LockscreenGestureLogger.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/LockscreenGestureLogger.java
index 8c3420a..83d398d 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/LockscreenGestureLogger.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/LockscreenGestureLogger.java
@@ -20,6 +20,9 @@
 import android.util.ArrayMap;
 
 import com.android.internal.logging.MetricsLogger;
+import com.android.internal.logging.UiEvent;
+import com.android.internal.logging.UiEventLogger;
+import com.android.internal.logging.UiEventLoggerImpl;
 import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
 import com.android.systemui.Dependency;
 import com.android.systemui.EventLogConstants;
@@ -34,6 +37,56 @@
  */
 @Singleton
 public class LockscreenGestureLogger {
+
+    /**
+     * Contains Lockscreen related Westworld UiEvent enums.
+     */
+    public enum LockscreenUiEvent implements UiEventLogger.UiEventEnum {
+        @UiEvent(doc = "Lockscreen > Pull shade open")
+        LOCKSCREEN_PULL_SHADE_OPEN(539),
+
+        @UiEvent(doc = "Lockscreen > Tap on lock, locks phone")
+        LOCKSCREEN_LOCK_TAP(540),
+
+        @UiEvent(doc = "Lockscreen > Swipe down to open quick settings")
+        LOCKSCREEN_QUICK_SETTINGS_OPEN(541),
+
+        @UiEvent(doc = "Swipe down to open quick settings when unlocked")
+        LOCKSCREEN_UNLOCKED_QUICK_SETTINGS_OPEN(542),
+
+        @UiEvent(doc = "Lockscreen > Tap on lock, shows hint")
+        LOCKSCREEN_LOCK_SHOW_HINT(543),
+
+        @UiEvent(doc = "Notification shade > Tap to open quick settings")
+        LOCKSCREEN_NOTIFICATION_SHADE_QUICK_SETTINGS_OPEN(544),
+
+        @UiEvent(doc = "Lockscreen > Dialer")
+        LOCKSCREEN_DIALER(545),
+
+        @UiEvent(doc = "Lockscreen > Camera")
+        LOCKSCREEN_CAMERA(546),
+
+        @UiEvent(doc = "Lockscreen > Unlock gesture")
+        LOCKSCREEN_UNLOCK(547),
+
+        @UiEvent(doc = "Lockscreen > Tap on notification, false touch rejection")
+        LOCKSCREEN_NOTIFICATION_FALSE_TOUCH(548),
+
+        @UiEvent(doc = "Expand the notification panel while unlocked")
+        LOCKSCREEN_UNLOCKED_NOTIFICATION_PANEL_EXPAND(549);
+
+        private final int mId;
+
+        LockscreenUiEvent(int id) {
+            mId = id;
+        }
+
+        @Override
+        public int getId() {
+            return mId;
+        }
+    }
+
     private ArrayMap<Integer, Integer> mLegacyMap;
     private final MetricsLogger mMetricsLogger = Dependency.get(MetricsLogger.class);
 
@@ -55,6 +108,13 @@
     }
 
     /**
+     * Logs {@link LockscreenUiEvent}.
+     */
+    public void log(LockscreenUiEvent lockscreenUiEvent) {
+        new UiEventLoggerImpl().log(lockscreenUiEvent);
+    }
+
+    /**
      * Record the location of a swipe gesture, expressed as percentages of the whole screen
      * @param category the action
      * @param xPercent x-location / width * 100
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/LockscreenLockIconController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/LockscreenLockIconController.java
index 8a5c8b0..5d3910b 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/LockscreenLockIconController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/LockscreenLockIconController.java
@@ -45,6 +45,7 @@
 import com.android.systemui.statusbar.StatusBarState;
 import com.android.systemui.statusbar.notification.NotificationWakeUpCoordinator;
 import com.android.systemui.statusbar.notification.NotificationWakeUpCoordinator.WakeUpListener;
+import com.android.systemui.statusbar.phone.LockscreenGestureLogger.LockscreenUiEvent;
 import com.android.systemui.statusbar.policy.AccessibilityController;
 import com.android.systemui.statusbar.policy.ConfigurationController;
 import com.android.systemui.statusbar.policy.ConfigurationController.ConfigurationListener;
@@ -436,6 +437,7 @@
     private boolean handleLongClick(View view) {
         mLockscreenGestureLogger.write(MetricsProto.MetricsEvent.ACTION_LS_LOCK,
                 0 /* lengthDp - N/A */, 0 /* velocityDp - N/A */);
+        mLockscreenGestureLogger.log(LockscreenUiEvent.LOCKSCREEN_LOCK_TAP);
         mKeyguardIndicationController.showTransientIndication(
                 R.string.keyguard_indication_trust_disabled);
         mKeyguardUpdateMonitor.onLockIconPressed();
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 26e80ad..df121f0 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarFragment.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarFragment.java
@@ -59,6 +59,7 @@
 import android.database.ContentObserver;
 import android.graphics.PixelFormat;
 import android.graphics.Rect;
+import android.graphics.RectF;
 import android.hardware.display.DisplayManager;
 import android.inputmethodservice.InputMethodService;
 import android.net.Uri;
@@ -83,6 +84,7 @@
 import android.view.Surface;
 import android.view.View;
 import android.view.ViewGroup;
+import android.view.ViewTreeObserver;
 import android.view.WindowInsetsController.Appearance;
 import android.view.WindowManager;
 import android.view.WindowManager.LayoutParams;
@@ -94,6 +96,8 @@
 
 import com.android.internal.accessibility.dialog.AccessibilityButtonChooserActivity;
 import com.android.internal.logging.MetricsLogger;
+import com.android.internal.logging.UiEvent;
+import com.android.internal.logging.UiEventLogger;
 import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
 import com.android.internal.util.LatencyTracker;
 import com.android.internal.view.AppearanceRegion;
@@ -217,11 +221,31 @@
      * original handle hidden and we'll flip the visibilities once the
      * {@link #mTasksFrozenListener} fires
      */
-    private NavigationHandle mOrientationHandle;
+    private VerticalNavigationHandle mOrientationHandle;
     private WindowManager.LayoutParams mOrientationParams;
     private int mStartingQuickSwitchRotation;
     private int mCurrentRotation;
     private boolean mFixedRotationEnabled;
+    private ViewTreeObserver.OnGlobalLayoutListener mOrientationHandleGlobalLayoutListener;
+    private UiEventLogger mUiEventLogger;
+
+    @com.android.internal.annotations.VisibleForTesting
+    public enum NavBarActionEvent implements UiEventLogger.UiEventEnum {
+
+        @UiEvent(doc = "Assistant invoked via home button long press.")
+        NAVBAR_ASSIST_LONGPRESS(550);
+
+        private final int mId;
+
+        NavBarActionEvent(int id) {
+            mId = id;
+        }
+
+        @Override
+        public int getId() {
+            return mId;
+        }
+    }
 
     /** Only for default display */
     @Nullable
@@ -299,6 +323,20 @@
                 buttonDispatcher.setAlpha(forceVisible ? 1f : alpha, animate);
             }
         }
+
+        @Override
+        public void onOverviewShown(boolean fromHome) {
+            // If the overview has fixed orientation that may change display to natural rotation,
+            // we don't want the user rotation to be reset. So after user returns to application,
+            // it can keep in the original rotation.
+            mNavigationBarView.getRotationButtonController().setSkipOverrideUserLockPrefsOnce();
+        }
+
+        @Override
+        public void onToggleRecentApps() {
+            // The same case as onOverviewShown but only for 3-button navigation.
+            mNavigationBarView.getRotationButtonController().setSkipOverrideUserLockPrefsOnce();
+        }
     };
 
     private NavigationBarTransitions.DarkIntensityListener mOrientationHandleIntensityListener =
@@ -364,7 +402,8 @@
             ShadeController shadeController,
             NotificationRemoteInputManager notificationRemoteInputManager,
             SystemActions systemActions,
-            @Main Handler mainHandler) {
+            @Main Handler mainHandler,
+            UiEventLogger uiEventLogger) {
         mAccessibilityManagerWrapper = accessibilityManagerWrapper;
         mDeviceProvisionedController = deviceProvisionedController;
         mStatusBarStateController = statusBarStateController;
@@ -384,6 +423,7 @@
         mRecentsOptional = recentsOptional;
         mSystemActions = systemActions;
         mHandler = mainHandler;
+        mUiEventLogger = uiEventLogger;
     }
 
     // ----- Fragment Lifecycle Callbacks -----
@@ -519,6 +559,8 @@
             getContext().getSystemService(DisplayManager.class).unregisterDisplayListener(this);
             getBarTransitions().removeDarkIntensityListener(mOrientationHandleIntensityListener);
             mWindowManager.removeView(mOrientationHandle);
+            mOrientationHandle.getViewTreeObserver().removeOnGlobalLayoutListener(
+                    mOrientationHandleGlobalLayoutListener);
         }
     }
 
@@ -573,6 +615,20 @@
                 PixelFormat.TRANSLUCENT);
         mWindowManager.addView(mOrientationHandle, mOrientationParams);
         mOrientationHandle.setVisibility(View.GONE);
+        mOrientationHandleGlobalLayoutListener =
+                () -> {
+                    if (mStartingQuickSwitchRotation == -1) {
+                        return;
+                    }
+
+                    RectF boundsOnScreen = mOrientationHandle.computeHomeHandleBounds();
+                    mOrientationHandle.mapRectFromViewToScreenCoords(boundsOnScreen, true);
+                    Rect boundsRounded = new Rect();
+                    boundsOnScreen.roundOut(boundsRounded);
+                    mNavigationBarView.setOrientedHandleSamplingRegion(boundsRounded);
+                };
+        mOrientationHandle.getViewTreeObserver().addOnGlobalLayoutListener(
+                mOrientationHandleGlobalLayoutListener);
     }
 
     private void orientSecondaryHomeHandle() {
@@ -586,6 +642,12 @@
             resetSecondaryHandle();
         } else {
             int deltaRotation = deltaRotation(mCurrentRotation, mStartingQuickSwitchRotation);
+            if (mStartingQuickSwitchRotation == -1 || deltaRotation == -1) {
+                // Curious if starting quickswitch can change between the if check and our delta
+                Log.d(TAG, "secondary nav delta rotation: " + deltaRotation
+                        + " current: " + mCurrentRotation
+                        + " starting: " + mStartingQuickSwitchRotation);
+            }
             int height = 0;
             int width = 0;
             Rect dispSize = mWindowManager.getCurrentWindowMetrics().getBounds();
@@ -621,6 +683,7 @@
         }
         if (mNavigationBarView != null) {
             mNavigationBarView.setVisibility(View.VISIBLE);
+            mNavigationBarView.setOrientedHandleSamplingRegion(null);
         }
     }
 
@@ -648,6 +711,8 @@
             dumpBarTransitions(pw, "mNavigationBarView", mNavigationBarView.getBarTransitions());
         }
 
+        pw.print("  mStartingQuickSwitchRotation=" + mStartingQuickSwitchRotation);
+        pw.print("  mCurrentRotation=" + mCurrentRotation);
         pw.print("  mNavigationBarView=");
         if (mNavigationBarView == null) {
             pw.println("null");
@@ -988,6 +1053,7 @@
             return false;
         }
         mMetricsLogger.action(MetricsEvent.ACTION_ASSIST_LONG_PRESS);
+        mUiEventLogger.log(NavBarActionEvent.NAVBAR_ASSIST_LONGPRESS);
         Bundle args  = new Bundle();
         args.putInt(
                 AssistManager.INVOCATION_TYPE_KEY, AssistManager.INVOCATION_HOME_BUTTON_LONG_PRESS);
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 6b37ac3..4821d8c 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java
@@ -35,6 +35,7 @@
 import android.animation.TimeInterpolator;
 import android.animation.ValueAnimator;
 import android.annotation.DrawableRes;
+import android.annotation.Nullable;
 import android.app.StatusBarManager;
 import android.content.Context;
 import android.content.res.Configuration;
@@ -158,6 +159,14 @@
      */
     private ScreenPinningNotify mScreenPinningNotify;
     private Rect mSamplingBounds = new Rect();
+    /**
+     * When quickswitching between apps of different orientations, we draw a secondary home handle
+     * in the position of the first app's orientation. This rect represents the region of that
+     * home handle so we can apply the correct light/dark luma on that.
+     * @see {@link NavigationBarFragment#mOrientationHandle}
+     */
+    @Nullable
+    private Rect mOrientedHandleSamplingRegion;
 
     private class NavTransitionListener implements TransitionListener {
         private boolean mBackTransitioning;
@@ -327,6 +336,10 @@
 
                     @Override
                     public Rect getSampledRegion(View sampledView) {
+                        if (mOrientedHandleSamplingRegion != null) {
+                            return mOrientedHandleSamplingRegion;
+                        }
+
                         updateSamplingRect();
                         return mSamplingBounds;
                     }
@@ -897,6 +910,11 @@
         }
     }
 
+    void setOrientedHandleSamplingRegion(Rect orientedHandleSamplingRegion) {
+        mOrientedHandleSamplingRegion = orientedHandleSamplingRegion;
+        mRegionSamplingHelper.updateSamplingRect();
+    }
+
     @Override
     protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
         super.onLayout(changed, left, top, right, bottom);
@@ -1190,6 +1208,8 @@
                         mIsVertical ? "true" : "false",
                         getLightTransitionsController().getCurrentDarkIntensity()));
 
+        pw.println("      mOrientedHandleSamplingRegion: " + mOrientedHandleSamplingRegion);
+
         dumpButton(pw, "back", getBackButton());
         dumpButton(pw, "home", getHomeButton());
         dumpButton(pw, "rcnt", getRecentsButton());
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationModeController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationModeController.java
index daefef5..c211de0 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationModeController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationModeController.java
@@ -16,14 +16,19 @@
 
 package com.android.systemui.statusbar.phone;
 
+import static android.content.Intent.ACTION_OVERLAY_CHANGED;
 import static android.view.WindowManagerPolicyConstants.NAV_BAR_MODE_GESTURAL;
 import static android.view.WindowManagerPolicyConstants.NAV_BAR_MODE_GESTURAL_OVERLAY;
 
+import android.content.BroadcastReceiver;
 import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
 import android.content.om.IOverlayManager;
 import android.content.om.OverlayInfo;
 import android.content.pm.PackageManager;
 import android.content.res.ApkAssets;
+import android.os.PatternMatcher;
 import android.os.RemoteException;
 import android.os.ServiceManager;
 import android.os.UserHandle;
@@ -79,6 +84,19 @@
                 }
             };
 
+    // The primary user SysUI process doesn't get AppInfo changes from overlay package changes for
+    // the secondary user (b/158613864), so we need to update the interaction mode here as well
+    // as a fallback if we don't receive the configuration change
+    private BroadcastReceiver mReceiver = new BroadcastReceiver() {
+        @Override
+        public void onReceive(Context context, Intent intent) {
+            if (DEBUG) {
+                Log.d(TAG, "ACTION_OVERLAY_CHANGED");
+            }
+            updateCurrentInteractionMode(true /* notify */);
+        }
+    };
+
 
     @Inject
     public NavigationModeController(Context context,
@@ -92,6 +110,11 @@
         mUiBgExecutor = uiBgExecutor;
         deviceProvisionedController.addCallback(mDeviceProvisionedCallback);
 
+        IntentFilter overlayFilter = new IntentFilter(ACTION_OVERLAY_CHANGED);
+        overlayFilter.addDataScheme("package");
+        overlayFilter.addDataSchemeSpecificPart("android", PatternMatcher.PATTERN_LITERAL);
+        mContext.registerReceiverAsUser(mReceiver, UserHandle.ALL, overlayFilter, null, null);
+
         configurationController.addCallback(new ConfigurationController.ConfigurationListener() {
             @Override
             public void onOverlayChanged() {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java
index 8889510..e720d82 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java
@@ -104,9 +104,9 @@
 import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
 import com.android.systemui.statusbar.notification.row.ExpandableView;
 import com.android.systemui.statusbar.notification.stack.AnimationProperties;
-import com.android.systemui.statusbar.notification.stack.MediaHeaderView;
 import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayout;
 import com.android.systemui.statusbar.notification.stack.StackStateAnimator;
+import com.android.systemui.statusbar.phone.LockscreenGestureLogger.LockscreenUiEvent;
 import com.android.systemui.statusbar.phone.dagger.StatusBarComponent;
 import com.android.systemui.statusbar.policy.ConfigurationController;
 import com.android.systemui.statusbar.policy.KeyguardStateController;
@@ -1328,11 +1328,15 @@
      *
      * @param velocity unit is in px / millis
      */
-    public void stopWaitingForOpenPanelGesture(final float velocity) {
+    public void stopWaitingForOpenPanelGesture(boolean cancel, final float velocity) {
         if (mExpectingSynthesizedDown) {
             mExpectingSynthesizedDown = false;
-            maybeVibrateOnOpening();
-            fling(velocity > 1f ? 1000f * velocity : 0, true /* expand */);
+            if (cancel) {
+                collapse(false /* delayed */, 1.0f /* speedUpFactor */);
+            } else {
+                maybeVibrateOnOpening();
+                fling(velocity > 1f ? 1000f * velocity : 0, true /* expand */);
+            }
             onTrackingStopped(false);
         }
     }
@@ -2474,6 +2478,8 @@
                     } else {
                         mLockscreenGestureLogger.write(MetricsEvent.ACTION_LS_HINT,
                                 0 /* lengthDp - N/A */, 0 /* velocityDp - N/A */);
+                        mLockscreenGestureLogger
+                            .log(LockscreenUiEvent.LOCKSCREEN_LOCK_SHOW_HINT);
                         startUnlockHintAnimation();
                     }
                 }
@@ -3069,7 +3075,7 @@
         return new TouchHandler() {
             @Override
             public boolean onInterceptTouchEvent(MotionEvent event) {
-                if (mBlockTouches || mQsFullyExpanded && mQs.onInterceptTouchEvent(event)) {
+                if (mBlockTouches || mQsFullyExpanded && mQs.disallowPanelTouches()) {
                     return false;
                 }
                 initDownStates(event);
@@ -3096,7 +3102,8 @@
 
             @Override
             public boolean onTouch(View v, MotionEvent event) {
-                if (mBlockTouches || (mQs != null && mQs.isCustomizing())) {
+                if (mBlockTouches || (mQsFullyExpanded && mQs != null
+                        && mQs.disallowPanelTouches())) {
                     return false;
                 }
 
@@ -3257,7 +3264,7 @@
             int velocityDp = Math.abs((int) (vel / displayDensity));
             if (start) {
                 mLockscreenGestureLogger.write(MetricsEvent.ACTION_LS_DIALER, lengthDp, velocityDp);
-
+                mLockscreenGestureLogger.log(LockscreenUiEvent.LOCKSCREEN_DIALER);
                 mFalsingManager.onLeftAffordanceOn();
                 if (mFalsingManager.shouldEnforceBouncer()) {
                     mStatusBar.executeRunnableDismissingKeyguard(
@@ -3272,6 +3279,7 @@
                         mLastCameraLaunchSource)) {
                     mLockscreenGestureLogger.write(
                             MetricsEvent.ACTION_LS_CAMERA, lengthDp, velocityDp);
+                    mLockscreenGestureLogger.log(LockscreenUiEvent.LOCKSCREEN_CAMERA);
                 }
                 mFalsingManager.onCameraOn();
                 if (mFalsingManager.shouldEnforceBouncer()) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelViewController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelViewController.java
index 57d36fc..a902e1b 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelViewController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelViewController.java
@@ -47,6 +47,7 @@
 import com.android.systemui.statusbar.StatusBarState;
 import com.android.systemui.statusbar.SysuiStatusBarStateController;
 import com.android.systemui.statusbar.VibratorHelper;
+import com.android.systemui.statusbar.phone.LockscreenGestureLogger.LockscreenUiEvent;
 import com.android.systemui.statusbar.policy.KeyguardStateController;
 
 import java.io.FileDescriptor;
@@ -319,6 +320,8 @@
 
         mLockscreenGestureLogger.writeAtFractionalPosition(MetricsEvent.ACTION_PANEL_VIEW_EXPAND,
                 (int) (event.getX() / width * 100), (int) (event.getY() / height * 100), rot);
+        mLockscreenGestureLogger
+                .log(LockscreenUiEvent.LOCKSCREEN_UNLOCKED_NOTIFICATION_PANEL_EXPAND);
     }
 
     protected void maybeVibrateOnOpening() {
@@ -378,6 +381,7 @@
                 int heightDp = (int) Math.abs((y - mInitialTouchY) / displayDensity);
                 int velocityDp = (int) Math.abs(vel / displayDensity);
                 mLockscreenGestureLogger.write(MetricsEvent.ACTION_LS_UNLOCK, heightDp, velocityDp);
+                mLockscreenGestureLogger.log(LockscreenUiEvent.LOCKSCREEN_UNLOCK);
             }
             fling(vel, expand, isFalseTouch(x, y));
             onTrackingStopped(expand);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/RotationButtonController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/RotationButtonController.java
index de9c745..59b10e4 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/RotationButtonController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/RotationButtonController.java
@@ -74,6 +74,7 @@
     private Consumer<Integer> mRotWatcherListener;
     private boolean mListenersRegistered = false;
     private boolean mIsNavigationBarShowing;
+    private boolean mSkipOverrideUserLockPrefsOnce;
 
     private final Runnable mRemoveRotationProposal =
             () -> setRotateSuggestionButtonState(false /* visible */);
@@ -349,7 +350,20 @@
         mUiEventLogger.log(RotationButtonEvent.ROTATION_SUGGESTION_SHOWN);
     }
 
+    /**
+     * Makes {@link #shouldOverrideUserLockPrefs} always return {@code false} once. It is used to
+     * avoid losing original user rotation when display rotation is changed by entering the fixed
+     * orientation overview.
+     */
+    void setSkipOverrideUserLockPrefsOnce() {
+        mSkipOverrideUserLockPrefsOnce = true;
+    }
+
     private boolean shouldOverrideUserLockPrefs(final int rotation) {
+        if (mSkipOverrideUserLockPrefsOnce) {
+            mSkipOverrideUserLockPrefsOnce = false;
+            return false;
+        }
         // Only override user prefs when returning to the natural rotation (normally portrait).
         // Don't let apps that force landscape or 180 alter user lock.
         return rotation == NATURAL_ROTATION;
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 1bc42d1..a21ca53 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
@@ -1275,7 +1275,7 @@
         mActivityLaunchAnimator = new ActivityLaunchAnimator(
                 mNotificationShadeWindowViewController, this, mNotificationPanelViewController,
                 mNotificationShadeDepthControllerLazy.get(),
-                (NotificationListContainer) mStackScroller);
+                (NotificationListContainer) mStackScroller, mContext.getMainExecutor());
 
         // TODO: inject this.
         mPresenter = new StatusBarNotificationPresenter(mContext, mNotificationPanelViewController,
@@ -1772,6 +1772,9 @@
     }
 
     public void setPanelExpanded(boolean isExpanded) {
+        if (mPanelExpanded != isExpanded) {
+            mNotificationLogger.onPanelExpandedChanged(isExpanded);
+        }
         mPanelExpanded = isExpanded;
         updateHideIconsForBouncer(false /* animate */);
         mNotificationShadeWindowController.setPanelExpanded(isExpanded);
@@ -2090,7 +2093,7 @@
     /**
      * Called when another window is about to transfer it's input focus.
      */
-    public void onInputFocusTransfer(boolean start, float velocity) {
+    public void onInputFocusTransfer(boolean start, boolean cancel, float velocity) {
         if (!mCommandQueue.panelsEnabled()) {
             return;
         }
@@ -2098,7 +2101,7 @@
         if (start) {
             mNotificationPanelViewController.startWaitingForOpenPanelGesture();
         } else {
-            mNotificationPanelViewController.stopWaitingForOpenPanelGesture(velocity);
+            mNotificationPanelViewController.stopWaitingForOpenPanelGesture(cancel, velocity);
         }
     }
 
@@ -2878,7 +2881,6 @@
     }
 
     // Visibility reporting
-
     protected void handleVisibleToUserChanged(boolean visibleToUser) {
         if (visibleToUser) {
             handleVisibleToUserChangedImpl(visibleToUser);
@@ -2900,12 +2902,12 @@
         }
     }
 
-    /**
-     * The LEDs are turned off when the notification panel is shown, even just a little bit.
-     * See also StatusBar.setPanelExpanded for another place where we attempt to do this.
-     */
-    private void handleVisibleToUserChangedImpl(boolean visibleToUser) {
+    // Visibility reporting
+
+    void handleVisibleToUserChangedImpl(boolean visibleToUser) {
         if (visibleToUser) {
+            /* The LEDs are turned off when the notification panel is shown, even just a little bit.
+             * See also StatusBar.setPanelExpanded for another place where we attempt to do this. */
             boolean pinnedHeadsUp = mHeadsUpManager.hasPinnedHeadsUp();
             boolean clearNotificationEffects =
                     !mPresenter.isPresenterFullyCollapsed() &&
@@ -3982,7 +3984,7 @@
         } else if (mIsKeyguard && !unlocking) {
             mScrimController.transitionTo(ScrimState.KEYGUARD);
         } else if (mBubbleController.isStackExpanded()) {
-            mScrimController.transitionTo(ScrimState.BUBBLE_EXPANDED);
+            mScrimController.transitionTo(ScrimState.BUBBLE_EXPANDED, mUnlockScrimCallback);
         } else {
             mScrimController.transitionTo(ScrimState.UNLOCKED, mUnlockScrimCallback);
         }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenter.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenter.java
index 84da35b..45f0c49 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenter.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenter.java
@@ -72,6 +72,7 @@
 import com.android.systemui.statusbar.notification.row.NotificationGutsManager.OnSettingsClickListener;
 import com.android.systemui.statusbar.notification.row.NotificationInfo.CheckSaveListener;
 import com.android.systemui.statusbar.notification.stack.NotificationListContainer;
+import com.android.systemui.statusbar.phone.LockscreenGestureLogger.LockscreenUiEvent;
 import com.android.systemui.statusbar.policy.ConfigurationController;
 import com.android.systemui.statusbar.policy.KeyguardStateController;
 
@@ -374,6 +375,7 @@
         mLockscreenGestureLogger.write(
                 MetricsEvent.ACTION_LS_NOTE,
                 0 /* lengthDp - N/A */, 0 /* velocityDp - N/A */);
+        mLockscreenGestureLogger.log(LockscreenUiEvent.LOCKSCREEN_NOTIFICATION_FALSE_TOUCH);
         mNotificationPanel.showTransientIndication(R.string.notification_tap_again);
         ActivatableNotificationView previousView = mNotificationPanel.getActivatedChild();
         if (previousView != null) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/VerticalNavigationHandle.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/VerticalNavigationHandle.java
index a15ca95..0cdf1d3 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/VerticalNavigationHandle.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/VerticalNavigationHandle.java
@@ -18,12 +18,14 @@
 
 import android.content.Context;
 import android.graphics.Canvas;
+import android.graphics.RectF;
 
 import com.android.systemui.R;
 
 /** Temporarily shown view when using QuickSwitch to switch between apps of different rotations */
 public class VerticalNavigationHandle extends NavigationHandle {
     private final int mWidth;
+    private final RectF mTmpBoundsRectF = new RectF();
 
     public VerticalNavigationHandle(Context context) {
         super(context);
@@ -32,16 +34,21 @@
 
     @Override
     protected void onDraw(Canvas canvas) {
+        canvas.drawRoundRect(computeHomeHandleBounds(), mRadius, mRadius, mPaint);
+    }
+
+    RectF computeHomeHandleBounds() {
         int left;
         int top;
         int bottom;
         int right;
-
+        int topStart = getLocationOnScreen()[1];
         int radiusOffset = mRadius * 2;
         right = getWidth() - mBottom;
-        top = getHeight() / 2 - (mWidth / 2); /* (height of screen / 2) - (height of bar / 2) */
+        top = getHeight() / 2 - (mWidth / 2) - (topStart / 2);
         left = getWidth() - mBottom - radiusOffset;
-        bottom = getHeight() / 2 + (mWidth / 2);
-        canvas.drawRoundRect(left, top, right, bottom, mRadius, mRadius, mPaint);
+        bottom = top + mWidth;
+        mTmpBoundsRectF.set(left, top, right, bottom);
+        return mTmpBoundsRectF;
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyButtonRipple.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyButtonRipple.java
index 0db76ec..c929243 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyButtonRipple.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyButtonRipple.java
@@ -28,6 +28,7 @@
 import android.graphics.RecordingCanvas;
 import android.graphics.drawable.Drawable;
 import android.os.Handler;
+import android.util.Log;
 import android.view.RenderNodeAnimator;
 import android.view.View;
 import android.view.ViewConfiguration;
@@ -220,7 +221,7 @@
 
     @Override
     public void jumpToCurrentState() {
-        cancelAnimations();
+        cancelAnimations("jumpToCurrentState");
     }
 
     @Override
@@ -234,6 +235,7 @@
     }
 
     public void setPressed(boolean pressed) {
+        Log.d("b/63783866", "KeyButtonRipple.setPressed: pressed=" + pressed);
         if (mDark != mLastDark && pressed) {
             mRipplePaint = null;
             mLastDark = mDark;
@@ -253,7 +255,8 @@
         mHandler.removeCallbacksAndMessages(null);
     }
 
-    private void cancelAnimations() {
+    private void cancelAnimations(String reason) {
+        Log.d("b/63783866", "KeyButtonRipple.cancelAnimations: reason=" + reason);
         mVisible = false;
         mTmpArray.addAll(mRunningAnimations);
         int size = mTmpArray.size();
@@ -284,7 +287,7 @@
     }
 
     private void enterSoftware() {
-        cancelAnimations();
+        cancelAnimations("enterSoftware");
         mVisible = true;
         mGlowAlpha = getMaxGlowAlpha();
         ObjectAnimator scaleAnimator = ObjectAnimator.ofFloat(this, "glowScale",
@@ -370,7 +373,8 @@
     }
 
     private void enterHardware() {
-        cancelAnimations();
+        Log.d("b/63783866", "enterHardware");
+        cancelAnimations("enterHardware");
         mVisible = true;
         mDrawingHardwareGlow = true;
         setExtendStart(CanvasProperty.createFloat(getExtendSize() / 2));
@@ -422,6 +426,7 @@
     }
 
     private void exitHardware() {
+        Log.d("b/63783866", "exitHardware");
         mPaintProp = CanvasProperty.createPaint(getRipplePaint());
         final RenderNodeAnimator opacityAnim = new RenderNodeAnimator(mPaintProp,
                 RenderNodeAnimator.PAINT_ALPHA, 0);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyButtonView.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyButtonView.java
index 58f5d2a..8d7ecd0 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyButtonView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyButtonView.java
@@ -87,7 +87,7 @@
     private boolean mHasOvalBg = false;
 
     @VisibleForTesting
-    public enum NavBarActionsEvent implements UiEventLogger.UiEventEnum {
+    public enum NavBarButtonEvent implements UiEventLogger.UiEventEnum {
 
         @UiEvent(doc = "The home button was pressed in the navigation bar.")
         NAVBAR_HOME_BUTTON_TAP(533),
@@ -111,7 +111,7 @@
 
         private final int mId;
 
-        NavBarActionsEvent(int id) {
+        NavBarButtonEvent(int id) {
             mId = id;
         }
 
@@ -368,7 +368,7 @@
 
     private void logSomePresses(int action, int flags) {
         boolean longPressSet = (flags & KeyEvent.FLAG_LONG_PRESS) != 0;
-        NavBarActionsEvent uiEvent = NavBarActionsEvent.NONE;
+        NavBarButtonEvent uiEvent = NavBarButtonEvent.NONE;
         if (action == MotionEvent.ACTION_UP && mLongClicked) {
             return;  // don't log the up after a long press
         }
@@ -382,21 +382,21 @@
         switch(mCode) {
             case KeyEvent.KEYCODE_BACK:
                 uiEvent = longPressSet
-                        ? NavBarActionsEvent.NAVBAR_BACK_BUTTON_LONGPRESS
-                        : NavBarActionsEvent.NAVBAR_BACK_BUTTON_TAP;
+                        ? NavBarButtonEvent.NAVBAR_BACK_BUTTON_LONGPRESS
+                        : NavBarButtonEvent.NAVBAR_BACK_BUTTON_TAP;
                 break;
             case KeyEvent.KEYCODE_HOME:
                 uiEvent = longPressSet
-                        ? NavBarActionsEvent.NAVBAR_HOME_BUTTON_LONGPRESS
-                        : NavBarActionsEvent.NAVBAR_HOME_BUTTON_TAP;
+                        ? NavBarButtonEvent.NAVBAR_HOME_BUTTON_LONGPRESS
+                        : NavBarButtonEvent.NAVBAR_HOME_BUTTON_TAP;
                 break;
             case KeyEvent.KEYCODE_APP_SWITCH:
                 uiEvent = longPressSet
-                        ? NavBarActionsEvent.NAVBAR_OVERVIEW_BUTTON_LONGPRESS
-                        : NavBarActionsEvent.NAVBAR_OVERVIEW_BUTTON_TAP;
+                        ? NavBarButtonEvent.NAVBAR_OVERVIEW_BUTTON_LONGPRESS
+                        : NavBarButtonEvent.NAVBAR_OVERVIEW_BUTTON_TAP;
                 break;
         }
-        if (uiEvent != NavBarActionsEvent.NONE) {
+        if (uiEvent != NavBarButtonEvent.NONE) {
             mUiEventLogger.log(uiEvent);
         }
     }
@@ -441,6 +441,7 @@
 
     @Override
     public void abortCurrentGesture() {
+        Log.d("b/63783866", "KeyButtonView.abortCurrentGesture");
         setPressed(false);
         mRipple.abortDelayedRipple();
         mGestureAborted = true;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardUserSwitcher.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardUserSwitcher.java
index df3748a..512d0f3 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardUserSwitcher.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardUserSwitcher.java
@@ -16,11 +16,15 @@
 
 package com.android.systemui.statusbar.policy;
 
+import static com.android.systemui.statusbar.policy.UserSwitcherController.USER_SWITCH_DISABLED_ALPHA;
+import static com.android.systemui.statusbar.policy.UserSwitcherController.USER_SWITCH_ENABLED_ALPHA;
+
 import android.animation.Animator;
 import android.animation.AnimatorListenerAdapter;
 import android.animation.ObjectAnimator;
 import android.content.Context;
 import android.database.DataSetObserver;
+import android.graphics.drawable.BitmapDrawable;
 import android.graphics.drawable.Drawable;
 import android.graphics.drawable.LayerDrawable;
 import android.util.AttributeSet;
@@ -46,8 +50,6 @@
 
     private static final String TAG = "KeyguardUserSwitcher";
     private static final boolean ALWAYS_ON = false;
-    private static final float USER_SWITCH_ENABLED_ALPHA = 1.0f;
-    private static final float USER_SWITCH_DISABLED_ALPHA = 0.38f;
 
     private final Container mUserSwitcherContainer;
     private final KeyguardStatusBarView mStatusBarView;
@@ -286,27 +288,34 @@
             if (item.picture == null) {
                 v.bind(name, getDrawable(mContext, item).mutate(), item.resolveId());
             } else {
-                v.bind(name, item.picture, item.info.id);
+                Drawable drawable = new BitmapDrawable(v.getResources(), item.picture);
+                drawable.setColorFilter(
+                        item.isSwitchToEnabled ? null : getDisabledUserAvatarColorFilter());
+                v.bind(name, drawable, item.info.id);
             }
-            // Disable the icon if switching is disabled
-            v.setAvatarEnabled(item.isSwitchToEnabled);
-            convertView.setActivated(item.isCurrent);
+            v.setActivated(item.isCurrent);
+            v.setDisabledByAdmin(item.isDisabledByAdmin);
+            v.setEnabled(item.isSwitchToEnabled);
+            v.setAlpha(v.isEnabled() ? USER_SWITCH_ENABLED_ALPHA : USER_SWITCH_DISABLED_ALPHA);
+
             if (item.isCurrent) {
-                mCurrentUserView = convertView;
+                mCurrentUserView = v;
             }
-            convertView.setTag(item);
-            convertView.setAlpha(
-                    item.isCurrent || item.isSwitchToEnabled ? USER_SWITCH_ENABLED_ALPHA
-                            : USER_SWITCH_DISABLED_ALPHA);
-            convertView.setEnabled(item.isSwitchToEnabled);
-            return convertView;
+            v.setTag(item);
+            return v;
         }
 
         private static Drawable getDrawable(Context context,
                 UserSwitcherController.UserRecord item) {
             Drawable drawable = getIconDrawable(context, item);
-            int iconColorRes = item.isCurrent ? R.color.kg_user_switcher_selected_avatar_icon_color
-                    : R.color.kg_user_switcher_avatar_icon_color;
+            int iconColorRes;
+            if (item.isCurrent) {
+                iconColorRes = R.color.kg_user_switcher_selected_avatar_icon_color;
+            } else if (!item.isSwitchToEnabled) {
+                iconColorRes = R.color.GM2_grey_600;
+            } else {
+                iconColorRes = R.color.kg_user_switcher_avatar_icon_color;
+            }
             drawable.setTint(context.getResources().getColor(iconColorRes, context.getTheme()));
 
             if (item.isCurrent) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserSwitcherController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserSwitcherController.java
index db00770..ce5bb05 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserSwitcherController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserSwitcherController.java
@@ -31,6 +31,9 @@
 import android.content.pm.UserInfo;
 import android.database.ContentObserver;
 import android.graphics.Bitmap;
+import android.graphics.ColorFilter;
+import android.graphics.ColorMatrix;
+import android.graphics.ColorMatrixColorFilter;
 import android.graphics.drawable.Drawable;
 import android.os.AsyncTask;
 import android.os.Handler;
@@ -81,6 +84,9 @@
 @Singleton
 public class UserSwitcherController implements Dumpable {
 
+    public static final float USER_SWITCH_ENABLED_ALPHA = 1.0f;
+    public static final float USER_SWITCH_DISABLED_ALPHA = 0.38f;
+
     private static final String TAG = "UserSwitcherController";
     private static final boolean DEBUG = false;
     private static final String SIMPLE_USER_SWITCHER_GLOBAL_SETTING =
@@ -361,8 +367,14 @@
         int id;
         if (record.isGuest && record.info == null) {
             // No guest user. Create one.
-            UserInfo guest = mUserManager.createGuest(
-                    mContext, mContext.getString(com.android.settingslib.R.string.guest_nickname));
+            UserInfo guest;
+            try {
+                guest = mUserManager.createGuest(mContext,
+                        mContext.getString(com.android.settingslib.R.string.guest_nickname));
+            } catch (UserManager.UserOperationException e) {
+                Log.e(TAG, "Couldn't create guest user", e);
+                return;
+            }
             if (guest == null) {
                 // Couldn't create guest, most likely because there already exists one, we just
                 // haven't reloaded the user list yet.
@@ -674,6 +686,12 @@
             }
         }
 
+        protected static ColorFilter getDisabledUserAvatarColorFilter() {
+            ColorMatrix matrix = new ColorMatrix();
+            matrix.setSaturation(0f);   // 0 - grayscale
+            return new ColorMatrixColorFilter(matrix);
+        }
+
         protected static Drawable getIconDrawable(Context context, UserRecord item) {
             int iconRes;
             if (item.isAddUser) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/tv/micdisclosure/AudioRecordingDisclosureBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/tv/micdisclosure/AudioRecordingDisclosureBar.java
index 9148683..8b85a0961 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/tv/micdisclosure/AudioRecordingDisclosureBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/tv/micdisclosure/AudioRecordingDisclosureBar.java
@@ -29,6 +29,8 @@
 import android.content.pm.ApplicationInfo;
 import android.content.pm.PackageManager;
 import android.graphics.PixelFormat;
+import android.provider.Settings;
+import android.text.TextUtils;
 import android.util.ArraySet;
 import android.util.Log;
 import android.view.Gravity;
@@ -63,6 +65,9 @@
     // CtsSystemUiHostTestCases:TvMicrophoneCaptureIndicatorTest
     private static final String LAYOUT_PARAMS_TITLE = "MicrophoneCaptureIndicator";
 
+    private static final String EXEMPT_PACKAGES_LIST = "sysui_mic_disclosure_exempt";
+    private static final String FORCED_PACKAGES_LIST = "sysui_mic_disclosure_forced";
+
     @Retention(RetentionPolicy.SOURCE)
     @IntDef(prefix = {"STATE_"}, value = {
             STATE_NOT_SHOWN,
@@ -134,6 +139,8 @@
         mExemptPackages = new ArraySet<>(
                 Arrays.asList(mContext.getResources().getStringArray(
                         R.array.audio_recording_disclosure_exempt_apps)));
+        mExemptPackages.addAll(Arrays.asList(getGlobalStringArray(EXEMPT_PACKAGES_LIST)));
+        mExemptPackages.removeAll(Arrays.asList(getGlobalStringArray(FORCED_PACKAGES_LIST)));
 
         mAudioActivityObservers = new AudioActivityObserver[]{
                 new RecordAudioAppOpObserver(mContext, this),
@@ -141,6 +148,11 @@
         };
     }
 
+    private String[] getGlobalStringArray(String setting) {
+        String result = Settings.Global.getString(mContext.getContentResolver(), setting);
+        return TextUtils.isEmpty(result) ? new String[0] : result.split(",");
+    }
+
     @UiThread
     @Override
     public void onAudioActivityStateChange(boolean active, String packageName) {
diff --git a/packages/SystemUI/src/com/android/systemui/usb/UsbDebuggingActivity.java b/packages/SystemUI/src/com/android/systemui/usb/UsbDebuggingActivity.java
index 2973e0a..bc2a55c 100644
--- a/packages/SystemUI/src/com/android/systemui/usb/UsbDebuggingActivity.java
+++ b/packages/SystemUI/src/com/android/systemui/usb/UsbDebuggingActivity.java
@@ -16,13 +16,19 @@
 
 package com.android.systemui.usb;
 
+import android.app.Activity;
 import android.app.AlertDialog;
+import android.content.BroadcastReceiver;
+import android.content.Context;
 import android.content.DialogInterface;
 import android.content.Intent;
+import android.content.IntentFilter;
 import android.debug.IAdbManager;
+import android.hardware.usb.UsbManager;
 import android.os.Bundle;
 import android.os.IBinder;
 import android.os.ServiceManager;
+import android.os.SystemProperties;
 import android.util.Log;
 import android.view.LayoutInflater;
 import android.view.View;
@@ -33,13 +39,25 @@
 import com.android.internal.app.AlertActivity;
 import com.android.internal.app.AlertController;
 import com.android.systemui.R;
+import com.android.systemui.broadcast.BroadcastDispatcher;
+
+import javax.inject.Inject;
 
 public class UsbDebuggingActivity extends AlertActivity
                                   implements DialogInterface.OnClickListener {
     private static final String TAG = "UsbDebuggingActivity";
 
     private CheckBox mAlwaysAllow;
+    private UsbDisconnectedReceiver mDisconnectedReceiver;
+    private final BroadcastDispatcher mBroadcastDispatcher;
     private String mKey;
+    private boolean mServiceNotified;
+
+    @Inject
+    public UsbDebuggingActivity(BroadcastDispatcher broadcastDispatcher) {
+        super();
+        mBroadcastDispatcher = broadcastDispatcher;
+    }
 
     @Override
     public void onCreate(Bundle icicle) {
@@ -50,6 +68,10 @@
 
         super.onCreate(icicle);
 
+        if (SystemProperties.getInt("service.adb.tcp.port", 0) == 0) {
+            mDisconnectedReceiver = new UsbDisconnectedReceiver(this);
+        }
+
         Intent intent = getIntent();
         String fingerprints = intent.getStringExtra("fingerprints");
         mKey = intent.getStringExtra("key");
@@ -83,10 +105,77 @@
         super.onWindowAttributesChanged(params);
     }
 
+    private class UsbDisconnectedReceiver extends BroadcastReceiver {
+        private final Activity mActivity;
+        UsbDisconnectedReceiver(Activity activity) {
+            mActivity = activity;
+        }
+
+        @Override
+        public void onReceive(Context content, Intent intent) {
+            String action = intent.getAction();
+            if (!UsbManager.ACTION_USB_STATE.equals(action)) {
+                return;
+            }
+            boolean connected = intent.getBooleanExtra(UsbManager.USB_CONNECTED, false);
+            if (!connected) {
+                notifyService(false);
+                mActivity.finish();
+            }
+        }
+    }
+
+    @Override
+    public void onStart() {
+        super.onStart();
+        if (mDisconnectedReceiver != null) {
+            IntentFilter filter = new IntentFilter(UsbManager.ACTION_USB_STATE);
+            mBroadcastDispatcher.registerReceiver(mDisconnectedReceiver, filter);
+        }
+    }
+
+    @Override
+    protected void onStop() {
+        if (mDisconnectedReceiver != null) {
+            mBroadcastDispatcher.unregisterReceiver(mDisconnectedReceiver);
+        }
+        // If the ADB service has not yet been notified due to this dialog being closed in some
+        // other way then notify the service to deny the connection to ensure system_server sends
+        // a response to adbd.
+        if (!mServiceNotified) {
+            notifyService(false);
+        }
+        super.onStop();
+    }
+
     @Override
     public void onClick(DialogInterface dialog, int which) {
         boolean allow = (which == AlertDialog.BUTTON_POSITIVE);
         boolean alwaysAllow = allow && mAlwaysAllow.isChecked();
+        notifyService(allow, alwaysAllow);
+        finish();
+    }
+
+    /**
+     * Notifies the ADB service as to whether the current ADB request should be allowed; if the
+     * request is allowed it is only allowed for this session, and the user should be prompted again
+     * on subsequent requests from this key.
+     *
+     * @param allow whether the connection should be allowed for this session
+     */
+    private void notifyService(boolean allow) {
+        notifyService(allow, false);
+    }
+
+    /**
+     * Notifies the ADB service as to whether the current ADB request should be allowed, and if
+     * subsequent requests from this key should be allowed without user consent.
+     *
+     * @param allow whether the connection should be allowed
+     * @param alwaysAllow whether subsequent requests from this key should be allowed without user
+     *                    consent
+     */
+    private void notifyService(boolean allow, boolean alwaysAllow) {
         try {
             IBinder b = ServiceManager.getService(ADB_SERVICE);
             IAdbManager service = IAdbManager.Stub.asInterface(b);
@@ -95,9 +184,9 @@
             } else {
                 service.denyDebugging();
             }
+            mServiceNotified = true;
         } catch (Exception e) {
             Log.e(TAG, "Unable to notify Usb service", e);
         }
-        finish();
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/usb/UsbDebuggingSecondaryUserActivity.java b/packages/SystemUI/src/com/android/systemui/usb/UsbDebuggingSecondaryUserActivity.java
index 4214242..4850a02 100644
--- a/packages/SystemUI/src/com/android/systemui/usb/UsbDebuggingSecondaryUserActivity.java
+++ b/packages/SystemUI/src/com/android/systemui/usb/UsbDebuggingSecondaryUserActivity.java
@@ -16,19 +16,47 @@
 
 package com.android.systemui.usb;
 
+import android.app.Activity;
+import android.content.BroadcastReceiver;
+import android.content.Context;
 import android.content.DialogInterface;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.debug.IAdbManager;
+import android.hardware.usb.UsbManager;
 import android.os.Bundle;
+import android.os.IBinder;
+import android.os.RemoteException;
+import android.os.ServiceManager;
+import android.os.SystemProperties;
+import android.util.Log;
 
 import com.android.internal.app.AlertActivity;
 import com.android.internal.app.AlertController;
 import com.android.systemui.R;
+import com.android.systemui.broadcast.BroadcastDispatcher;
+
+import javax.inject.Inject;
 
 public class UsbDebuggingSecondaryUserActivity extends AlertActivity
         implements DialogInterface.OnClickListener {
+    private static final String TAG = "UsbDebuggingSecondaryUserActivity";
+    private UsbDisconnectedReceiver mDisconnectedReceiver;
+    private final BroadcastDispatcher mBroadcastDispatcher;
+
+    @Inject
+    public UsbDebuggingSecondaryUserActivity(BroadcastDispatcher broadcastDispatcher) {
+        mBroadcastDispatcher = broadcastDispatcher;
+    }
+
     @Override
     public void onCreate(Bundle icicle) {
         super.onCreate(icicle);
 
+        if (SystemProperties.getInt("service.adb.tcp.port", 0) == 0) {
+            mDisconnectedReceiver = new UsbDisconnectedReceiver(this);
+        }
+
         final AlertController.AlertParams ap = mAlertParams;
         ap.mTitle = getString(R.string.usb_debugging_secondary_user_title);
         ap.mMessage = getString(R.string.usb_debugging_secondary_user_message);
@@ -38,6 +66,48 @@
         setupAlert();
     }
 
+    private class UsbDisconnectedReceiver extends BroadcastReceiver {
+        private final Activity mActivity;
+        UsbDisconnectedReceiver(Activity activity) {
+            mActivity = activity;
+        }
+
+        @Override
+        public void onReceive(Context content, Intent intent) {
+            String action = intent.getAction();
+            if (UsbManager.ACTION_USB_STATE.equals(action)) {
+                boolean connected = intent.getBooleanExtra(UsbManager.USB_CONNECTED, false);
+                if (!connected) {
+                    mActivity.finish();
+                }
+            }
+        }
+    }
+
+    @Override
+    public void onStart() {
+        super.onStart();
+        if (mDisconnectedReceiver != null) {
+            IntentFilter filter = new IntentFilter(UsbManager.ACTION_USB_STATE);
+            mBroadcastDispatcher.registerReceiver(mDisconnectedReceiver, filter);
+        }
+    }
+
+    @Override
+    protected void onStop() {
+        if (mDisconnectedReceiver != null) {
+            mBroadcastDispatcher.unregisterReceiver(mDisconnectedReceiver);
+        }
+        try {
+            IBinder b = ServiceManager.getService(ADB_SERVICE);
+            IAdbManager service = IAdbManager.Stub.asInterface(b);
+            service.denyDebugging();
+        } catch (RemoteException e) {
+            Log.e(TAG, "Unable to notify Usb service", e);
+        }
+        super.onStop();
+    }
+
     @Override
     public void onClick(DialogInterface dialog, int which) {
         finish();
diff --git a/packages/SystemUI/src/com/android/systemui/util/ConvenienceExtensions.kt b/packages/SystemUI/src/com/android/systemui/util/ConvenienceExtensions.kt
index c91033e..631ea9d6 100644
--- a/packages/SystemUI/src/com/android/systemui/util/ConvenienceExtensions.kt
+++ b/packages/SystemUI/src/com/android/systemui/util/ConvenienceExtensions.kt
@@ -22,4 +22,14 @@
 val ViewGroup.children
     get() = sequence {
         for (i in 0 until childCount) yield(getChildAt(i))
-    }
\ No newline at end of file
+    }
+
+/** Inclusive version of [Iterable.takeWhile] */
+fun <T> Sequence<T>.takeUntil(pred: (T) -> Boolean): Sequence<T> = sequence {
+    for (x in this@takeUntil) {
+        yield(x)
+        if (pred(x)) {
+            break
+        }
+    }
+}
\ No newline at end of file
diff --git a/packages/SystemUI/src/com/android/systemui/util/NeverExactlyLinearLayout.kt b/packages/SystemUI/src/com/android/systemui/util/NeverExactlyLinearLayout.kt
new file mode 100644
index 0000000..bab9347
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/util/NeverExactlyLinearLayout.kt
@@ -0,0 +1,60 @@
+/*
+ * Copyright (C) 2020 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.util
+
+import android.content.Context
+import android.util.AttributeSet
+import android.widget.LinearLayout
+
+/**
+ * Basically a normal linear layout but doesn't grow its children with weight 1 even when its
+ * measured with exactly.
+ */
+class NeverExactlyLinearLayout @JvmOverloads constructor(
+    context: Context,
+    attrs: AttributeSet? = null,
+    defStyleAttr: Int = 0
+) : LinearLayout(context, attrs, defStyleAttr) {
+    override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) {
+
+        val (widthExactly, usedWidthSpec, width) = getNonExactlyMeasureSpec(widthMeasureSpec)
+        val (heightExactly, usedHeightSpec, height) = getNonExactlyMeasureSpec(heightMeasureSpec)
+
+        super.onMeasure(usedWidthSpec, usedHeightSpec)
+        if (widthExactly || heightExactly) {
+            val newWidth = if (widthExactly) width else measuredWidth
+            val newHeight = if (heightExactly) height else measuredHeight
+            setMeasuredDimension(newWidth, newHeight)
+        }
+    }
+
+    /**
+     * Obtain a measurespec that's not exactly
+     *
+     * @return a triple, where we return 1. if this was exactly, 2. the new measurespec, 3. the size
+     *         of the measurespec
+     */
+    private fun getNonExactlyMeasureSpec(measureSpec: Int): Triple<Boolean, Int, Int> {
+        var newSpec = measureSpec
+        val isExactly = MeasureSpec.getMode(measureSpec) == MeasureSpec.EXACTLY
+        val size = MeasureSpec.getSize(measureSpec)
+        if (isExactly) {
+            newSpec = MeasureSpec.makeMeasureSpec(size, MeasureSpec.AT_MOST)
+        }
+        return Triple(isExactly, newSpec, size)
+    }
+}
\ No newline at end of file
diff --git a/packages/SystemUI/src/com/android/systemui/util/SparseArrayUtils.kt b/packages/SystemUI/src/com/android/systemui/util/SparseArrayUtils.kt
index accb81e..1a25c84 100644
--- a/packages/SystemUI/src/com/android/systemui/util/SparseArrayUtils.kt
+++ b/packages/SystemUI/src/com/android/systemui/util/SparseArrayUtils.kt
@@ -19,6 +19,22 @@
 import android.util.SparseArray
 
 /**
+ * Transforms a sequence of Key/Value pairs into a SparseArray.
+ *
+ * See [kotlin.collections.toMap].
+ */
+fun <T> Sequence<Pair<Int, T>>.toSparseArray(size: Int = -1): SparseArray<T> {
+    val sparseArray = when {
+        size < 0 -> SparseArray<T>()
+        else -> SparseArray<T>(size)
+    }
+    for ((i, v) in this) {
+        sparseArray.put(i, v)
+    }
+    return sparseArray
+}
+
+/**
  * Transforms an [Array] into a [SparseArray], by applying each element to [keySelector] in order to
  * generate the index at which it will be placed. If two elements produce the same index, the latter
  * replaces the former in the final result.
diff --git a/packages/SystemUI/src/com/android/systemui/util/animation/PhysicsAnimator.kt b/packages/SystemUI/src/com/android/systemui/util/animation/PhysicsAnimator.kt
index 318a6d7..016f4de 100644
--- a/packages/SystemUI/src/com/android/systemui/util/animation/PhysicsAnimator.kt
+++ b/packages/SystemUI/src/com/android/systemui/util/animation/PhysicsAnimator.kt
@@ -644,6 +644,12 @@
                 it.onInternalAnimationEnd(
                         property, canceled, value, velocity, anim is FlingAnimation)
             }
+            if (springAnimations[property] == anim) {
+                springAnimations.remove(property)
+            }
+            if (flingAnimations[property] == anim) {
+                flingAnimations.remove(property)
+            }
         }
         return anim
     }
diff --git a/packages/SystemUI/src/com/android/systemui/util/animation/TransitionLayout.kt b/packages/SystemUI/src/com/android/systemui/util/animation/TransitionLayout.kt
index 701ff5e..eeca1e3 100644
--- a/packages/SystemUI/src/com/android/systemui/util/animation/TransitionLayout.kt
+++ b/packages/SystemUI/src/com/android/systemui/util/animation/TransitionLayout.kt
@@ -17,6 +17,7 @@
 package com.android.systemui.util.animation
 
 import android.content.Context
+import android.graphics.PointF
 import android.graphics.Rect
 import android.util.AttributeSet
 import android.view.View
@@ -37,6 +38,7 @@
 ) : ConstraintLayout(context, attrs, defStyleAttr) {
 
     private val originalGoneChildrenSet: MutableSet<Int> = mutableSetOf()
+    private val originalViewAlphas: MutableMap<Int, Float> = mutableMapOf()
     private var measureAsConstraint: Boolean = false
     private var currentState: TransitionViewState = TransitionViewState()
     private var updateScheduled = false
@@ -67,6 +69,7 @@
             if (child.visibility == GONE) {
                 originalGoneChildrenSet.add(child.id)
             }
+            originalViewAlphas[child.id] = child.alpha
         }
     }
 
@@ -149,6 +152,11 @@
         val layoutTop = top
         setLeftTopRightBottom(layoutLeft, layoutTop, layoutLeft + currentState.width,
                 layoutTop + currentState.height)
+        val bounds = clipBounds ?: Rect()
+        bounds.set(left, top, right, bottom)
+        clipBounds = bounds
+        translationX = currentState.translation.x
+        translationY = currentState.translation.y
     }
 
     /**
@@ -198,6 +206,8 @@
             if (originalGoneChildrenSet.contains(child.id)) {
                 child.visibility = View.GONE
             }
+            // Reset the alphas, to only have the alphas present from the constraintset
+            child.alpha = originalViewAlphas[child.id] ?: 1.0f
         }
         // Let's now apply the constraintSet to get the full state
         constraintSet.applyTo(this)
@@ -230,11 +240,13 @@
     var widgetStates: MutableMap<Int, WidgetState> = mutableMapOf()
     var width: Int = 0
     var height: Int = 0
+    val translation = PointF()
     fun copy(reusedState: TransitionViewState? = null): TransitionViewState {
         // we need a deep copy of this, so we can't use a data class
         val copy = reusedState ?: TransitionViewState()
         copy.width = width
         copy.height = height
+        copy.translation.set(translation.x, translation.y)
         for (entry in widgetStates) {
             copy.widgetStates[entry.key] = entry.value.copy()
         }
@@ -252,6 +264,7 @@
         }
         width = transitionLayout.measuredWidth
         height = transitionLayout.measuredHeight
+        translation.set(0.0f, 0.0f)
     }
 }
 
diff --git a/packages/SystemUI/src/com/android/systemui/util/animation/TransitionLayoutController.kt b/packages/SystemUI/src/com/android/systemui/util/animation/TransitionLayoutController.kt
index 9ee1410..b73aeb3 100644
--- a/packages/SystemUI/src/com/android/systemui/util/animation/TransitionLayoutController.kt
+++ b/packages/SystemUI/src/com/android/systemui/util/animation/TransitionLayoutController.kt
@@ -17,6 +17,7 @@
 package com.android.systemui.util.animation
 
 import android.animation.ValueAnimator
+import android.graphics.PointF
 import android.util.MathUtils
 import com.android.systemui.Interpolators
 
@@ -43,6 +44,7 @@
     private var currentState = TransitionViewState()
     private var animationStartState: TransitionViewState? = null
     private var state = TransitionViewState()
+    private var pivot = PointF()
     private var animator: ValueAnimator = ValueAnimator.ofFloat(0.0f, 1.0f)
 
     init {
@@ -63,6 +65,7 @@
                 startState = animationStartState!!,
                 endState = state,
                 progress = animator.animatedFraction,
+                pivot = pivot,
                 resultState = currentState)
         view.setState(currentState)
     }
@@ -75,8 +78,10 @@
         startState: TransitionViewState,
         endState: TransitionViewState,
         progress: Float,
+        pivot: PointF,
         resultState: TransitionViewState
     ) {
+        this.pivot.set(pivot)
         val view = transitionLayout ?: return
         val childCount = view.childCount
         for (i in 0 until childCount) {
@@ -178,6 +183,8 @@
                     progress).toInt()
             height = MathUtils.lerp(startState.height.toFloat(), endState.height.toFloat(),
                     progress).toInt()
+            translation.x = (endState.width - width) * pivot.x
+            translation.y = (endState.height - height) * pivot.y
         }
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/util/magnetictarget/MagnetizedObject.kt b/packages/SystemUI/src/com/android/systemui/util/magnetictarget/MagnetizedObject.kt
index e905e67..5a2b064 100644
--- a/packages/SystemUI/src/com/android/systemui/util/magnetictarget/MagnetizedObject.kt
+++ b/packages/SystemUI/src/com/android/systemui/util/magnetictarget/MagnetizedObject.kt
@@ -32,6 +32,7 @@
 import androidx.dynamicanimation.animation.FloatPropertyCompat
 import androidx.dynamicanimation.animation.SpringForce
 import com.android.systemui.util.animation.PhysicsAnimator
+import kotlin.math.abs
 import kotlin.math.hypot
 
 /**
@@ -231,11 +232,11 @@
     var flingUnstuckFromTargetMinVelocity = 1000f
 
     /**
-     * Sets the maximum velocity above which the object will not stick to the target. Even if the
+     * Sets the maximum X velocity above which the object will not stick to the target. Even if the
      * object is dragged through the magnetic field, it will not stick to the target until the
-     * velocity is below this value.
+     * horizontal velocity is below this value.
      */
-    var stickToTargetMaxVelocity = 2000f
+    var stickToTargetMaxXVelocity = 2000f
 
     /**
      * Enable or disable haptic vibration effects when the object interacts with the magnetic field.
@@ -245,9 +246,6 @@
      */
     var hapticsEnabled = true
 
-    /** Whether the HAPTIC_FEEDBACK_ENABLED setting is true. */
-    private var systemHapticsEnabled = false
-
     /** Default spring configuration to use for animating the object into a target. */
     var springConfig = PhysicsAnimator.SpringConfig(
             SpringForce.STIFFNESS_MEDIUM, SpringForce.DAMPING_RATIO_NO_BOUNCY)
@@ -259,24 +257,7 @@
     var flungIntoTargetSpringConfig = springConfig
 
     init {
-        val hapticSettingObserver =
-                object : ContentObserver(Handler.getMain()) {
-            override fun onChange(selfChange: Boolean) {
-                systemHapticsEnabled =
-                        Settings.System.getIntForUser(
-                                context.contentResolver,
-                                Settings.System.HAPTIC_FEEDBACK_ENABLED,
-                                0,
-                                UserHandle.USER_CURRENT) != 0
-            }
-        }
-
-        context.contentResolver.registerContentObserver(
-                Settings.System.getUriFor(Settings.System.HAPTIC_FEEDBACK_ENABLED),
-                true /* notifyForDescendants */, hapticSettingObserver)
-
-        // Trigger the observer once to initialize systemHapticsEnabled.
-        hapticSettingObserver.onChange(false /* selfChange */)
+        initHapticSettingObserver(context)
     }
 
     /**
@@ -383,7 +364,7 @@
             // If the object is moving too quickly within the magnetic field, do not stick it. This
             // only applies to objects newly stuck to a target. If the object is moved into a new
             // target, it wasn't moving at all (since it was stuck to the previous one).
-            if (objectNewlyStuckToTarget && hypot(velX, velY) > stickToTargetMaxVelocity) {
+            if (objectNewlyStuckToTarget && abs(velX) > stickToTargetMaxXVelocity) {
                 return false
             }
 
@@ -623,6 +604,43 @@
     companion object {
 
         /**
+         * Whether the HAPTIC_FEEDBACK_ENABLED setting is true.
+         *
+         * We put it in the companion object because we need to register a settings observer and
+         * [MagnetizedObject] doesn't have an obvious lifecycle so we don't have a good time to
+         * remove that observer. Since this settings is shared among all instances we just let all
+         * instances read from this value.
+         */
+        private var systemHapticsEnabled = false
+        private var hapticSettingObserverInitialized = false
+
+        private fun initHapticSettingObserver(context: Context) {
+            if (hapticSettingObserverInitialized) {
+                return
+            }
+
+            val hapticSettingObserver =
+                    object : ContentObserver(Handler.getMain()) {
+                        override fun onChange(selfChange: Boolean) {
+                            systemHapticsEnabled =
+                                    Settings.System.getIntForUser(
+                                            context.contentResolver,
+                                            Settings.System.HAPTIC_FEEDBACK_ENABLED,
+                                            0,
+                                            UserHandle.USER_CURRENT) != 0
+                        }
+                    }
+
+            context.contentResolver.registerContentObserver(
+                    Settings.System.getUriFor(Settings.System.HAPTIC_FEEDBACK_ENABLED),
+                    true /* notifyForDescendants */, hapticSettingObserver)
+
+            // Trigger the observer once to initialize systemHapticsEnabled.
+            hapticSettingObserver.onChange(false /* selfChange */)
+            hapticSettingObserverInitialized = true
+        }
+
+        /**
          * Magnetizes the given view. Magnetized views are attracted to one or more magnetic
          * targets. Magnetic targets attract objects that are dragged near them, and hold them there
          * unless they're moved away or released. Releasing objects inside a magnetic target
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSecurityContainerTest.java b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSecurityContainerTest.java
index e324d84..a867825 100644
--- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSecurityContainerTest.java
+++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSecurityContainerTest.java
@@ -18,7 +18,9 @@
 
 import static android.view.WindowInsets.Type.ime;
 
+import static org.mockito.ArgumentMatchers.any;
 import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.ArgumentMatchers.anyLong;
 import static org.mockito.ArgumentMatchers.eq;
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
@@ -110,6 +112,7 @@
 
         mKeyguardSecurityContainer.startDisappearAnimation(null);
         verify(mSecurityView).startDisappearAnimation(eq(null));
-        verify(mWindowInsetsController).hide(eq(ime()));
+        verify(mWindowInsetsController).controlWindowInsetsAnimation(eq(ime()), anyLong(), any(),
+                any(), any());
     }
 }
\ No newline at end of file
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardUpdateMonitorTest.java b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardUpdateMonitorTest.java
index 7bc453a..0238799 100644
--- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardUpdateMonitorTest.java
+++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardUpdateMonitorTest.java
@@ -452,12 +452,6 @@
     }
 
     @Test
-    public void requiresAuthentication_whenEncryptedKeyguard_andBypass() {
-        testStrongAuthExceptOnBouncer(
-                KeyguardUpdateMonitor.StrongAuthTracker.STRONG_AUTH_REQUIRED_AFTER_BOOT);
-    }
-
-    @Test
     public void requiresAuthentication_whenTimeoutKeyguard_andBypass() {
         testStrongAuthExceptOnBouncer(
                 KeyguardUpdateMonitor.StrongAuthTracker.STRONG_AUTH_REQUIRED_AFTER_TIMEOUT);
@@ -513,10 +507,20 @@
 
     @Test
     public void testIgnoresAuth_whenLockdown() {
+        testIgnoresAuth(
+                KeyguardUpdateMonitor.StrongAuthTracker.STRONG_AUTH_REQUIRED_AFTER_USER_LOCKDOWN);
+    }
+
+    @Test
+    public void testIgnoresAuth_whenEncrypted() {
+        testIgnoresAuth(
+                KeyguardUpdateMonitor.StrongAuthTracker.STRONG_AUTH_REQUIRED_AFTER_BOOT);
+    }
+
+    private void testIgnoresAuth(int strongAuth) {
         mKeyguardUpdateMonitor.dispatchStartedWakingUp();
         mTestableLooper.processAllMessages();
-        when(mStrongAuthTracker.getStrongAuthForUser(anyInt())).thenReturn(
-                KeyguardUpdateMonitor.StrongAuthTracker.STRONG_AUTH_REQUIRED_AFTER_USER_LOCKDOWN);
+        when(mStrongAuthTracker.getStrongAuthForUser(anyInt())).thenReturn(strongAuth);
 
         mKeyguardUpdateMonitor.onKeyguardVisibilityChanged(true);
         verify(mFaceManager, never()).authenticate(any(), any(), anyInt(), any(), any(), anyInt());
diff --git a/packages/SystemUI/tests/src/com/android/systemui/SysuiTestCase.java b/packages/SystemUI/tests/src/com/android/systemui/SysuiTestCase.java
index b2c3586..713aef9 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/SysuiTestCase.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/SysuiTestCase.java
@@ -35,6 +35,7 @@
 import com.android.settingslib.bluetooth.LocalBluetoothManager;
 import com.android.systemui.broadcast.BroadcastDispatcher;
 import com.android.systemui.broadcast.FakeBroadcastDispatcher;
+import com.android.systemui.broadcast.logging.BroadcastDispatcherLogger;
 import com.android.systemui.classifier.FalsingManagerFake;
 import com.android.systemui.dump.DumpManager;
 import com.android.systemui.plugins.FalsingManager;
@@ -72,8 +73,8 @@
     public void SysuiSetup() throws Exception {
         SystemUIFactory.createFromConfig(mContext);
         mDependency = new TestableDependency(mContext);
-        mFakeBroadcastDispatcher = new FakeBroadcastDispatcher(mContext, mock(Handler.class),
-                mock(Looper.class), mock(DumpManager.class));
+        mFakeBroadcastDispatcher = new FakeBroadcastDispatcher(mContext, mock(Looper.class),
+                mock(DumpManager.class), mock(BroadcastDispatcherLogger.class));
 
         mRealInstrumentation = InstrumentationRegistry.getInstrumentation();
         Instrumentation inst = spy(mRealInstrumentation);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/broadcast/BroadcastDispatcherTest.kt b/packages/SystemUI/tests/src/com/android/systemui/broadcast/BroadcastDispatcherTest.kt
index 3357c58..4ed284e 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/broadcast/BroadcastDispatcherTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/broadcast/BroadcastDispatcherTest.kt
@@ -18,6 +18,7 @@
 
 import android.content.BroadcastReceiver
 import android.content.Context
+import android.content.Intent
 import android.content.IntentFilter
 import android.os.Handler
 import android.os.Looper
@@ -27,6 +28,7 @@
 import android.testing.AndroidTestingRunner
 import android.testing.TestableLooper
 import com.android.systemui.SysuiTestCase
+import com.android.systemui.broadcast.logging.BroadcastDispatcherLogger
 import com.android.systemui.dump.DumpManager
 import com.android.systemui.util.concurrency.FakeExecutor
 import com.android.systemui.util.time.FakeSystemClock
@@ -76,6 +78,8 @@
     private lateinit var intentFilterOther: IntentFilter
     @Mock
     private lateinit var mockHandler: Handler
+    @Mock
+    private lateinit var logger: BroadcastDispatcherLogger
 
     private lateinit var executor: Executor
 
@@ -93,9 +97,9 @@
 
         broadcastDispatcher = TestBroadcastDispatcher(
                 mockContext,
-                Handler(testableLooper.looper),
                 testableLooper.looper,
                 mock(DumpManager::class.java),
+                logger,
                 mapOf(0 to mockUBRUser0, 1 to mockUBRUser1))
 
         // These should be valid filters
@@ -173,7 +177,12 @@
 
     @Test
     fun testRegisterCurrentAsActualUser() {
-        setUserMock(mockContext, user1)
+        val intent = Intent(Intent.ACTION_USER_SWITCHED).apply {
+            putExtra(Intent.EXTRA_USER_HANDLE, user1.identifier)
+        }
+        broadcastDispatcher.onReceive(mockContext, intent)
+        testableLooper.processAllMessages()
+
         broadcastDispatcher.registerReceiverWithHandler(broadcastReceiver, intentFilter,
                 mockHandler, UserHandle.CURRENT)
 
@@ -236,11 +245,11 @@
 
     private class TestBroadcastDispatcher(
         context: Context,
-        mainHandler: Handler,
         bgLooper: Looper,
         dumpManager: DumpManager,
+        logger: BroadcastDispatcherLogger,
         var mockUBRMap: Map<Int, UserBroadcastDispatcher>
-    ) : BroadcastDispatcher(context, mainHandler, bgLooper, dumpManager) {
+    ) : BroadcastDispatcher(context, bgLooper, dumpManager, logger) {
         override fun createUBRForUser(userId: Int): UserBroadcastDispatcher {
             return mockUBRMap.getOrDefault(userId, mock(UserBroadcastDispatcher::class.java))
         }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/broadcast/FakeBroadcastDispatcher.kt b/packages/SystemUI/tests/src/com/android/systemui/broadcast/FakeBroadcastDispatcher.kt
index 9a5773a..09a0916 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/broadcast/FakeBroadcastDispatcher.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/broadcast/FakeBroadcastDispatcher.kt
@@ -24,15 +24,16 @@
 import android.util.ArraySet
 import android.util.Log
 import com.android.systemui.SysuiTestableContext
+import com.android.systemui.broadcast.logging.BroadcastDispatcherLogger
 import com.android.systemui.dump.DumpManager
 import java.util.concurrent.Executor
 
 class FakeBroadcastDispatcher(
     context: SysuiTestableContext,
-    handler: Handler,
     looper: Looper,
-    dumpManager: DumpManager
-) : BroadcastDispatcher(context, handler, looper, dumpManager) {
+    dumpManager: DumpManager,
+    logger: BroadcastDispatcherLogger
+) : BroadcastDispatcher(context, looper, dumpManager, logger) {
 
     private val registeredReceivers = ArraySet<BroadcastReceiver>()
 
diff --git a/packages/SystemUI/tests/src/com/android/systemui/broadcast/UserBroadcastDispatcherTest.kt b/packages/SystemUI/tests/src/com/android/systemui/broadcast/UserBroadcastDispatcherTest.kt
index 847e442..4433576 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/broadcast/UserBroadcastDispatcherTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/broadcast/UserBroadcastDispatcherTest.kt
@@ -26,6 +26,7 @@
 import android.testing.AndroidTestingRunner
 import android.testing.TestableLooper
 import com.android.systemui.SysuiTestCase
+import com.android.systemui.broadcast.logging.BroadcastDispatcherLogger
 import com.android.systemui.util.concurrency.FakeExecutor
 import com.android.systemui.util.time.FakeSystemClock
 import junit.framework.Assert.assertEquals
@@ -40,6 +41,7 @@
 import org.mockito.ArgumentMatchers.eq
 import org.mockito.Captor
 import org.mockito.Mock
+import org.mockito.Mockito
 import org.mockito.Mockito.anyString
 import org.mockito.Mockito.atLeastOnce
 import org.mockito.Mockito.never
@@ -62,6 +64,8 @@
         private val USER_HANDLE = UserHandle.of(USER_ID)
 
         fun <T> capture(argumentCaptor: ArgumentCaptor<T>): T = argumentCaptor.capture()
+        fun <T> any(): T = Mockito.any()
+        fun <T> eq(v: T) = Mockito.eq(v) ?: v
     }
 
     @Mock
@@ -72,6 +76,8 @@
     private lateinit var mockContext: Context
     @Mock
     private lateinit var mPendingResult: BroadcastReceiver.PendingResult
+    @Mock
+    private lateinit var logger: BroadcastDispatcherLogger
 
     @Captor
     private lateinit var argumentCaptor: ArgumentCaptor<IntentFilter>
@@ -91,7 +97,7 @@
         fakeExecutor = FakeExecutor(FakeSystemClock())
 
         userBroadcastDispatcher = UserBroadcastDispatcher(
-                mockContext, USER_ID, testableLooper.looper)
+                mockContext, USER_ID, testableLooper.looper, logger)
         userBroadcastDispatcher.pendingResult = mPendingResult
     }
 
@@ -106,6 +112,13 @@
     }
 
     @Test
+    fun testNotRegisteredOnStart_logging() {
+        testableLooper.processAllMessages()
+
+        verify(logger, never()).logContextReceiverRegistered(anyInt(), any())
+    }
+
+    @Test
     fun testSingleReceiverRegistered() {
         intentFilter = IntentFilter(ACTION_1)
 
@@ -126,6 +139,18 @@
     }
 
     @Test
+    fun testSingleReceiverRegistered_logging() {
+        intentFilter = IntentFilter(ACTION_1)
+
+        userBroadcastDispatcher.registerReceiver(
+                ReceiverData(broadcastReceiver, intentFilter, fakeExecutor, USER_HANDLE))
+        testableLooper.processAllMessages()
+
+        verify(logger).logReceiverRegistered(USER_HANDLE.identifier, broadcastReceiver)
+        verify(logger).logContextReceiverRegistered(eq(USER_HANDLE.identifier), any())
+    }
+
+    @Test
     fun testSingleReceiverUnregistered() {
         intentFilter = IntentFilter(ACTION_1)
 
@@ -145,6 +170,21 @@
     }
 
     @Test
+    fun testSingleReceiverUnregistered_logger() {
+        intentFilter = IntentFilter(ACTION_1)
+
+        userBroadcastDispatcher.registerReceiver(
+                ReceiverData(broadcastReceiver, intentFilter, fakeExecutor, USER_HANDLE))
+        testableLooper.processAllMessages()
+
+        userBroadcastDispatcher.unregisterReceiver(broadcastReceiver)
+        testableLooper.processAllMessages()
+
+        verify(logger).logReceiverUnregistered(USER_HANDLE.identifier, broadcastReceiver)
+        verify(logger).logContextReceiverUnregistered(USER_HANDLE.identifier)
+    }
+
+    @Test
     fun testFilterHasAllActionsAndCategories_twoReceivers() {
         intentFilter = IntentFilter(ACTION_1)
         intentFilterOther = IntentFilter(ACTION_2).apply {
@@ -196,6 +236,30 @@
     }
 
     @Test
+    fun testDispatch_logger() {
+        intentFilter = IntentFilter(ACTION_1)
+        intentFilterOther = IntentFilter(ACTION_2)
+
+        userBroadcastDispatcher.registerReceiver(
+                ReceiverData(broadcastReceiver, intentFilter, fakeExecutor, USER_HANDLE))
+        userBroadcastDispatcher.registerReceiver(
+                ReceiverData(broadcastReceiverOther, intentFilterOther, fakeExecutor, USER_HANDLE))
+
+        val intent = Intent(ACTION_2)
+
+        userBroadcastDispatcher.onReceive(mockContext, intent)
+        testableLooper.processAllMessages()
+        fakeExecutor.runAllReady()
+
+        val captor = ArgumentCaptor.forClass(Int::class.java)
+        verify(logger)
+                .logBroadcastReceived(captor.capture(), eq(USER_HANDLE.identifier), eq(intent))
+        verify(logger).logBroadcastDispatched(captor.value, ACTION_2, broadcastReceiverOther)
+        verify(logger, never())
+                .logBroadcastDispatched(eq(captor.value), any(), eq(broadcastReceiver))
+    }
+
+    @Test
     fun testDispatchToCorrectReceiver_differentFiltersSameReceiver() {
         intentFilter = IntentFilter(ACTION_1)
         intentFilterOther = IntentFilter(ACTION_2)
diff --git a/packages/SystemUI/tests/src/com/android/systemui/bubbles/BubbleControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/bubbles/BubbleControllerTest.java
index c89f6c2..59f8c4e 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/bubbles/BubbleControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/bubbles/BubbleControllerTest.java
@@ -44,7 +44,6 @@
 import android.app.INotificationManager;
 import android.app.Notification;
 import android.app.PendingIntent;
-import android.content.res.Resources;
 import android.hardware.display.AmbientDisplayConfiguration;
 import android.hardware.face.FaceManager;
 import android.os.Handler;
@@ -59,7 +58,7 @@
 import androidx.test.filters.SmallTest;
 
 import com.android.internal.colorextraction.ColorExtractor;
-import com.android.systemui.SystemUIFactory;
+import com.android.internal.statusbar.IStatusBarService;
 import com.android.systemui.SysuiTestCase;
 import com.android.systemui.colorextraction.SysuiColorExtractor;
 import com.android.systemui.dump.DumpManager;
@@ -70,20 +69,16 @@
 import com.android.systemui.statusbar.NotificationLockscreenUserManager;
 import com.android.systemui.statusbar.NotificationRemoveInterceptor;
 import com.android.systemui.statusbar.RankingBuilder;
-import com.android.systemui.statusbar.SuperStatusBarViewFactory;
 import com.android.systemui.statusbar.SysuiStatusBarStateController;
 import com.android.systemui.statusbar.notification.NotificationEntryListener;
 import com.android.systemui.statusbar.notification.NotificationEntryManager;
 import com.android.systemui.statusbar.notification.NotificationFilter;
 import com.android.systemui.statusbar.notification.collection.NotifPipeline;
 import com.android.systemui.statusbar.notification.collection.NotificationEntry;
-import com.android.systemui.statusbar.notification.row.ActivatableNotificationView;
 import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
 import com.android.systemui.statusbar.notification.row.NotificationTestHelper;
-import com.android.systemui.statusbar.notification.row.dagger.NotificationRowComponent;
 import com.android.systemui.statusbar.phone.DozeParameters;
 import com.android.systemui.statusbar.phone.KeyguardBypassController;
-import com.android.systemui.statusbar.phone.LockscreenLockIconController;
 import com.android.systemui.statusbar.phone.NotificationGroupManager;
 import com.android.systemui.statusbar.phone.NotificationShadeWindowController;
 import com.android.systemui.statusbar.phone.NotificationShadeWindowView;
@@ -93,11 +88,11 @@
 import com.android.systemui.statusbar.policy.HeadsUpManager;
 import com.android.systemui.statusbar.policy.ZenModeController;
 import com.android.systemui.util.FloatingContentCoordinator;
-import com.android.systemui.util.InjectionInflationController;
 
 import com.google.common.collect.ImmutableList;
 
 import org.junit.Before;
+import org.junit.Ignore;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.mockito.ArgumentCaptor;
@@ -173,23 +168,18 @@
     @Mock
     ColorExtractor.GradientColors mGradientColors;
     @Mock
-    private Resources mResources;
-    @Mock
     private ShadeController mShadeController;
     @Mock
-    private NotificationRowComponent mNotificationRowComponent;
-    @Mock
     private NotifPipeline mNotifPipeline;
     @Mock
     private FeatureFlags mFeatureFlagsOldPipeline;
     @Mock
     private DumpManager mDumpManager;
     @Mock
-    private LockscreenLockIconController mLockIconController;
-    @Mock
     private NotificationShadeWindowView mNotificationShadeWindowView;
+    @Mock
+    private IStatusBarService mStatusBarService;
 
-    private SuperStatusBarViewFactory mSuperStatusBarViewFactory;
     private BubbleData mBubbleData;
 
     private TestableLooper mTestableLooper;
@@ -203,23 +193,6 @@
         mContext.addMockSystemService(FaceManager.class, mFaceManager);
         when(mColorExtractor.getNeutralColors()).thenReturn(mGradientColors);
 
-        mSuperStatusBarViewFactory = new SuperStatusBarViewFactory(mContext,
-                new InjectionInflationController(SystemUIFactory.getInstance().getRootComponent()),
-                new NotificationRowComponent.Builder() {
-                    @Override
-                    public NotificationRowComponent.Builder activatableNotificationView(
-                            ActivatableNotificationView view) {
-                        return this;
-                    }
-
-                    @Override
-                    public NotificationRowComponent build() {
-                        return mNotificationRowComponent;
-                    }
-                },
-                mLockIconController);
-
-        // Bubbles get added to status bar window view
         mNotificationShadeWindowController = new NotificationShadeWindowController(mContext,
                 mWindowManager, mActivityManager, mDozeParameters, mStatusBarStateController,
                 mConfigurationController, mKeyguardBypassController, mColorExtractor,
@@ -282,6 +255,7 @@
                 mDataRepository,
                 mSysUiState,
                 mock(INotificationManager.class),
+                mStatusBarService,
                 mWindowManager);
         mBubbleController.setExpandListener(mBubbleExpandListener);
 
@@ -327,7 +301,7 @@
     }
 
     @Test
-    public void testPromoteBubble_autoExpand() {
+    public void testPromoteBubble_autoExpand() throws Exception {
         mBubbleController.updateBubble(mRow2.getEntry());
         mBubbleController.updateBubble(mRow.getEntry());
         mBubbleController.removeBubble(
@@ -337,13 +311,19 @@
         assertThat(mBubbleData.getOverflowBubbles()).isEqualTo(ImmutableList.of(b));
         verify(mNotificationEntryManager, never()).performRemoveNotification(
                 eq(mRow.getEntry().getSbn()), anyInt());
-        assertFalse(mRow.getEntry().isBubble());
+        assertThat(mRow.getEntry().isBubble()).isFalse();
 
         Bubble b2 = mBubbleData.getBubbleInStackWithKey(mRow2.getEntry().getKey());
         assertThat(mBubbleData.getSelectedBubble()).isEqualTo(b2);
 
         mBubbleController.promoteBubbleFromOverflow(b);
-        assertThat(mBubbleData.getSelectedBubble()).isEqualTo(b);
+
+        assertThat(b.isBubble()).isTrue();
+        assertThat(b.shouldAutoExpand()).isTrue();
+        int flags = Notification.BubbleMetadata.FLAG_AUTO_EXPAND_BUBBLE
+                | Notification.BubbleMetadata.FLAG_SUPPRESS_NOTIFICATION;
+        verify(mStatusBarService, times(1)).onNotificationBubbleChanged(
+                eq(b.getKey()), eq(true), eq(flags));
     }
 
     @Test
@@ -428,6 +408,7 @@
     }
 
     @Test
+    @Ignore("Currently broken.")
     public void testCollapseAfterChangingExpandedBubble() {
         // Mark it as a bubble and add it explicitly
         mEntryListener.onPendingEntryAdded(mRow.getEntry());
@@ -446,7 +427,8 @@
         BubbleStackView stackView = mBubbleController.getStackView();
         mBubbleData.setExpanded(true);
         assertTrue(mBubbleController.isStackExpanded());
-        verify(mBubbleExpandListener).onBubbleExpandChanged(true, mRow2.getEntry().getKey());
+        verify(mBubbleExpandListener, atLeastOnce()).onBubbleExpandChanged(
+                true, mRow2.getEntry().getKey());
 
         assertTrue(mSysUiStateBubblesExpanded);
 
@@ -464,9 +446,11 @@
                 mRow.getEntry()));
 
         // collapse for previous bubble
-        verify(mBubbleExpandListener).onBubbleExpandChanged(false, mRow2.getEntry().getKey());
+        verify(mBubbleExpandListener, atLeastOnce()).onBubbleExpandChanged(
+                false, mRow2.getEntry().getKey());
         // expand for selected bubble
-        verify(mBubbleExpandListener).onBubbleExpandChanged(true, mRow.getEntry().getKey());
+        verify(mBubbleExpandListener, atLeastOnce()).onBubbleExpandChanged(
+                true, mRow.getEntry().getKey());
 
         // Collapse
         mBubbleController.collapseStack();
diff --git a/packages/SystemUI/tests/src/com/android/systemui/bubbles/BubbleDataTest.java b/packages/SystemUI/tests/src/com/android/systemui/bubbles/BubbleDataTest.java
index 8224c88e..1ca2f02 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/bubbles/BubbleDataTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/bubbles/BubbleDataTest.java
@@ -278,7 +278,7 @@
         assertBubbleRemoved(mBubbleA1, BubbleController.DISMISS_AGED);
         assertOverflowChangedTo(ImmutableList.of(mBubbleA1));
 
-        Bubble bubbleA1 = mBubbleData.getOrCreateBubble(mEntryA1);
+        Bubble bubbleA1 = mBubbleData.getOrCreateBubble(mEntryA1, null /* persistedBubble */);
         bubbleA1.markUpdatedAt(7000L);
         mBubbleData.notificationEntryUpdated(bubbleA1, false /* suppressFlyout*/,
                 true /* showInShade */);
@@ -537,7 +537,7 @@
         // Verify the selection was cleared.
         verifyUpdateReceived();
         assertThat(mBubbleData.isExpanded()).isFalse();
-        assertSelectionCleared();
+        assertThat(mBubbleData.getSelectedBubble()).isNull();
     }
 
     // EXPANDED / ADD / UPDATE
@@ -890,7 +890,7 @@
     private void sendUpdatedEntryAtTime(NotificationEntry entry, long postTime) {
         setPostTime(entry, postTime);
         // BubbleController calls this:
-        Bubble b = mBubbleData.getOrCreateBubble(entry);
+        Bubble b = mBubbleData.getOrCreateBubble(entry, null /* persistedBubble */);
         // And then this
         mBubbleData.notificationEntryUpdated(b, false /* suppressFlyout*/,
                 true /* showInShade */);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/bubbles/NewNotifPipelineBubbleControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/bubbles/NewNotifPipelineBubbleControllerTest.java
index ead95ca1..58e06b5 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/bubbles/NewNotifPipelineBubbleControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/bubbles/NewNotifPipelineBubbleControllerTest.java
@@ -55,7 +55,7 @@
 import androidx.test.filters.SmallTest;
 
 import com.android.internal.colorextraction.ColorExtractor;
-import com.android.systemui.SystemUIFactory;
+import com.android.internal.statusbar.IStatusBarService;
 import com.android.systemui.SysuiTestCase;
 import com.android.systemui.colorextraction.SysuiColorExtractor;
 import com.android.systemui.dump.DumpManager;
@@ -64,14 +64,12 @@
 import com.android.systemui.statusbar.FeatureFlags;
 import com.android.systemui.statusbar.NotificationLockscreenUserManager;
 import com.android.systemui.statusbar.RankingBuilder;
-import com.android.systemui.statusbar.SuperStatusBarViewFactory;
 import com.android.systemui.statusbar.SysuiStatusBarStateController;
 import com.android.systemui.statusbar.notification.NotificationEntryManager;
 import com.android.systemui.statusbar.notification.NotificationFilter;
 import com.android.systemui.statusbar.notification.collection.NotifPipeline;
 import com.android.systemui.statusbar.notification.collection.NotificationEntry;
 import com.android.systemui.statusbar.notification.collection.notifcollection.NotifCollectionListener;
-import com.android.systemui.statusbar.notification.row.ActivatableNotificationView;
 import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
 import com.android.systemui.statusbar.notification.row.NotificationTestHelper;
 import com.android.systemui.statusbar.notification.row.dagger.NotificationRowComponent;
@@ -87,9 +85,9 @@
 import com.android.systemui.statusbar.policy.HeadsUpManager;
 import com.android.systemui.statusbar.policy.ZenModeController;
 import com.android.systemui.util.FloatingContentCoordinator;
-import com.android.systemui.util.InjectionInflationController;
 
 import org.junit.Before;
+import org.junit.Ignore;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.mockito.ArgumentCaptor;
@@ -174,8 +172,9 @@
     private DumpManager mDumpManager;
     @Mock
     private LockscreenLockIconController mLockIconController;
+    @Mock
+    private IStatusBarService mStatusBarService;
 
-    private SuperStatusBarViewFactory mSuperStatusBarViewFactory;
     private BubbleData mBubbleData;
 
     private TestableLooper mTestableLooper;
@@ -189,22 +188,6 @@
         mContext.addMockSystemService(FaceManager.class, mFaceManager);
         when(mColorExtractor.getNeutralColors()).thenReturn(mGradientColors);
 
-        mSuperStatusBarViewFactory = new SuperStatusBarViewFactory(mContext,
-                new InjectionInflationController(SystemUIFactory.getInstance().getRootComponent()),
-                new NotificationRowComponent.Builder() {
-                    @Override
-                    public NotificationRowComponent.Builder activatableNotificationView(
-                            ActivatableNotificationView view) {
-                        return this;
-                    }
-
-                    @Override
-                    public NotificationRowComponent build() {
-                        return mNotificationRowComponent;
-                    }
-                },
-                mLockIconController);
-
         // Bubbles get added to status bar window view
         mNotificationShadeWindowController = new NotificationShadeWindowController(mContext,
                 mWindowManager, mActivityManager, mDozeParameters, mStatusBarStateController,
@@ -257,6 +240,7 @@
                 mDataRepository,
                 mSysUiState,
                 mock(INotificationManager.class),
+                mStatusBarService,
                 mWindowManager);
         mBubbleController.addNotifCallback(mNotifCallback);
         mBubbleController.setExpandListener(mBubbleExpandListener);
@@ -381,6 +365,7 @@
     }
 
     @Test
+    @Ignore("Currently broken.")
     public void testCollapseAfterChangingExpandedBubble() {
         // Mark it as a bubble and add it explicitly
         mEntryListener.onEntryAdded(mRow.getEntry());
@@ -399,7 +384,8 @@
         BubbleStackView stackView = mBubbleController.getStackView();
         mBubbleData.setExpanded(true);
         assertTrue(mBubbleController.isStackExpanded());
-        verify(mBubbleExpandListener).onBubbleExpandChanged(true, mRow2.getEntry().getKey());
+        verify(mBubbleExpandListener, atLeastOnce()).onBubbleExpandChanged(
+                true, mRow.getEntry().getKey());
 
         // Last added is the one that is expanded
         assertEquals(mRow2.getEntry(), mBubbleData.getSelectedBubble().getEntry());
@@ -414,9 +400,11 @@
                 mRow.getEntry()));
 
         // collapse for previous bubble
-        verify(mBubbleExpandListener).onBubbleExpandChanged(false, mRow2.getEntry().getKey());
+        verify(mBubbleExpandListener, atLeastOnce()).onBubbleExpandChanged(
+                false, mRow2.getEntry().getKey());
         // expand for selected bubble
-        verify(mBubbleExpandListener).onBubbleExpandChanged(true, mRow.getEntry().getKey());
+        verify(mBubbleExpandListener, atLeastOnce()).onBubbleExpandChanged(
+                true, mRow.getEntry().getKey());
 
         // Collapse
         mBubbleController.collapseStack();
diff --git a/packages/SystemUI/tests/src/com/android/systemui/bubbles/TestableBubbleController.java b/packages/SystemUI/tests/src/com/android/systemui/bubbles/TestableBubbleController.java
index bdb7944..ab49134 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/bubbles/TestableBubbleController.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/bubbles/TestableBubbleController.java
@@ -20,6 +20,7 @@
 import android.content.Context;
 import android.view.WindowManager;
 
+import com.android.internal.statusbar.IStatusBarService;
 import com.android.systemui.dump.DumpManager;
 import com.android.systemui.model.SysUiState;
 import com.android.systemui.plugins.statusbar.StatusBarStateController;
@@ -59,13 +60,14 @@
             BubbleDataRepository dataRepository,
             SysUiState sysUiState,
             INotificationManager notificationManager,
+            IStatusBarService statusBarService,
             WindowManager windowManager) {
         super(context,
                 notificationShadeWindowController, statusBarStateController, shadeController,
                 data, Runnable::run, configurationController, interruptionStateProvider,
                 zenModeController, lockscreenUserManager, groupManager, entryManager,
                 notifPipeline, featureFlags, dumpManager, floatingContentCoordinator,
-                dataRepository, sysUiState, notificationManager,
+                dataRepository, sysUiState, notificationManager, statusBarService,
                 windowManager);
         setInflateSynchronously(true);
     }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/globalactions/GlobalActionsDialogTest.java b/packages/SystemUI/tests/src/com/android/systemui/globalactions/GlobalActionsDialogTest.java
index 329af2b..3c1cc23 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/globalactions/GlobalActionsDialogTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/globalactions/GlobalActionsDialogTest.java
@@ -438,6 +438,9 @@
         GlobalActionsDialog.ActionsDialog dialog = mGlobalActionsDialog.mDialog;
         assertThat(dialog).isNotNull();
         assertThat(dialog.mLockMessageContainer.getVisibility()).isEqualTo(View.VISIBLE);
+
+        // Dismiss the dialog so that it does not pollute other tests
+        mGlobalActionsDialog.showOrHideDialog(false, true, mWalletPlugin);
     }
 
     @Test
@@ -455,6 +458,9 @@
         GlobalActionsDialog.ActionsDialog dialog = mGlobalActionsDialog.mDialog;
         assertThat(dialog).isNotNull();
         assertThat(dialog.mLockMessageContainer.getVisibility()).isEqualTo(View.GONE);
+
+        // Dismiss the dialog so that it does not pollute other tests
+        mGlobalActionsDialog.showOrHideDialog(false, true, mWalletPlugin);
     }
 
     @Test
@@ -473,6 +479,9 @@
         GlobalActionsDialog.ActionsDialog dialog = mGlobalActionsDialog.mDialog;
         assertThat(dialog).isNotNull();
         assertThat(dialog.mLockMessageContainer.getVisibility()).isEqualTo(View.GONE);
+
+        // Dismiss the dialog so that it does not pollute other tests
+        mGlobalActionsDialog.showOrHideDialog(false, true, mWalletPlugin);
     }
 
     private void setupDefaultActions() {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/MediaControlPanelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/media/MediaControlPanelTest.kt
index 737ced6..e6a41fb 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/media/MediaControlPanelTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/media/MediaControlPanelTest.kt
@@ -31,6 +31,7 @@
 import android.widget.ImageView
 import android.widget.SeekBar
 import android.widget.TextView
+import androidx.constraintlayout.widget.ConstraintSet
 import androidx.lifecycle.LiveData
 import androidx.test.filters.SmallTest
 import com.android.systemui.R
@@ -75,9 +76,9 @@
 
     @Mock private lateinit var holder: PlayerViewHolder
     @Mock private lateinit var view: TransitionLayout
-    @Mock private lateinit var mediaHostStatesManager: MediaHostStatesManager
     @Mock private lateinit var seekBarViewModel: SeekBarViewModel
     @Mock private lateinit var seekBarData: LiveData<SeekBarViewModel.Progress>
+    @Mock private lateinit var mediaViewController: MediaViewController
     private lateinit var appIcon: ImageView
     private lateinit var appName: TextView
     private lateinit var albumView: ImageView
@@ -104,8 +105,10 @@
     @Before
     fun setUp() {
         bgExecutor = FakeExecutor(FakeSystemClock())
+        whenever(mediaViewController.expandedLayout).thenReturn(mock(ConstraintSet::class.java))
+        whenever(mediaViewController.collapsedLayout).thenReturn(mock(ConstraintSet::class.java))
 
-        player = MediaControlPanel(context, bgExecutor, activityStarter, mediaHostStatesManager,
+        player = MediaControlPanel(context, bgExecutor, activityStarter, mediaViewController,
                 seekBarViewModel)
         whenever(seekBarViewModel.progress).thenReturn(seekBarData)
 
@@ -172,7 +175,7 @@
     @Test
     fun bindWhenUnattached() {
         val state = MediaData(true, BG_COLOR, APP, null, ARTIST, TITLE, null, emptyList(),
-                emptyList(), PACKAGE, null, null, device, null)
+                emptyList(), PACKAGE, null, null, device, true, null)
         player.bind(state)
         assertThat(player.isPlaying()).isFalse()
     }
@@ -181,7 +184,7 @@
     fun bindText() {
         player.attach(holder)
         val state = MediaData(true, BG_COLOR, APP, null, ARTIST, TITLE, null, emptyList(),
-                emptyList(), PACKAGE, session.getSessionToken(), null, device, null)
+                emptyList(), PACKAGE, session.getSessionToken(), null, device, true, null)
         player.bind(state)
         assertThat(appName.getText()).isEqualTo(APP)
         assertThat(titleText.getText()).isEqualTo(TITLE)
@@ -192,7 +195,7 @@
     fun bindBackgroundColor() {
         player.attach(holder)
         val state = MediaData(true, BG_COLOR, APP, null, ARTIST, TITLE, null, emptyList(),
-                emptyList(), PACKAGE, session.getSessionToken(), null, device, null)
+                emptyList(), PACKAGE, session.getSessionToken(), null, device, true, null)
         player.bind(state)
         val list = ArgumentCaptor.forClass(ColorStateList::class.java)
         verify(view).setBackgroundTintList(list.capture())
@@ -203,7 +206,7 @@
     fun bindDevice() {
         player.attach(holder)
         val state = MediaData(true, BG_COLOR, APP, null, ARTIST, TITLE, null, emptyList(),
-                emptyList(), PACKAGE, session.getSessionToken(), null, device, null)
+                emptyList(), PACKAGE, session.getSessionToken(), null, device, true, null)
         player.bind(state)
         assertThat(seamlessText.getText()).isEqualTo(DEVICE_NAME)
         assertThat(seamless.isEnabled()).isTrue()
@@ -213,7 +216,7 @@
     fun bindDisabledDevice() {
         player.attach(holder)
         val state = MediaData(true, BG_COLOR, APP, null, ARTIST, TITLE, null, emptyList(),
-                emptyList(), PACKAGE, session.getSessionToken(), null, disabledDevice, null)
+                emptyList(), PACKAGE, session.getSessionToken(), null, disabledDevice, true, null)
         player.bind(state)
         assertThat(seamless.isEnabled()).isFalse()
         assertThat(seamlessText.getText()).isEqualTo(context.getResources().getString(
@@ -224,7 +227,7 @@
     fun bindNullDevice() {
         player.attach(holder)
         val state = MediaData(true, BG_COLOR, APP, null, ARTIST, TITLE, null, emptyList(),
-                emptyList(), PACKAGE, session.getSessionToken(), null, null, null)
+                emptyList(), PACKAGE, session.getSessionToken(), null, null, true, null)
         player.bind(state)
         assertThat(seamless.isEnabled()).isTrue()
         assertThat(seamlessText.getText()).isEqualTo(context.getResources().getString(
diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/MediaDataCombineLatestTest.java b/packages/SystemUI/tests/src/com/android/systemui/media/MediaDataCombineLatestTest.java
index bed5c9e..618ee89 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/media/MediaDataCombineLatestTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/media/MediaDataCombineLatestTest.java
@@ -79,7 +79,8 @@
         mManager.addListener(mListener);
 
         mMediaData = new MediaData(true, BG_COLOR, APP, null, ARTIST, TITLE, null,
-                new ArrayList<>(), new ArrayList<>(), PACKAGE, null, null, null, null, KEY, false);
+                new ArrayList<>(), new ArrayList<>(), PACKAGE, null, null, null, true, null, KEY,
+                false);
         mDeviceData = new MediaDeviceData(true, null, DEVICE_NAME);
     }
 
diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/MediaDeviceManagerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/media/MediaDeviceManagerTest.kt
index 3a3140f..6c7f2e8 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/media/MediaDeviceManagerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/media/MediaDeviceManagerTest.kt
@@ -30,6 +30,7 @@
 import com.android.settingslib.media.LocalMediaManager
 import com.android.settingslib.media.MediaDevice
 import com.android.systemui.SysuiTestCase
+import com.android.systemui.dump.DumpManager
 import com.android.systemui.util.concurrency.FakeExecutor
 import com.android.systemui.util.time.FakeSystemClock
 
@@ -51,6 +52,7 @@
 import org.mockito.junit.MockitoJUnit
 
 private const val KEY = "TEST_KEY"
+private const val KEY_OLD = "TEST_KEY_OLD"
 private const val PACKAGE = "PKG"
 private const val SESSION_KEY = "SESSION_KEY"
 private const val SESSION_ARTIST = "SESSION_ARTIST"
@@ -69,8 +71,8 @@
     @Mock private lateinit var lmmFactory: LocalMediaManagerFactory
     @Mock private lateinit var lmm: LocalMediaManager
     @Mock private lateinit var mr2: MediaRouter2Manager
-    @Mock private lateinit var featureFlag: MediaFeatureFlag
     private lateinit var fakeExecutor: FakeExecutor
+    @Mock private lateinit var dumpster: DumpManager
     @Mock private lateinit var listener: MediaDeviceManager.Listener
     @Mock private lateinit var device: MediaDevice
     @Mock private lateinit var icon: Drawable
@@ -85,8 +87,8 @@
     @Before
     fun setUp() {
         fakeExecutor = FakeExecutor(FakeSystemClock())
-        manager = MediaDeviceManager(context, lmmFactory, mr2, featureFlag, fakeExecutor,
-            mediaDataManager)
+        manager = MediaDeviceManager(context, lmmFactory, mr2, fakeExecutor, mediaDataManager,
+                dumpster)
         manager.addListener(listener)
 
         // Configure mocks.
@@ -95,7 +97,6 @@
         whenever(lmmFactory.create(PACKAGE)).thenReturn(lmm)
         whenever(lmm.getCurrentConnectedDevice()).thenReturn(device)
         whenever(mr2.getRoutingSessionForMediaController(any())).thenReturn(route)
-        whenever(featureFlag.enabled).thenReturn(true)
 
         // Create a media sesssion and notification for testing.
         metadataBuilder = MediaMetadata.Builder().apply {
@@ -118,7 +119,8 @@
             setStyle(Notification.MediaStyle().setMediaSession(session.getSessionToken()))
         }
         mediaData = MediaData(true, 0, PACKAGE, null, null, SESSION_TITLE, null,
-            emptyList(), emptyList(), PACKAGE, session.sessionToken, null, null, null)
+            emptyList(), emptyList(), PACKAGE, session.sessionToken, clickIntent = null,
+            device = null, active = true, resumeAction = null)
     }
 
     @After
@@ -132,26 +134,77 @@
     }
 
     @Test
-    fun addNotification() {
+    fun loadMediaData() {
         manager.onMediaDataLoaded(KEY, null, mediaData)
         verify(lmmFactory).create(PACKAGE)
     }
 
     @Test
-    fun featureDisabled() {
-        whenever(featureFlag.enabled).thenReturn(false)
-        manager.onMediaDataLoaded(KEY, null, mediaData)
-        verify(lmmFactory, never()).create(PACKAGE)
-    }
-
-    @Test
-    fun addAndRemoveNotification() {
+    fun loadAndRemoveMediaData() {
         manager.onMediaDataLoaded(KEY, null, mediaData)
         manager.onMediaDataRemoved(KEY)
         verify(lmm).unregisterCallback(any())
     }
 
     @Test
+    fun loadMediaDataWithNullToken() {
+        manager.onMediaDataLoaded(KEY, null, mediaData.copy(token = null))
+        fakeExecutor.runAllReady()
+        val data = captureDeviceData(KEY)
+        assertThat(data.enabled).isTrue()
+        assertThat(data.name).isEqualTo(DEVICE_NAME)
+    }
+
+    @Test
+    fun loadWithNewKey() {
+        // GIVEN that media data has been loaded with an old key
+        manager.onMediaDataLoaded(KEY_OLD, null, mediaData)
+        reset(listener)
+        // WHEN data is loaded with a new key
+        manager.onMediaDataLoaded(KEY, KEY_OLD, mediaData)
+        // THEN the listener for the old key should removed.
+        verify(lmm).unregisterCallback(any())
+        // AND a new device event emitted
+        val data = captureDeviceData(KEY)
+        assertThat(data.enabled).isTrue()
+        assertThat(data.name).isEqualTo(DEVICE_NAME)
+    }
+
+    @Test
+    fun newKeySameAsOldKey() {
+        // GIVEN that media data has been loaded
+        manager.onMediaDataLoaded(KEY, null, mediaData)
+        reset(listener)
+        // WHEN the new key is the same as the old key
+        manager.onMediaDataLoaded(KEY, KEY, mediaData)
+        // THEN no event should be emitted
+        verify(listener, never()).onMediaDeviceChanged(eq(KEY), any())
+    }
+
+    @Test
+    fun unknownOldKey() {
+        manager.onMediaDataLoaded(KEY, "unknown", mediaData)
+        verify(listener).onMediaDeviceChanged(eq(KEY), any())
+    }
+
+    @Test
+    fun updateToSessionTokenWithNullRoute() {
+        // GIVEN that media data has been loaded with a null token
+        manager.onMediaDataLoaded(KEY, null, mediaData.copy(token = null))
+        // WHEN media data is loaded with a different token
+        // AND that token results in a null route
+        reset(listener)
+        whenever(mr2.getRoutingSessionForMediaController(any())).thenReturn(null)
+        manager.onMediaDataLoaded(KEY, null, mediaData)
+        // THEN the device should be disabled
+        fakeExecutor.runAllReady()
+        val data = captureDeviceData(KEY)
+        assertThat(data.enabled).isFalse()
+        assertThat(data.name).isNull()
+        assertThat(data.icon).isNull()
+    }
+
+    @Test
     fun deviceEventOnAddNotification() {
         // WHEN a notification is added
         manager.onMediaDataLoaded(KEY, null, mediaData)
@@ -164,6 +217,15 @@
     }
 
     @Test
+    fun removeListener() {
+        // WHEN a listener is removed
+        manager.removeListener(listener)
+        // THEN it doesn't receive device events
+        manager.onMediaDataLoaded(KEY, null, mediaData)
+        verify(listener, never()).onMediaDeviceChanged(eq(KEY), any())
+    }
+
+    @Test
     fun deviceListUpdate() {
         manager.onMediaDataLoaded(KEY, null, mediaData)
         val deviceCallback = captureCallback()
diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/MediaTimeoutListenerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/media/MediaTimeoutListenerTest.kt
index 7d44327..082c8ba 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/media/MediaTimeoutListenerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/media/MediaTimeoutListenerTest.kt
@@ -93,7 +93,8 @@
         }
         session.setActive(true)
         mediaData = MediaData(true, 0, PACKAGE, null, null, SESSION_TITLE, null,
-            emptyList(), emptyList(), PACKAGE, session.sessionToken, null, null, null)
+            emptyList(), emptyList(), PACKAGE, session.sessionToken, clickIntent = null,
+            device = null, active = true, resumeAction = null)
     }
 
     @Test
diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/SeekBarViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/media/SeekBarViewModelTest.kt
index 24e9bd8..c8ef9fb 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/media/SeekBarViewModelTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/media/SeekBarViewModelTest.kt
@@ -40,6 +40,7 @@
 import org.mockito.ArgumentCaptor
 import org.mockito.Mock
 import org.mockito.Mockito.any
+import org.mockito.Mockito.eq
 import org.mockito.Mockito.mock
 import org.mockito.Mockito.never
 import org.mockito.Mockito.times
@@ -204,7 +205,7 @@
 
     @Test
     fun updateElapsedTime() {
-        // GIVEN that the PlaybackState contins the current position
+        // GIVEN that the PlaybackState contains the current position
         val position = 200L
         val state = PlaybackState.Builder().run {
             setState(PlaybackState.STATE_PLAYING, position, 1f)
@@ -246,7 +247,7 @@
     }
 
     @Test
-    fun handleSeek() {
+    fun onSeek() {
         whenever(mockController.getTransportControls()).thenReturn(mockTransport)
         viewModel.updateController(mockController)
         // WHEN user input is dispatched
@@ -258,19 +259,73 @@
     }
 
     @Test
-    fun handleProgressChangedUser() {
+    fun onSeekWithFalse() {
         whenever(mockController.getTransportControls()).thenReturn(mockTransport)
         viewModel.updateController(mockController)
-        // WHEN user starts dragging the seek bar
-        val pos = 42
-        viewModel.seekBarListener.onProgressChanged(SeekBar(context), pos, true)
+        // WHEN a false is received during the seek gesture
+        val pos = 42L
+        with(viewModel) {
+            onSeekStarting()
+            onSeekFalse()
+            onSeek(pos)
+        }
         fakeExecutor.runAllReady()
-        // THEN transport controls should be used
-        verify(mockTransport).seekTo(pos.toLong())
+        // THEN the seek is rejected and the transport never receives seekTo
+        verify(mockTransport, never()).seekTo(pos)
     }
 
     @Test
-    fun handleProgressChangedOther() {
+    fun onSeekProgress() {
+        val pos = 42L
+        with(viewModel) {
+            onSeekStarting()
+            onSeekProgress(pos)
+        }
+        fakeExecutor.runAllReady()
+        // THEN then elapsed time should be updated
+        assertThat(viewModel.progress.value!!.elapsedTime).isEqualTo(pos)
+    }
+
+    @Test
+    fun onSeekProgressWithSeekStarting() {
+        val pos = 42L
+        with(viewModel) {
+            onSeekProgress(pos)
+        }
+        fakeExecutor.runAllReady()
+        // THEN then elapsed time should not be updated
+        assertThat(viewModel.progress.value!!.elapsedTime).isNull()
+    }
+
+    @Test
+    fun onProgressChangedFromUser() {
+        // WHEN user starts dragging the seek bar
+        val pos = 42
+        val bar = SeekBar(context)
+        with(viewModel.seekBarListener) {
+            onStartTrackingTouch(bar)
+            onProgressChanged(bar, pos, true)
+        }
+        fakeExecutor.runAllReady()
+        // THEN then elapsed time should be updated
+        assertThat(viewModel.progress.value!!.elapsedTime).isEqualTo(pos)
+    }
+
+    @Test
+    fun onProgressChangedFromUserWithoutStartTrackingTouch() {
+        // WHEN user starts dragging the seek bar
+        val pos = 42
+        val bar = SeekBar(context)
+        with(viewModel.seekBarListener) {
+            onProgressChanged(bar, pos, true)
+        }
+        fakeExecutor.runAllReady()
+        // THEN then elapsed time should not be updated
+        assertThat(viewModel.progress.value!!.elapsedTime).isNull()
+    }
+
+    @Test
+    fun onProgressChangedNotFromUser() {
         whenever(mockController.getTransportControls()).thenReturn(mockTransport)
         viewModel.updateController(mockController)
         // WHEN user starts dragging the seek bar
@@ -282,7 +337,7 @@
     }
 
     @Test
-    fun handleStartTrackingTouch() {
+    fun onStartTrackingTouch() {
         whenever(mockController.getTransportControls()).thenReturn(mockTransport)
         viewModel.updateController(mockController)
         // WHEN user starts dragging the seek bar
@@ -297,7 +352,7 @@
     }
 
     @Test
-    fun handleStopTrackingTouch() {
+    fun onStopTrackingTouch() {
         whenever(mockController.getTransportControls()).thenReturn(mockTransport)
         viewModel.updateController(mockController)
         // WHEN user ends drag
@@ -312,6 +367,26 @@
     }
 
     @Test
+    fun onStopTrackingTouchAfterProgress() {
+        whenever(mockController.getTransportControls()).thenReturn(mockTransport)
+        viewModel.updateController(mockController)
+        // WHEN user starts dragging the seek bar
+        val pos = 42
+        val progPos = 84
+        val bar = SeekBar(context).apply {
+            progress = pos
+        }
+        with(viewModel.seekBarListener) {
+            onStartTrackingTouch(bar)
+            onProgressChanged(bar, progPos, true)
+            onStopTrackingTouch(bar)
+        }
+        fakeExecutor.runAllReady()
+        // THEN then elapsed time should be updated
+        verify(mockTransport).seekTo(eq(pos.toLong()))
+    }
+
+    @Test
     fun queuePollTaskWhenPlaying() {
         // GIVEN that the track is playing
         val state = PlaybackState.Builder().run {
@@ -369,7 +444,7 @@
         }
         // AND the playback state is playing
         val state = PlaybackState.Builder().run {
-            setState(PlaybackState.STATE_STOPPED, 200L, 1f)
+            setState(PlaybackState.STATE_PLAYING, 200L, 1f)
             build()
         }
         whenever(mockController.getPlaybackState()).thenReturn(state)
@@ -398,6 +473,90 @@
     }
 
     @Test
+    fun noQueuePollTaskWhenSeeking() {
+        // GIVEN listening
+        viewModel.listening = true
+        // AND the playback state is playing
+        val state = PlaybackState.Builder().run {
+            setState(PlaybackState.STATE_PLAYING, 200L, 1f)
+            build()
+        }
+        whenever(mockController.getPlaybackState()).thenReturn(state)
+        viewModel.updateController(mockController)
+        with(fakeExecutor) {
+            advanceClockToNext()
+            runAllReady()
+        }
+        // WHEN seek starts
+        viewModel.onSeekStarting()
+        with(fakeExecutor) {
+            advanceClockToNext()
+            runAllReady()
+        }
+        // THEN an update task is not queued because we don't want it fighting with the user when
+        // they are trying to move the thumb.
+        assertThat(fakeExecutor.numPending()).isEqualTo(0)
+    }
+
+    @Test
+    fun queuePollTaskWhenDoneSeekingWithFalse() {
+        // GIVEN listening
+        viewModel.listening = true
+        // AND the playback state is playing
+        val state = PlaybackState.Builder().run {
+            setState(PlaybackState.STATE_PLAYING, 200L, 1f)
+            build()
+        }
+        whenever(mockController.getPlaybackState()).thenReturn(state)
+        viewModel.updateController(mockController)
+        with(fakeExecutor) {
+            advanceClockToNext()
+            runAllReady()
+        }
+        // WHEN seek finishes after a false
+        with(viewModel) {
+            onSeekStarting()
+            onSeekFalse()
+            onSeek(42L)
+        }
+        with(fakeExecutor) {
+            advanceClockToNext()
+            runAllReady()
+        }
+        // THEN an update task is queued because the gesture was ignored and progress was restored.
+        assertThat(fakeExecutor.numPending()).isEqualTo(1)
+    }
+
+    @Test
+    fun noQueuePollTaskWhenDoneSeeking() {
+        // GIVEN listening
+        viewModel.listening = true
+        // AND the playback state is playing
+        val state = PlaybackState.Builder().run {
+            setState(PlaybackState.STATE_PLAYING, 200L, 1f)
+            build()
+        }
+        whenever(mockController.getPlaybackState()).thenReturn(state)
+        viewModel.updateController(mockController)
+        with(fakeExecutor) {
+            advanceClockToNext()
+            runAllReady()
+        }
+        // WHEN seek finishes after a false
+        with(viewModel) {
+            onSeekStarting()
+            onSeek(42L)
+        }
+        with(fakeExecutor) {
+            advanceClockToNext()
+            runAllReady()
+        }
+        // THEN no update task is queued because we are waiting for an updated playback state to be
+        // returned in response to the seek.
+        assertThat(fakeExecutor.numPending()).isEqualTo(0)
+    }
+
+    @Test
     fun startListeningQueuesPollTask() {
         // GIVEN not listening
         viewModel.listening = false
diff --git a/packages/SystemUI/tests/src/com/android/systemui/pip/PipAnimationControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/pip/PipAnimationControllerTest.java
index 536cae4..b7a2633 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/pip/PipAnimationControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/pip/PipAnimationControllerTest.java
@@ -82,7 +82,7 @@
     @Test
     public void getAnimator_withBounds_returnBoundsAnimator() {
         final PipAnimationController.PipTransitionAnimator animator = mPipAnimationController
-                .getAnimator(mLeash, new Rect(), new Rect(), null);
+                .getAnimator(mLeash, new Rect(), new Rect());
 
         assertEquals("Expect ANIM_TYPE_BOUNDS animation",
                 animator.getAnimationType(), PipAnimationController.ANIM_TYPE_BOUNDS);
@@ -94,12 +94,12 @@
         final Rect endValue1 = new Rect(100, 100, 200, 200);
         final Rect endValue2 = new Rect(200, 200, 300, 300);
         final PipAnimationController.PipTransitionAnimator oldAnimator = mPipAnimationController
-                .getAnimator(mLeash, startValue, endValue1, null);
+                .getAnimator(mLeash, startValue, endValue1);
         oldAnimator.setSurfaceControlTransactionFactory(DummySurfaceControlTx::new);
         oldAnimator.start();
 
         final PipAnimationController.PipTransitionAnimator newAnimator = mPipAnimationController
-                .getAnimator(mLeash, startValue, endValue2, null);
+                .getAnimator(mLeash, startValue, endValue2);
 
         assertEquals("getAnimator with same type returns same animator",
                 oldAnimator, newAnimator);
@@ -129,7 +129,7 @@
         final Rect endValue1 = new Rect(100, 100, 200, 200);
         final Rect endValue2 = new Rect(200, 200, 300, 300);
         final PipAnimationController.PipTransitionAnimator animator = mPipAnimationController
-                .getAnimator(mLeash, startValue, endValue1, null);
+                .getAnimator(mLeash, startValue, endValue1);
 
         animator.updateEndValue(endValue2);
 
@@ -141,7 +141,7 @@
         final Rect startValue = new Rect(0, 0, 100, 100);
         final Rect endValue = new Rect(100, 100, 200, 200);
         final PipAnimationController.PipTransitionAnimator animator = mPipAnimationController
-                .getAnimator(mLeash, startValue, endValue, null);
+                .getAnimator(mLeash, startValue, endValue);
         animator.setSurfaceControlTransactionFactory(DummySurfaceControlTx::new);
 
         animator.setPipAnimationCallback(mPipAnimationCallback);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/QSPanelTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/QSPanelTest.java
index 05b31c8..cbb0711 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/QSPanelTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/QSPanelTest.java
@@ -51,6 +51,7 @@
 import com.android.systemui.qs.tileimpl.QSTileImpl;
 import com.android.systemui.statusbar.notification.NotificationEntryManager;
 import com.android.systemui.statusbar.policy.SecurityController;
+import com.android.systemui.util.animation.UniqueObjectHostView;
 
 import org.junit.Before;
 import org.junit.Test;
@@ -108,12 +109,14 @@
         mDependency.injectMockDependency(SecurityController.class);
         mDependency.injectTestDependency(Dependency.BG_LOOPER, mTestableLooper.getLooper());
         mContext.addMockSystemService(Context.USER_SERVICE, mock(UserManager.class));
+        when(mMediaHost.getHostView()).thenReturn(new UniqueObjectHostView(getContext()));
 
         mUiEventLogger = new UiEventLoggerFake();
         mTestableLooper.runWithLooper(() -> {
             mMetricsLogger = mDependency.injectMockDependency(MetricsLogger.class);
             mQsPanel = new QSPanel(mContext, null, mDumpManager, mBroadcastDispatcher,
                     mQSLogger, mMediaHost, mUiEventLogger);
+            mQsPanel.onFinishInflate();
             // Provides a parent with non-zero size for QSPanel
             mParentView = new FrameLayout(mContext);
             mParentView.addView(mQsPanel);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/ScreenRecordTileTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/ScreenRecordTileTest.java
index 8a8d227..e502459 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/ScreenRecordTileTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/ScreenRecordTileTest.java
@@ -29,6 +29,7 @@
 
 import androidx.test.filters.SmallTest;
 
+import com.android.internal.logging.UiEventLogger;
 import com.android.systemui.Dependency;
 import com.android.systemui.R;
 import com.android.systemui.SysuiTestCase;
@@ -53,6 +54,8 @@
     private ActivityStarter mActivityStarter;
     @Mock
     private QSTileHost mHost;
+    @Mock
+    private UiEventLogger mUiEventLogger;
 
     private TestableLooper mTestableLooper;
     private ScreenRecordTile mTile;
@@ -68,7 +71,7 @@
 
         when(mHost.getContext()).thenReturn(mContext);
 
-        mTile = new ScreenRecordTile(mHost, mController, mActivityStarter);
+        mTile = new ScreenRecordTile(mHost, mController, mActivityStarter, mUiEventLogger);
     }
 
     // Test that the tile is inactive and labeled correctly when the controller is neither starting
diff --git a/packages/SystemUI/tests/src/com/android/systemui/screenrecord/RecordingServiceTest.java b/packages/SystemUI/tests/src/com/android/systemui/screenrecord/RecordingServiceTest.java
new file mode 100644
index 0000000..283a47c
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/screenrecord/RecordingServiceTest.java
@@ -0,0 +1,114 @@
+/*
+ * Copyright (C) 2020 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.screenrecord;
+
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.Mockito.doNothing;
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+
+import android.app.Notification;
+import android.app.NotificationManager;
+import android.content.Intent;
+import android.testing.AndroidTestingRunner;
+
+import androidx.test.filters.SmallTest;
+
+import com.android.internal.logging.UiEventLogger;
+import com.android.systemui.SysuiTestCase;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.Mockito;
+import org.mockito.MockitoAnnotations;
+
+import java.util.concurrent.Executor;
+
+@RunWith(AndroidTestingRunner.class)
+@SmallTest
+public class RecordingServiceTest extends SysuiTestCase {
+
+    @Mock
+    private UiEventLogger mUiEventLogger;
+    @Mock
+    private RecordingController mController;
+    @Mock
+    private NotificationManager mNotificationManager;
+    @Mock
+    private ScreenMediaRecorder mScreenMediaRecorder;
+    @Mock
+    private Notification mNotification;
+    @Mock
+    private Executor mExecutor;
+
+    private RecordingService mRecordingService;
+
+    @Before
+    public void setUp() throws Exception {
+        MockitoAnnotations.initMocks(this);
+        mRecordingService = Mockito.spy(new RecordingService(mController, mExecutor, mUiEventLogger,
+                mNotificationManager));
+
+        // Return actual context info
+        doReturn(mContext).when(mRecordingService).getApplicationContext();
+        doReturn(mContext.getUserId()).when(mRecordingService).getUserId();
+        doReturn(mContext.getPackageName()).when(mRecordingService).getPackageName();
+        doReturn(mContext.getContentResolver()).when(mRecordingService).getContentResolver();
+
+        // Mock notifications
+        doNothing().when(mRecordingService).createRecordingNotification();
+        doReturn(mNotification).when(mRecordingService).createProcessingNotification();
+        doReturn(mNotification).when(mRecordingService).createSaveNotification(any());
+
+        doNothing().when(mRecordingService).startForeground(anyInt(), any());
+        doReturn(mScreenMediaRecorder).when(mRecordingService).getRecorder();
+    }
+
+    @Test
+    public void testLogStartRecording() {
+        Intent startIntent = RecordingService.getStartIntent(mContext, 0, 0, false);
+        mRecordingService.onStartCommand(startIntent, 0, 0);
+
+        verify(mUiEventLogger, times(1)).log(Events.ScreenRecordEvent.SCREEN_RECORD_START);
+    }
+
+    @Test
+    public void testLogStopFromQsTile() {
+        Intent stopIntent = RecordingService.getStopIntent(mContext);
+        mRecordingService.onStartCommand(stopIntent, 0, 0);
+
+        // Verify that we log the correct event
+        verify(mUiEventLogger, times(1)).log(Events.ScreenRecordEvent.SCREEN_RECORD_END_QS_TILE);
+        verify(mUiEventLogger, times(0))
+                .log(Events.ScreenRecordEvent.SCREEN_RECORD_END_NOTIFICATION);
+    }
+
+    @Test
+    public void testLogStopFromNotificationIntent() {
+        Intent stopIntent = RecordingService.getNotificationIntent(mContext);
+        mRecordingService.onStartCommand(stopIntent, 0, 0);
+
+        // Verify that we log the correct event
+        verify(mUiEventLogger, times(1))
+                .log(Events.ScreenRecordEvent.SCREEN_RECORD_END_NOTIFICATION);
+        verify(mUiEventLogger, times(0)).log(Events.ScreenRecordEvent.SCREEN_RECORD_END_QS_TILE);
+    }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/ActivityLaunchAnimatorTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/ActivityLaunchAnimatorTest.java
index cdef49d..2fa6cf0 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/ActivityLaunchAnimatorTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/ActivityLaunchAnimatorTest.java
@@ -36,6 +36,8 @@
 import com.android.systemui.statusbar.phone.NotificationPanelViewController;
 import com.android.systemui.statusbar.phone.NotificationShadeWindowView;
 import com.android.systemui.statusbar.phone.NotificationShadeWindowViewController;
+import com.android.systemui.util.concurrency.FakeExecutor;
+import com.android.systemui.util.time.FakeSystemClock;
 
 import org.junit.Assert;
 import org.junit.Before;
@@ -51,6 +53,7 @@
 @TestableLooper.RunWithLooper
 public class ActivityLaunchAnimatorTest extends SysuiTestCase {
 
+    private final FakeExecutor mExecutor = new FakeExecutor(new FakeSystemClock());
     private ActivityLaunchAnimator mLaunchAnimator;
     @Mock
     private ActivityLaunchAnimator.Callback mCallback;
@@ -80,8 +83,8 @@
                 mCallback,
                 mNotificationPanelViewController,
                 mNotificationShadeDepthController,
-                mNotificationContainer);
-
+                mNotificationContainer,
+                mExecutor);
     }
 
     @Test
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/HighPriorityProviderTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/HighPriorityProviderTest.java
index 78e9b33..2b12c22 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/HighPriorityProviderTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/HighPriorityProviderTest.java
@@ -38,6 +38,7 @@
 import com.android.systemui.statusbar.RankingBuilder;
 import com.android.systemui.statusbar.notification.collection.provider.HighPriorityProvider;
 import com.android.systemui.statusbar.notification.people.PeopleNotificationIdentifier;
+import com.android.systemui.statusbar.phone.NotificationGroupManager;
 
 import org.junit.Before;
 import org.junit.Test;
@@ -45,16 +46,22 @@
 import org.mockito.Mock;
 import org.mockito.MockitoAnnotations;
 
+import java.util.ArrayList;
+import java.util.Arrays;
+
 @SmallTest
 @RunWith(AndroidTestingRunner.class)
 public class HighPriorityProviderTest extends SysuiTestCase {
     @Mock private PeopleNotificationIdentifier mPeopleNotificationIdentifier;
+    @Mock private NotificationGroupManager mGroupManager;
     private HighPriorityProvider mHighPriorityProvider;
 
     @Before
     public void setup() {
         MockitoAnnotations.initMocks(this);
-        mHighPriorityProvider = new HighPriorityProvider(mPeopleNotificationIdentifier);
+        mHighPriorityProvider = new HighPriorityProvider(
+                mPeopleNotificationIdentifier,
+                mGroupManager);
     }
 
     @Test
@@ -166,6 +173,22 @@
     }
 
     @Test
+    public void testIsHighPriority_checkChildrenToCalculatePriority() {
+        // GIVEN: a summary with low priority has a highPriorityChild and a lowPriorityChild
+        final NotificationEntry summary = createNotifEntry(false);
+        final NotificationEntry lowPriorityChild = createNotifEntry(false);
+        final NotificationEntry highPriorityChild = createNotifEntry(true);
+        when(mGroupManager.isGroupSummary(summary.getSbn())).thenReturn(true);
+        when(mGroupManager.getChildren(summary.getSbn())).thenReturn(
+                new ArrayList<>(Arrays.asList(lowPriorityChild, highPriorityChild)));
+
+        // THEN the summary is high priority since it has a high priority child
+        assertTrue(mHighPriorityProvider.isHighPriority(summary));
+    }
+
+    // Tests below here are only relevant to the NEW notification pipeline which uses GroupEntry
+
+    @Test
     public void testIsHighPriority_summaryUpdated() {
         // GIVEN a GroupEntry with a lowPrioritySummary and no children
         final GroupEntry parentEntry = new GroupEntry("test_group_key");
@@ -186,7 +209,7 @@
     }
 
     @Test
-    public void testIsHighPriority_checkChildrenToCalculatePriority() {
+    public void testIsHighPriority_checkChildrenToCalculatePriorityOf() {
         // GIVEN:
         // GroupEntry = parentEntry, summary = lowPrioritySummary
         //      NotificationEntry = lowPriorityChild
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/NotifCollectionTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/NotifCollectionTest.java
index ca9cc29..363fe95 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/NotifCollectionTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/NotifCollectionTest.java
@@ -80,6 +80,7 @@
 import com.android.systemui.statusbar.notification.collection.notifcollection.NotifCollectionLogger;
 import com.android.systemui.statusbar.notification.collection.notifcollection.NotifDismissInterceptor;
 import com.android.systemui.statusbar.notification.collection.notifcollection.NotifLifetimeExtender;
+import com.android.systemui.util.time.FakeSystemClock;
 
 import org.junit.Before;
 import org.junit.Test;
@@ -131,6 +132,7 @@
     private InOrder mListenerInOrder;
 
     private NoManSimulator mNoMan;
+    private FakeSystemClock mClock = new FakeSystemClock();
 
     @Before
     public void setUp() {
@@ -146,10 +148,11 @@
 
         mCollection = new NotifCollection(
                 mStatusBarService,
-                mock(DumpManager.class),
+                mClock,
                 mFeatureFlags,
                 mLogger,
-                mEulogizer);
+                mEulogizer,
+                mock(DumpManager.class));
         mCollection.attach(mGroupCoalescer);
         mCollection.addCollectionListener(mCollectionListener);
         mCollection.setBuildListener(mBuildListener);
@@ -161,6 +164,8 @@
 
         mNoMan = new NoManSimulator();
         mNoMan.addListener(mNotifHandler);
+
+        mNotifHandler.onNotificationsInitialized();
     }
 
     @Test
@@ -1268,6 +1273,42 @@
         verify(mInterceptor3, never()).shouldInterceptDismissal(clearable);
     }
 
+    @Test(expected = IllegalStateException.class)
+    public void testClearNotificationThrowsIfMissing() {
+        // GIVEN that enough time has passed that we're beyond the forgiveness window
+        mClock.advanceTime(5001);
+
+        // WHEN we get a remove event for a notification we don't know about
+        final NotificationEntry container = new NotificationEntryBuilder()
+                .setPkg(TEST_PACKAGE)
+                .setId(47)
+                .build();
+        mNotifHandler.onNotificationRemoved(
+                container.getSbn(),
+                new RankingMap(new Ranking[]{ container.getRanking() }));
+
+        // THEN an exception is thrown
+    }
+
+    @Test
+    public void testClearNotificationDoesntThrowIfInForgivenessWindow() {
+        // GIVEN that some time has passed but we're still within the initialization forgiveness
+        // window
+        mClock.advanceTime(4999);
+
+        // WHEN we get a remove event for a notification we don't know about
+        final NotificationEntry container = new NotificationEntryBuilder()
+                .setPkg(TEST_PACKAGE)
+                .setId(47)
+                .build();
+        mNotifHandler.onNotificationRemoved(
+                container.getSbn(),
+                new RankingMap(new Ranking[]{ container.getRanking() }));
+
+        // THEN no exception is thrown, but no event is fired
+        verify(mCollectionListener, never()).onEntryRemoved(any(NotificationEntry.class), anyInt());
+    }
+
     private static NotificationEntryBuilder buildNotif(String pkg, int id, String tag) {
         return new NotificationEntryBuilder()
                 .setPkg(pkg)
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/NotificationRankingManagerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/NotificationRankingManagerTest.kt
index 1c47131..82a7774 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/NotificationRankingManagerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/NotificationRankingManagerTest.kt
@@ -77,7 +77,8 @@
                 mock(NotificationEntryManagerLogger::class.java),
                 sectionsManager,
                 personNotificationIdentifier,
-                HighPriorityProvider(personNotificationIdentifier)
+                HighPriorityProvider(personNotificationIdentifier,
+                    mock(NotificationGroupManager::class.java))
         )
     }
 
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/icon/IconManagerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/icon/IconManagerTest.kt
new file mode 100644
index 0000000..b63e66f
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/icon/IconManagerTest.kt
@@ -0,0 +1,209 @@
+/*
+ * Copyright (C) 2020 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.notification.icon;
+
+import android.app.ActivityManager;
+import android.app.Notification;
+import android.app.NotificationChannel
+import android.app.NotificationManager.IMPORTANCE_DEFAULT
+import android.app.Person
+import android.content.pm.LauncherApps
+import android.content.pm.ShortcutInfo
+import android.graphics.drawable.Drawable
+import android.graphics.drawable.Icon
+import android.os.SystemClock
+import android.os.UserHandle
+import android.testing.AndroidTestingRunner;
+import androidx.test.InstrumentationRegistry
+import androidx.test.filters.SmallTest
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.controls.controller.AuxiliaryPersistenceWrapperTest.Companion.any
+import com.android.systemui.statusbar.notification.collection.NotificationEntry
+import com.android.systemui.statusbar.notification.collection.NotificationEntryBuilder
+import com.android.systemui.statusbar.notification.collection.notifcollection.CommonNotifCollection
+import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow
+import org.junit.Assert.assertEquals
+import org.junit.Before
+import org.junit.Test
+
+import org.junit.runner.RunWith;
+import org.mockito.Mock
+import org.mockito.Mockito.`when`
+import org.mockito.Mockito.anyInt
+import org.mockito.MockitoAnnotations
+
+@SmallTest
+@RunWith(AndroidTestingRunner::class)
+class IconManagerTest: SysuiTestCase() {
+    companion object {
+        private const val TEST_PACKAGE_NAME = "test";
+        private const val TEST_UID = 0;
+    }
+
+
+    private var id = 0
+    private val context = InstrumentationRegistry.getTargetContext();
+    @Mock private lateinit var shortcut: ShortcutInfo
+    @Mock private lateinit var shortcutIc: Icon
+    @Mock private lateinit var messageIc: Icon
+    @Mock private lateinit var largeIc: Icon
+    @Mock private lateinit var smallIc: Icon
+    @Mock private lateinit var drawable: Drawable
+    @Mock private lateinit var row: ExpandableNotificationRow
+
+    @Mock private lateinit var notifCollection: CommonNotifCollection
+    @Mock private lateinit var launcherApps: LauncherApps
+
+    private val iconBuilder = IconBuilder(context)
+
+    private lateinit var iconManager: IconManager
+
+    @Before
+    fun setUp() {
+        MockitoAnnotations.initMocks(this)
+
+        `when`(shortcutIc.loadDrawableAsUser(any(), anyInt())).thenReturn(drawable)
+        `when`(messageIc.loadDrawableAsUser(any(), anyInt())).thenReturn(drawable)
+        `when`(largeIc.loadDrawableAsUser(any(), anyInt())).thenReturn(drawable)
+        `when`(smallIc.loadDrawableAsUser(any(), anyInt())).thenReturn(drawable)
+
+        `when`(shortcut.icon).thenReturn(shortcutIc)
+        `when`(launcherApps.getShortcutIcon(shortcut)).thenReturn(shortcutIc)
+
+        iconManager = IconManager(notifCollection, launcherApps, iconBuilder)
+    }
+
+    @Test
+    fun testCreateIcons_importantConversation_shortcutIcon() {
+        val entry = notificationEntry(true, true, true)
+        entry?.channel?.isImportantConversation = true
+        entry?.let {
+            iconManager.createIcons(it)
+        }
+        assertEquals(entry?.icons?.statusBarIcon?.sourceIcon, shortcutIc)
+    }
+
+    @Test
+    fun testCreateIcons_importantConversation_messageIcon() {
+        val entry = notificationEntry(false, true, true)
+        entry?.channel?.isImportantConversation = true
+        entry?.let {
+            iconManager.createIcons(it)
+        }
+        assertEquals(entry?.icons?.statusBarIcon?.sourceIcon, messageIc)
+    }
+
+    @Test
+    fun testCreateIcons_importantConversation_largeIcon() {
+        val entry = notificationEntry(false, false, true)
+        entry?.channel?.isImportantConversation = true
+        entry?.let {
+            iconManager.createIcons(it)
+        }
+        assertEquals(entry?.icons?.statusBarIcon?.sourceIcon, largeIc)
+    }
+
+    @Test
+    fun testCreateIcons_importantConversation_smallIcon() {
+        val entry = notificationEntry(false, false, false)
+        entry?.channel?.isImportantConversation = true
+        entry?.let {
+            iconManager.createIcons(it)
+        }
+        assertEquals(entry?.icons?.statusBarIcon?.sourceIcon, smallIc)
+    }
+
+    @Test
+    fun testCreateIcons_notImportantConversation() {
+        val entry = notificationEntry(true, true, true)
+        entry?.let {
+            iconManager.createIcons(it)
+        }
+        assertEquals(entry?.icons?.statusBarIcon?.sourceIcon, smallIc)
+    }
+
+    @Test
+    fun testCreateIcons_sensitiveImportantConversation() {
+        val entry = notificationEntry(true, false, false)
+        entry?.setSensitive(true, true);
+        entry?.channel?.isImportantConversation = true
+        entry?.let {
+            iconManager.createIcons(it)
+        }
+        assertEquals(entry?.icons?.statusBarIcon?.sourceIcon, shortcutIc)
+        assertEquals(entry?.icons?.shelfIcon?.sourceIcon, smallIc)
+        assertEquals(entry?.icons?.aodIcon?.sourceIcon, smallIc)
+    }
+
+    @Test
+    fun testUpdateIcons_sensitivityChange() {
+        val entry = notificationEntry(true, false, false)
+        entry?.channel?.isImportantConversation = true
+        entry?.setSensitive(true, true);
+        entry?.let {
+            iconManager.createIcons(it)
+        }
+        assertEquals(entry?.icons?.aodIcon?.sourceIcon, smallIc)
+        entry?.setSensitive(false, false);
+        entry?.let {
+            iconManager.updateIcons(it)
+        }
+        assertEquals(entry?.icons?.shelfIcon?.sourceIcon, shortcutIc)
+    }
+
+    private fun notificationEntry(
+            hasShortcut: Boolean,
+            hasMessage: Boolean,
+            hasLargeIcon: Boolean
+    ): NotificationEntry? {
+        val n = Notification.Builder(mContext, "id")
+                .setSmallIcon(smallIc)
+                .setContentTitle("Title")
+                .setContentText("Text")
+
+        if (hasMessage) {
+            n.style = Notification.MessagingStyle("")
+                    .addMessage(Notification.MessagingStyle.Message(
+                            "",
+                            SystemClock.currentThreadTimeMillis(),
+                            Person.Builder().setIcon(messageIc).build()
+                    ))
+        }
+
+        if (hasLargeIcon) {
+            n.setLargeIcon(largeIc)
+        }
+
+        val builder = NotificationEntryBuilder()
+                .setPkg(TEST_PACKAGE_NAME)
+                .setOpPkg(TEST_PACKAGE_NAME)
+                .setUid(TEST_UID)
+                .setId(id++)
+                .setNotification(n.build())
+                .setChannel(NotificationChannel("id", "", IMPORTANCE_DEFAULT))
+                .setUser(UserHandle(ActivityManager.getCurrentUser()))
+
+        if (hasShortcut) {
+            builder.setShortcutInfo(shortcut)
+        }
+
+        val entry = builder.build()
+        entry.row = row
+        entry.setSensitive(false, true);
+        return entry
+    }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/logging/NotificationLoggerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/logging/NotificationLoggerTest.java
index a3a46f6..06bad80 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/logging/NotificationLoggerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/logging/NotificationLoggerTest.java
@@ -20,6 +20,8 @@
 
 import static org.junit.Assert.assertArrayEquals;
 import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
 import static org.mockito.ArgumentMatchers.any;
 import static org.mockito.Mockito.doAnswer;
 import static org.mockito.Mockito.mock;
@@ -42,6 +44,7 @@
 import com.android.internal.statusbar.NotificationVisibility;
 import com.android.systemui.SysuiTestCase;
 import com.android.systemui.statusbar.NotificationListener;
+import com.android.systemui.statusbar.StatusBarState;
 import com.android.systemui.statusbar.StatusBarStateControllerImpl;
 import com.android.systemui.statusbar.notification.NotificationEntryListener;
 import com.android.systemui.statusbar.notification.NotificationEntryManager;
@@ -163,29 +166,62 @@
         mUiBgExecutor.runAllReady();
         Mockito.reset(mBarService);
 
-        mLogger.stopNotificationLogging();
+        setStateAsleep();
+        mLogger.onDozingChanged(false);  // Wake to lockscreen
+        mLogger.onDozingChanged(true);  // And go back to sleep, turning off logging
         mUiBgExecutor.runAllReady();
         // The visibility objects are recycled by NotificationLogger, so we can't use specific
         // matchers here.
         verify(mBarService, times(1)).onNotificationVisibilityChanged(any(), any());
     }
 
+    private void setStateAsleep() {
+        mLogger.onPanelExpandedChanged(true);
+        mLogger.onDozingChanged(true);
+        mLogger.onStateChanged(StatusBarState.KEYGUARD);
+    }
+
+    private void setStateAwake() {
+        mLogger.onPanelExpandedChanged(false);
+        mLogger.onDozingChanged(false);
+        mLogger.onStateChanged(StatusBarState.SHADE);
+    }
+
     @Test
-    public void testLogPanelShownOnLoggingStart() {
+    public void testLogPanelShownOnWake() {
         when(mEntryManager.getVisibleNotifications()).thenReturn(Lists.newArrayList(mEntry));
-        mLogger.startNotificationLogging();
+        setStateAsleep();
+        mLogger.onDozingChanged(false);  // Wake to lockscreen
         assertEquals(1, mNotificationPanelLoggerFake.getCalls().size());
-        assertEquals(false, mNotificationPanelLoggerFake.get(0).isLockscreen);
+        assertTrue(mNotificationPanelLoggerFake.get(0).isLockscreen);
         assertEquals(1, mNotificationPanelLoggerFake.get(0).list.notifications.length);
         Notifications.Notification n = mNotificationPanelLoggerFake.get(0).list.notifications[0];
         assertEquals(TEST_PACKAGE_NAME, n.packageName);
         assertEquals(TEST_UID, n.uid);
         assertEquals(1, n.instanceId);
-        assertEquals(false, n.isGroupSummary);
+        assertFalse(n.isGroupSummary);
         assertEquals(1 + BUCKET_ALERTING, n.section);
     }
 
     @Test
+    public void testLogPanelShownOnShadePull() {
+        when(mEntryManager.getVisibleNotifications()).thenReturn(Lists.newArrayList(mEntry));
+        setStateAwake();
+        // Now expand panel
+        mLogger.onPanelExpandedChanged(true);
+        assertEquals(1, mNotificationPanelLoggerFake.getCalls().size());
+        assertFalse(mNotificationPanelLoggerFake.get(0).isLockscreen);
+        assertEquals(1, mNotificationPanelLoggerFake.get(0).list.notifications.length);
+        Notifications.Notification n = mNotificationPanelLoggerFake.get(0).list.notifications[0];
+        assertEquals(TEST_PACKAGE_NAME, n.packageName);
+        assertEquals(TEST_UID, n.uid);
+        assertEquals(1, n.instanceId);
+        assertFalse(n.isGroupSummary);
+        assertEquals(1 + BUCKET_ALERTING, n.section);
+    }
+
+
+    @Test
     public void testLogPanelShownHandlesNullInstanceIds() {
         // Construct a NotificationEntry like mEntry, but with a null instance id.
         NotificationEntry entry = new NotificationEntryBuilder()
@@ -198,7 +234,8 @@
         entry.setRow(mRow);
 
         when(mEntryManager.getVisibleNotifications()).thenReturn(Lists.newArrayList(entry));
-        mLogger.startNotificationLogging();
+        setStateAsleep();
+        mLogger.onDozingChanged(false);  // Wake to lockscreen
         assertEquals(1, mNotificationPanelLoggerFake.getCalls().size());
         assertEquals(1, mNotificationPanelLoggerFake.get(0).list.notifications.length);
         Notifications.Notification n = mNotificationPanelLoggerFake.get(0).list.notifications[0];
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/PartialConversationInfoTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/PartialConversationInfoTest.java
index f327967..43aa8fe 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/PartialConversationInfoTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/PartialConversationInfoTest.java
@@ -25,6 +25,7 @@
 import static junit.framework.Assert.assertEquals;
 import static junit.framework.Assert.assertTrue;
 
+import static org.mockito.ArgumentMatchers.anyObject;
 import static org.mockito.Mockito.any;
 import static org.mockito.Mockito.anyBoolean;
 import static org.mockito.Mockito.anyInt;
@@ -162,6 +163,7 @@
 
     @Test
     public void testBindNotification_SetsName() {
+        when(mMockPackageManager.getApplicationLabel(any())).thenReturn("Package");
         mInfo.bindNotification(
                 mMockPackageManager,
                 mMockINotificationManager,
@@ -174,15 +176,13 @@
                 true,
                 false);
         final TextView textView = mInfo.findViewById(R.id.name);
-        assertTrue(textView.getText().toString().contains("title"));
+        assertTrue(textView.getText().toString().equals("Package"));
     }
 
+
     @Test
-    public void testBindNotification_groupSetsPackageIcon() {
-        mEntry.getSbn().getNotification().extras.putBoolean(EXTRA_IS_GROUP_CONVERSATION, true);
-        final Drawable iconDrawable = mock(Drawable.class);
-        when(mMockPackageManager.getApplicationIcon(any(ApplicationInfo.class)))
-                .thenReturn(iconDrawable);
+    public void testBindNotification_setsIcon() {
+        when(mMockPackageManager.getApplicationIcon((ApplicationInfo) any())).thenReturn(mDrawable);
         mInfo.bindNotification(
                 mMockPackageManager,
                 mMockINotificationManager,
@@ -194,34 +194,7 @@
                 null,
                 true,
                 false);
-        final ImageView iconView = mInfo.findViewById(R.id.conversation_icon);
-        assertEquals(iconDrawable, iconView.getDrawable());
-    }
-
-    @Test
-    public void testBindNotification_notGroupSetsMessageIcon() {
-        Notification n = new Notification.Builder(mContext, TEST_CHANNEL_NAME)
-                .setStyle(new Notification.MessagingStyle(
-                        new Person.Builder().setName("me").build())
-                .addMessage(new Notification.MessagingStyle.Message("hello", 0,
-                        new Person.Builder().setName("friend").setIcon(mIcon).build())))
-                .build();
-        mSbn = new StatusBarNotification(TEST_PACKAGE_NAME, TEST_PACKAGE_NAME, 0, null, TEST_UID, 0,
-                n, UserHandle.CURRENT, null, 0);
-        mEntry.setSbn(mSbn);
-        mEntry.getSbn().getNotification().extras.putBoolean(EXTRA_IS_GROUP_CONVERSATION, false);
-        mInfo.bindNotification(
-                mMockPackageManager,
-                mMockINotificationManager,
-                mChannelEditorDialogController,
-                TEST_PACKAGE_NAME,
-                mNotificationChannel,
-                mNotificationChannelSet,
-                mEntry,
-                null,
-                true,
-                false);
-        final ImageView iconView = mInfo.findViewById(R.id.conversation_icon);
+        final ImageView iconView = mInfo.findViewById(R.id.icon);
         assertEquals(mDrawable.hashCode() + "", mDrawable, iconView.getDrawable());
     }
 
@@ -270,64 +243,6 @@
     }
 
     @Test
-    public void testBindNotification_GroupNameHiddenIfNoGroup() throws Exception {
-        mInfo.bindNotification(
-                mMockPackageManager,
-                mMockINotificationManager,
-                mChannelEditorDialogController,
-                TEST_PACKAGE_NAME,
-                mNotificationChannel,
-                mNotificationChannelSet,
-                mEntry,
-                null,
-                true,
-                false);
-        final TextView groupNameView = mInfo.findViewById(R.id.group_name);
-        assertEquals(GONE, groupNameView.getVisibility());
-    }
-
-    @Test
-    public void testBindNotification_SetsGroupNameIfNonNull() throws Exception {
-        mNotificationChannel.setGroup("test_group_id");
-        final NotificationChannelGroup notificationChannelGroup =
-                new NotificationChannelGroup("test_group_id", "Test Group Name");
-        when(mMockINotificationManager.getNotificationChannelGroupForPackage(
-                eq("test_group_id"), eq(TEST_PACKAGE_NAME), eq(TEST_UID)))
-                .thenReturn(notificationChannelGroup);
-        mInfo.bindNotification(
-                mMockPackageManager,
-                mMockINotificationManager,
-                mChannelEditorDialogController,
-                TEST_PACKAGE_NAME,
-                mNotificationChannel,
-                mNotificationChannelSet,
-                mEntry,
-                null,
-                true,
-                false);
-        final TextView groupNameView = mInfo.findViewById(R.id.group_name);
-        assertEquals(View.VISIBLE, groupNameView.getVisibility());
-        assertEquals("Test Group Name", groupNameView.getText());
-    }
-
-    @Test
-    public void testBindNotification_SetsTextChannelName() {
-        mInfo.bindNotification(
-                mMockPackageManager,
-                mMockINotificationManager,
-                mChannelEditorDialogController,
-                TEST_PACKAGE_NAME,
-                mNotificationChannel,
-                mNotificationChannelSet,
-                mEntry,
-                null,
-                true,
-                false);
-        final TextView textView = mInfo.findViewById(R.id.parent_channel_name);
-        assertEquals(TEST_CHANNEL_NAME, textView.getText());
-    }
-
-    @Test
     public void testBindNotification_SetsOnClickListenerForSettings() {
         final CountDownLatch latch = new CountDownLatch(1);
         mInfo.bindNotification(
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationSectionsManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationSectionsManagerTest.java
index c55391a..243503d 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationSectionsManagerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationSectionsManagerTest.java
@@ -403,11 +403,11 @@
         enablePeopleFiltering();
 
         setupMockStack(
-                PERSON.headsUp(),   // personHeaderTarget = 0
-                INCOMING_HEADER,    // currentIncomingHeaderIdx = 1
-                ALERTING.headsUp(), // alertingHeaderTarget = 1
-                PEOPLE_HEADER,      // currentPeopleHeaderIdx = 3
-                PERSON              //
+                PERSON.headsUp(),
+                INCOMING_HEADER,
+                ALERTING.headsUp(),
+                PEOPLE_HEADER,
+                PERSON
         );
         mSectionsManager.updateSectionBoundaries();
 
@@ -520,6 +520,70 @@
                 ChildType.GENTLE);
     }
 
+    @Test
+    public void testRemoveIncomingHeader() {
+        enablePeopleFiltering();
+        enableMediaControls();
+
+        setupMockStack(
+                MEDIA_CONTROLS,
+                INCOMING_HEADER,
+                PERSON,
+                ALERTING,
+                PEOPLE_HEADER,
+                ALERTING_HEADER,
+                ALERTING,
+                ALERTING,
+                GENTLE_HEADER,
+                GENTLE,
+                GENTLE
+        );
+
+        mSectionsManager.updateSectionBoundaries();
+
+        verifyMockStack(
+                ChildType.MEDIA_CONTROLS,
+                ChildType.PEOPLE_HEADER,
+                ChildType.PERSON,
+                ChildType.ALERTING_HEADER,
+                ChildType.ALERTING,
+                ChildType.ALERTING,
+                ChildType.ALERTING,
+                ChildType.GENTLE_HEADER,
+                ChildType.GENTLE,
+                ChildType.GENTLE
+        );
+    }
+
+    @Test
+    public void testExpandIncomingSection() {
+        enablePeopleFiltering();
+
+        setupMockStack(
+                INCOMING_HEADER,
+                PERSON,
+                ALERTING,
+                PEOPLE_HEADER,
+                ALERTING,
+                PERSON,
+                ALERTING_HEADER,
+                ALERTING
+        );
+
+        mSectionsManager.updateSectionBoundaries();
+
+        verifyMockStack(
+                ChildType.INCOMING_HEADER,
+                ChildType.HEADS_UP,
+                ChildType.HEADS_UP,
+                ChildType.HEADS_UP,
+                ChildType.PEOPLE_HEADER,
+                ChildType.PERSON,
+                ChildType.ALERTING_HEADER,
+                ChildType.ALERTING
+        );
+    }
+
     private void enablePeopleFiltering() {
         when(mSectionsFeatureManager.isFilteringEnabled()).thenReturn(true);
     }
@@ -657,7 +721,13 @@
         final List<View> children = new ArrayList<>();
         when(mNssl.getChildCount()).thenAnswer(invocation -> children.size());
         when(mNssl.getChildAt(anyInt()))
-                .thenAnswer(invocation -> children.get(invocation.getArgument(0)));
+                .thenAnswer(invocation -> {
+                    Integer index = invocation.getArgument(0);
+                    if (index == null || index < 0 || index >= children.size()) {
+                        return null;
+                    }
+                    return children.get(index);
+                });
         when(mNssl.indexOfChild(any()))
                 .thenAnswer(invocation -> children.indexOf(invocation.getArgument(0)));
         doAnswer(invocation -> {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NavigationBarFragmentTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NavigationBarFragmentTest.java
index a77f8c6..00cbddc 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NavigationBarFragmentTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NavigationBarFragmentTest.java
@@ -21,6 +21,8 @@
 import static android.view.Display.DEFAULT_DISPLAY;
 import static android.view.DisplayAdjustments.DEFAULT_DISPLAY_ADJUSTMENTS;
 
+import static com.android.systemui.statusbar.phone.NavigationBarFragment.NavBarActionEvent.NAVBAR_ASSIST_LONGPRESS;
+
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertNotNull;
@@ -28,6 +30,7 @@
 import static org.mockito.ArgumentMatchers.anyBoolean;
 import static org.mockito.ArgumentMatchers.anyInt;
 import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.times;
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
 
@@ -59,6 +62,7 @@
 import androidx.test.filters.SmallTest;
 
 import com.android.internal.logging.MetricsLogger;
+import com.android.internal.logging.UiEventLogger;
 import com.android.systemui.Dependency;
 import com.android.systemui.SysuiBaseFragmentTest;
 import com.android.systemui.SysuiTestableContext;
@@ -105,6 +109,8 @@
     private Recents mRecents;
     @Mock
     private SystemActions mSystemActions;
+    @Mock
+    private UiEventLogger mUiEventLogger;
 
     private AccessibilityManagerWrapper mAccessibilityWrapper =
             new AccessibilityManagerWrapper(mContext) {
@@ -187,6 +193,8 @@
         mFragments.dispatchResume();
         processAllMessages();
         navigationBarFragment.onHomeLongClick(navigationBarFragment.getView());
+
+        verify(mUiEventLogger, times(1)).log(NAVBAR_ASSIST_LONGPRESS);
     }
 
     @Test
@@ -242,6 +250,7 @@
     protected Fragment instantiate(Context context, String className, Bundle arguments) {
         DeviceProvisionedController deviceProvisionedController =
                 mock(DeviceProvisionedController.class);
+        when(deviceProvisionedController.isDeviceProvisioned()).thenReturn(true);
         assertNotNull(mAccessibilityWrapper);
         return new NavigationBarFragment(
                 context.getDisplayId() == DEFAULT_DISPLAY ? mAccessibilityWrapper
@@ -261,7 +270,8 @@
                 mock(ShadeController.class),
                 mock(NotificationRemoteInputManager.class),
                 mock(SystemActions.class),
-                mHandler);
+                mHandler,
+                mUiEventLogger);
     }
 
     private class HostCallbacksForExternalDisplay extends
@@ -319,6 +329,7 @@
                     mock(LightBarTransitionsController.class));
             when(view.getRotationButtonController()).thenReturn(
                     mock(RotationButtonController.class));
+            when(view.isRecentsButtonVisible()).thenReturn(true);
             return view;
         }
     }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/KeyButtonViewTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/KeyButtonViewTest.java
index 5e9d592..d52d686 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/KeyButtonViewTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/KeyButtonViewTest.java
@@ -23,12 +23,12 @@
 import static android.view.KeyEvent.KEYCODE_BACK;
 import static android.view.KeyEvent.KEYCODE_HOME;
 
-import static com.android.systemui.statusbar.policy.KeyButtonView.NavBarActionsEvent.NAVBAR_BACK_BUTTON_LONGPRESS;
-import static com.android.systemui.statusbar.policy.KeyButtonView.NavBarActionsEvent.NAVBAR_BACK_BUTTON_TAP;
-import static com.android.systemui.statusbar.policy.KeyButtonView.NavBarActionsEvent.NAVBAR_HOME_BUTTON_LONGPRESS;
-import static com.android.systemui.statusbar.policy.KeyButtonView.NavBarActionsEvent.NAVBAR_HOME_BUTTON_TAP;
-import static com.android.systemui.statusbar.policy.KeyButtonView.NavBarActionsEvent.NAVBAR_OVERVIEW_BUTTON_LONGPRESS;
-import static com.android.systemui.statusbar.policy.KeyButtonView.NavBarActionsEvent.NAVBAR_OVERVIEW_BUTTON_TAP;
+import static com.android.systemui.statusbar.policy.KeyButtonView.NavBarButtonEvent.NAVBAR_BACK_BUTTON_LONGPRESS;
+import static com.android.systemui.statusbar.policy.KeyButtonView.NavBarButtonEvent.NAVBAR_BACK_BUTTON_TAP;
+import static com.android.systemui.statusbar.policy.KeyButtonView.NavBarButtonEvent.NAVBAR_HOME_BUTTON_LONGPRESS;
+import static com.android.systemui.statusbar.policy.KeyButtonView.NavBarButtonEvent.NAVBAR_HOME_BUTTON_TAP;
+import static com.android.systemui.statusbar.policy.KeyButtonView.NavBarButtonEvent.NAVBAR_OVERVIEW_BUTTON_LONGPRESS;
+import static com.android.systemui.statusbar.policy.KeyButtonView.NavBarButtonEvent.NAVBAR_OVERVIEW_BUTTON_TAP;
 
 import static junit.framework.Assert.assertEquals;
 
@@ -140,11 +140,11 @@
     }
 
     private void checkmetrics(int code, int action, int flag,
-            KeyButtonView.NavBarActionsEvent expected) {
+            KeyButtonView.NavBarButtonEvent expected) {
         mKeyButtonView.setCode(code);
         mKeyButtonView.sendEvent(action, flag);
         if (expected == null) {
-            verify(mUiEventLogger, never()).log(any(KeyButtonView.NavBarActionsEvent.class));
+            verify(mUiEventLogger, never()).log(any(KeyButtonView.NavBarButtonEvent.class));
         } else {
             verify(mUiEventLogger, times(1)).log(expected);
         }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/util/animation/PhysicsAnimatorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/util/animation/PhysicsAnimatorTest.kt
index 661fad2..bd59680 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/util/animation/PhysicsAnimatorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/util/animation/PhysicsAnimatorTest.kt
@@ -38,6 +38,7 @@
 @TestableLooper.RunWithLooper
 @RunWith(AndroidTestingRunner::class)
 @SmallTest
+@Ignore("Blocking presubmits - investigating in b/158697054")
 class PhysicsAnimatorTest : SysuiTestCase() {
     private lateinit var viewGroup: ViewGroup
     private lateinit var testView: View
diff --git a/packages/Tethering/Android.bp b/packages/Tethering/Android.bp
index d07a70c..32e2b04 100644
--- a/packages/Tethering/Android.bp
+++ b/packages/Tethering/Android.bp
@@ -25,7 +25,7 @@
     ],
     static_libs: [
         "androidx.annotation_annotation",
-        "netd_aidl_interface-V3-java",
+        "netd_aidl_interface-java",
         "netlink-client",
         "networkstack-aidl-interfaces-java",
         "android.hardware.tetheroffload.config-V1.0-java",
diff --git a/packages/Tethering/TEST_MAPPING b/packages/Tethering/TEST_MAPPING
index 73254cd..5617b0c 100644
--- a/packages/Tethering/TEST_MAPPING
+++ b/packages/Tethering/TEST_MAPPING
@@ -1,7 +1,12 @@
 {
-  "postsubmit": [
+  "presubmit": [
     {
       "name": "TetheringTests"
     }
+  ],
+  "postsubmit": [
+    {
+      "name": "TetheringIntegrationTests"
+    }
   ]
 }
diff --git a/packages/Tethering/src/android/net/ip/IpServer.java b/packages/Tethering/src/android/net/ip/IpServer.java
index 3fd9ee9..1671dda 100644
--- a/packages/Tethering/src/android/net/ip/IpServer.java
+++ b/packages/Tethering/src/android/net/ip/IpServer.java
@@ -33,7 +33,6 @@
 import android.net.LinkProperties;
 import android.net.MacAddress;
 import android.net.RouteInfo;
-import android.net.TetherOffloadRuleParcel;
 import android.net.TetheredClient;
 import android.net.TetheringManager;
 import android.net.TetheringRequestParcel;
@@ -65,6 +64,8 @@
 import com.android.internal.util.MessageUtils;
 import com.android.internal.util.State;
 import com.android.internal.util.StateMachine;
+import com.android.networkstack.tethering.BpfCoordinator;
+import com.android.networkstack.tethering.BpfCoordinator.Ipv6ForwardingRule;
 import com.android.networkstack.tethering.PrivateAddressCoordinator;
 
 import java.io.IOException;
@@ -76,7 +77,6 @@
 import java.util.Arrays;
 import java.util.Collections;
 import java.util.HashSet;
-import java.util.LinkedHashMap;
 import java.util.List;
 import java.util.Objects;
 import java.util.Random;
@@ -225,6 +225,8 @@
 
     private final SharedLog mLog;
     private final INetd mNetd;
+    @NonNull
+    private final BpfCoordinator mBpfCoordinator;
     private final Callback mCallback;
     private final InterfaceController mInterfaceCtrl;
     private final PrivateAddressCoordinator mPrivateAddressCoordinator;
@@ -269,43 +271,6 @@
         }
     }
 
-    static class Ipv6ForwardingRule {
-        public final int upstreamIfindex;
-        public final int downstreamIfindex;
-        public final Inet6Address address;
-        public final MacAddress srcMac;
-        public final MacAddress dstMac;
-
-        Ipv6ForwardingRule(int upstreamIfindex, int downstreamIfIndex, Inet6Address address,
-                MacAddress srcMac, MacAddress dstMac) {
-            this.upstreamIfindex = upstreamIfindex;
-            this.downstreamIfindex = downstreamIfIndex;
-            this.address = address;
-            this.srcMac = srcMac;
-            this.dstMac = dstMac;
-        }
-
-        public Ipv6ForwardingRule onNewUpstream(int newUpstreamIfindex) {
-            return new Ipv6ForwardingRule(newUpstreamIfindex, downstreamIfindex, address, srcMac,
-                    dstMac);
-        }
-
-        // Don't manipulate TetherOffloadRuleParcel directly because implementing onNewUpstream()
-        // would be error-prone due to generated stable AIDL classes not having a copy constructor.
-        public TetherOffloadRuleParcel toTetherOffloadRuleParcel() {
-            final TetherOffloadRuleParcel parcel = new TetherOffloadRuleParcel();
-            parcel.inputInterfaceIndex = upstreamIfindex;
-            parcel.outputInterfaceIndex = downstreamIfindex;
-            parcel.destination = address.getAddress();
-            parcel.prefixLength = 128;
-            parcel.srcL2Address = srcMac.toByteArray();
-            parcel.dstL2Address = dstMac.toByteArray();
-            return parcel;
-        }
-    }
-    private final LinkedHashMap<Inet6Address, Ipv6ForwardingRule> mIpv6ForwardingRules =
-            new LinkedHashMap<>();
-
     private final IpNeighborMonitor mIpNeighborMonitor;
 
     private LinkAddress mIpv4Address;
@@ -314,11 +279,13 @@
     // object. It helps to reduce the arguments of the constructor.
     public IpServer(
             String ifaceName, Looper looper, int interfaceType, SharedLog log,
-            INetd netd, Callback callback, boolean usingLegacyDhcp, boolean usingBpfOffload,
+            INetd netd, @NonNull BpfCoordinator coordinator, Callback callback,
+            boolean usingLegacyDhcp, boolean usingBpfOffload,
             PrivateAddressCoordinator addressCoordinator, Dependencies deps) {
         super(ifaceName, looper);
         mLog = log.forSubComponent(ifaceName);
         mNetd = netd;
+        mBpfCoordinator = coordinator;
         mCallback = callback;
         mInterfaceCtrl = new InterfaceController(ifaceName, mNetd, mLog);
         mIfaceName = ifaceName;
@@ -749,6 +716,14 @@
             }
 
             upstreamIfindex = mDeps.getIfindex(upstreamIface);
+
+            // Add upstream index to name mapping for the tether stats usage in the coordinator.
+            // Although this mapping could be added by both class Tethering and IpServer, adding
+            // mapping from IpServer guarantees that the mapping is added before the adding
+            // forwarding rules. That is because there are different state machines in both
+            // classes. It is hard to guarantee the link property update order between multiple
+            // state machines.
+            mBpfCoordinator.addUpstreamNameToLookupTable(upstreamIfindex, upstreamIface);
         }
 
         // If v6only is null, we pass in null to setRaParams(), which handles
@@ -864,43 +839,29 @@
         // TODO: Perhaps remove this protection check.
         if (!mUsingBpfOffload) return;
 
-        try {
-            mNetd.tetherOffloadRuleAdd(rule.toTetherOffloadRuleParcel());
-            mIpv6ForwardingRules.put(rule.address, rule);
-        } catch (RemoteException | ServiceSpecificException e) {
-            mLog.e("Could not add IPv6 downstream rule: ", e);
-        }
+        mBpfCoordinator.tetherOffloadRuleAdd(this, rule);
     }
 
-    private void removeIpv6ForwardingRule(Ipv6ForwardingRule rule, boolean removeFromMap) {
-        // Theoretically, we don't need this check because IP neighbor monitor doesn't start if BPF
-        // offload is disabled. Add this check just in case.
+    private void removeIpv6ForwardingRule(Ipv6ForwardingRule rule) {
         // TODO: Perhaps remove this protection check.
+        // See the related comment in #addIpv6ForwardingRule.
         if (!mUsingBpfOffload) return;
 
-        try {
-            mNetd.tetherOffloadRuleRemove(rule.toTetherOffloadRuleParcel());
-            if (removeFromMap) {
-                mIpv6ForwardingRules.remove(rule.address);
-            }
-        } catch (RemoteException | ServiceSpecificException e) {
-            mLog.e("Could not remove IPv6 downstream rule: ", e);
-        }
+        mBpfCoordinator.tetherOffloadRuleRemove(this, rule);
     }
 
     private void clearIpv6ForwardingRules() {
-        for (Ipv6ForwardingRule rule : mIpv6ForwardingRules.values()) {
-            removeIpv6ForwardingRule(rule, false /*removeFromMap*/);
-        }
-        mIpv6ForwardingRules.clear();
+        if (!mUsingBpfOffload) return;
+
+        mBpfCoordinator.tetherOffloadRuleClear(this);
     }
 
-    // Convenience method to replace a rule with the same rule on a new upstream interface.
-    // Allows replacing the rules in one iteration pass without ConcurrentModificationExceptions.
-    // Relies on the fact that rules are in a map indexed by IP address.
-    private void updateIpv6ForwardingRule(Ipv6ForwardingRule rule, int newIfindex) {
-        addIpv6ForwardingRule(rule.onNewUpstream(newIfindex));
-        removeIpv6ForwardingRule(rule, false /*removeFromMap*/);
+    private void updateIpv6ForwardingRule(int newIfindex) {
+        // TODO: Perhaps remove this protection check.
+        // See the related comment in #addIpv6ForwardingRule.
+        if (!mUsingBpfOffload) return;
+
+        mBpfCoordinator.tetherOffloadRuleUpdate(this, newIfindex);
     }
 
     // Handles all updates to IPv6 forwarding rules. These can currently change only if the upstream
@@ -916,9 +877,7 @@
         // If the upstream interface has changed, remove all rules and re-add them with the new
         // upstream interface.
         if (prevUpstreamIfindex != upstreamIfindex) {
-            for (Ipv6ForwardingRule rule : mIpv6ForwardingRules.values()) {
-                updateIpv6ForwardingRule(rule, upstreamIfindex);
-            }
+            updateIpv6ForwardingRule(upstreamIfindex);
         }
 
         // If we're here to process a NeighborEvent, do so now.
@@ -938,7 +897,7 @@
         if (e.isValid()) {
             addIpv6ForwardingRule(rule);
         } else {
-            removeIpv6ForwardingRule(rule, true /*removeFromMap*/);
+            removeIpv6ForwardingRule(rule);
         }
     }
 
diff --git a/packages/Tethering/src/android/net/util/TetheringUtils.java b/packages/Tethering/src/android/net/util/TetheringUtils.java
index dd67ddd..b17b4ba 100644
--- a/packages/Tethering/src/android/net/util/TetheringUtils.java
+++ b/packages/Tethering/src/android/net/util/TetheringUtils.java
@@ -15,19 +15,94 @@
  */
 package android.net.util;
 
+import android.net.TetherStatsParcel;
 import android.net.TetheringRequestParcel;
 
+import androidx.annotation.NonNull;
+
 import java.io.FileDescriptor;
 import java.net.SocketException;
 import java.util.Objects;
 
 /**
- * Native methods for tethering utilization.
+ * The classes and the methods for tethering utilization.
  *
  * {@hide}
  */
 public class TetheringUtils {
     /**
+     *  The object which records offload Tx/Rx forwarded bytes/packets.
+     *  TODO: Replace the inner class ForwardedStats of class OffloadHardwareInterface with
+     *  this class as well.
+     */
+    public static class ForwardedStats {
+        public final long rxBytes;
+        public final long rxPackets;
+        public final long txBytes;
+        public final long txPackets;
+
+        public ForwardedStats() {
+            rxBytes = 0;
+            rxPackets = 0;
+            txBytes = 0;
+            txPackets = 0;
+        }
+
+        public ForwardedStats(long rxBytes, long txBytes) {
+            this.rxBytes = rxBytes;
+            this.rxPackets = 0;
+            this.txBytes = txBytes;
+            this.txPackets = 0;
+        }
+
+        public ForwardedStats(long rxBytes, long rxPackets, long txBytes, long txPackets) {
+            this.rxBytes = rxBytes;
+            this.rxPackets = rxPackets;
+            this.txBytes = txBytes;
+            this.txPackets = txPackets;
+        }
+
+        public ForwardedStats(@NonNull TetherStatsParcel tetherStats) {
+            rxBytes = tetherStats.rxBytes;
+            rxPackets = tetherStats.rxPackets;
+            txBytes = tetherStats.txBytes;
+            txPackets = tetherStats.txPackets;
+        }
+
+        public ForwardedStats(@NonNull ForwardedStats other) {
+            rxBytes = other.rxBytes;
+            rxPackets = other.rxPackets;
+            txBytes = other.txBytes;
+            txPackets = other.txPackets;
+        }
+
+        /** Add Tx/Rx bytes/packets and return the result as a new object. */
+        @NonNull
+        public ForwardedStats add(@NonNull ForwardedStats other) {
+            return new ForwardedStats(rxBytes + other.rxBytes, rxPackets + other.rxPackets,
+                    txBytes + other.txBytes, txPackets + other.txPackets);
+        }
+
+        /** Subtract Tx/Rx bytes/packets and return the result as a new object. */
+        @NonNull
+        public ForwardedStats subtract(@NonNull ForwardedStats other) {
+            // TODO: Perhaps throw an exception if any negative difference value just in case.
+            final long rxBytesDiff = Math.max(rxBytes - other.rxBytes, 0);
+            final long rxPacketsDiff = Math.max(rxPackets - other.rxPackets, 0);
+            final long txBytesDiff = Math.max(txBytes - other.txBytes, 0);
+            final long txPacketsDiff = Math.max(txPackets - other.txPackets, 0);
+            return new ForwardedStats(rxBytesDiff, rxPacketsDiff, txBytesDiff, txPacketsDiff);
+        }
+
+        /** Returns the string representation of this object. */
+        @NonNull
+        public String toString() {
+            return String.format("ForwardedStats(rxb: %d, rxp: %d, txb: %d, txp: %d)", rxBytes,
+                    rxPackets, txBytes, txPackets);
+        }
+    }
+
+    /**
      * Configures a socket for receiving ICMPv6 router solicitations and sending advertisements.
      * @param fd the socket's {@link FileDescriptor}.
      * @param ifIndex the interface index.
diff --git a/packages/Tethering/src/com/android/networkstack/tethering/BpfCoordinator.java b/packages/Tethering/src/com/android/networkstack/tethering/BpfCoordinator.java
new file mode 100644
index 0000000..fc27b6add
--- /dev/null
+++ b/packages/Tethering/src/com/android/networkstack/tethering/BpfCoordinator.java
@@ -0,0 +1,637 @@
+/*
+ * Copyright (C) 2020 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.networkstack.tethering;
+
+import static android.net.NetworkStats.DEFAULT_NETWORK_NO;
+import static android.net.NetworkStats.METERED_NO;
+import static android.net.NetworkStats.ROAMING_NO;
+import static android.net.NetworkStats.SET_DEFAULT;
+import static android.net.NetworkStats.TAG_NONE;
+import static android.net.NetworkStats.UID_ALL;
+import static android.net.NetworkStats.UID_TETHERING;
+import static android.net.netstats.provider.NetworkStatsProvider.QUOTA_UNLIMITED;
+
+import android.app.usage.NetworkStatsManager;
+import android.net.INetd;
+import android.net.MacAddress;
+import android.net.NetworkStats;
+import android.net.NetworkStats.Entry;
+import android.net.TetherOffloadRuleParcel;
+import android.net.TetherStatsParcel;
+import android.net.ip.IpServer;
+import android.net.netstats.provider.NetworkStatsProvider;
+import android.net.util.SharedLog;
+import android.net.util.TetheringUtils.ForwardedStats;
+import android.os.Handler;
+import android.os.RemoteException;
+import android.os.ServiceSpecificException;
+import android.text.TextUtils;
+import android.util.Log;
+import android.util.SparseArray;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+
+import com.android.internal.annotations.VisibleForTesting;
+
+import java.net.Inet6Address;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.LinkedHashMap;
+import java.util.Objects;
+
+/**
+ *  This coordinator is responsible for providing BPF offload relevant functionality.
+ *  - Get tethering stats.
+ *  - Set data limit.
+ *  - Set global alert.
+ *  - Add/remove forwarding rules.
+ *
+ * @hide
+ */
+public class BpfCoordinator {
+    private static final String TAG = BpfCoordinator.class.getSimpleName();
+    @VisibleForTesting
+    static final int DEFAULT_PERFORM_POLL_INTERVAL_MS = 5000; // TODO: Make it customizable.
+
+    @VisibleForTesting
+    enum StatsType {
+        STATS_PER_IFACE,
+        STATS_PER_UID,
+    }
+
+    @NonNull
+    private final Handler mHandler;
+    @NonNull
+    private final INetd mNetd;
+    @NonNull
+    private final SharedLog mLog;
+    @NonNull
+    private final Dependencies mDeps;
+    @Nullable
+    private final BpfTetherStatsProvider mStatsProvider;
+
+    // Tracks whether BPF tethering is started or not. This is set by tethering before it
+    // starts the first IpServer and is cleared by tethering shortly before the last IpServer
+    // is stopped. Note that rule updates (especially deletions, but sometimes additions as
+    // well) may arrive when this is false. If they do, they must be communicated to netd.
+    // Changes in data limits may also arrive when this is false, and if they do, they must
+    // also be communicated to netd.
+    private boolean mPollingStarted = false;
+
+    // Tracking remaining alert quota. Unlike limit quota is subject to interface, the alert
+    // quota is interface independent and global for tether offload.
+    private long mRemainingAlertQuota = QUOTA_UNLIMITED;
+
+    // Maps upstream interface index to offloaded traffic statistics.
+    // Always contains the latest total bytes/packets, since each upstream was started, received
+    // from the BPF maps for each interface.
+    private final SparseArray<ForwardedStats> mStats = new SparseArray<>();
+
+    // Maps upstream interface names to interface quotas.
+    // Always contains the latest value received from the framework for each interface, regardless
+    // of whether offload is currently running (or is even supported) on that interface. Only
+    // includes interfaces that have a quota set. Note that this map is used for storing the quota
+    // which is set from the service. Because the service uses the interface name to present the
+    // interface, this map uses the interface name to be the mapping index.
+    private final HashMap<String, Long> mInterfaceQuotas = new HashMap<>();
+
+    // Maps upstream interface index to interface names.
+    // Store all interface name since boot. Used for lookup what interface name it is from the
+    // tether stats got from netd because netd reports interface index to present an interface.
+    // TODO: Remove the unused interface name.
+    private final SparseArray<String> mInterfaceNames = new SparseArray<>();
+
+    // Map of downstream rule maps. Each of these maps represents the IPv6 forwarding rules for a
+    // given downstream. Each map:
+    // - Is owned by the IpServer that is responsible for that downstream.
+    // - Must only be modified by that IpServer.
+    // - Is created when the IpServer adds its first rule, and deleted when the IpServer deletes
+    //   its last rule (or clears its rules).
+    // TODO: Perhaps seal the map and rule operations which communicates with netd into a class.
+    // TODO: Does this need to be a LinkedHashMap or can it just be a HashMap? Also, could it be
+    // a ConcurrentHashMap, in order to avoid the copies in tetherOffloadRuleClear
+    // and tetherOffloadRuleUpdate?
+    // TODO: Perhaps use one-dimensional map and access specific downstream rules via downstream
+    // index. For doing that, IpServer must guarantee that it always has a valid IPv6 downstream
+    // interface index while calling function to clear all rules. IpServer may be calling clear
+    // rules function without a valid IPv6 downstream interface index even if it may have one
+    // before. IpServer would need to call getInterfaceParams() in the constructor instead of when
+    // startIpv6() is called, and make mInterfaceParams final.
+    private final HashMap<IpServer, LinkedHashMap<Inet6Address, Ipv6ForwardingRule>>
+            mIpv6ForwardingRules = new LinkedHashMap<>();
+
+    // Runnable that used by scheduling next polling of stats.
+    private final Runnable mScheduledPollingTask = () -> {
+        updateForwardedStatsFromNetd();
+        maybeSchedulePollingStats();
+    };
+
+    @VisibleForTesting
+    public static class Dependencies {
+        int getPerformPollInterval() {
+            // TODO: Consider make this configurable.
+            return DEFAULT_PERFORM_POLL_INTERVAL_MS;
+        }
+    }
+
+    @VisibleForTesting
+    public BpfCoordinator(@NonNull Handler handler, @NonNull INetd netd,
+            @NonNull NetworkStatsManager nsm, @NonNull SharedLog log, @NonNull Dependencies deps) {
+        mHandler = handler;
+        mNetd = netd;
+        mLog = log.forSubComponent(TAG);
+        BpfTetherStatsProvider provider = new BpfTetherStatsProvider();
+        try {
+            nsm.registerNetworkStatsProvider(getClass().getSimpleName(), provider);
+        } catch (RuntimeException e) {
+            // TODO: Perhaps not allow to use BPF offload because the reregistration failure
+            // implied that no data limit could be applies on a metered upstream if any.
+            Log.wtf(TAG, "Cannot register offload stats provider: " + e);
+            provider = null;
+        }
+        mStatsProvider = provider;
+        mDeps = deps;
+    }
+
+    /**
+     * Start BPF tethering offload stats polling when the first upstream is started.
+     * Note that this can be only called on handler thread.
+     * TODO: Perhaps check BPF support before starting.
+     * TODO: Start the stats polling only if there is any client on the downstream.
+     */
+    public void startPolling() {
+        if (mPollingStarted) return;
+
+        mPollingStarted = true;
+        maybeSchedulePollingStats();
+
+        mLog.i("Polling started");
+    }
+
+    /**
+     * Stop BPF tethering offload stats polling.
+     * The data limit cleanup and the tether stats maps cleanup are not implemented here.
+     * These cleanups rely on all IpServers calling #tetherOffloadRuleRemove. After the
+     * last rule is removed from the upstream, #tetherOffloadRuleRemove does the cleanup
+     * functionality.
+     * Note that this can be only called on handler thread.
+     */
+    public void stopPolling() {
+        if (!mPollingStarted) return;
+
+        // Stop scheduled polling tasks and poll the latest stats from BPF maps.
+        if (mHandler.hasCallbacks(mScheduledPollingTask)) {
+            mHandler.removeCallbacks(mScheduledPollingTask);
+        }
+        updateForwardedStatsFromNetd();
+        mPollingStarted = false;
+
+        mLog.i("Polling stopped");
+    }
+
+    /**
+     * Add forwarding rule. After adding the first rule on a given upstream, must add the data
+     * limit on the given upstream.
+     * Note that this can be only called on handler thread.
+     */
+    public void tetherOffloadRuleAdd(
+            @NonNull final IpServer ipServer, @NonNull final Ipv6ForwardingRule rule) {
+        try {
+            // TODO: Perhaps avoid to add a duplicate rule.
+            mNetd.tetherOffloadRuleAdd(rule.toTetherOffloadRuleParcel());
+        } catch (RemoteException | ServiceSpecificException e) {
+            mLog.e("Could not add IPv6 forwarding rule: ", e);
+            return;
+        }
+
+        if (!mIpv6ForwardingRules.containsKey(ipServer)) {
+            mIpv6ForwardingRules.put(ipServer, new LinkedHashMap<Inet6Address,
+                    Ipv6ForwardingRule>());
+        }
+        LinkedHashMap<Inet6Address, Ipv6ForwardingRule> rules = mIpv6ForwardingRules.get(ipServer);
+
+        // Setup the data limit on the given upstream if the first rule is added.
+        final int upstreamIfindex = rule.upstreamIfindex;
+        if (!isAnyRuleOnUpstream(upstreamIfindex)) {
+            // If failed to set a data limit, probably should not use this upstream, because
+            // the upstream may not want to blow through the data limit that was told to apply.
+            // TODO: Perhaps stop the coordinator.
+            boolean success = updateDataLimit(upstreamIfindex);
+            if (!success) {
+                final String iface = mInterfaceNames.get(upstreamIfindex);
+                mLog.e("Setting data limit for " + iface + " failed.");
+            }
+        }
+
+        // Must update the adding rule after calling #isAnyRuleOnUpstream because it needs to
+        // check if it is about adding a first rule for a given upstream.
+        rules.put(rule.address, rule);
+    }
+
+    /**
+     * Remove forwarding rule. After removing the last rule on a given upstream, must clear
+     * data limit, update the last tether stats and remove the tether stats in the BPF maps.
+     * Note that this can be only called on handler thread.
+     */
+    public void tetherOffloadRuleRemove(
+            @NonNull final IpServer ipServer, @NonNull final Ipv6ForwardingRule rule) {
+        try {
+            // TODO: Perhaps avoid to remove a non-existent rule.
+            mNetd.tetherOffloadRuleRemove(rule.toTetherOffloadRuleParcel());
+        } catch (RemoteException | ServiceSpecificException e) {
+            mLog.e("Could not remove IPv6 forwarding rule: ", e);
+            return;
+        }
+
+        LinkedHashMap<Inet6Address, Ipv6ForwardingRule> rules = mIpv6ForwardingRules.get(ipServer);
+        if (rules == null) return;
+
+        // Must remove rules before calling #isAnyRuleOnUpstream because it needs to check if
+        // the last rule is removed for a given upstream. If no rule is removed, return early.
+        // Avoid unnecessary work on a non-existent rule which may have never been added or
+        // removed already.
+        if (rules.remove(rule.address) == null) return;
+
+        // Remove the downstream entry if it has no more rule.
+        if (rules.isEmpty()) {
+            mIpv6ForwardingRules.remove(ipServer);
+        }
+
+        // Do cleanup functionality if there is no more rule on the given upstream.
+        final int upstreamIfindex = rule.upstreamIfindex;
+        if (!isAnyRuleOnUpstream(upstreamIfindex)) {
+            try {
+                final TetherStatsParcel stats =
+                        mNetd.tetherOffloadGetAndClearStats(upstreamIfindex);
+                // Update the last stats delta and delete the local cache for a given upstream.
+                updateQuotaAndStatsFromSnapshot(new TetherStatsParcel[] {stats});
+                mStats.remove(upstreamIfindex);
+            } catch (RemoteException | ServiceSpecificException e) {
+                Log.wtf(TAG, "Exception when cleanup tether stats for upstream index "
+                        + upstreamIfindex + ": ", e);
+            }
+        }
+    }
+
+    /**
+     * Clear all forwarding rules for a given downstream.
+     * Note that this can be only called on handler thread.
+     */
+    public void tetherOffloadRuleClear(@NonNull final IpServer ipServer) {
+        final LinkedHashMap<Inet6Address, Ipv6ForwardingRule> rules = mIpv6ForwardingRules.get(
+                ipServer);
+        if (rules == null) return;
+
+        // Need to build a rule list because the rule map may be changed in the iteration.
+        for (final Ipv6ForwardingRule rule : new ArrayList<Ipv6ForwardingRule>(rules.values())) {
+            tetherOffloadRuleRemove(ipServer, rule);
+        }
+    }
+
+    /**
+     * Update existing forwarding rules to new upstream for a given downstream.
+     * Note that this can be only called on handler thread.
+     */
+    public void tetherOffloadRuleUpdate(@NonNull final IpServer ipServer, int newUpstreamIfindex) {
+        final LinkedHashMap<Inet6Address, Ipv6ForwardingRule> rules = mIpv6ForwardingRules.get(
+                ipServer);
+        if (rules == null) return;
+
+        // Need to build a rule list because the rule map may be changed in the iteration.
+        for (final Ipv6ForwardingRule rule : new ArrayList<Ipv6ForwardingRule>(rules.values())) {
+            // Remove the old rule before adding the new one because the map uses the same key for
+            // both rules. Reversing the processing order causes that the new rule is removed as
+            // unexpected.
+            // TODO: Add new rule first to reduce the latency which has no rule.
+            tetherOffloadRuleRemove(ipServer, rule);
+            tetherOffloadRuleAdd(ipServer, rule.onNewUpstream(newUpstreamIfindex));
+        }
+    }
+
+    /**
+     * Add upstream name to lookup table. The lookup table is used for tether stats interface name
+     * lookup because the netd only reports interface index in BPF tether stats but the service
+     * expects the interface name in NetworkStats object.
+     * Note that this can be only called on handler thread.
+     */
+    public void addUpstreamNameToLookupTable(int upstreamIfindex, @NonNull String upstreamIface) {
+        if (upstreamIfindex == 0 || TextUtils.isEmpty(upstreamIface)) return;
+
+        // The same interface index to name mapping may be added by different IpServer objects or
+        // re-added by reconnection on the same upstream interface. Ignore the duplicate one.
+        final String iface = mInterfaceNames.get(upstreamIfindex);
+        if (iface == null) {
+            mInterfaceNames.put(upstreamIfindex, upstreamIface);
+        } else if (!TextUtils.equals(iface, upstreamIface)) {
+            Log.wtf(TAG, "The upstream interface name " + upstreamIface
+                    + " is different from the existing interface name "
+                    + iface + " for index " + upstreamIfindex);
+        }
+    }
+
+    /** IPv6 forwarding rule class. */
+    public static class Ipv6ForwardingRule {
+        public final int upstreamIfindex;
+        public final int downstreamIfindex;
+
+        @NonNull
+        public final Inet6Address address;
+        @NonNull
+        public final MacAddress srcMac;
+        @NonNull
+        public final MacAddress dstMac;
+
+        public Ipv6ForwardingRule(int upstreamIfindex, int downstreamIfIndex,
+                @NonNull Inet6Address address, @NonNull MacAddress srcMac,
+                @NonNull MacAddress dstMac) {
+            this.upstreamIfindex = upstreamIfindex;
+            this.downstreamIfindex = downstreamIfIndex;
+            this.address = address;
+            this.srcMac = srcMac;
+            this.dstMac = dstMac;
+        }
+
+        /** Return a new rule object which updates with new upstream index. */
+        @NonNull
+        public Ipv6ForwardingRule onNewUpstream(int newUpstreamIfindex) {
+            return new Ipv6ForwardingRule(newUpstreamIfindex, downstreamIfindex, address, srcMac,
+                    dstMac);
+        }
+
+        /**
+         * Don't manipulate TetherOffloadRuleParcel directly because implementing onNewUpstream()
+         * would be error-prone due to generated stable AIDL classes not having a copy constructor.
+         */
+        @NonNull
+        public TetherOffloadRuleParcel toTetherOffloadRuleParcel() {
+            final TetherOffloadRuleParcel parcel = new TetherOffloadRuleParcel();
+            parcel.inputInterfaceIndex = upstreamIfindex;
+            parcel.outputInterfaceIndex = downstreamIfindex;
+            parcel.destination = address.getAddress();
+            parcel.prefixLength = 128;
+            parcel.srcL2Address = srcMac.toByteArray();
+            parcel.dstL2Address = dstMac.toByteArray();
+            return parcel;
+        }
+
+        @Override
+        public boolean equals(Object o) {
+            if (!(o instanceof Ipv6ForwardingRule)) return false;
+            Ipv6ForwardingRule that = (Ipv6ForwardingRule) o;
+            return this.upstreamIfindex == that.upstreamIfindex
+                    && this.downstreamIfindex == that.downstreamIfindex
+                    && Objects.equals(this.address, that.address)
+                    && Objects.equals(this.srcMac, that.srcMac)
+                    && Objects.equals(this.dstMac, that.dstMac);
+        }
+
+        @Override
+        public int hashCode() {
+            // TODO: if this is ever used in production code, don't pass ifindices
+            // to Objects.hash() to avoid autoboxing overhead.
+            return Objects.hash(upstreamIfindex, downstreamIfindex, address, srcMac, dstMac);
+        }
+    }
+
+    /**
+     * A BPF tethering stats provider to provide network statistics to the system.
+     * Note that this class' data may only be accessed on the handler thread.
+     */
+    @VisibleForTesting
+    class BpfTetherStatsProvider extends NetworkStatsProvider {
+        // The offloaded traffic statistics per interface that has not been reported since the
+        // last call to pushTetherStats. Only the interfaces that were ever tethering upstreams
+        // and has pending tether stats delta are included in this NetworkStats object.
+        private NetworkStats mIfaceStats = new NetworkStats(0L, 0);
+
+        // The same stats as above, but counts network stats per uid.
+        private NetworkStats mUidStats = new NetworkStats(0L, 0);
+
+        @Override
+        public void onRequestStatsUpdate(int token) {
+            mHandler.post(() -> pushTetherStats());
+        }
+
+        @Override
+        public void onSetAlert(long quotaBytes) {
+            mHandler.post(() -> updateAlertQuota(quotaBytes));
+        }
+
+        @Override
+        public void onSetLimit(@NonNull String iface, long quotaBytes) {
+            if (quotaBytes < QUOTA_UNLIMITED) {
+                throw new IllegalArgumentException("invalid quota value " + quotaBytes);
+            }
+
+            mHandler.post(() -> {
+                final Long curIfaceQuota = mInterfaceQuotas.get(iface);
+
+                if (null == curIfaceQuota && QUOTA_UNLIMITED == quotaBytes) return;
+
+                if (quotaBytes == QUOTA_UNLIMITED) {
+                    mInterfaceQuotas.remove(iface);
+                } else {
+                    mInterfaceQuotas.put(iface, quotaBytes);
+                }
+                maybeUpdateDataLimit(iface);
+            });
+        }
+
+        @VisibleForTesting
+        void pushTetherStats() {
+            try {
+                // The token is not used for now. See b/153606961.
+                notifyStatsUpdated(0 /* token */, mIfaceStats, mUidStats);
+
+                // Clear the accumulated tether stats delta after reported. Note that create a new
+                // empty object because NetworkStats#clear is @hide.
+                mIfaceStats = new NetworkStats(0L, 0);
+                mUidStats = new NetworkStats(0L, 0);
+            } catch (RuntimeException e) {
+                mLog.e("Cannot report network stats: ", e);
+            }
+        }
+
+        private void accumulateDiff(@NonNull NetworkStats ifaceDiff,
+                @NonNull NetworkStats uidDiff) {
+            mIfaceStats = mIfaceStats.add(ifaceDiff);
+            mUidStats = mUidStats.add(uidDiff);
+        }
+    }
+
+    private int getInterfaceIndexFromRules(@NonNull String ifName) {
+        for (LinkedHashMap<Inet6Address, Ipv6ForwardingRule> rules : mIpv6ForwardingRules
+                .values()) {
+            for (Ipv6ForwardingRule rule : rules.values()) {
+                final int upstreamIfindex = rule.upstreamIfindex;
+                if (TextUtils.equals(ifName, mInterfaceNames.get(upstreamIfindex))) {
+                    return upstreamIfindex;
+                }
+            }
+        }
+        return 0;
+    }
+
+    private long getQuotaBytes(@NonNull String iface) {
+        final Long limit = mInterfaceQuotas.get(iface);
+        final long quotaBytes = (limit != null) ? limit : QUOTA_UNLIMITED;
+
+        return quotaBytes;
+    }
+
+    private boolean sendDataLimitToNetd(int ifIndex, long quotaBytes) {
+        if (ifIndex == 0) {
+            Log.wtf(TAG, "Invalid interface index.");
+            return false;
+        }
+
+        try {
+            mNetd.tetherOffloadSetInterfaceQuota(ifIndex, quotaBytes);
+        } catch (RemoteException | ServiceSpecificException e) {
+            mLog.e("Exception when updating quota " + quotaBytes + ": ", e);
+            return false;
+        }
+
+        return true;
+    }
+
+    // Handle the data limit update from the service which is the stats provider registered for.
+    private void maybeUpdateDataLimit(@NonNull String iface) {
+        // Set data limit only on a given upstream which has at least one rule. If we can't get
+        // an interface index for a given interface name, it means either there is no rule for
+        // a given upstream or the interface name is not an upstream which is monitored by the
+        // coordinator.
+        final int ifIndex = getInterfaceIndexFromRules(iface);
+        if (ifIndex == 0) return;
+
+        final long quotaBytes = getQuotaBytes(iface);
+        sendDataLimitToNetd(ifIndex, quotaBytes);
+    }
+
+    // Handle the data limit update while adding forwarding rules.
+    private boolean updateDataLimit(int ifIndex) {
+        final String iface = mInterfaceNames.get(ifIndex);
+        if (iface == null) {
+            mLog.e("Fail to get the interface name for index " + ifIndex);
+            return false;
+        }
+        final long quotaBytes = getQuotaBytes(iface);
+        return sendDataLimitToNetd(ifIndex, quotaBytes);
+    }
+
+    private boolean isAnyRuleOnUpstream(int upstreamIfindex) {
+        for (LinkedHashMap<Inet6Address, Ipv6ForwardingRule> rules : mIpv6ForwardingRules
+                .values()) {
+            for (Ipv6ForwardingRule rule : rules.values()) {
+                if (upstreamIfindex == rule.upstreamIfindex) return true;
+            }
+        }
+        return false;
+    }
+
+    @NonNull
+    private NetworkStats buildNetworkStats(@NonNull StatsType type, int ifIndex,
+            @NonNull final ForwardedStats diff) {
+        NetworkStats stats = new NetworkStats(0L, 0);
+        final String iface = mInterfaceNames.get(ifIndex);
+        if (iface == null) {
+            // TODO: Use Log.wtf once the coordinator owns full control of tether stats from netd.
+            // For now, netd may add the empty stats for the upstream which is not monitored by
+            // the coordinator. Silently ignore it.
+            return stats;
+        }
+        final int uid = (type == StatsType.STATS_PER_UID) ? UID_TETHERING : UID_ALL;
+        // Note that the argument 'metered', 'roaming' and 'defaultNetwork' are not recorded for
+        // network stats snapshot. See NetworkStatsRecorder#recordSnapshotLocked.
+        return stats.addEntry(new Entry(iface, uid, SET_DEFAULT, TAG_NONE, METERED_NO,
+                ROAMING_NO, DEFAULT_NETWORK_NO, diff.rxBytes, diff.rxPackets,
+                diff.txBytes, diff.txPackets, 0L /* operations */));
+    }
+
+    private void updateAlertQuota(long newQuota) {
+        if (newQuota < QUOTA_UNLIMITED) {
+            throw new IllegalArgumentException("invalid quota value " + newQuota);
+        }
+        if (mRemainingAlertQuota == newQuota) return;
+
+        mRemainingAlertQuota = newQuota;
+        if (mRemainingAlertQuota == 0) {
+            mLog.i("onAlertReached");
+            if (mStatsProvider != null) mStatsProvider.notifyAlertReached();
+        }
+    }
+
+    private void updateQuotaAndStatsFromSnapshot(
+            @NonNull final TetherStatsParcel[] tetherStatsList) {
+        long usedAlertQuota = 0;
+        for (TetherStatsParcel tetherStats : tetherStatsList) {
+            final Integer ifIndex = tetherStats.ifIndex;
+            final ForwardedStats curr = new ForwardedStats(tetherStats);
+            final ForwardedStats base = mStats.get(ifIndex);
+            final ForwardedStats diff = (base != null) ? curr.subtract(base) : curr;
+            usedAlertQuota += diff.rxBytes + diff.txBytes;
+
+            // Update the local cache for counting tether stats delta.
+            mStats.put(ifIndex, curr);
+
+            // Update the accumulated tether stats delta to the stats provider for the service
+            // querying.
+            if (mStatsProvider != null) {
+                try {
+                    mStatsProvider.accumulateDiff(
+                            buildNetworkStats(StatsType.STATS_PER_IFACE, ifIndex, diff),
+                            buildNetworkStats(StatsType.STATS_PER_UID, ifIndex, diff));
+                } catch (ArrayIndexOutOfBoundsException e) {
+                    Log.wtf(TAG, "Fail to update the accumulated stats delta for interface index "
+                            + ifIndex + " : ", e);
+                }
+            }
+        }
+
+        if (mRemainingAlertQuota > 0 && usedAlertQuota > 0) {
+            // Trim to zero if overshoot.
+            final long newQuota = Math.max(mRemainingAlertQuota - usedAlertQuota, 0);
+            updateAlertQuota(newQuota);
+        }
+
+        // TODO: Count the used limit quota for notifying data limit reached.
+    }
+
+    private void updateForwardedStatsFromNetd() {
+        final TetherStatsParcel[] tetherStatsList;
+        try {
+            // The reported tether stats are total data usage for all currently-active upstream
+            // interfaces since tethering start.
+            tetherStatsList = mNetd.tetherOffloadGetStats();
+        } catch (RemoteException | ServiceSpecificException e) {
+            mLog.e("Problem fetching tethering stats: ", e);
+            return;
+        }
+        updateQuotaAndStatsFromSnapshot(tetherStatsList);
+    }
+
+    private void maybeSchedulePollingStats() {
+        if (!mPollingStarted) return;
+
+        if (mHandler.hasCallbacks(mScheduledPollingTask)) {
+            mHandler.removeCallbacks(mScheduledPollingTask);
+        }
+
+        mHandler.postDelayed(mScheduledPollingTask, mDeps.getPerformPollInterval());
+    }
+}
diff --git a/packages/Tethering/src/com/android/networkstack/tethering/Tethering.java b/packages/Tethering/src/com/android/networkstack/tethering/Tethering.java
index 69eec8d..df67458 100644
--- a/packages/Tethering/src/com/android/networkstack/tethering/Tethering.java
+++ b/packages/Tethering/src/com/android/networkstack/tethering/Tethering.java
@@ -232,6 +232,7 @@
     private final TetheringThreadExecutor mExecutor;
     private final TetheringNotificationUpdater mNotificationUpdater;
     private final UserManager mUserManager;
+    private final BpfCoordinator mBpfCoordinator;
     private final PrivateAddressCoordinator mPrivateAddressCoordinator;
     private int mActiveDataSubId = INVALID_SUBSCRIPTION_ID;
     // All the usage of mTetheringEventCallback should run in the same thread.
@@ -284,6 +285,8 @@
         mUpstreamNetworkMonitor = mDeps.getUpstreamNetworkMonitor(mContext, mTetherMasterSM, mLog,
                 TetherMasterSM.EVENT_UPSTREAM_CALLBACK);
         mForwardedDownstreams = new LinkedHashSet<>();
+        mBpfCoordinator = mDeps.getBpfCoordinator(
+                mHandler, mNetd, mLog, new BpfCoordinator.Dependencies());
 
         IntentFilter filter = new IntentFilter();
         filter.addAction(ACTION_CARRIER_CONFIG_CHANGED);
@@ -1704,6 +1707,9 @@
                     chooseUpstreamType(true);
                     mTryCell = false;
                 }
+
+                // TODO: Check the upstream interface if it is managed by BPF offload.
+                mBpfCoordinator.startPolling();
             }
 
             @Override
@@ -1716,6 +1722,7 @@
                     mTetherUpstream = null;
                     reportUpstreamChanged(null);
                 }
+                mBpfCoordinator.stopPolling();
             }
 
             private boolean updateUpstreamWanted() {
@@ -2341,7 +2348,7 @@
 
         mLog.log("adding TetheringInterfaceStateMachine for: " + iface);
         final TetherState tetherState = new TetherState(
-                new IpServer(iface, mLooper, interfaceType, mLog, mNetd,
+                new IpServer(iface, mLooper, interfaceType, mLog, mNetd, mBpfCoordinator,
                              makeControlCallback(), mConfig.enableLegacyDhcpServer,
                              mConfig.enableBpfOffload, mPrivateAddressCoordinator,
                              mDeps.getIpServerDependencies()));
diff --git a/packages/Tethering/src/com/android/networkstack/tethering/TetheringDependencies.java b/packages/Tethering/src/com/android/networkstack/tethering/TetheringDependencies.java
index ce546c7..d637c86 100644
--- a/packages/Tethering/src/com/android/networkstack/tethering/TetheringDependencies.java
+++ b/packages/Tethering/src/com/android/networkstack/tethering/TetheringDependencies.java
@@ -41,6 +41,17 @@
  */
 public abstract class TetheringDependencies {
     /**
+     * Get a reference to the BpfCoordinator to be used by tethering.
+     */
+    public @NonNull BpfCoordinator getBpfCoordinator(
+            @NonNull Handler handler, @NonNull INetd netd, @NonNull SharedLog log,
+            @NonNull BpfCoordinator.Dependencies deps) {
+        final NetworkStatsManager statsManager =
+                (NetworkStatsManager) getContext().getSystemService(Context.NETWORK_STATS_SERVICE);
+        return new BpfCoordinator(handler, netd, statsManager, log, deps);
+    }
+
+    /**
      * Get a reference to the offload hardware interface to be used by tethering.
      */
     public OffloadHardwareInterface getOffloadHardwareInterface(Handler h, SharedLog log) {
diff --git a/packages/Tethering/src/com/android/networkstack/tethering/TetheringNotificationUpdater.java b/packages/Tethering/src/com/android/networkstack/tethering/TetheringNotificationUpdater.java
index d03deda..593d04a 100644
--- a/packages/Tethering/src/com/android/networkstack/tethering/TetheringNotificationUpdater.java
+++ b/packages/Tethering/src/com/android/networkstack/tethering/TetheringNotificationUpdater.java
@@ -24,8 +24,10 @@
 import android.app.NotificationChannel;
 import android.app.NotificationManager;
 import android.app.PendingIntent;
+import android.content.ComponentName;
 import android.content.Context;
 import android.content.Intent;
+import android.content.pm.PackageManager;
 import android.content.res.Configuration;
 import android.content.res.Resources;
 import android.net.NetworkCapabilities;
@@ -253,6 +255,14 @@
     }
 
     @VisibleForTesting
+    static String getSettingsPackageName(@NonNull final PackageManager pm) {
+        final Intent settingsIntent = new Intent(Settings.ACTION_SETTINGS);
+        final ComponentName settingsComponent = settingsIntent.resolveActivity(pm);
+        return settingsComponent != null
+                ? settingsComponent.getPackageName() : "com.android.settings";
+    }
+
+    @VisibleForTesting
     void notifyTetheringDisabledByRestriction() {
         final Resources res = getResourcesForSubId(mContext, mActiveDataSubId);
         final String title = res.getString(R.string.disable_tether_notification_title);
@@ -262,8 +272,9 @@
         final PendingIntent pi = PendingIntent.getActivity(
                 mContext.createContextAsUser(UserHandle.CURRENT, 0 /* flags */),
                 0 /* requestCode */,
-                new Intent(Settings.ACTION_TETHER_SETTINGS),
-                Intent.FLAG_ACTIVITY_NEW_TASK,
+                new Intent(Settings.ACTION_TETHER_SETTINGS)
+                        .setPackage(getSettingsPackageName(mContext.getPackageManager())),
+                Intent.FLAG_ACTIVITY_NEW_TASK | PendingIntent.FLAG_IMMUTABLE,
                 null /* options */);
 
         showNotification(R.drawable.stat_sys_tether_general, title, message,
@@ -284,7 +295,7 @@
                 mContext.createContextAsUser(UserHandle.CURRENT, 0 /* flags */),
                 0 /* requestCode */,
                 intent,
-                0 /* flags */);
+                PendingIntent.FLAG_IMMUTABLE);
         final Action action = new Action.Builder(NO_ICON_ID, disableButton, pi).build();
 
         showNotification(R.drawable.stat_sys_tether_general, title, message,
@@ -305,8 +316,9 @@
         final PendingIntent pi = PendingIntent.getActivity(
                 mContext.createContextAsUser(UserHandle.CURRENT, 0 /* flags */),
                 0 /* requestCode */,
-                new Intent(Settings.ACTION_TETHER_SETTINGS),
-                Intent.FLAG_ACTIVITY_NEW_TASK,
+                new Intent(Settings.ACTION_TETHER_SETTINGS)
+                        .setPackage(getSettingsPackageName(mContext.getPackageManager())),
+                Intent.FLAG_ACTIVITY_NEW_TASK | PendingIntent.FLAG_IMMUTABLE,
                 null /* options */);
 
         showNotification(R.drawable.stat_sys_tether_general, title, message,
diff --git a/packages/Tethering/tests/unit/src/android/net/ip/IpServerTest.java b/packages/Tethering/tests/unit/src/android/net/ip/IpServerTest.java
index 0cda29a..c3bc915 100644
--- a/packages/Tethering/tests/unit/src/android/net/ip/IpServerTest.java
+++ b/packages/Tethering/tests/unit/src/android/net/ip/IpServerTest.java
@@ -54,12 +54,14 @@
 import static org.mockito.Mockito.inOrder;
 import static org.mockito.Mockito.never;
 import static org.mockito.Mockito.reset;
+import static org.mockito.Mockito.spy;
 import static org.mockito.Mockito.timeout;
 import static org.mockito.Mockito.times;
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.verifyNoMoreInteractions;
 import static org.mockito.Mockito.when;
 
+import android.app.usage.NetworkStatsManager;
 import android.net.INetd;
 import android.net.InetAddresses;
 import android.net.InterfaceConfigurationParcel;
@@ -69,6 +71,7 @@
 import android.net.MacAddress;
 import android.net.RouteInfo;
 import android.net.TetherOffloadRuleParcel;
+import android.net.TetherStatsParcel;
 import android.net.dhcp.DhcpServingParamsParcel;
 import android.net.dhcp.IDhcpEventCallbacks;
 import android.net.dhcp.IDhcpServer;
@@ -80,13 +83,17 @@
 import android.net.util.InterfaceSet;
 import android.net.util.PrefixUtils;
 import android.net.util.SharedLog;
+import android.os.Handler;
 import android.os.RemoteException;
 import android.os.test.TestLooper;
 import android.text.TextUtils;
 
+import androidx.annotation.NonNull;
 import androidx.test.filters.SmallTest;
 import androidx.test.runner.AndroidJUnit4;
 
+import com.android.networkstack.tethering.BpfCoordinator;
+import com.android.networkstack.tethering.BpfCoordinator.Ipv6ForwardingRule;
 import com.android.networkstack.tethering.PrivateAddressCoordinator;
 
 import org.junit.Before;
@@ -100,6 +107,7 @@
 import org.mockito.MockitoAnnotations;
 
 import java.net.Inet4Address;
+import java.net.Inet6Address;
 import java.net.InetAddress;
 import java.util.Arrays;
 import java.util.List;
@@ -133,6 +141,7 @@
     @Mock private IpNeighborMonitor mIpNeighborMonitor;
     @Mock private IpServer.Dependencies mDependencies;
     @Mock private PrivateAddressCoordinator mAddressCoordinator;
+    @Mock private NetworkStatsManager mStatsManager;
 
     @Captor private ArgumentCaptor<DhcpServingParamsParcel> mDhcpParamsCaptor;
 
@@ -142,6 +151,7 @@
     private IpServer mIpServer;
     private InterfaceConfigurationParcel mInterfaceConfiguration;
     private NeighborEventConsumer mNeighborEventConsumer;
+    private BpfCoordinator mBpfCoordinator;
 
     private void initStateMachine(int interfaceType) throws Exception {
         initStateMachine(interfaceType, false /* usingLegacyDhcp */, DEFAULT_USING_BPF_OFFLOAD);
@@ -179,7 +189,7 @@
                 neighborCaptor.capture());
 
         mIpServer = new IpServer(
-                IFACE_NAME, mLooper.getLooper(), interfaceType, mSharedLog, mNetd,
+                IFACE_NAME, mLooper.getLooper(), interfaceType, mSharedLog, mNetd, mBpfCoordinator,
                 mCallback, usingLegacyDhcp, usingBpfOffload, mAddressCoordinator, mDependencies);
         mIpServer.start();
         mNeighborEventConsumer = neighborCaptor.getValue();
@@ -215,6 +225,10 @@
         MockitoAnnotations.initMocks(this);
         when(mSharedLog.forSubComponent(anyString())).thenReturn(mSharedLog);
         when(mAddressCoordinator.requestDownstreamAddress(any())).thenReturn(mTestAddress);
+
+        BpfCoordinator bc = new BpfCoordinator(new Handler(mLooper.getLooper()), mNetd,
+                mStatsManager, mSharedLog, new BpfCoordinator.Dependencies());
+        mBpfCoordinator = spy(bc);
     }
 
     @Test
@@ -222,8 +236,8 @@
         when(mDependencies.getIpNeighborMonitor(any(), any(), any()))
                 .thenReturn(mIpNeighborMonitor);
         mIpServer = new IpServer(IFACE_NAME, mLooper.getLooper(), TETHERING_BLUETOOTH, mSharedLog,
-                mNetd, mCallback, false /* usingLegacyDhcp */, DEFAULT_USING_BPF_OFFLOAD,
-                mAddressCoordinator, mDependencies);
+                mNetd, mBpfCoordinator, mCallback, false /* usingLegacyDhcp */,
+                DEFAULT_USING_BPF_OFFLOAD, mAddressCoordinator, mDependencies);
         mIpServer.start();
         mLooper.dispatchAll();
         verify(mCallback).updateInterfaceState(
@@ -619,6 +633,10 @@
      * (actual: "android.net.TetherOffloadRuleParcel@8c827b0" or some such), but at least it does
      * work.
      *
+     * TODO: consider making the error message more readable by adding a method that catching the
+     * AssertionFailedError and throwing a new assertion with more details. See
+     * NetworkMonitorTest#verifyNetworkTested.
+     *
      * See ConnectivityServiceTest#assertRoutesAdded for an alternative approach which solves the
      * TooManyActualInvocations problem described above by forcing the caller of the custom assert
      * method to specify all expected invocations in one call. This is useful when the stable
@@ -658,6 +676,27 @@
         return argThat(new TetherOffloadRuleParcelMatcher(upstreamIfindex, dst, dstMac));
     }
 
+    private static Ipv6ForwardingRule makeForwardingRule(
+            int upstreamIfindex, @NonNull InetAddress dst, @NonNull MacAddress dstMac) {
+        return new Ipv6ForwardingRule(upstreamIfindex, TEST_IFACE_PARAMS.index,
+                (Inet6Address) dst, TEST_IFACE_PARAMS.macAddr, dstMac);
+    }
+
+    private TetherStatsParcel buildEmptyTetherStatsParcel(int ifIndex) {
+        TetherStatsParcel parcel = new TetherStatsParcel();
+        parcel.ifIndex = ifIndex;
+        return parcel;
+    }
+
+    private void resetNetdAndBpfCoordinator() throws Exception {
+        reset(mNetd, mBpfCoordinator);
+        when(mNetd.tetherOffloadGetStats()).thenReturn(new TetherStatsParcel[0]);
+        when(mNetd.tetherOffloadGetAndClearStats(UPSTREAM_IFINDEX))
+                .thenReturn(buildEmptyTetherStatsParcel(UPSTREAM_IFINDEX));
+        when(mNetd.tetherOffloadGetAndClearStats(UPSTREAM_IFINDEX2))
+                .thenReturn(buildEmptyTetherStatsParcel(UPSTREAM_IFINDEX2));
+    }
+
     @Test
     public void addRemoveipv6ForwardingRules() throws Exception {
         initTetheredStateMachine(TETHERING_WIFI, UPSTREAM_IFACE, false /* usingLegacyDhcp */,
@@ -675,75 +714,100 @@
         final MacAddress macA = MacAddress.fromString("00:00:00:00:00:0a");
         final MacAddress macB = MacAddress.fromString("11:22:33:00:00:0b");
 
-        reset(mNetd);
+        resetNetdAndBpfCoordinator();
+        verifyNoMoreInteractions(mBpfCoordinator, mNetd);
+
+        // TODO: Perhaps verify the interaction of tetherOffloadSetInterfaceQuota and
+        // tetherOffloadGetAndClearStats in netd while the rules are changed.
 
         // Events on other interfaces are ignored.
         recvNewNeigh(notMyIfindex, neighA, NUD_REACHABLE, macA);
-        verifyNoMoreInteractions(mNetd);
+        verifyNoMoreInteractions(mBpfCoordinator, mNetd);
 
         // Events on this interface are received and sent to netd.
         recvNewNeigh(myIfindex, neighA, NUD_REACHABLE, macA);
+        verify(mBpfCoordinator).tetherOffloadRuleAdd(
+                mIpServer, makeForwardingRule(UPSTREAM_IFINDEX, neighA, macA));
         verify(mNetd).tetherOffloadRuleAdd(matches(UPSTREAM_IFINDEX, neighA, macA));
-        reset(mNetd);
+        resetNetdAndBpfCoordinator();
 
         recvNewNeigh(myIfindex, neighB, NUD_REACHABLE, macB);
+        verify(mBpfCoordinator).tetherOffloadRuleAdd(
+                mIpServer, makeForwardingRule(UPSTREAM_IFINDEX, neighB, macB));
         verify(mNetd).tetherOffloadRuleAdd(matches(UPSTREAM_IFINDEX, neighB, macB));
-        reset(mNetd);
+        resetNetdAndBpfCoordinator();
 
         // Link-local and multicast neighbors are ignored.
         recvNewNeigh(myIfindex, neighLL, NUD_REACHABLE, macA);
-        verifyNoMoreInteractions(mNetd);
+        verifyNoMoreInteractions(mBpfCoordinator, mNetd);
         recvNewNeigh(myIfindex, neighMC, NUD_REACHABLE, macA);
-        verifyNoMoreInteractions(mNetd);
+        verifyNoMoreInteractions(mBpfCoordinator, mNetd);
 
         // A neighbor that is no longer valid causes the rule to be removed.
         // NUD_FAILED events do not have a MAC address.
         recvNewNeigh(myIfindex, neighA, NUD_FAILED, null);
+        verify(mBpfCoordinator).tetherOffloadRuleRemove(
+                mIpServer, makeForwardingRule(UPSTREAM_IFINDEX, neighA, macNull));
         verify(mNetd).tetherOffloadRuleRemove(matches(UPSTREAM_IFINDEX, neighA, macNull));
-        reset(mNetd);
+        resetNetdAndBpfCoordinator();
 
         // A neighbor that is deleted causes the rule to be removed.
         recvDelNeigh(myIfindex, neighB, NUD_STALE, macB);
+        verify(mBpfCoordinator).tetherOffloadRuleRemove(
+                mIpServer,  makeForwardingRule(UPSTREAM_IFINDEX, neighB, macNull));
         verify(mNetd).tetherOffloadRuleRemove(matches(UPSTREAM_IFINDEX, neighB, macNull));
-        reset(mNetd);
+        resetNetdAndBpfCoordinator();
 
-        // Upstream changes result in deleting and re-adding the rules.
+        // Upstream changes result in updating the rules.
         recvNewNeigh(myIfindex, neighA, NUD_REACHABLE, macA);
         recvNewNeigh(myIfindex, neighB, NUD_REACHABLE, macB);
-        reset(mNetd);
+        resetNetdAndBpfCoordinator();
 
         InOrder inOrder = inOrder(mNetd);
         LinkProperties lp = new LinkProperties();
         lp.setInterfaceName(UPSTREAM_IFACE2);
         dispatchTetherConnectionChanged(UPSTREAM_IFACE2, lp, -1);
-        inOrder.verify(mNetd).tetherOffloadRuleAdd(matches(UPSTREAM_IFINDEX2, neighA, macA));
+        verify(mBpfCoordinator).tetherOffloadRuleUpdate(mIpServer, UPSTREAM_IFINDEX2);
         inOrder.verify(mNetd).tetherOffloadRuleRemove(matches(UPSTREAM_IFINDEX, neighA, macA));
-        inOrder.verify(mNetd).tetherOffloadRuleAdd(matches(UPSTREAM_IFINDEX2, neighB, macB));
+        inOrder.verify(mNetd).tetherOffloadRuleAdd(matches(UPSTREAM_IFINDEX2, neighA, macA));
         inOrder.verify(mNetd).tetherOffloadRuleRemove(matches(UPSTREAM_IFINDEX, neighB, macB));
-        reset(mNetd);
+        inOrder.verify(mNetd).tetherOffloadRuleAdd(matches(UPSTREAM_IFINDEX2, neighB, macB));
+        resetNetdAndBpfCoordinator();
 
         // When the upstream is lost, rules are removed.
         dispatchTetherConnectionChanged(null, null, 0);
+        // Clear function is called two times by:
+        // - processMessage CMD_TETHER_CONNECTION_CHANGED for the upstream is lost.
+        // - processMessage CMD_IPV6_TETHER_UPDATE for the IPv6 upstream is lost.
+        // See dispatchTetherConnectionChanged.
+        verify(mBpfCoordinator, times(2)).tetherOffloadRuleClear(mIpServer);
         verify(mNetd).tetherOffloadRuleRemove(matches(UPSTREAM_IFINDEX2, neighA, macA));
         verify(mNetd).tetherOffloadRuleRemove(matches(UPSTREAM_IFINDEX2, neighB, macB));
-        reset(mNetd);
+        resetNetdAndBpfCoordinator();
 
         // If the upstream is IPv4-only, no rules are added.
         dispatchTetherConnectionChanged(UPSTREAM_IFACE);
-        reset(mNetd);
+        resetNetdAndBpfCoordinator();
         recvNewNeigh(myIfindex, neighA, NUD_REACHABLE, macA);
-        verifyNoMoreInteractions(mNetd);
+        // Clear function is called by #updateIpv6ForwardingRules for the IPv6 upstream is lost.
+        verify(mBpfCoordinator).tetherOffloadRuleClear(mIpServer);
+        verifyNoMoreInteractions(mBpfCoordinator, mNetd);
 
         // Rules can be added again once upstream IPv6 connectivity is available.
         lp.setInterfaceName(UPSTREAM_IFACE);
         dispatchTetherConnectionChanged(UPSTREAM_IFACE, lp, -1);
         recvNewNeigh(myIfindex, neighB, NUD_REACHABLE, macB);
+        verify(mBpfCoordinator).tetherOffloadRuleAdd(
+                mIpServer, makeForwardingRule(UPSTREAM_IFINDEX, neighB, macB));
         verify(mNetd).tetherOffloadRuleAdd(matches(UPSTREAM_IFINDEX, neighB, macB));
+        verify(mBpfCoordinator, never()).tetherOffloadRuleAdd(
+                mIpServer, makeForwardingRule(UPSTREAM_IFINDEX, neighA, macA));
         verify(mNetd, never()).tetherOffloadRuleAdd(matches(UPSTREAM_IFINDEX, neighA, macA));
 
         // If upstream IPv6 connectivity is lost, rules are removed.
-        reset(mNetd);
+        resetNetdAndBpfCoordinator();
         dispatchTetherConnectionChanged(UPSTREAM_IFACE, null, 0);
+        verify(mBpfCoordinator).tetherOffloadRuleClear(mIpServer);
         verify(mNetd).tetherOffloadRuleRemove(matches(UPSTREAM_IFINDEX, neighB, macB));
 
         // When the interface goes down, rules are removed.
@@ -751,15 +815,20 @@
         dispatchTetherConnectionChanged(UPSTREAM_IFACE, lp, -1);
         recvNewNeigh(myIfindex, neighA, NUD_REACHABLE, macA);
         recvNewNeigh(myIfindex, neighB, NUD_REACHABLE, macB);
+        verify(mBpfCoordinator).tetherOffloadRuleAdd(
+                mIpServer, makeForwardingRule(UPSTREAM_IFINDEX, neighA, macA));
         verify(mNetd).tetherOffloadRuleAdd(matches(UPSTREAM_IFINDEX, neighA, macA));
+        verify(mBpfCoordinator).tetherOffloadRuleAdd(
+                mIpServer, makeForwardingRule(UPSTREAM_IFINDEX, neighB, macB));
         verify(mNetd).tetherOffloadRuleAdd(matches(UPSTREAM_IFINDEX, neighB, macB));
-        reset(mNetd);
+        resetNetdAndBpfCoordinator();
 
         mIpServer.stop();
         mLooper.dispatchAll();
+        verify(mBpfCoordinator).tetherOffloadRuleClear(mIpServer);
         verify(mNetd).tetherOffloadRuleRemove(matches(UPSTREAM_IFINDEX, neighA, macA));
         verify(mNetd).tetherOffloadRuleRemove(matches(UPSTREAM_IFINDEX, neighB, macB));
-        reset(mNetd);
+        resetNetdAndBpfCoordinator();
     }
 
     @Test
@@ -769,35 +838,46 @@
         final MacAddress macA = MacAddress.fromString("00:00:00:00:00:0a");
         final MacAddress macNull = MacAddress.fromString("00:00:00:00:00:00");
 
-        reset(mNetd);
-
         // Expect that rules can be only added/removed when the BPF offload config is enabled.
-        // Note that the usingBpfOffload false case is not a realistic test case. Because IP
+        // Note that the BPF offload disabled case is not a realistic test case. Because IP
         // neighbor monitor doesn't start if BPF offload is disabled, there should have no
         // neighbor event listening. This is used for testing the protection check just in case.
-        // TODO: Perhaps remove this test once we don't need this check anymore.
-        for (boolean usingBpfOffload : new boolean[]{true, false}) {
-            initTetheredStateMachine(TETHERING_WIFI, UPSTREAM_IFACE, false /* usingLegacyDhcp */,
-                    usingBpfOffload);
+        // TODO: Perhaps remove the BPF offload disabled case test once this check isn't needed
+        // anymore.
 
-            // A neighbor is added.
-            recvNewNeigh(myIfindex, neigh, NUD_REACHABLE, macA);
-            if (usingBpfOffload) {
-                verify(mNetd).tetherOffloadRuleAdd(matches(UPSTREAM_IFINDEX, neigh, macA));
-            } else {
-                verify(mNetd, never()).tetherOffloadRuleAdd(any());
-            }
-            reset(mNetd);
+        // [1] Enable BPF offload.
+        // A neighbor that is added or deleted causes the rule to be added or removed.
+        initTetheredStateMachine(TETHERING_WIFI, UPSTREAM_IFACE, false /* usingLegacyDhcp */,
+                true /* usingBpfOffload */);
+        resetNetdAndBpfCoordinator();
 
-            // A neighbor is deleted.
-            recvDelNeigh(myIfindex, neigh, NUD_STALE, macA);
-            if (usingBpfOffload) {
-                verify(mNetd).tetherOffloadRuleRemove(matches(UPSTREAM_IFINDEX, neigh, macNull));
-            } else {
-                verify(mNetd, never()).tetherOffloadRuleRemove(any());
-            }
-            reset(mNetd);
-        }
+        recvNewNeigh(myIfindex, neigh, NUD_REACHABLE, macA);
+        verify(mBpfCoordinator).tetherOffloadRuleAdd(
+                mIpServer, makeForwardingRule(UPSTREAM_IFINDEX, neigh, macA));
+        verify(mNetd).tetherOffloadRuleAdd(matches(UPSTREAM_IFINDEX, neigh, macA));
+        resetNetdAndBpfCoordinator();
+
+        recvDelNeigh(myIfindex, neigh, NUD_STALE, macA);
+        verify(mBpfCoordinator).tetherOffloadRuleRemove(
+                mIpServer, makeForwardingRule(UPSTREAM_IFINDEX, neigh, macNull));
+        verify(mNetd).tetherOffloadRuleRemove(matches(UPSTREAM_IFINDEX, neigh, macNull));
+        resetNetdAndBpfCoordinator();
+
+        // [2] Disable BPF offload.
+        // A neighbor that is added or deleted doesn’t cause the rule to be added or removed.
+        initTetheredStateMachine(TETHERING_WIFI, UPSTREAM_IFACE, false /* usingLegacyDhcp */,
+                false /* usingBpfOffload */);
+        resetNetdAndBpfCoordinator();
+
+        recvNewNeigh(myIfindex, neigh, NUD_REACHABLE, macA);
+        verify(mBpfCoordinator, never()).tetherOffloadRuleAdd(any(), any());
+        verify(mNetd, never()).tetherOffloadRuleAdd(any());
+        resetNetdAndBpfCoordinator();
+
+        recvDelNeigh(myIfindex, neigh, NUD_STALE, macA);
+        verify(mBpfCoordinator, never()).tetherOffloadRuleRemove(any(), any());
+        verify(mNetd, never()).tetherOffloadRuleRemove(any());
+        resetNetdAndBpfCoordinator();
     }
 
     @Test
diff --git a/packages/Tethering/tests/unit/src/com/android/networkstack/tethering/BpfCoordinatorTest.java b/packages/Tethering/tests/unit/src/com/android/networkstack/tethering/BpfCoordinatorTest.java
new file mode 100644
index 0000000..e2d7aab
--- /dev/null
+++ b/packages/Tethering/tests/unit/src/com/android/networkstack/tethering/BpfCoordinatorTest.java
@@ -0,0 +1,246 @@
+/*
+ * Copyright (C) 2020 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.networkstack.tethering;
+
+import static android.net.NetworkStats.DEFAULT_NETWORK_NO;
+import static android.net.NetworkStats.METERED_NO;
+import static android.net.NetworkStats.ROAMING_NO;
+import static android.net.NetworkStats.SET_DEFAULT;
+import static android.net.NetworkStats.TAG_NONE;
+import static android.net.NetworkStats.UID_ALL;
+import static android.net.NetworkStats.UID_TETHERING;
+import static android.net.netstats.provider.NetworkStatsProvider.QUOTA_UNLIMITED;
+
+import static com.android.networkstack.tethering.BpfCoordinator
+        .DEFAULT_PERFORM_POLL_INTERVAL_MS;
+import static com.android.networkstack.tethering.BpfCoordinator.StatsType;
+import static com.android.networkstack.tethering.BpfCoordinator.StatsType.STATS_PER_IFACE;
+import static com.android.networkstack.tethering.BpfCoordinator.StatsType.STATS_PER_UID;
+
+import static junit.framework.Assert.assertNotNull;
+
+import static org.mockito.Matchers.anyString;
+import static org.mockito.Mockito.clearInvocations;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import android.annotation.NonNull;
+import android.app.usage.NetworkStatsManager;
+import android.net.INetd;
+import android.net.NetworkStats;
+import android.net.TetherStatsParcel;
+import android.net.util.SharedLog;
+import android.os.Handler;
+import android.os.test.TestLooper;
+
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
+
+import com.android.testutils.TestableNetworkStatsProviderCbBinder;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.ArgumentCaptor;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+import java.util.ArrayList;
+
+@RunWith(AndroidJUnit4.class)
+@SmallTest
+public class BpfCoordinatorTest {
+    @Mock private NetworkStatsManager mStatsManager;
+    @Mock private INetd mNetd;
+    // Late init since methods must be called by the thread that created this object.
+    private TestableNetworkStatsProviderCbBinder mTetherStatsProviderCb;
+    private BpfCoordinator.BpfTetherStatsProvider mTetherStatsProvider;
+    private final ArgumentCaptor<ArrayList> mStringArrayCaptor =
+            ArgumentCaptor.forClass(ArrayList.class);
+    private final TestLooper mTestLooper = new TestLooper();
+    private BpfCoordinator.Dependencies mDeps =
+            new BpfCoordinator.Dependencies() {
+            @Override
+            int getPerformPollInterval() {
+                return DEFAULT_PERFORM_POLL_INTERVAL_MS;
+            }
+    };
+
+    @Before public void setUp() {
+        MockitoAnnotations.initMocks(this);
+    }
+
+    private void waitForIdle() {
+        mTestLooper.dispatchAll();
+    }
+
+    private void setupFunctioningNetdInterface() throws Exception {
+        when(mNetd.tetherOffloadGetStats()).thenReturn(new TetherStatsParcel[0]);
+    }
+
+    @NonNull
+    private BpfCoordinator makeBpfCoordinator() throws Exception {
+        BpfCoordinator coordinator = new BpfCoordinator(
+                new Handler(mTestLooper.getLooper()), mNetd, mStatsManager, new SharedLog("test"),
+                mDeps);
+        final ArgumentCaptor<BpfCoordinator.BpfTetherStatsProvider>
+                tetherStatsProviderCaptor =
+                ArgumentCaptor.forClass(BpfCoordinator.BpfTetherStatsProvider.class);
+        verify(mStatsManager).registerNetworkStatsProvider(anyString(),
+                tetherStatsProviderCaptor.capture());
+        mTetherStatsProvider = tetherStatsProviderCaptor.getValue();
+        assertNotNull(mTetherStatsProvider);
+        mTetherStatsProviderCb = new TestableNetworkStatsProviderCbBinder();
+        mTetherStatsProvider.setProviderCallbackBinder(mTetherStatsProviderCb);
+        return coordinator;
+    }
+
+    @NonNull
+    private static NetworkStats.Entry buildTestEntry(@NonNull StatsType how,
+            @NonNull String iface, long rxBytes, long rxPackets, long txBytes, long txPackets) {
+        return new NetworkStats.Entry(iface, how == STATS_PER_IFACE ? UID_ALL : UID_TETHERING,
+                SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO, DEFAULT_NETWORK_NO, rxBytes,
+                rxPackets, txBytes, txPackets, 0L);
+    }
+
+    @NonNull
+    private static TetherStatsParcel buildTestTetherStatsParcel(@NonNull Integer ifIndex,
+            long rxBytes, long rxPackets, long txBytes, long txPackets) {
+        final TetherStatsParcel parcel = new TetherStatsParcel();
+        parcel.ifIndex = ifIndex;
+        parcel.rxBytes = rxBytes;
+        parcel.rxPackets = rxPackets;
+        parcel.txBytes = txBytes;
+        parcel.txPackets = txPackets;
+        return parcel;
+    }
+
+    private void setTetherOffloadStatsList(TetherStatsParcel[] tetherStatsList) throws Exception {
+        when(mNetd.tetherOffloadGetStats()).thenReturn(tetherStatsList);
+        mTestLooper.moveTimeForward(DEFAULT_PERFORM_POLL_INTERVAL_MS);
+        waitForIdle();
+    }
+
+    @Test
+    public void testGetForwardedStats() throws Exception {
+        setupFunctioningNetdInterface();
+
+        final BpfCoordinator coordinator = makeBpfCoordinator();
+        coordinator.startPolling();
+
+        final String wlanIface = "wlan0";
+        final Integer wlanIfIndex = 100;
+        final String mobileIface = "rmnet_data0";
+        final Integer mobileIfIndex = 101;
+
+        // Add interface name to lookup table. In realistic case, the upstream interface name will
+        // be added by IpServer when IpServer has received with a new IPv6 upstream update event.
+        coordinator.addUpstreamNameToLookupTable(wlanIfIndex, wlanIface);
+        coordinator.addUpstreamNameToLookupTable(mobileIfIndex, mobileIface);
+
+        // [1] Both interface stats are changed.
+        // Setup the tether stats of wlan and mobile interface. Note that move forward the time of
+        // the looper to make sure the new tether stats has been updated by polling update thread.
+        setTetherOffloadStatsList(new TetherStatsParcel[] {
+                buildTestTetherStatsParcel(wlanIfIndex, 1000, 100, 2000, 200),
+                buildTestTetherStatsParcel(mobileIfIndex, 3000, 300, 4000, 400)});
+
+        final NetworkStats expectedIfaceStats = new NetworkStats(0L, 2)
+                .addEntry(buildTestEntry(STATS_PER_IFACE, wlanIface, 1000, 100, 2000, 200))
+                .addEntry(buildTestEntry(STATS_PER_IFACE, mobileIface, 3000, 300, 4000, 400));
+
+        final NetworkStats expectedUidStats = new NetworkStats(0L, 2)
+                .addEntry(buildTestEntry(STATS_PER_UID, wlanIface, 1000, 100, 2000, 200))
+                .addEntry(buildTestEntry(STATS_PER_UID, mobileIface, 3000, 300, 4000, 400));
+
+        // Force pushing stats update to verify the stats reported.
+        // TODO: Perhaps make #expectNotifyStatsUpdated to use test TetherStatsParcel object for
+        // verifying the notification.
+        mTetherStatsProvider.pushTetherStats();
+        mTetherStatsProviderCb.expectNotifyStatsUpdated(expectedIfaceStats, expectedUidStats);
+
+        // [2] Only one interface stats is changed.
+        // The tether stats of mobile interface is accumulated and The tether stats of wlan
+        // interface is the same.
+        setTetherOffloadStatsList(new TetherStatsParcel[] {
+                buildTestTetherStatsParcel(wlanIfIndex, 1000, 100, 2000, 200),
+                buildTestTetherStatsParcel(mobileIfIndex, 3010, 320, 4030, 440)});
+
+        final NetworkStats expectedIfaceStatsDiff = new NetworkStats(0L, 2)
+                .addEntry(buildTestEntry(STATS_PER_IFACE, wlanIface, 0, 0, 0, 0))
+                .addEntry(buildTestEntry(STATS_PER_IFACE, mobileIface, 10, 20, 30, 40));
+
+        final NetworkStats expectedUidStatsDiff = new NetworkStats(0L, 2)
+                .addEntry(buildTestEntry(STATS_PER_UID, wlanIface, 0, 0, 0, 0))
+                .addEntry(buildTestEntry(STATS_PER_UID, mobileIface, 10, 20, 30, 40));
+
+        // Force pushing stats update to verify that only diff of stats is reported.
+        mTetherStatsProvider.pushTetherStats();
+        mTetherStatsProviderCb.expectNotifyStatsUpdated(expectedIfaceStatsDiff,
+                expectedUidStatsDiff);
+
+        // [3] Stop coordinator.
+        // Shutdown the coordinator and clear the invocation history, especially the
+        // tetherOffloadGetStats() calls.
+        coordinator.stopPolling();
+        clearInvocations(mNetd);
+
+        // Verify the polling update thread stopped.
+        mTestLooper.moveTimeForward(DEFAULT_PERFORM_POLL_INTERVAL_MS);
+        waitForIdle();
+        verify(mNetd, never()).tetherOffloadGetStats();
+    }
+
+    @Test
+    public void testOnSetAlert() throws Exception {
+        setupFunctioningNetdInterface();
+
+        final BpfCoordinator coordinator = makeBpfCoordinator();
+        coordinator.startPolling();
+
+        final String mobileIface = "rmnet_data0";
+        final Integer mobileIfIndex = 100;
+        coordinator.addUpstreamNameToLookupTable(mobileIfIndex, mobileIface);
+
+        // Verify that set quota to 0 will immediately triggers a callback.
+        mTetherStatsProvider.onSetAlert(0);
+        waitForIdle();
+        mTetherStatsProviderCb.expectNotifyAlertReached();
+
+        // Verify that notifyAlertReached never fired if quota is not yet reached.
+        when(mNetd.tetherOffloadGetStats()).thenReturn(
+                new TetherStatsParcel[] {buildTestTetherStatsParcel(mobileIfIndex, 0, 0, 0, 0)});
+        mTetherStatsProvider.onSetAlert(100);
+        mTestLooper.moveTimeForward(DEFAULT_PERFORM_POLL_INTERVAL_MS);
+        waitForIdle();
+        mTetherStatsProviderCb.assertNoCallback();
+
+        // Verify that notifyAlertReached fired when quota is reached.
+        when(mNetd.tetherOffloadGetStats()).thenReturn(
+                new TetherStatsParcel[] {buildTestTetherStatsParcel(mobileIfIndex, 50, 0, 50, 0)});
+        mTestLooper.moveTimeForward(DEFAULT_PERFORM_POLL_INTERVAL_MS);
+        waitForIdle();
+        mTetherStatsProviderCb.expectNotifyAlertReached();
+
+        // Verify that set quota with UNLIMITED won't trigger any callback.
+        mTetherStatsProvider.onSetAlert(QUOTA_UNLIMITED);
+        mTestLooper.moveTimeForward(DEFAULT_PERFORM_POLL_INTERVAL_MS);
+        waitForIdle();
+        mTetherStatsProviderCb.assertNoCallback();
+    }
+}
diff --git a/packages/Tethering/tests/unit/src/com/android/networkstack/tethering/TetheringNotificationUpdaterTest.kt b/packages/Tethering/tests/unit/src/com/android/networkstack/tethering/TetheringNotificationUpdaterTest.kt
index 7d5471f..4b6bbac0 100644
--- a/packages/Tethering/tests/unit/src/com/android/networkstack/tethering/TetheringNotificationUpdaterTest.kt
+++ b/packages/Tethering/tests/unit/src/com/android/networkstack/tethering/TetheringNotificationUpdaterTest.kt
@@ -19,6 +19,10 @@
 import android.app.Notification
 import android.app.NotificationManager
 import android.content.Context
+import android.content.pm.ActivityInfo
+import android.content.pm.ApplicationInfo
+import android.content.pm.PackageManager
+import android.content.pm.ResolveInfo
 import android.content.res.Resources
 import android.net.ConnectivityManager.TETHERING_WIFI
 import android.os.Handler
@@ -51,6 +55,7 @@
 import org.mockito.ArgumentMatchers.eq
 import org.mockito.Mock
 import org.mockito.Mockito.doReturn
+import org.mockito.Mockito.mock
 import org.mockito.Mockito.never
 import org.mockito.Mockito.reset
 import org.mockito.Mockito.times
@@ -351,4 +356,26 @@
         notificationUpdater.onUpstreamCapabilitiesChanged(ROAMING_CAPABILITIES)
         verifyNotificationCancelled(listOf(NO_UPSTREAM_NOTIFICATION_ID, ROAMING_NOTIFICATION_ID))
     }
+
+    @Test
+    fun testGetSettingsPackageName() {
+        val defaultSettingsPackageName = "com.android.settings"
+        val testSettingsPackageName = "com.android.test.settings"
+        val pm = mock(PackageManager::class.java)
+        doReturn(null).`when`(pm).resolveActivity(any(), anyInt())
+        assertEquals(defaultSettingsPackageName,
+                TetheringNotificationUpdater.getSettingsPackageName(pm))
+
+        val resolveInfo = ResolveInfo().apply {
+            activityInfo = ActivityInfo().apply {
+                name = "test"
+                applicationInfo = ApplicationInfo().apply {
+                    packageName = testSettingsPackageName
+                }
+            }
+        }
+        doReturn(resolveInfo).`when`(pm).resolveActivity(any(), anyInt())
+        assertEquals(testSettingsPackageName,
+                TetheringNotificationUpdater.getSettingsPackageName(pm))
+    }
 }
diff --git a/packages/Tethering/tests/unit/src/com/android/networkstack/tethering/TetheringTest.java b/packages/Tethering/tests/unit/src/com/android/networkstack/tethering/TetheringTest.java
index bb65b18..8146a58d 100644
--- a/packages/Tethering/tests/unit/src/com/android/networkstack/tethering/TetheringTest.java
+++ b/packages/Tethering/tests/unit/src/com/android/networkstack/tethering/TetheringTest.java
@@ -203,6 +203,7 @@
     @Mock private ConnectivityManager mCm;
     @Mock private EthernetManager mEm;
     @Mock private TetheringNotificationUpdater mNotificationUpdater;
+    @Mock private BpfCoordinator mBpfCoordinator;
 
     private final MockIpServerDependencies mIpServerDependencies =
             spy(new MockIpServerDependencies());
@@ -337,6 +338,12 @@
         }
 
         @Override
+        public BpfCoordinator getBpfCoordinator(Handler handler, INetd netd,
+                SharedLog log, BpfCoordinator.Dependencies deps) {
+            return mBpfCoordinator;
+        }
+
+        @Override
         public OffloadHardwareInterface getOffloadHardwareInterface(Handler h, SharedLog log) {
             return mOffloadHardwareInterface;
         }
diff --git a/packages/overlays/IconPackCircularLauncherOverlay/res/drawable/ic_select.xml b/packages/overlays/IconPackCircularLauncherOverlay/res/drawable/ic_select.xml
index 4e265fd..0f37561 100644
--- a/packages/overlays/IconPackCircularLauncherOverlay/res/drawable/ic_select.xml
+++ b/packages/overlays/IconPackCircularLauncherOverlay/res/drawable/ic_select.xml
@@ -18,15 +18,6 @@
     android:viewportWidth="24"
     android:viewportHeight="24">
   <path
-      android:fillColor="#FF000000"
-      android:pathData="M11.25,1h1.5v3h-1.5z"/>
-  <path
-      android:fillColor="#FF000000"
-      android:pathData="M15.5983,5.3402l2.1213,-2.1213l1.0606,1.0606l-2.1213,2.1213z"/>
-  <path
-      android:fillColor="#FF000000"
-      android:pathData="M5.2187,4.2803l1.0606,-1.0606l2.1213,2.1213l-1.0606,1.0606z"/>
-  <path
-      android:fillColor="#FF000000"
-      android:pathData="M15.5,12.5l-1.25,0V8.12C14.25,6.95 13.3,6 12.12,6S10,6.95 10,8.12v7.9L8.03,15.5c-0.39,-0.1 -1.23,-0.36 -2.56,0.97c-0.29,0.29 -0.29,0.75 -0.01,1.05l3.79,3.98c0,0 0,0 0,0.01c1.37,1.41 3.28,1.51 4.04,1.49l2.2,0c2.12,0.06 5.25,-1.01 5.25,-5.25C20.75,13.19 17.23,12.46 15.5,12.5zM15.5,21.5l-2.25,0c-0.44,0.01 -1.93,-0.02 -2.92,-1.03l-3.27,-3.43c0.17,-0.1 0.38,-0.13 0.58,-0.08l2.91,0.78c0.47,0.12 0.94,-0.23 0.94,-0.72V8.12c0,-0.34 0.28,-0.62 0.62,-0.62s0.62,0.28 0.62,0.62v5.12c0,0.41 0.33,0.75 0.75,0.75l2.05,0c1.26,-0.03 3.7,0.37 3.7,3.75C19.25,21.14 16.78,21.53 15.5,21.5z"/>
+      android:fillColor="@android:color/white"
+      android:pathData="M18.04,13.71c-0.71,-0.77 -1.71,-1.21 -2.76,-1.21h-1.15V8.12C14.13,6.95 13.18,6 12,6S9.88,6.95 9.88,8.12v7.9l-1.44,-0.38c-1.1,-0.29 -2.28,0.02 -3.09,0.83l-0.52,0.52L10.56,23h7.92l0.54,-6.44C19.1,15.52 18.75,14.48 18.04,13.71zM17.1,21.5h-5.9l-4.16,-4.37c0.32,-0.11 0.68,-0.13 1.01,-0.04l3.33,0.89V8.12c0,-0.34 0.28,-0.62 0.62,-0.62s0.62,0.28 0.62,0.62V14h2.65c0.64,0 1.22,0.26 1.66,0.73c0.43,0.47 0.64,1.08 0.59,1.71L17.1,21.5zM2.81,8.25h0.38c0.31,0 0.56,0.26 0.56,0.56v0.38c0,0.31 -0.26,0.56 -0.56,0.56H2.81c-0.31,0 -0.56,-0.26 -0.56,-0.56V8.81C2.25,8.51 2.51,8.25 2.81,8.25zM5.81,8.25h0.38c0.31,0 0.56,0.26 0.56,0.56v0.38c0,0.31 -0.26,0.56 -0.56,0.56H5.81c-0.31,0 -0.56,-0.26 -0.56,-0.56V8.81C5.25,8.51 5.51,8.25 5.81,8.25zM17.81,8.25h0.38c0.31,0 0.56,0.26 0.56,0.56v0.38c0,0.31 -0.26,0.56 -0.56,0.56h-0.38c-0.31,0 -0.56,-0.26 -0.56,-0.56V8.81C17.25,8.51 17.5,8.25 17.81,8.25zM20.81,8.25h0.38c0.31,0 0.56,0.26 0.56,0.56v0.38c0,0.31 -0.26,0.56 -0.56,0.56h-0.38c-0.31,0 -0.56,-0.26 -0.56,-0.56V8.81C20.25,8.51 20.5,8.25 20.81,8.25zM2.81,5.25h0.38c0.31,0 0.56,0.26 0.56,0.56v0.38c0,0.31 -0.26,0.56 -0.56,0.56H2.81c-0.31,0 -0.56,-0.26 -0.56,-0.56V5.81C2.25,5.5 2.51,5.25 2.81,5.25zM20.81,5.25h0.38c0.31,0 0.56,0.26 0.56,0.56v0.38c0,0.31 -0.26,0.56 -0.56,0.56h-0.38c-0.31,0 -0.56,-0.26 -0.56,-0.56V5.81C20.25,5.5 20.5,5.25 20.81,5.25zM2.81,2.25h0.38c0.31,0 0.56,0.26 0.56,0.56v0.38c0,0.31 -0.26,0.56 -0.56,0.56H2.81c-0.31,0 -0.56,-0.26 -0.56,-0.56V2.81C2.25,2.51 2.51,2.25 2.81,2.25zM5.81,2.25h0.38c0.31,0 0.56,0.26 0.56,0.56v0.38c0,0.31 -0.26,0.56 -0.56,0.56H5.81c-0.31,0 -0.56,-0.26 -0.56,-0.56V2.81C5.25,2.51 5.51,2.25 5.81,2.25zM8.81,2.25h0.38c0.31,0 0.56,0.26 0.56,0.56v0.38c0,0.31 -0.26,0.56 -0.56,0.56H8.81c-0.31,0 -0.56,-0.26 -0.56,-0.56V2.81C8.25,2.51 8.51,2.25 8.81,2.25zM11.81,2.25h0.38c0.31,0 0.56,0.26 0.56,0.56v0.38c0,0.31 -0.26,0.56 -0.56,0.56h-0.38c-0.31,0 -0.56,-0.26 -0.56,-0.56V2.81C11.25,2.51 11.51,2.25 11.81,2.25zM14.81,2.25h0.38c0.31,0 0.56,0.26 0.56,0.56v0.38c0,0.31 -0.26,0.56 -0.56,0.56h-0.38c-0.31,0 -0.56,-0.26 -0.56,-0.56V2.81C14.25,2.51 14.51,2.25 14.81,2.25zM17.81,2.25h0.38c0.31,0 0.56,0.26 0.56,0.56v0.38c0,0.31 -0.26,0.56 -0.56,0.56h-0.38c-0.31,0 -0.56,-0.26 -0.56,-0.56V2.81C17.25,2.51 17.5,2.25 17.81,2.25zM17.81,2.25h0.38c0.31,0 0.56,0.26 0.56,0.56v0.38c0,0.31 -0.26,0.56 -0.56,0.56h-0.38c-0.31,0 -0.56,-0.26 -0.56,-0.56V2.81C17.25,2.51 17.5,2.25 17.81,2.25zM20.81,2.25h0.38c0.31,0 0.56,0.26 0.56,0.56v0.38c0,0.31 -0.26,0.56 -0.56,0.56h-0.38c-0.31,0 -0.56,-0.26 -0.56,-0.56V2.81C20.25,2.51 20.5,2.25 20.81,2.25z"/>
 </vector>
diff --git a/packages/overlays/IconPackFilledLauncherOverlay/res/drawable/ic_select.xml b/packages/overlays/IconPackFilledLauncherOverlay/res/drawable/ic_select.xml
index df4525d..51d4a11 100644
--- a/packages/overlays/IconPackFilledLauncherOverlay/res/drawable/ic_select.xml
+++ b/packages/overlays/IconPackFilledLauncherOverlay/res/drawable/ic_select.xml
@@ -18,15 +18,6 @@
     android:viewportWidth="24"
     android:viewportHeight="24">
   <path
-      android:fillColor="#FF000000"
-      android:pathData="M17.59,5.83l0.71,-0.71c0.39,-0.39 0.39,-1.02 0,-1.41l0,0c-0.39,-0.39 -1.02,-0.39 -1.41,0l-0.71,0.71c-0.39,0.39 -0.39,1.02 0,1.41C16.56,6.21 17.2,6.21 17.59,5.83z"/>
-  <path
-      android:fillColor="#FF000000"
-      android:pathData="M12,4c0.55,0 1,-0.45 1,-1V2c0,-0.55 -0.45,-1 -1,-1s-1,0.45 -1,1v1C11,3.55 11.45,4 12,4z"/>
-  <path
-      android:fillColor="#FF000000"
-      android:pathData="M6.42,5.83c0.39,0.39 1.02,0.39 1.41,0c0.39,-0.39 0.39,-1.02 0,-1.41L7.12,3.71c-0.39,-0.39 -1.02,-0.39 -1.41,0l0,0c-0.39,0.39 -0.39,1.02 0,1.41L6.42,5.83z"/>
-  <path
-      android:fillColor="#FF000000"
-      android:pathData="M17.95,14.43l-3.23,-1.61c-0.42,-0.21 -0.88,-0.32 -1.34,-0.32H13v-5C13,6.67 12.33,6 11.5,6C10.67,6 10,6.67 10,7.5v9.12c0,0.32 -0.29,0.55 -0.6,0.49l-2.84,-0.6c-0.37,-0.08 -0.76,0.04 -1.03,0.31c-0.43,0.44 -0.43,1.14 0.01,1.58l3.71,3.71C9.81,22.68 10.58,23 11.37,23h4.82c1.49,0 2.76,-1.1 2.97,-2.58l0.41,-2.89C19.76,16.26 19.1,15.01 17.95,14.43z"/>
+      android:fillColor="@android:color/white"
+      android:pathData="M19.09,14.75L15,12.71c-0.28,-0.14 -0.58,-0.21 -0.89,-0.21H13.5v-5C13.5,6.67 12.83,6 12,6s-1.5,0.67 -1.5,1.5v9.74L7,16.5c-0.33,-0.07 -0.68,0.03 -0.92,0.28l-0.13,0.13c-0.39,0.39 -0.38,1.02 0,1.41l4.09,4.09c0.38,0.38 0.89,0.59 1.42,0.59h6.1c1,0 1.84,-0.73 1.98,-1.72l0.63,-4.46C20.3,15.97 19.86,15.14 19.09,14.75zM2.62,9.75h0.75c0.21,0 0.38,-0.17 0.38,-0.38V8.62c0,-0.21 -0.17,-0.38 -0.38,-0.38H2.62c-0.21,0 -0.38,0.16 -0.38,0.38v0.75C2.25,9.58 2.42,9.75 2.62,9.75zM5.62,9.75h0.75c0.21,0 0.38,-0.17 0.38,-0.38V8.62c0,-0.21 -0.17,-0.38 -0.38,-0.38H5.62c-0.21,0 -0.38,0.16 -0.38,0.38v0.75C5.25,9.58 5.41,9.75 5.62,9.75zM17.62,9.75h0.75c0.21,0 0.38,-0.17 0.38,-0.38V8.62c0,-0.21 -0.17,-0.38 -0.38,-0.38h-0.75c-0.21,0 -0.38,0.16 -0.38,0.38v0.75C17.25,9.58 17.42,9.75 17.62,9.75zM20.62,9.75h0.75c0.21,0 0.38,-0.17 0.38,-0.38V8.62c0,-0.21 -0.17,-0.38 -0.38,-0.38h-0.75c-0.21,0 -0.38,0.16 -0.38,0.38v0.75C20.25,9.58 20.42,9.75 20.62,9.75zM2.62,6.75h0.75c0.21,0 0.38,-0.16 0.38,-0.38V5.62c0,-0.21 -0.17,-0.38 -0.38,-0.38H2.62c-0.21,0 -0.38,0.17 -0.38,0.38v0.75C2.25,6.58 2.42,6.75 2.62,6.75zM20.62,6.75h0.75c0.21,0 0.38,-0.16 0.38,-0.38V5.62c0,-0.21 -0.17,-0.38 -0.38,-0.38h-0.75c-0.21,0 -0.38,0.17 -0.38,0.38v0.75C20.25,6.58 20.42,6.75 20.62,6.75zM2.62,3.75h0.75c0.21,0 0.38,-0.17 0.38,-0.38V2.62c0,-0.21 -0.17,-0.38 -0.38,-0.38H2.62c-0.21,0 -0.38,0.17 -0.38,0.38v0.75C2.25,3.58 2.42,3.75 2.62,3.75zM5.62,3.75h0.75c0.21,0 0.38,-0.17 0.38,-0.38V2.62c0,-0.21 -0.16,-0.38 -0.38,-0.38H5.62c-0.21,0 -0.38,0.17 -0.38,0.38v0.75C5.25,3.58 5.41,3.75 5.62,3.75zM8.62,3.75h0.75c0.21,0 0.38,-0.17 0.38,-0.38V2.62c0,-0.21 -0.16,-0.38 -0.38,-0.38H8.62c-0.21,0 -0.38,0.17 -0.38,0.38v0.75C8.25,3.58 8.41,3.75 8.62,3.75zM14.62,3.75h0.75c0.21,0 0.38,-0.17 0.38,-0.38V2.62c0,-0.21 -0.16,-0.38 -0.38,-0.38h-0.75c-0.21,0 -0.38,0.17 -0.38,0.38v0.75C14.25,3.58 14.41,3.75 14.62,3.75zM17.62,3.75h0.75c0.21,0 0.38,-0.17 0.38,-0.38V2.62c0,-0.21 -0.17,-0.38 -0.38,-0.38h-0.75c-0.21,0 -0.38,0.17 -0.38,0.38v0.75C17.25,3.58 17.42,3.75 17.62,3.75zM20.62,3.75h0.75c0.21,0 0.38,-0.17 0.38,-0.38V2.62c0,-0.21 -0.17,-0.38 -0.38,-0.38h-0.75c-0.21,0 -0.38,0.17 -0.38,0.38v0.75C20.25,3.58 20.42,3.75 20.62,3.75zM11.62,3.75h0.75c0.21,0 0.38,-0.17 0.38,-0.38V2.62c0,-0.21 -0.16,-0.38 -0.38,-0.38h-0.75c-0.21,0 -0.38,0.17 -0.38,0.38v0.75C11.25,3.58 11.41,3.75 11.62,3.75z"/>
 </vector>
diff --git a/packages/overlays/IconPackRoundedLauncherOverlay/res/drawable/ic_select.xml b/packages/overlays/IconPackRoundedLauncherOverlay/res/drawable/ic_select.xml
index b699a44..7bd92ef 100644
--- a/packages/overlays/IconPackRoundedLauncherOverlay/res/drawable/ic_select.xml
+++ b/packages/overlays/IconPackRoundedLauncherOverlay/res/drawable/ic_select.xml
@@ -17,16 +17,7 @@
     android:height="24dp"
     android:viewportWidth="24"
     android:viewportHeight="24">
-  <path
-      android:fillColor="#FF000000"
-      android:pathData="M16.19,12.5h-1.94V8.12C14.25,6.95 13.3,6 12.12,6S10,6.95 10,8.12v7.9l-3.22,-0.86l-1.82,1.82L10.68,23h8.6l1.57,-7.96L16.19,12.5zM18.04,21.5h-6.72l-4.27,-4.49l0.18,-0.18l4.28,1.14V8.12c0,-0.34 0.28,-0.62 0.62,-0.62s0.62,0.28 0.62,0.62V14h3.06l3.35,1.83L18.04,21.5z"/>
-  <path
-      android:fillColor="#FF000000"
-      android:pathData="M11.25,1h1.5v3h-1.5z"/>
-  <path
-      android:fillColor="#FF000000"
-      android:pathData="M15.5983,5.3402l2.1213,-2.1213l1.0606,1.0606l-2.1213,2.1213z"/>
-  <path
-      android:fillColor="#FF000000"
-      android:pathData="M5.2187,4.2803l1.0606,-1.0606l2.1213,2.1213l-1.0606,1.0606z"/>
+    <path
+        android:fillColor="@android:color/white"
+        android:pathData="M18.46,14.17l-4.33,-1.46V8.12C14.13,6.95 13.18,6 12,6S9.88,6.95 9.88,8.12v7.9l-2.3,-0.61c-0.57,-0.15 -1.18,0.01 -1.6,0.43c-0.64,0.64 -0.66,1.66 -0.03,2.32l3.79,3.99c0.52,0.54 1.24,0.85 1.99,0.85h5.16c1.31,0 2.44,-0.93 2.7,-2.22l0.69,-3.48C20.54,15.95 19.76,14.6 18.46,14.17zM18.81,17.01l-0.69,3.48c-0.11,0.58 -0.63,1.01 -1.23,1.01h-5.16c-0.34,0 -0.67,-0.14 -0.91,-0.39l-3.8,-3.99c-0.06,-0.06 -0.06,-0.16 0,-0.23c0.03,-0.03 0.07,-0.05 0.11,-0.05c0.01,0 0.03,0 0.04,0.01l3.24,0.86c0.22,0.06 0.46,0.01 0.65,-0.13c0.18,-0.14 0.29,-0.36 0.29,-0.59V8.12c0,-0.34 0.28,-0.62 0.62,-0.62s0.62,0.28 0.62,0.62v5.12c0,0.32 0.21,0.61 0.51,0.71l4.84,1.63C18.57,15.79 18.93,16.4 18.81,17.01zM3.38,8.25H2.62c-0.21,0 -0.38,0.16 -0.38,0.38v0.75c0,0.21 0.16,0.38 0.38,0.38h0.75c0.21,0 0.38,-0.17 0.38,-0.38V8.62C3.75,8.41 3.59,8.25 3.38,8.25zM6.38,8.25H5.62c-0.21,0 -0.38,0.16 -0.38,0.38v0.75c0,0.21 0.16,0.38 0.38,0.38h0.75c0.21,0 0.38,-0.17 0.38,-0.38V8.62C6.75,8.41 6.59,8.25 6.38,8.25zM18.38,8.25h-0.75c-0.21,0 -0.38,0.16 -0.38,0.38v0.75c0,0.21 0.16,0.38 0.38,0.38h0.75c0.21,0 0.38,-0.17 0.38,-0.38V8.62C18.75,8.41 18.59,8.25 18.38,8.25zM21.38,8.25h-0.75c-0.21,0 -0.38,0.16 -0.38,0.38v0.75c0,0.21 0.16,0.38 0.38,0.38h0.75c0.21,0 0.38,-0.17 0.38,-0.38V8.62C21.75,8.41 21.59,8.25 21.38,8.25zM3.38,5.25H2.62c-0.21,0 -0.38,0.16 -0.38,0.38v0.75c0,0.21 0.16,0.38 0.38,0.38h0.75c0.21,0 0.38,-0.17 0.38,-0.38V5.62C3.75,5.41 3.59,5.25 3.38,5.25zM21.38,5.25h-0.75c-0.21,0 -0.38,0.16 -0.38,0.38v0.75c0,0.21 0.16,0.38 0.38,0.38h0.75c0.21,0 0.38,-0.17 0.38,-0.38V5.62C21.75,5.41 21.59,5.25 21.38,5.25zM3.38,2.25H2.62c-0.21,0 -0.38,0.17 -0.38,0.38v0.75c0,0.21 0.16,0.38 0.38,0.38h0.75c0.21,0 0.38,-0.17 0.38,-0.38V2.62C3.75,2.42 3.59,2.25 3.38,2.25zM6.38,2.25H5.62c-0.21,0 -0.38,0.17 -0.38,0.38v0.75c0,0.21 0.16,0.38 0.38,0.38h0.75c0.21,0 0.38,-0.17 0.38,-0.38V2.62C6.75,2.42 6.59,2.25 6.38,2.25zM9.38,2.25H8.62c-0.21,0 -0.38,0.17 -0.38,0.38v0.75c0,0.21 0.16,0.38 0.38,0.38h0.75c0.21,0 0.38,-0.17 0.38,-0.38V2.62C9.75,2.42 9.59,2.25 9.38,2.25zM12.38,2.25h-0.75c-0.21,0 -0.38,0.17 -0.38,0.38v0.75c0,0.21 0.16,0.38 0.38,0.38h0.75c0.21,0 0.38,-0.17 0.38,-0.38V2.62C12.75,2.42 12.59,2.25 12.38,2.25zM15.38,2.25h-0.75c-0.21,0 -0.38,0.17 -0.38,0.38v0.75c0,0.21 0.16,0.38 0.38,0.38h0.75c0.21,0 0.38,-0.17 0.38,-0.38V2.62C15.75,2.42 15.59,2.25 15.38,2.25zM18.38,2.25h-0.75c-0.21,0 -0.38,0.17 -0.38,0.38v0.75c0,0.21 0.16,0.38 0.38,0.38h0.75c0.21,0 0.38,-0.17 0.38,-0.38V2.62C18.75,2.42 18.59,2.25 18.38,2.25zM18.38,2.25h-0.75c-0.21,0 -0.38,0.17 -0.38,0.38v0.75c0,0.21 0.16,0.38 0.38,0.38h0.75c0.21,0 0.38,-0.17 0.38,-0.38V2.62C18.75,2.42 18.59,2.25 18.38,2.25zM21.38,2.25h-0.75c-0.21,0 -0.38,0.17 -0.38,0.38v0.75c0,0.21 0.16,0.38 0.38,0.38h0.75c0.21,0 0.38,-0.17 0.38,-0.38V2.62C21.75,2.42 21.59,2.25 21.38,2.25z" />
 </vector>
diff --git a/services/accessibility/java/com/android/server/accessibility/AccessibilityServiceConnection.java b/services/accessibility/java/com/android/server/accessibility/AccessibilityServiceConnection.java
index 0f98992..fea2e7b 100644
--- a/services/accessibility/java/com/android/server/accessibility/AccessibilityServiceConnection.java
+++ b/services/accessibility/java/com/android/server/accessibility/AccessibilityServiceConnection.java
@@ -21,6 +21,7 @@
 import android.Manifest;
 import android.accessibilityservice.AccessibilityServiceInfo;
 import android.accessibilityservice.IAccessibilityServiceClient;
+import android.app.PendingIntent;
 import android.content.ComponentName;
 import android.content.Context;
 import android.content.Intent;
@@ -83,7 +84,8 @@
         final long identity = Binder.clearCallingIdentity();
         try {
             mIntent.putExtra(Intent.EXTRA_CLIENT_INTENT, mSystemSupport.getPendingIntentActivity(
-                    mContext, 0, new Intent(Settings.ACTION_ACCESSIBILITY_SETTINGS), 0));
+                    mContext, 0, new Intent(Settings.ACTION_ACCESSIBILITY_SETTINGS),
+                    PendingIntent.FLAG_IMMUTABLE));
         } finally {
             Binder.restoreCallingIdentity(identity);
         }
diff --git a/services/appprediction/java/com/android/server/appprediction/AppPredictionPerUserService.java b/services/appprediction/java/com/android/server/appprediction/AppPredictionPerUserService.java
index 26e85be..103151d 100644
--- a/services/appprediction/java/com/android/server/appprediction/AppPredictionPerUserService.java
+++ b/services/appprediction/java/com/android/server/appprediction/AppPredictionPerUserService.java
@@ -51,7 +51,7 @@
  */
 public class AppPredictionPerUserService extends
         AbstractPerUserSystemService<AppPredictionPerUserService, AppPredictionManagerService>
-        implements RemoteAppPredictionService.RemoteAppPredictionServiceCallbacks {
+             implements RemoteAppPredictionService.RemoteAppPredictionServiceCallbacks {
 
     private static final String TAG = AppPredictionPerUserService.class.getSimpleName();
     private static final String PREDICT_USING_PEOPLE_SERVICE_PREFIX =
@@ -114,11 +114,8 @@
     public void onCreatePredictionSessionLocked(@NonNull AppPredictionContext context,
             @NonNull AppPredictionSessionId sessionId) {
         if (!mSessionInfos.containsKey(sessionId)) {
-            // TODO(b/157500121): remove below forceUsingPeopleService logic after testing
-            //  PeopleService for 2 weeks on Droidfood.
-            final boolean forceUsingPeopleService = context.getUiSurface().equals("share");
             mSessionInfos.put(sessionId, new AppPredictionSessionInfo(sessionId, context,
-                    forceUsingPeopleService || DeviceConfig.getBoolean(NAMESPACE_SYSTEMUI,
+                    DeviceConfig.getBoolean(NAMESPACE_SYSTEMUI,
                             PREDICT_USING_PEOPLE_SERVICE_PREFIX + context.getUiSurface(), false),
                     this::removeAppPredictionSessionInfo));
         }
diff --git a/services/autofill/java/com/android/server/autofill/AutofillInlineSessionController.java b/services/autofill/java/com/android/server/autofill/AutofillInlineSessionController.java
index 0ec8654..398ece4 100644
--- a/services/autofill/java/com/android/server/autofill/AutofillInlineSessionController.java
+++ b/services/autofill/java/com/android/server/autofill/AutofillInlineSessionController.java
@@ -77,8 +77,8 @@
         if (mSession != null) {
             // Destroy the existing session.
             mSession.destroySessionLocked();
-            mInlineFillUi = null;
         }
+        mInlineFillUi = null;
         // TODO(b/151123764): consider reusing the same AutofillInlineSession object for the
         // same field.
         mSession = new AutofillInlineSuggestionsRequestSession(mInputMethodManagerInternal, mUserId,
@@ -87,6 +87,22 @@
     }
 
     /**
+     * Destroys the current session. May send an empty response to IME to clear the suggestions if
+     * the focus didn't change to a different field.
+     *
+     * @param autofillId the currently focused view from the autofill session
+     */
+    @GuardedBy("mLock")
+    void destroyLocked(@NonNull AutofillId autofillId) {
+        if (mSession != null) {
+            mSession.onInlineSuggestionsResponseLocked(InlineFillUi.emptyUi(autofillId));
+            mSession.destroySessionLocked();
+            mSession = null;
+        }
+        mInlineFillUi = null;
+    }
+
+    /**
      * Returns the {@link InlineSuggestionsRequest} provided by IME for the last request.
      *
      * <p> The caller is responsible for making sure Autofill hears back from IME before calling
diff --git a/services/autofill/java/com/android/server/autofill/AutofillInlineSuggestionsRequestSession.java b/services/autofill/java/com/android/server/autofill/AutofillInlineSuggestionsRequestSession.java
index e7a43b7..48895ad 100644
--- a/services/autofill/java/com/android/server/autofill/AutofillInlineSuggestionsRequestSession.java
+++ b/services/autofill/java/com/android/server/autofill/AutofillInlineSuggestionsRequestSession.java
@@ -93,7 +93,7 @@
     @Nullable
     private InlineFillUi mInlineFillUi;
     @GuardedBy("mLock")
-    private boolean mPreviousResponseIsNotEmpty;
+    private Boolean mPreviousResponseIsNotEmpty = null;
 
     @GuardedBy("mLock")
     private boolean mDestroyed = false;
@@ -213,7 +213,7 @@
             // if IME is visible, and response is not null, send the response
             InlineSuggestionsResponse response = mInlineFillUi.getInlineSuggestionsResponse();
             boolean isEmptyResponse = response.getInlineSuggestions().isEmpty();
-            if (isEmptyResponse && !mPreviousResponseIsNotEmpty) {
+            if (isEmptyResponse && Boolean.FALSE.equals(mPreviousResponseIsNotEmpty)) {
                 // No-op if both the previous response and current response are empty.
                 return;
             }
diff --git a/services/autofill/java/com/android/server/autofill/RemoteAugmentedAutofillService.java b/services/autofill/java/com/android/server/autofill/RemoteAugmentedAutofillService.java
index 851e4cc..a7d0061 100644
--- a/services/autofill/java/com/android/server/autofill/RemoteAugmentedAutofillService.java
+++ b/services/autofill/java/com/android/server/autofill/RemoteAugmentedAutofillService.java
@@ -245,6 +245,11 @@
         if (inlineSuggestionsData == null || inlineSuggestionsData.isEmpty()
                 || inlineSuggestionsCallback == null || request == null
                 || remoteRenderService == null) {
+            // If it was an inline request and the response doesn't have any inline suggestions,
+            // we will send an empty response to IME.
+            if (inlineSuggestionsCallback != null && request != null) {
+                inlineSuggestionsCallback.apply(InlineFillUi.emptyUi(focusedId));
+            }
             return;
         }
         mCallbacks.setLastResponse(sessionId);
diff --git a/services/autofill/java/com/android/server/autofill/Session.java b/services/autofill/java/com/android/server/autofill/Session.java
index 642526d..c7490b3 100644
--- a/services/autofill/java/com/android/server/autofill/Session.java
+++ b/services/autofill/java/com/android/server/autofill/Session.java
@@ -2715,7 +2715,9 @@
                 final ViewState currentView = mViewStates.get(mCurrentViewId);
                 currentView.maybeCallOnFillReady(flags);
             }
-        } else if (viewState.id.equals(this.mCurrentViewId)
+        }
+
+        if (viewState.id.equals(this.mCurrentViewId)
                 && (viewState.getState() & ViewState.STATE_INLINE_SHOWN) != 0) {
             if ((viewState.getState() & ViewState.STATE_INLINE_DISABLED) != 0) {
                 mInlineSessionController.disableFilterMatching(viewState.id);
@@ -3700,6 +3702,9 @@
         unlinkClientVultureLocked();
         mUi.destroyAll(mPendingSaveUi, this, true);
         mUi.clearCallback(this);
+        if (mCurrentViewId != null) {
+            mInlineSessionController.destroyLocked(mCurrentViewId);
+        }
         mDestroyed = true;
 
         // Log metrics
diff --git a/services/companion/java/com/android/server/companion/CompanionDeviceManagerService.java b/services/companion/java/com/android/server/companion/CompanionDeviceManagerService.java
index 6ccdf24..961dc15 100644
--- a/services/companion/java/com/android/server/companion/CompanionDeviceManagerService.java
+++ b/services/companion/java/com/android/server/companion/CompanionDeviceManagerService.java
@@ -22,10 +22,14 @@
 import static com.android.internal.util.Preconditions.checkArgument;
 import static com.android.internal.util.Preconditions.checkNotNull;
 import static com.android.internal.util.Preconditions.checkState;
+import static com.android.internal.util.function.pooled.PooledLambda.obtainMessage;
 import static com.android.internal.util.function.pooled.PooledLambda.obtainRunnable;
 
+import static java.util.concurrent.TimeUnit.MINUTES;
+
 import android.annotation.CheckResult;
 import android.annotation.Nullable;
+import android.app.AppOpsManager;
 import android.app.PendingIntent;
 import android.companion.Association;
 import android.companion.AssociationRequest;
@@ -36,6 +40,7 @@
 import android.content.ComponentName;
 import android.content.Context;
 import android.content.Intent;
+import android.content.SharedPreferences;
 import android.content.pm.FeatureInfo;
 import android.content.pm.PackageInfo;
 import android.content.pm.PackageItemInfo;
@@ -55,6 +60,7 @@
 import android.os.ShellCallback;
 import android.os.ShellCommand;
 import android.os.UserHandle;
+import android.os.UserManagerInternal;
 import android.provider.Settings;
 import android.provider.SettingsStringUtil.ComponentNameSet;
 import android.text.BidiFormatter;
@@ -71,6 +77,7 @@
 import com.android.internal.infra.PerUser;
 import com.android.internal.infra.ServiceConnector;
 import com.android.internal.notification.NotificationAccessConfirmationActivityContract;
+import com.android.internal.os.BackgroundThread;
 import com.android.internal.util.ArrayUtils;
 import com.android.internal.util.CollectionUtils;
 import com.android.internal.util.function.pooled.PooledLambda;
@@ -112,6 +119,9 @@
     private static final boolean DEBUG = false;
     private static final String LOG_TAG = "CompanionDeviceManagerService";
 
+    private static final String PREF_FILE_NAME = "companion_device_preferences.xml";
+    private static final String PREF_KEY_AUTO_REVOKE_GRANTS_DONE = "auto_revoke_grants_done";
+
     private static final String XML_TAG_ASSOCIATIONS = "associations";
     private static final String XML_TAG_ASSOCIATION = "association";
     private static final String XML_ATTR_PACKAGE = "package";
@@ -150,7 +160,6 @@
             }
         };
 
-
         registerPackageMonitor();
     }
 
@@ -195,6 +204,36 @@
         if (atmInternal != null) {
             atmInternal.setCompanionAppPackages(userHandle, companionAppPackages);
         }
+
+        BackgroundThread.getHandler().sendMessageDelayed(
+                obtainMessage(CompanionDeviceManagerService::maybeGrantAutoRevokeExemptions, this),
+                MINUTES.toMillis(10));
+    }
+
+    void maybeGrantAutoRevokeExemptions() {
+        PackageManager pm = getContext().getPackageManager();
+        for (int userId : LocalServices.getService(UserManagerInternal.class).getUserIds()) {
+            SharedPreferences pref = getContext().getSharedPreferences(
+                    new File(Environment.getUserSystemDirectory(userId), PREF_FILE_NAME),
+                    Context.MODE_PRIVATE);
+            if (pref.getBoolean(PREF_KEY_AUTO_REVOKE_GRANTS_DONE, false)) {
+                continue;
+            }
+
+            try {
+                Set<Association> associations = readAllAssociations(userId);
+                for (Association a : associations) {
+                    try {
+                        int uid = pm.getPackageUidAsUser(a.companionAppPackage, userId);
+                        exemptFromAutoRevoke(a.companionAppPackage, uid);
+                    } catch (PackageManager.NameNotFoundException e) {
+                        Log.w(LOG_TAG, "Unknown companion package: " + a.companionAppPackage, e);
+                    }
+                }
+            } finally {
+                pref.edit().putBoolean(PREF_KEY_AUTO_REVOKE_GRANTS_DONE, true).apply();
+            }
+        }
     }
 
     @Override
@@ -469,6 +508,21 @@
                     packageInfo.applicationInfo.uid,
                     NetworkPolicyManager.POLICY_ALLOW_METERED_BACKGROUND);
         }
+
+        exemptFromAutoRevoke(packageInfo.packageName, packageInfo.applicationInfo.uid);
+    }
+
+    private void exemptFromAutoRevoke(String packageName, int uid) {
+        try {
+            mAppOpsManager.setMode(
+                    AppOpsManager.OP_AUTO_REVOKE_PERMISSIONS_IF_UNUSED,
+                    uid,
+                    packageName,
+                    AppOpsManager.MODE_IGNORED);
+        } catch (RemoteException e) {
+            Log.w(LOG_TAG,
+                    "Error while granting auto revoke exemption for " + packageName, e);
+        }
     }
 
     private static <T> boolean containsEither(T[] array, T a, T b) {
diff --git a/services/core/Android.bp b/services/core/Android.bp
index 9e8a872..65e98ac 100644
--- a/services/core/Android.bp
+++ b/services/core/Android.bp
@@ -100,7 +100,7 @@
         "android.net.ipsec.ike.stubs.module_lib",
         "app-compat-annotations",
         "framework-tethering.stubs.module_lib",
-        "service-permission-stubs",
+        "service-permission.stubs.system_server",
     ],
 
     required: [
diff --git a/services/core/java/android/content/pm/PackageManagerInternal.java b/services/core/java/android/content/pm/PackageManagerInternal.java
index 81de29c..b241bd1 100644
--- a/services/core/java/android/content/pm/PackageManagerInternal.java
+++ b/services/core/java/android/content/pm/PackageManagerInternal.java
@@ -988,4 +988,14 @@
      * Unblocks uninstall for all packages for the user.
      */
     public abstract void clearBlockUninstallForUser(@UserIdInt int userId);
+
+    /**
+     * Unsuspends all packages suspended by the given package for the user.
+     */
+    public abstract void unsuspendForSuspendingPackage(String suspendingPackage, int userId);
+
+    /**
+     * Returns {@code true} if the package is suspending any packages for the user.
+     */
+    public abstract boolean isSuspendingAnyPackages(String suspendingPackage, int userId);
 }
diff --git a/services/core/java/com/android/server/AppStateTracker.java b/services/core/java/com/android/server/AppStateTracker.java
index b765d81..74f79e0 100644
--- a/services/core/java/com/android/server/AppStateTracker.java
+++ b/services/core/java/com/android/server/AppStateTracker.java
@@ -1120,7 +1120,8 @@
                 return false;
             }
             final int userId = UserHandle.getUserId(uid);
-            if (mExemptedPackages.contains(userId, packageName)) {
+            if (mAppStandbyInternal.isAppIdleEnabled() && !mAppStandbyInternal.isInParole()
+                    && mExemptedPackages.contains(userId, packageName)) {
                 return false;
             }
             return mForceAllAppsStandby;
diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java
index 0ab5718..2958fd2 100644
--- a/services/core/java/com/android/server/ConnectivityService.java
+++ b/services/core/java/com/android/server/ConnectivityService.java
@@ -6426,7 +6426,7 @@
             final boolean shouldFilter = requiresVpnIsolation(nai, newNc, nai.linkProperties);
             final String iface = nai.linkProperties.getInterfaceName();
             // For VPN uid interface filtering, old ranges need to be removed before new ranges can
-            // be added, due to the range being expanded and stored as invidiual UIDs. For example
+            // be added, due to the range being expanded and stored as individual UIDs. For example
             // the UIDs might be updated from [0, 99999] to ([0, 10012], [10014, 99999]) which means
             // prevRanges = [0, 99999] while newRanges = [0, 10012], [10014, 99999]. If prevRanges
             // were added first and then newRanges got removed later, there would be only one uid
diff --git a/services/core/java/com/android/server/TelephonyRegistry.java b/services/core/java/com/android/server/TelephonyRegistry.java
index 9080bdb..23bf955 100644
--- a/services/core/java/com/android/server/TelephonyRegistry.java
+++ b/services/core/java/com/android/server/TelephonyRegistry.java
@@ -310,27 +310,30 @@
     private List<Map<Integer, PreciseDataConnectionState>> mPreciseDataConnectionStates =
             new ArrayList<Map<Integer, PreciseDataConnectionState>>();
 
-    // Nothing here yet, but putting it here in case we want to add more in the future.
-    static final int ENFORCE_COARSE_LOCATION_PERMISSION_MASK = 0;
+    static final int ENFORCE_COARSE_LOCATION_PERMISSION_MASK =
+            PhoneStateListener.LISTEN_REGISTRATION_FAILURE
+                    | PhoneStateListener.LISTEN_BARRING_INFO;
 
     static final int ENFORCE_FINE_LOCATION_PERMISSION_MASK =
             PhoneStateListener.LISTEN_CELL_LOCATION
-                    | PhoneStateListener.LISTEN_CELL_INFO;
+                    | PhoneStateListener.LISTEN_CELL_INFO
+                    | PhoneStateListener.LISTEN_REGISTRATION_FAILURE
+                    | PhoneStateListener.LISTEN_BARRING_INFO;
 
     static final int ENFORCE_PHONE_STATE_PERMISSION_MASK =
-                PhoneStateListener.LISTEN_CALL_FORWARDING_INDICATOR
-                        | PhoneStateListener.LISTEN_MESSAGE_WAITING_INDICATOR
-                        | PhoneStateListener.LISTEN_EMERGENCY_NUMBER_LIST
-                        | PhoneStateListener.LISTEN_DISPLAY_INFO_CHANGED;
+            PhoneStateListener.LISTEN_CALL_FORWARDING_INDICATOR
+                    | PhoneStateListener.LISTEN_MESSAGE_WAITING_INDICATOR
+                    | PhoneStateListener.LISTEN_EMERGENCY_NUMBER_LIST
+                    | PhoneStateListener.LISTEN_DISPLAY_INFO_CHANGED;
 
     static final int ENFORCE_PRECISE_PHONE_STATE_PERMISSION_MASK =
-                PhoneStateListener.LISTEN_PRECISE_CALL_STATE
-                        | PhoneStateListener.LISTEN_PRECISE_DATA_CONNECTION_STATE
-                        | PhoneStateListener.LISTEN_CALL_DISCONNECT_CAUSES
-                        | PhoneStateListener.LISTEN_CALL_ATTRIBUTES_CHANGED
-                        | PhoneStateListener.LISTEN_IMS_CALL_DISCONNECT_CAUSES
-                        | PhoneStateListener.LISTEN_REGISTRATION_FAILURE
-                        | PhoneStateListener.LISTEN_BARRING_INFO;
+            PhoneStateListener.LISTEN_PRECISE_CALL_STATE
+                    | PhoneStateListener.LISTEN_PRECISE_DATA_CONNECTION_STATE
+                    | PhoneStateListener.LISTEN_CALL_DISCONNECT_CAUSES
+                    | PhoneStateListener.LISTEN_CALL_ATTRIBUTES_CHANGED
+                    | PhoneStateListener.LISTEN_IMS_CALL_DISCONNECT_CAUSES
+                    | PhoneStateListener.LISTEN_REGISTRATION_FAILURE
+                    | PhoneStateListener.LISTEN_BARRING_INFO;
 
     static final int READ_ACTIVE_EMERGENCY_SESSION_PERMISSION_MASK =
             PhoneStateListener.LISTEN_OUTGOING_EMERGENCY_CALL
@@ -338,9 +341,9 @@
 
     static final int READ_PRIVILEGED_PHONE_STATE_PERMISSION_MASK =
             PhoneStateListener.LISTEN_OEM_HOOK_RAW_EVENT
-                | PhoneStateListener.LISTEN_SRVCC_STATE_CHANGED
-                | PhoneStateListener.LISTEN_RADIO_POWER_STATE_CHANGED
-                | PhoneStateListener.LISTEN_VOICE_ACTIVATION_STATE;
+                    | PhoneStateListener.LISTEN_SRVCC_STATE_CHANGED
+                    | PhoneStateListener.LISTEN_RADIO_POWER_STATE_CHANGED
+                    | PhoneStateListener.LISTEN_VOICE_ACTIVATION_STATE;
 
     private static final int MSG_USER_SWITCHED = 1;
     private static final int MSG_UPDATE_DEFAULT_SUB = 2;
@@ -1606,7 +1609,7 @@
                 for (Record r : mRecords) {
                     if (r.matchPhoneStateListenerEvent(
                             PhoneStateListener.LISTEN_DISPLAY_INFO_CHANGED)
-                            && idMatch(r.subId, subId, phoneId)) {
+                            && idMatchWithoutDefaultPhoneCheck(r.subId, subId)) {
                         try {
                             r.callback.onDisplayInfoChanged(telephonyDisplayInfo);
                         } catch (RemoteException ex) {
@@ -2726,6 +2729,24 @@
         Rlog.e(TAG, s);
     }
 
+    /**
+     * If the registrant specified a subId, then we should only notify it if subIds match.
+     * If the registrant registered with DEFAULT subId, we should notify only when the related subId
+     * is default subId (which could be INVALID if there's no default subId).
+     *
+     * This should be the correct way to check record ID match. in idMatch the record's phoneId is
+     * speculated based on subId passed by the registrant so it's not a good reference.
+     * But to avoid triggering potential regression only replace idMatch with it when an issue with
+     * idMatch is reported. Eventually this should replace all instances of idMatch.
+     */
+    private boolean idMatchWithoutDefaultPhoneCheck(int subIdInRecord, int subIdToNotify) {
+        if (subIdInRecord == SubscriptionManager.DEFAULT_SUBSCRIPTION_ID) {
+            return (subIdToNotify == mDefaultSubId);
+        } else {
+            return (subIdInRecord == subIdToNotify);
+        }
+    }
+
     boolean idMatch(int rSubId, int subId, int phoneId) {
 
         if(subId < 0) {
diff --git a/services/core/java/com/android/server/UiModeManagerService.java b/services/core/java/com/android/server/UiModeManagerService.java
index 35936ba..be080e5 100644
--- a/services/core/java/com/android/server/UiModeManagerService.java
+++ b/services/core/java/com/android/server/UiModeManagerService.java
@@ -233,7 +233,7 @@
         public void onTwilightStateChanged(@Nullable TwilightState state) {
             synchronized (mLock) {
                 if (mNightMode == UiModeManager.MODE_NIGHT_AUTO && mSystemReady) {
-                    if (mCar) {
+                    if (shouldApplyAutomaticChangesImmediately()) {
                         updateLocked(0, 0);
                     } else {
                         registerScreenOffEventLocked();
@@ -1155,7 +1155,6 @@
     void updateLocked(int enableFlags, int disableFlags) {
         String action = null;
         String oldAction = null;
-        boolean originalComputedNightMode = mComputedNightMode;
         if (mLastBroadcastState == Intent.EXTRA_DOCK_STATE_CAR) {
             adjustStatusBarCarModeLocked();
             oldAction = UiModeManager.ACTION_EXIT_CAR_MODE;
@@ -1236,16 +1235,11 @@
             sendConfigurationAndStartDreamOrDockAppLocked(category);
         }
 
-        // reset overrides if mComputedNightMode changes
-        if (originalComputedNightMode != mComputedNightMode) {
-            resetNightModeOverrideLocked();
-        }
-
         // keep screen on when charging and in car mode
         boolean keepScreenOn = mCharging &&
                 ((mCarModeEnabled && mCarModeKeepsScreenOn &&
-                  (mCarModeEnableFlags & UiModeManager.ENABLE_CAR_MODE_ALLOW_SLEEP) == 0) ||
-                 (mCurUiMode == Configuration.UI_MODE_TYPE_DESK && mDeskModeKeepsScreenOn));
+                (mCarModeEnableFlags & UiModeManager.ENABLE_CAR_MODE_ALLOW_SLEEP) == 0) ||
+                (mCurUiMode == Configuration.UI_MODE_TYPE_DESK && mDeskModeKeepsScreenOn));
         if (keepScreenOn != mWakeLock.isHeld()) {
             if (keepScreenOn) {
                 mWakeLock.acquire();
@@ -1403,6 +1397,7 @@
             mComputedNightMode = false;
             return;
         }
+        resetNightModeOverrideLocked();
     }
 
     private boolean resetNightModeOverrideLocked() {
diff --git a/services/core/java/com/android/server/adb/AdbDebuggingManager.java b/services/core/java/com/android/server/adb/AdbDebuggingManager.java
index 27ea471..df3b688 100644
--- a/services/core/java/com/android/server/adb/AdbDebuggingManager.java
+++ b/services/core/java/com/android/server/adb/AdbDebuggingManager.java
@@ -337,6 +337,7 @@
 
     class PortListenerImpl implements AdbConnectionPortListener {
         public void onPortReceived(int port) {
+            if (DEBUG) Slog.d(TAG, "Received tls port=" + port);
             Message msg = mHandler.obtainMessage(port > 0
                      ? AdbDebuggingHandler.MSG_SERVER_CONNECTED
                      : AdbDebuggingHandler.MSG_SERVER_DISCONNECTED);
@@ -392,6 +393,7 @@
 
                 mOutputStream = mSocket.getOutputStream();
                 mInputStream = mSocket.getInputStream();
+                mHandler.sendEmptyMessage(AdbDebuggingHandler.MSG_ADBD_SOCKET_CONNECTED);
             } catch (IOException ioe) {
                 Slog.e(TAG, "Caught an exception opening the socket: " + ioe);
                 closeSocketLocked();
@@ -504,6 +506,7 @@
             } catch (IOException ex) {
                 Slog.e(TAG, "Failed closing socket: " + ex);
             }
+            mHandler.sendEmptyMessage(AdbDebuggingHandler.MSG_ADBD_SOCKET_DISCONNECTED);
         }
 
         /** Call to stop listening on the socket and exit the thread. */
@@ -729,6 +732,10 @@
         static final int MSG_SERVER_CONNECTED = 24;
         // Notifies us the TLS server is disconnected
         static final int MSG_SERVER_DISCONNECTED = 25;
+        // Notification when adbd socket successfully connects.
+        static final int MSG_ADBD_SOCKET_CONNECTED = 26;
+        // Notification when adbd socket is disconnected.
+        static final int MSG_ADBD_SOCKET_DISCONNECTED = 27;
 
         // === Messages we can send to adbd ===========
         static final String MSG_DISCONNECT_DEVICE = "DD";
@@ -1170,6 +1177,28 @@
                     }
                     break;
                 }
+                case MSG_ADBD_SOCKET_CONNECTED: {
+                    if (DEBUG) Slog.d(TAG, "adbd socket connected");
+                    if (mAdbWifiEnabled) {
+                        // In scenarios where adbd is restarted, the tls port may change.
+                        mConnectionPortPoller =
+                                new AdbDebuggingManager.AdbConnectionPortPoller(mPortListener);
+                        mConnectionPortPoller.start();
+                    }
+                    break;
+                }
+                case MSG_ADBD_SOCKET_DISCONNECTED: {
+                    if (DEBUG) Slog.d(TAG, "adbd socket disconnected");
+                    if (mConnectionPortPoller != null) {
+                        mConnectionPortPoller.cancelAndWait();
+                        mConnectionPortPoller = null;
+                    }
+                    if (mAdbWifiEnabled) {
+                        // In scenarios where adbd is restarted, the tls port may change.
+                        onAdbdWifiServerDisconnected(-1);
+                    }
+                    break;
+                }
             }
         }
 
diff --git a/services/core/java/com/android/server/adb/AdbService.java b/services/core/java/com/android/server/adb/AdbService.java
index e1f9a7a..ef81d71 100644
--- a/services/core/java/com/android/server/adb/AdbService.java
+++ b/services/core/java/com/android/server/adb/AdbService.java
@@ -241,12 +241,7 @@
     private AdbService(Context context) {
         mContext = context;
         mContentResolver = context.getContentResolver();
-
-        boolean secureAdbEnabled = AdbProperties.secure().orElse(false);
-        boolean dataEncrypted = "1".equals(SystemProperties.get("vold.decrypt"));
-        if (secureAdbEnabled && !dataEncrypted) {
-            mDebuggingManager = new AdbDebuggingManager(context);
-        }
+        mDebuggingManager = new AdbDebuggingManager(context);
 
         initAdbState();
         LocalServices.addService(AdbManagerInternal.class, new AdbManagerInternalImpl());
diff --git a/services/core/java/com/android/server/am/ActiveServices.java b/services/core/java/com/android/server/am/ActiveServices.java
index c5c3caf..a7bf982 100644
--- a/services/core/java/com/android/server/am/ActiveServices.java
+++ b/services/core/java/com/android/server/am/ActiveServices.java
@@ -4918,52 +4918,6 @@
         if (isDeviceOwner) {
             return true;
         }
-
-        r.mInfoDenyWhileInUsePermissionInFgs =
-                "Background FGS start while-in-use permission restriction [callingPackage: "
-                + callingPackage
-                + "; callingUid: " + callingUid
-                + "; intent: " + intent
-                + "]";
         return false;
     }
-
-    // TODO: remove this toast after feature development is done
-    void showWhileInUseDebugToastLocked(int uid, int op, int mode) {
-        final UidRecord uidRec = mAm.mProcessList.getUidRecordLocked(uid);
-        if (uidRec == null) {
-            return;
-        }
-
-        for (int i = uidRec.procRecords.size() - 1; i >= 0; i--) {
-            ProcessRecord pr = uidRec.procRecords.valueAt(i);
-            if (pr.uid != uid) {
-                continue;
-            }
-            for (int j = pr.numberOfRunningServices() - 1; j >= 0; j--) {
-                ServiceRecord r = pr.getRunningServiceAt(j);
-                if (!r.isForeground) {
-                    continue;
-                }
-                if (mode == DEBUG_FGS_ALLOW_WHILE_IN_USE) {
-                    if (!r.mAllowWhileInUsePermissionInFgs
-                            && r.mInfoDenyWhileInUsePermissionInFgs != null) {
-                        final String msg = r.mInfoDenyWhileInUsePermissionInFgs
-                                + " affected while-in-use permission:"
-                                + AppOpsManager.opToPublicName(op);
-                        Slog.wtf(TAG, msg);
-                    }
-                } else if (mode == DEBUG_FGS_ENFORCE_TYPE) {
-                    final String msg =
-                            "FGS Missing foregroundServiceType in manifest file [callingPackage: "
-                            + r.mRecentCallingPackage
-                            + "; intent:" + r.intent.getIntent()
-                            + "] affected while-in-use permission:"
-                            + AppOpsManager.opToPublicName(op)
-                            + "; targetSdkVersion:" + r.appInfo.targetSdkVersion;
-                    Slog.wtf(TAG, msg);
-                }
-            }
-        }
-    }
 }
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index caaa837..0795122 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -28,6 +28,7 @@
 import static android.app.ActivityManager.INSTR_FLAG_MOUNT_EXTERNAL_STORAGE_FULL;
 import static android.app.ActivityManager.PROCESS_STATE_LAST_ACTIVITY;
 import static android.app.ActivityManager.PROCESS_STATE_NONEXISTENT;
+import static android.app.ActivityManager.PROCESS_STATE_TOP;
 import static android.app.ActivityManagerInternal.ALLOW_FULL_ONLY;
 import static android.app.ActivityManagerInternal.ALLOW_NON_FULL;
 import static android.app.AppOpsManager.OP_NONE;
@@ -299,7 +300,6 @@
 import android.util.Slog;
 import android.util.SparseArray;
 import android.util.SparseIntArray;
-import android.util.SparseLongArray;
 import android.util.TimeUtils;
 import android.util.proto.ProtoOutputStream;
 import android.util.proto.ProtoUtils;
@@ -421,7 +421,6 @@
      * Priority we boost main thread and RT of top app to.
      */
     public static final int TOP_APP_PRIORITY_BOOST = -10;
-
     private static final String SYSTEM_PROPERTY_DEVICE_PROVISIONED =
             "persist.sys.device_provisioned";
 
@@ -823,45 +822,7 @@
         }
     }
 
-    /**
-     * While starting activity, WindowManager posts a runnable to DisplayThread to updateOomAdj.
-     * The latency of the thread switch could cause client app failure when the app is checking
-     * {@link #isUidActive} before updateOomAdj is done.
-     *
-     * Use PendingStartActivityUids to save uid after WindowManager start activity and before
-     * updateOomAdj is done.
-     *
-     * <p>NOTE: This object is protected by its own lock, NOT the global activity manager lock!
-     */
-    final PendingStartActivityUids mPendingStartActivityUidsLocked = new PendingStartActivityUids();
-    final class PendingStartActivityUids {
-        // Key is uid, value is SystemClock.elapsedRealtime() when the key is added.
-        private final SparseLongArray mPendingUids = new SparseLongArray();
-
-        void add(int uid) {
-            if (mPendingUids.indexOfKey(uid) < 0) {
-                mPendingUids.put(uid, SystemClock.elapsedRealtime());
-            }
-        }
-
-        void delete(int uid) {
-            if (mPendingUids.indexOfKey(uid) >= 0) {
-                long delay = SystemClock.elapsedRealtime() - mPendingUids.get(uid);
-                if (delay >= 1000) {
-                    Slog.wtf(TAG,
-                            "PendingStartActivityUids startActivity to updateOomAdj delay:"
-                            + delay + "ms,"
-                            + " uid:" + uid
-                            + " packageName:" + Settings.getPackageNameForUid(mContext, uid));
-                }
-                mPendingUids.delete(uid);
-            }
-        }
-
-        boolean isPendingTopUid(int uid) {
-            return mPendingUids.indexOfKey(uid) >= 0;
-        }
-    }
+    private final PendingStartActivityUids mPendingStartActivityUids;
 
     /**
      * Puts the process record in the map.
@@ -1710,6 +1671,12 @@
      */
     @Nullable ContentCaptureManagerInternal mContentCaptureService;
 
+    /**
+     * Set of {@link ProcessRecord} that have either {@link ProcessRecord#hasTopUi()} or
+     * {@link ProcessRecord#runningRemoteAnimation} set to {@code true}.
+     */
+    final ArraySet<ProcessRecord> mTopUiOrRunningRemoteAnimApps = new ArraySet<>();
+
     final class UiHandler extends Handler {
         public UiHandler() {
             super(com.android.server.UiThread.get().getLooper(), null, true);
@@ -2585,6 +2552,7 @@
         mFactoryTest = FACTORY_TEST_OFF;
         mUgmInternal = LocalServices.getService(UriGrantsManagerInternal.class);
         mInternal = new LocalService();
+        mPendingStartActivityUids = new PendingStartActivityUids(mContext);
     }
 
     // Note: This method is invoked on the main thread but may need to attach various
@@ -2742,6 +2710,7 @@
         }
 
         mInternal = new LocalService();
+        mPendingStartActivityUids = new PendingStartActivityUids(mContext);
     }
 
     public void setSystemServiceManager(SystemServiceManager mgr) {
@@ -6093,9 +6062,18 @@
         synchronized (mPidsSelfLocked) {
             for (int i = 0; i < pids.length; i++) {
                 ProcessRecord pr = mPidsSelfLocked.get(pids[i]);
-                states[i] = (pr == null) ? PROCESS_STATE_NONEXISTENT : pr.getCurProcState();
-                if (scores != null) {
-                    scores[i] = (pr == null) ? ProcessList.INVALID_ADJ : pr.curAdj;
+                if (pr != null) {
+                    final boolean isPendingTop =
+                                mPendingStartActivityUids.isPendingTopPid(pr.uid, pids[i]);
+                    states[i] = isPendingTop ? PROCESS_STATE_TOP : pr.getCurProcState();
+                    if (scores != null) {
+                        scores[i] = isPendingTop ? ProcessList.FOREGROUND_APP_ADJ : pr.curAdj;
+                    }
+                } else {
+                    states[i] = PROCESS_STATE_NONEXISTENT;
+                    if (scores != null) {
+                        scores[i] = ProcessList.INVALID_ADJ;
+                    }
                 }
             }
         }
@@ -8839,15 +8817,7 @@
                 return true;
             }
         }
-
-        if (mInternal.isPendingTopUid(uid)) {
-            Slog.wtf(TAG, "PendingStartActivityUids isUidActive false but"
-                    + " isPendingTopUid true, uid:" + uid
-                    + " callingPackage:" + callingPackage);
-            return true;
-        } else {
-            return false;
-        }
+        return mInternal.isPendingTopUid(uid);
     }
 
     boolean isUidActiveLocked(int uid) {
@@ -14738,6 +14708,7 @@
 
         mProcessesToGc.remove(app);
         mPendingPssProcesses.remove(app);
+        mTopUiOrRunningRemoteAnimApps.remove(app);
         ProcessList.abortNextPssTime(app.procStateMemTracker);
 
         // Dismiss any open dialogs.
@@ -18526,6 +18497,22 @@
         return proc;
     }
 
+    /**
+     * @return {@code true} if {@link #mTopUiOrRunningRemoteAnimApps} set contains {@code app} or when there are no apps
+     *         in this list, an false otherwise.
+     */
+    boolean containsTopUiOrRunningRemoteAnimOrEmptyLocked(ProcessRecord app) {
+        return mTopUiOrRunningRemoteAnimApps.isEmpty() || mTopUiOrRunningRemoteAnimApps.contains(app);
+    }
+
+    void addTopUiOrRunningRemoteAnim(ProcessRecord app) {
+        mTopUiOrRunningRemoteAnimApps.add(app);
+    }
+
+    void removeTopUiOrRunningRemoteAnim(ProcessRecord app) {
+        mTopUiOrRunningRemoteAnimApps.remove(app);
+    }
+
     @Override
     public boolean dumpHeap(String process, int userId, boolean managed, boolean mallocInfo,
             boolean runGc, String path, ParcelFileDescriptor fd, RemoteCallback finishCallback) {
@@ -19707,15 +19694,6 @@
             return false;
         }
 
-        // TODO: remove this toast after feature development is done
-        @Override
-        public void showWhileInUseDebugToast(int uid, int op, int mode) {
-            synchronized (ActivityManagerService.this) {
-                ActivityManagerService.this.mServices.showWhileInUseDebugToastLocked(
-                        uid, op, mode);
-            }
-        }
-
         @Override
         public void setDeviceOwnerUid(int uid) {
             synchronized (ActivityManagerService.this) {
@@ -19731,22 +19709,18 @@
         }
 
         @Override
-        public void updatePendingTopUid(int uid, boolean pending) {
-            synchronized (mPendingStartActivityUidsLocked) {
-                if (pending) {
-                    mPendingStartActivityUidsLocked.add(uid);
-                } else {
-                    mPendingStartActivityUidsLocked.delete(uid);
-                }
-            }
+        public void addPendingTopUid(int uid, int pid) {
+                mPendingStartActivityUids.add(uid, pid);
+        }
 
+        @Override
+        public void deletePendingTopUid(int uid) {
+            mPendingStartActivityUids.delete(uid);
         }
 
         @Override
         public boolean isPendingTopUid(int uid) {
-            synchronized (mPendingStartActivityUidsLocked) {
-                return mPendingStartActivityUidsLocked.isPendingTopUid(uid);
-            }
+            return mPendingStartActivityUids.isPendingTopUid(uid);
         }
     }
 
diff --git a/services/core/java/com/android/server/am/OomAdjuster.java b/services/core/java/com/android/server/am/OomAdjuster.java
index 14c5b2cb..58b0a15 100644
--- a/services/core/java/com/android/server/am/OomAdjuster.java
+++ b/services/core/java/com/android/server/am/OomAdjuster.java
@@ -951,7 +951,7 @@
                     mService.mServices.foregroundServiceProcStateChangedLocked(uidRec);
                 }
             }
-            mService.mInternal.updatePendingTopUid(uidRec.uid, false);
+            mService.mInternal.deletePendingTopUid(uidRec.uid);
         }
         if (mLocalPowerManager != null) {
             mLocalPowerManager.finishUidChanges();
@@ -1151,8 +1151,17 @@
             // is currently showing UI.
             app.systemNoUi = true;
             if (app == topApp) {
+                // If specific system app has set ProcessRecord.mHasTopUi or is running a remote
+                // animation (ProcessRecord.runningRemoteAnimation), this will prevent topApp
+                // to use SCHED_GROUP_TOP_APP to ensure process with mHasTopUi will have exclusive
+                // access to configured cores.
+                if (mService.containsTopUiOrRunningRemoteAnimOrEmptyLocked(app)) {
+                    app.setCurrentSchedulingGroup(ProcessList.SCHED_GROUP_TOP_APP);
+                } else {
+                    app.setCurrentSchedulingGroup(ProcessList.SCHED_GROUP_DEFAULT);
+                }
                 app.systemNoUi = false;
-                app.setCurrentSchedulingGroup(ProcessList.SCHED_GROUP_TOP_APP);
+
                 app.adjType = "pers-top-activity";
             } else if (app.hasTopUi()) {
                 // sched group/proc state adjustment is below
@@ -1193,10 +1202,20 @@
 
         boolean foregroundActivities = false;
         if (PROCESS_STATE_CUR_TOP == PROCESS_STATE_TOP && app == topApp) {
-            // The last app on the list is the foreground app.
-            adj = ProcessList.FOREGROUND_APP_ADJ;
-            schedGroup = ProcessList.SCHED_GROUP_TOP_APP;
-            app.adjType = "top-activity";
+
+            // If specific system app has set ProcessRecord.mHasTopUi or is running a remote
+            // animation (ProcessRecord.runningRemoteAnimation), this will prevent topApp
+            // to use SCHED_GROUP_TOP_APP to ensure process with mHasTopUi will have exclusive
+            // access to configured cores.
+            if (mService.containsTopUiOrRunningRemoteAnimOrEmptyLocked(app)) {
+                adj = ProcessList.FOREGROUND_APP_ADJ;
+                schedGroup = ProcessList.SCHED_GROUP_TOP_APP;
+                app.adjType = "top-activity";
+            } else {
+                adj = ProcessList.FOREGROUND_APP_ADJ;
+                schedGroup = ProcessList.SCHED_GROUP_DEFAULT;
+                app.adjType = "top-activity-behind-topui";
+            }
             foregroundActivities = true;
             procState = PROCESS_STATE_CUR_TOP;
             if (DEBUG_OOM_ADJ_REASON || logUid == appUid) {
@@ -1508,16 +1527,7 @@
                     capabilityFromFGS |=
                             (fgsType & FOREGROUND_SERVICE_TYPE_LOCATION)
                                     != 0 ? PROCESS_CAPABILITY_FOREGROUND_LOCATION : 0;
-                } else {
-                    //The FGS has the location capability, but due to FGS BG start restriction it
-                    //lost the capability, use temp location capability to mark this case.
-                    //TODO: remove this block when development is done.
-                    capabilityFromFGS |=
-                            (fgsType & FOREGROUND_SERVICE_TYPE_LOCATION) != 0
-                                    ? ActivityManager.DEBUG_PROCESS_CAPABILITY_FOREGROUND_LOCATION
-                                    : 0;
-                }
-                if (s.mAllowWhileInUsePermissionInFgs) {
+
                     boolean enabled = false;
                     try {
                         enabled = mPlatformCompat.isChangeEnabled(
@@ -1527,23 +1537,13 @@
                     if (enabled) {
                         capabilityFromFGS |=
                                 (fgsType & FOREGROUND_SERVICE_TYPE_CAMERA)
-                                        != 0 ? PROCESS_CAPABILITY_FOREGROUND_CAMERA
-                                        : ActivityManager.DEBUG_PROCESS_CAPABILITY_FOREGROUND_CAMERA;
+                                        != 0 ? PROCESS_CAPABILITY_FOREGROUND_CAMERA : 0;
                         capabilityFromFGS |=
                                 (fgsType & FOREGROUND_SERVICE_TYPE_MICROPHONE)
-                                        != 0 ? PROCESS_CAPABILITY_FOREGROUND_MICROPHONE
-                                        : ActivityManager.DEBUG_PROCESS_CAPABILITY_FOREGROUND_MICROPHONE;
+                                        != 0 ? PROCESS_CAPABILITY_FOREGROUND_MICROPHONE : 0;
                     } else {
-                        // Remove fgsType check and assign PROCESS_CAPABILITY_FOREGROUND_CAMERA
-                        // and MICROPHONE when finish debugging.
-                        capabilityFromFGS |=
-                                (fgsType & FOREGROUND_SERVICE_TYPE_CAMERA)
-                                        != 0 ? PROCESS_CAPABILITY_FOREGROUND_CAMERA
-                                        : ActivityManager.DEBUG_PROCESS_CAPABILITY_FOREGROUND_CAMERA_Q;
-                        capabilityFromFGS |=
-                                (fgsType & FOREGROUND_SERVICE_TYPE_MICROPHONE)
-                                        != 0 ? PROCESS_CAPABILITY_FOREGROUND_MICROPHONE
-                                        : ActivityManager.DEBUG_PROCESS_CAPABILITY_FOREGROUND_MICROPHONE_Q;
+                        capabilityFromFGS |= PROCESS_CAPABILITY_FOREGROUND_CAMERA
+                                | PROCESS_CAPABILITY_FOREGROUND_MICROPHONE;
                     }
                 }
             }
diff --git a/services/core/java/com/android/server/am/PendingStartActivityUids.java b/services/core/java/com/android/server/am/PendingStartActivityUids.java
new file mode 100644
index 0000000..6bf9d4e
--- /dev/null
+++ b/services/core/java/com/android/server/am/PendingStartActivityUids.java
@@ -0,0 +1,78 @@
+/*
+ * Copyright (C) 2020 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.am;
+
+import android.content.Context;
+import android.os.SystemClock;
+import android.util.Pair;
+import android.util.Slog;
+import android.util.SparseArray;
+
+/**
+ * While starting activity, WindowManager posts a runnable to DisplayThread to updateOomAdj.
+ * The latency of the thread switch could cause client app failure when the app is checking
+ * {@link ActivityManagerService#isUidActive} before updateOomAdj is done.
+ *
+ * Use PendingStartActivityUids to save uid after WindowManager start activity and before
+ * updateOomAdj is done.
+ *
+ * <p>NOTE: This object is protected by its own lock, NOT the global activity manager lock!
+ */
+final class PendingStartActivityUids {
+    static final String TAG = ActivityManagerService.TAG;
+
+    // Key is uid, value is Pair of pid and SystemClock.elapsedRealtime() when the
+    // uid is added.
+    private final SparseArray<Pair<Integer, Long>> mPendingUids = new SparseArray();
+    private Context mContext;
+
+    PendingStartActivityUids(Context context) {
+        mContext = context;
+    }
+
+    synchronized void add(int uid, int pid) {
+        if (mPendingUids.get(uid) == null) {
+            mPendingUids.put(uid, new Pair<>(pid, SystemClock.elapsedRealtime()));
+        }
+    }
+
+    synchronized void delete(int uid) {
+        final Pair<Integer, Long> pendingPid = mPendingUids.get(uid);
+        if (pendingPid != null) {
+            final long delay = SystemClock.elapsedRealtime() - pendingPid.second;
+            if (delay >= 1000 /*ms*/) {
+                Slog.i(TAG,
+                        "PendingStartActivityUids startActivity to updateOomAdj delay:"
+                                + delay + "ms," + " uid:" + uid);
+            }
+            mPendingUids.delete(uid);
+        }
+    }
+
+    synchronized boolean isPendingTopPid(int uid, int pid) {
+        final Pair<Integer, Long> pendingPid = mPendingUids.get(uid);
+        if (pendingPid != null) {
+            return pendingPid.first == pid;
+        } else {
+            return false;
+        }
+    }
+
+    synchronized boolean isPendingTopUid(int uid) {
+        return mPendingUids.get(uid) != null;
+    }
+}
\ No newline at end of file
diff --git a/services/core/java/com/android/server/am/ProcessRecord.java b/services/core/java/com/android/server/am/ProcessRecord.java
index c5152c0..4c75ab2 100644
--- a/services/core/java/com/android/server/am/ProcessRecord.java
+++ b/services/core/java/com/android/server/am/ProcessRecord.java
@@ -1268,6 +1268,7 @@
     void setHasTopUi(boolean hasTopUi) {
         mHasTopUi = hasTopUi;
         mWindowProcessController.setHasTopUi(hasTopUi);
+        updateTopUiOrRunningRemoteAnim();
     }
 
     boolean hasTopUi() {
@@ -1518,10 +1519,19 @@
                 Slog.i(TAG, "Setting runningRemoteAnimation=" + runningRemoteAnimation
                         + " for pid=" + pid);
             }
+            updateTopUiOrRunningRemoteAnim();
             mService.updateOomAdjLocked(this, true, OomAdjuster.OOM_ADJ_REASON_UI_VISIBILITY);
         }
     }
 
+    void updateTopUiOrRunningRemoteAnim() {
+        if (runningRemoteAnimation || hasTopUi()) {
+            mService.addTopUiOrRunningRemoteAnim(this);
+        } else {
+            mService.removeTopUiOrRunningRemoteAnim(this);
+        }
+    }
+
     public long getInputDispatchingTimeout() {
         return mWindowProcessController.getInputDispatchingTimeout();
     }
diff --git a/services/core/java/com/android/server/am/ServiceRecord.java b/services/core/java/com/android/server/am/ServiceRecord.java
index 4670d58..9c96e6e 100644
--- a/services/core/java/com/android/server/am/ServiceRecord.java
+++ b/services/core/java/com/android/server/am/ServiceRecord.java
@@ -138,10 +138,7 @@
     // allow while-in-use permissions in foreground service or not.
     // while-in-use permissions in FGS started from background might be restricted.
     boolean mAllowWhileInUsePermissionInFgs;
-    // information string what/why service is denied while-in-use permissions when
-    // foreground service is started from background.
-    // TODO: remove this field after feature development is done
-    String mInfoDenyWhileInUsePermissionInFgs;
+
     // the most recent package that start/bind this service.
     String mRecentCallingPackage;
 
diff --git a/services/core/java/com/android/server/am/UserController.java b/services/core/java/com/android/server/am/UserController.java
index ea70598..f2c4e44 100644
--- a/services/core/java/com/android/server/am/UserController.java
+++ b/services/core/java/com/android/server/am/UserController.java
@@ -2515,7 +2515,7 @@
                 showUserSwitchDialog(fromToUserPair);
                 break;
             case CLEAR_USER_JOURNEY_SESSION_MSG:
-                clearSessionId(msg.arg1);
+                logAndClearSessionId(msg.arg1);
                 break;
         }
         return false;
@@ -2630,6 +2630,21 @@
     }
 
     /**
+     * Log a final event of the {@link UserJourneySession} and clear it.
+     */
+    private void logAndClearSessionId(@UserIdInt int userId) {
+        synchronized (mUserIdToUserJourneyMap) {
+            final UserJourneySession userJourneySession = mUserIdToUserJourneyMap.get(userId);
+            if (userJourneySession != null) {
+                FrameworkStatsLog.write(FrameworkStatsLog.USER_LIFECYCLE_EVENT_OCCURRED,
+                        userJourneySession.mSessionId, userId, USER_LIFECYCLE_EVENT_UNKNOWN,
+                        USER_LIFECYCLE_EVENT_STATE_NONE);
+            }
+            clearSessionId(userId);
+        }
+    }
+
+    /**
      * Helper class to store user journey and session id.
      *
      * <p> User journey tracks a chain of user lifecycle events occurring during different user
diff --git a/services/core/java/com/android/server/appop/AppOpsService.java b/services/core/java/com/android/server/appop/AppOpsService.java
index 9f27146..73c98da 100644
--- a/services/core/java/com/android/server/appop/AppOpsService.java
+++ b/services/core/java/com/android/server/appop/AppOpsService.java
@@ -16,11 +16,6 @@
 
 package com.android.server.appop;
 
-import static android.app.ActivityManager.DEBUG_PROCESS_CAPABILITY_FOREGROUND_CAMERA;
-import static android.app.ActivityManager.DEBUG_PROCESS_CAPABILITY_FOREGROUND_CAMERA_Q;
-import static android.app.ActivityManager.DEBUG_PROCESS_CAPABILITY_FOREGROUND_LOCATION;
-import static android.app.ActivityManager.DEBUG_PROCESS_CAPABILITY_FOREGROUND_MICROPHONE;
-import static android.app.ActivityManager.DEBUG_PROCESS_CAPABILITY_FOREGROUND_MICROPHONE_Q;
 import static android.app.ActivityManager.PROCESS_CAPABILITY_FOREGROUND_CAMERA;
 import static android.app.ActivityManager.PROCESS_CAPABILITY_FOREGROUND_LOCATION;
 import static android.app.ActivityManager.PROCESS_CAPABILITY_FOREGROUND_MICROPHONE;
@@ -520,9 +515,6 @@
         public SparseBooleanArray foregroundOps;
         public boolean hasForegroundWatchers;
 
-        public long lastTimeShowDebugToast;
-        public long lastTimePendingTopUid;
-
         public UidState(int uid) {
             this.uid = uid;
         }
@@ -545,7 +537,6 @@
                     return MODE_ALLOWED;
                 } else if (mActivityManagerInternal != null
                         && mActivityManagerInternal.isPendingTopUid(uid)) {
-                    maybeLogPendingTopUid(op, mode);
                     return MODE_ALLOWED;
                 } else if (state <= UID_STATE_TOP) {
                     // process is in TOP.
@@ -559,44 +550,19 @@
                         case AppOpsManager.OP_MONITOR_HIGH_POWER_LOCATION:
                             if ((capability & PROCESS_CAPABILITY_FOREGROUND_LOCATION) != 0) {
                                 return MODE_ALLOWED;
-                            } else if ((capability
-                                    & DEBUG_PROCESS_CAPABILITY_FOREGROUND_LOCATION) != 0) {
-                                // The FGS has the location capability, but due to FGS BG start
-                                // restriction it lost the capability, use temp location capability
-                                // to mark this case.
-                                maybeShowWhileInUseDebugToast(op, DEBUG_FGS_ALLOW_WHILE_IN_USE);
-                                return MODE_IGNORED;
                             } else {
                                 return MODE_IGNORED;
                             }
                         case OP_CAMERA:
                             if ((capability & PROCESS_CAPABILITY_FOREGROUND_CAMERA) != 0) {
                                 return MODE_ALLOWED;
-                            } else if ((capability & DEBUG_PROCESS_CAPABILITY_FOREGROUND_CAMERA_Q)
-                                    != 0) {
-                                maybeShowWhileInUseDebugToast(op, DEBUG_FGS_ENFORCE_TYPE);
-                                return MODE_ALLOWED;
-                            } else if ((capability & DEBUG_PROCESS_CAPABILITY_FOREGROUND_CAMERA)
-                                    != 0) {
-                                maybeShowWhileInUseDebugToast(op, DEBUG_FGS_ENFORCE_TYPE);
-                                return MODE_IGNORED;
                             } else {
-                                maybeShowWhileInUseDebugToast(op, DEBUG_FGS_ALLOW_WHILE_IN_USE);
                                 return MODE_IGNORED;
                             }
                         case OP_RECORD_AUDIO:
                             if ((capability & PROCESS_CAPABILITY_FOREGROUND_MICROPHONE) != 0) {
                                 return MODE_ALLOWED;
-                            } else if ((capability
-                                    & DEBUG_PROCESS_CAPABILITY_FOREGROUND_MICROPHONE_Q) != 0) {
-                                maybeShowWhileInUseDebugToast(op, DEBUG_FGS_ENFORCE_TYPE);
-                                return MODE_ALLOWED;
-                            } else if  ((capability
-                                    & DEBUG_PROCESS_CAPABILITY_FOREGROUND_MICROPHONE) != 0) {
-                                maybeShowWhileInUseDebugToast(op, DEBUG_FGS_ENFORCE_TYPE);
-                                return MODE_IGNORED;
                             } else {
-                                maybeShowWhileInUseDebugToast(op, DEBUG_FGS_ALLOW_WHILE_IN_USE);
                                 return MODE_IGNORED;
                             }
                         default:
@@ -611,38 +577,19 @@
                     case OP_CAMERA:
                         if (mActivityManagerInternal != null
                                 && mActivityManagerInternal.isPendingTopUid(uid)) {
-                            maybeLogPendingTopUid(op, mode);
                             return MODE_ALLOWED;
                         } else if ((capability & PROCESS_CAPABILITY_FOREGROUND_CAMERA) != 0) {
                             return MODE_ALLOWED;
-                        } else if ((capability
-                                & DEBUG_PROCESS_CAPABILITY_FOREGROUND_CAMERA_Q) != 0) {
-                            maybeShowWhileInUseDebugToast(op, DEBUG_FGS_ENFORCE_TYPE);
-                            return MODE_ALLOWED;
-                        } else if ((capability & DEBUG_PROCESS_CAPABILITY_FOREGROUND_CAMERA) != 0) {
-                            maybeShowWhileInUseDebugToast(op, DEBUG_FGS_ENFORCE_TYPE);
-                            return MODE_IGNORED;
                         } else {
-                            maybeShowWhileInUseDebugToast(op, DEBUG_FGS_ALLOW_WHILE_IN_USE);
                             return MODE_IGNORED;
                         }
                     case OP_RECORD_AUDIO:
                         if (mActivityManagerInternal != null
                                 && mActivityManagerInternal.isPendingTopUid(uid)) {
-                            maybeLogPendingTopUid(op, mode);
                             return MODE_ALLOWED;
                         } else if ((capability & PROCESS_CAPABILITY_FOREGROUND_MICROPHONE) != 0) {
                             return MODE_ALLOWED;
-                        } else if ((capability & DEBUG_PROCESS_CAPABILITY_FOREGROUND_MICROPHONE_Q)
-                                != 0) {
-                            maybeShowWhileInUseDebugToast(op, DEBUG_FGS_ENFORCE_TYPE);
-                            return MODE_ALLOWED;
-                        } else if ((capability & DEBUG_PROCESS_CAPABILITY_FOREGROUND_MICROPHONE)
-                                != 0) {
-                            maybeShowWhileInUseDebugToast(op, DEBUG_FGS_ENFORCE_TYPE);
-                            return MODE_IGNORED;
                         } else {
-                            maybeShowWhileInUseDebugToast(op, DEBUG_FGS_ALLOW_WHILE_IN_USE);
                             return MODE_IGNORED;
                         }
                     default:
@@ -696,40 +643,6 @@
             }
             foregroundOps = which;
         }
-
-        // TODO: remove this toast after feature development is done
-        // For DEBUG_FGS_ALLOW_WHILE_IN_USE, if the procstate is foreground service and while-in-use
-        // permission is denied, show a toast message and generate a WTF log so we know
-        // how many apps are impacted by the new background started foreground service while-in-use
-        // permission restriction.
-        // For DEBUG_FGS_ENFORCE_TYPE, The process has a foreground service that does not have
-        // camera/microphone foregroundServiceType in manifest file, and the process is asking
-        // AppOps for camera/microphone ops, show a toast message and generate a WTF log.
-        void maybeShowWhileInUseDebugToast(int op, int mode) {
-            if (mode == DEBUG_FGS_ALLOW_WHILE_IN_USE && state != UID_STATE_FOREGROUND_SERVICE) {
-                return;
-            }
-            final long now = System.currentTimeMillis();
-            if (lastTimeShowDebugToast == 0 ||  now - lastTimeShowDebugToast > 600000) {
-                lastTimeShowDebugToast = now;
-                mHandler.sendMessage(PooledLambda.obtainMessage(
-                        ActivityManagerInternal::showWhileInUseDebugToast,
-                        mActivityManagerInternal, uid, op, mode));
-            }
-        }
-
-
-        void maybeLogPendingTopUid(int op, int mode) {
-            final long now = System.currentTimeMillis();
-            if (lastTimePendingTopUid == 0 ||  now - lastTimePendingTopUid > 300000) {
-                lastTimePendingTopUid = now;
-                Slog.wtf(TAG, "PendingStartActivityUids evalMode, isPendingTopUid true, uid:"
-                        + uid
-                        + " packageName:" + Settings.getPackageNameForUid(mContext, uid)
-                        + " op:" + op
-                        + " mode:" + mode);
-            }
-        }
     }
 
     final static class Ops extends SparseArray<Op> {
@@ -6052,7 +5965,7 @@
         List<String> runtimeAppOpsList = getRuntimeAppOpsList();
         AppOpsManager.HistoricalOpsRequest histOpsRequest =
                 new AppOpsManager.HistoricalOpsRequest.Builder(
-                        Instant.now().minus(7, ChronoUnit.DAYS).toEpochMilli(),
+                        Math.max(Instant.now().minus(7, ChronoUnit.DAYS).toEpochMilli(), 0),
                         Long.MAX_VALUE).setOpNames(runtimeAppOpsList).setFlags(
                         OP_FLAG_SELF | OP_FLAG_TRUSTED_PROXIED).build();
         appOps.getHistoricalOps(histOpsRequest, AsyncTask.THREAD_POOL_EXECUTOR,
diff --git a/services/core/java/com/android/server/audio/AudioDeviceBroker.java b/services/core/java/com/android/server/audio/AudioDeviceBroker.java
index 5c6b481..45f95fd 100644
--- a/services/core/java/com/android/server/audio/AudioDeviceBroker.java
+++ b/services/core/java/com/android/server/audio/AudioDeviceBroker.java
@@ -38,6 +38,7 @@
 import android.os.PowerManager;
 import android.os.RemoteException;
 import android.os.SystemClock;
+import android.text.TextUtils;
 import android.util.Log;
 import android.util.PrintWriterPrinter;
 
@@ -329,11 +330,13 @@
         final BtDeviceConnectionInfo info = new BtDeviceConnectionInfo(device, state, profile,
                 suppressNoisyIntent, a2dpVolume);
 
+        final String name = TextUtils.emptyIfNull(device.getName());
         new MediaMetrics.Item(MediaMetrics.Name.AUDIO_DEVICE + MediaMetrics.SEPARATOR
                 + "postBluetoothA2dpDeviceConnectionStateSuppressNoisyIntent")
                 .set(MediaMetrics.Property.STATE, state == BluetoothProfile.STATE_CONNECTED
                         ? MediaMetrics.Value.CONNECTED : MediaMetrics.Value.DISCONNECTED)
                 .set(MediaMetrics.Property.INDEX, a2dpVolume)
+                .set(MediaMetrics.Property.NAME, name)
                 .record();
 
         // operations of removing and posting messages related to A2DP device state change must be
diff --git a/services/core/java/com/android/server/audio/AudioService.java b/services/core/java/com/android/server/audio/AudioService.java
index 27d9ba0..3627227 100755
--- a/services/core/java/com/android/server/audio/AudioService.java
+++ b/services/core/java/com/android/server/audio/AudioService.java
@@ -1893,7 +1893,7 @@
                             Binder.getCallingUid(), true, keyEventMode);
                 break;
             case KeyEvent.KEYCODE_VOLUME_MUTE:
-                if (event.getRepeatCount() == 0) {
+                if (event.getAction() == KeyEvent.ACTION_DOWN && event.getRepeatCount() == 0) {
                     adjustSuggestedStreamVolume(AudioManager.ADJUST_TOGGLE_MUTE,
                             AudioManager.USE_DEFAULT_STREAM_TYPE, flags, callingPackage, caller,
                             Binder.getCallingUid(), true, VOL_ADJUST_NORMAL);
@@ -2155,7 +2155,8 @@
         }
         int oldIndex = mStreamStates[streamType].getIndex(device);
 
-        if (adjustVolume && (direction != AudioManager.ADJUST_SAME)) {
+        if (adjustVolume
+                && (direction != AudioManager.ADJUST_SAME) && (keyEventMode != VOL_ADJUST_END)) {
             mAudioHandler.removeMessages(MSG_UNMUTE_STREAM);
 
             if (isMuteAdjust) {
@@ -2238,6 +2239,11 @@
             if (streamTypeAlias == AudioSystem.STREAM_MUSIC) {
                 setSystemAudioVolume(oldIndex, newIndex, getStreamMaxVolume(streamType), flags);
             }
+        }
+
+        final int newIndex = mStreamStates[streamType].getIndex(device);
+
+        if (adjustVolume) {
             synchronized (mHdmiClientLock) {
                 if (mHdmiManager != null) {
                     // mHdmiCecSink true => mHdmiPlaybackClient != null
@@ -2290,8 +2296,7 @@
                 }
             }
         }
-        int index = mStreamStates[streamType].getIndex(device);
-        sendVolumeUpdate(streamType, oldIndex, index, flags, device);
+        sendVolumeUpdate(streamType, oldIndex, newIndex, flags, device);
     }
 
     // Called after a delay when volume down is pressed while muted
@@ -5317,6 +5322,15 @@
         }
 
         private void setVolumeIndexInt(int index, int device, int flags) {
+            // Reflect mute state of corresponding stream by forcing index to 0 if muted
+            // Only set audio policy BT SCO stream volume to 0 when the stream is actually muted.
+            // This allows RX path muting by the audio HAL only when explicitly muted but not when
+            // index is just set to 0 to repect BT requirements
+            if (mStreamStates[mPublicStreamType].isFullyMuted()) {
+                index = 0;
+            } else if (mPublicStreamType == AudioSystem.STREAM_BLUETOOTH_SCO && index == 0) {
+                index = 1;
+            }
             // Set the volume index
             AudioSystem.setVolumeIndexForAttributes(mAudioAttributes, index, device);
         }
diff --git a/services/core/java/com/android/server/compat/PlatformCompat.java b/services/core/java/com/android/server/compat/PlatformCompat.java
index 8ed864c..d7e9499 100644
--- a/services/core/java/com/android/server/compat/PlatformCompat.java
+++ b/services/core/java/com/android/server/compat/PlatformCompat.java
@@ -102,6 +102,13 @@
     @Override
     public boolean isChangeEnabled(long changeId, ApplicationInfo appInfo) {
         checkCompatChangeReadAndLogPermission();
+        return isChangeEnabledInternal(changeId, appInfo);
+    }
+
+    /**
+     * Internal version of the above method. Does not perform costly permission check.
+     */
+    public boolean isChangeEnabledInternal(long changeId, ApplicationInfo appInfo) {
         if (mCompatConfig.isChangeEnabled(changeId, appInfo)) {
             reportChange(changeId, appInfo.uid,
                     ChangeReporter.STATE_ENABLED);
diff --git a/services/core/java/com/android/server/display/BrightnessMappingStrategy.java b/services/core/java/com/android/server/display/BrightnessMappingStrategy.java
index 787f7f3..6f12155 100644
--- a/services/core/java/com/android/server/display/BrightnessMappingStrategy.java
+++ b/services/core/java/com/android/server/display/BrightnessMappingStrategy.java
@@ -28,6 +28,7 @@
 import android.util.Slog;
 import android.util.Spline;
 
+import com.android.internal.BrightnessSynchronizer;
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.util.Preconditions;
 import com.android.server.display.utils.Plog;
@@ -348,9 +349,9 @@
 
     // Normalize entire brightness range to 0 - 1.
     protected static float normalizeAbsoluteBrightness(int brightness) {
-        brightness = MathUtils.constrain(brightness,
-                PowerManager.BRIGHTNESS_OFF, PowerManager.BRIGHTNESS_ON);
-        return (float) brightness / PowerManager.BRIGHTNESS_ON;
+        return BrightnessSynchronizer.brightnessIntToFloat(brightness,
+                PowerManager.BRIGHTNESS_OFF + 1, PowerManager.BRIGHTNESS_ON,
+                PowerManager.BRIGHTNESS_MIN, PowerManager.BRIGHTNESS_MAX);
     }
 
     private Pair<float[], float[]> insertControlPoint(
diff --git a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
index a498e38..65a1301 100644
--- a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
+++ b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
@@ -2352,6 +2352,16 @@
         mImeTargetWindowMap.put(startInputToken, mCurFocusedWindow);
         mStartInputHistory.addEntry(info);
 
+        // Seems that PackageManagerInternal#grantImplicitAccess() doesn't handle cross-user
+        // implicit visibility (e.g. IME[user=10] -> App[user=0]) thus we do this only for the
+        // same-user scenarios.
+        // That said ignoring cross-user scenario will never affect IMEs that do not have
+        // INTERACT_ACROSS_USERS(_FULL) permissions, which is actually almost always the case.
+        if (mSettings.getCurrentUserId() == UserHandle.getUserId(mCurClient.uid)) {
+            mPackageManagerInternal.grantImplicitAccess(mSettings.getCurrentUserId(),
+                    null /* intent */, UserHandle.getAppId(mCurMethodUid), mCurClient.uid, true);
+        }
+
         final SessionState session = mCurClient.curSession;
         executeOrSendMessage(session.method, mCaller.obtainMessageIIOOOO(
                 MSG_START_INPUT, mCurInputContextMissingMethods, initial ? 0 : 1 /* restarting */,
diff --git a/services/core/java/com/android/server/inputmethod/MultiClientInputMethodManagerService.java b/services/core/java/com/android/server/inputmethod/MultiClientInputMethodManagerService.java
index 2129e9b..6c415ca 100644
--- a/services/core/java/com/android/server/inputmethod/MultiClientInputMethodManagerService.java
+++ b/services/core/java/com/android/server/inputmethod/MultiClientInputMethodManagerService.java
@@ -1347,13 +1347,14 @@
                 for (WindowInfo windowInfo : clientInfo.mWindowMap.values()) {
                     if (windowInfo.mWindowHandle == targetWindowHandle) {
                         final IBinder targetWindowToken = windowInfo.mWindowToken;
-                        // TODO(yukawa): Report targetWindowToken and targetWindowToken to WMS.
                         if (DEBUG) {
                             Slog.v(TAG, "reportImeWindowTarget"
                                     + " clientId=" + clientId
                                     + " imeWindowToken=" + imeWindowToken
                                     + " targetWindowToken=" + targetWindowToken);
                         }
+                        mIWindowManagerInternal.updateInputMethodTargetWindow(
+                                imeWindowToken, targetWindowToken);
                     }
                 }
                 // not found.
@@ -1490,6 +1491,9 @@
                     case InputMethodClientState.ALREADY_SENT_BIND_RESULT:
                         try {
                             clientInfo.mMSInputMethodSession.showSoftInput(flags, resultReceiver);
+
+                            // Forcing WM to show IME on imeTargetWindow
+                            mWindowManagerInternal.showImePostLayout(token);
                         } catch (RemoteException e) {
                         }
                         break;
diff --git a/services/core/java/com/android/server/location/LocationManagerService.java b/services/core/java/com/android/server/location/LocationManagerService.java
index 067bdcb..bfcbe46 100644
--- a/services/core/java/com/android/server/location/LocationManagerService.java
+++ b/services/core/java/com/android/server/location/LocationManagerService.java
@@ -231,7 +231,7 @@
     private final AppForegroundHelper mAppForegroundHelper;
     private final LocationUsageLogger mLocationUsageLogger;
 
-    @Nullable private GnssManagerService mGnssManagerService = null;
+    @Nullable private volatile GnssManagerService mGnssManagerService = null;
 
     private final PassiveLocationProviderManager mPassiveManager;
 
@@ -381,6 +381,10 @@
             // prepare providers
             initializeProvidersLocked();
         }
+
+        // initialize gnss last because it has no awareness of boot phases and blindly assumes that
+        // all other location providers are loaded at initialization
+        initializeGnss();
     }
 
     private void onAppOpChanged(String packageName) {
@@ -602,16 +606,19 @@
             }
             manager.setMockProvider(new MockProvider(properties));
         }
+    }
 
-        // initialize gnss last because it has no awareness of boot phases and blindly assumes that
-        // all other location providers are loaded at initialization
+    private void initializeGnss() {
+        // Do not hold mLock when calling GnssManagerService#isGnssSupported() which calls into HAL.
         if (GnssManagerService.isGnssSupported()) {
             mGnssManagerService = new GnssManagerService(mContext, mAppOpsHelper, mSettingsHelper,
                     mAppForegroundHelper, mLocationUsageLogger);
             mGnssManagerService.onSystemReady();
 
             LocationProviderManager gnssManager = new LocationProviderManager(GPS_PROVIDER);
-            mProviderManagers.add(gnssManager);
+            synchronized (mLock) {
+                mProviderManagers.add(gnssManager);
+            }
             gnssManager.setRealProvider(mGnssManagerService.getGnssLocationProvider());
 
             // bind to geofence proxy
diff --git a/services/core/java/com/android/server/location/SettingsHelper.java b/services/core/java/com/android/server/location/SettingsHelper.java
index cbb06b8..8a35302 100644
--- a/services/core/java/com/android/server/location/SettingsHelper.java
+++ b/services/core/java/com/android/server/location/SettingsHelper.java
@@ -168,7 +168,7 @@
      * Remove a listener for changes to the location enabled setting.
      */
     public void removeOnLocationEnabledChangedListener(UserSettingChangedListener listener) {
-        mLocationMode.addListener(listener);
+        mLocationMode.removeListener(listener);
     }
 
     /**
diff --git a/services/core/java/com/android/server/locksettings/ManagedProfilePasswordCache.java b/services/core/java/com/android/server/locksettings/ManagedProfilePasswordCache.java
index d38ee67..7950fcf 100644
--- a/services/core/java/com/android/server/locksettings/ManagedProfilePasswordCache.java
+++ b/services/core/java/com/android/server/locksettings/ManagedProfilePasswordCache.java
@@ -104,8 +104,6 @@
                         // Generate auth-bound key to user 0 (since we the caller is user 0)
                         .setUserAuthenticationRequired(true)
                         .setUserAuthenticationValidityDurationSeconds(CACHE_TIMEOUT_SECONDS)
-                        // Only accessible after user 0's keyguard is unlocked
-                        .setUnlockedDeviceRequired(true)
                         .build());
                 key = generator.generateKey();
             } catch (GeneralSecurityException e) {
@@ -171,10 +169,14 @@
     public void removePassword(int userId) {
         synchronized (mEncryptedPasswords) {
             String keyName = getEncryptionKeyName(userId);
+            String legacyKeyName = getLegacyEncryptionKeyName(userId);
             try {
                 if (mKeyStore.containsAlias(keyName)) {
                     mKeyStore.deleteEntry(keyName);
                 }
+                if (mKeyStore.containsAlias(legacyKeyName)) {
+                    mKeyStore.deleteEntry(legacyKeyName);
+                }
             } catch (KeyStoreException e) {
                 Slog.d(TAG, "Cannot delete key", e);
             }
@@ -186,6 +188,14 @@
     }
 
     private static String getEncryptionKeyName(int userId) {
+        return "com.android.server.locksettings.unified_profile_cache_v2_" + userId;
+    }
+
+    /**
+     * Returns the legacy keystore key name when setUnlockedDeviceRequired() was set explicitly.
+     * Only existed during Android 11 internal testing period.
+     */
+    private static String getLegacyEncryptionKeyName(int userId) {
         return "com.android.server.locksettings.unified_profile_cache_" + userId;
     }
 }
diff --git a/services/core/java/com/android/server/locksettings/RebootEscrowManager.java b/services/core/java/com/android/server/locksettings/RebootEscrowManager.java
index 8d4efed..5787f7c4 100644
--- a/services/core/java/com/android/server/locksettings/RebootEscrowManager.java
+++ b/services/core/java/com/android/server/locksettings/RebootEscrowManager.java
@@ -26,6 +26,7 @@
 import android.hardware.rebootescrow.IRebootEscrow;
 import android.os.RemoteException;
 import android.os.ServiceManager;
+import android.os.ServiceSpecificException;
 import android.os.SystemClock;
 import android.os.UserManager;
 import android.provider.Settings;
@@ -244,6 +245,9 @@
         } catch (RemoteException e) {
             Slog.w(TAG, "Could not retrieve escrow data");
             return null;
+        } catch (ServiceSpecificException e) {
+            Slog.w(TAG, "Got service-specific exception: " + e.errorCode);
+            return null;
         }
     }
 
@@ -335,7 +339,7 @@
 
         try {
             rebootEscrow.storeKey(new byte[32]);
-        } catch (RemoteException e) {
+        } catch (RemoteException | ServiceSpecificException e) {
             Slog.w(TAG, "Could not call RebootEscrow HAL to shred key");
         }
 
@@ -373,7 +377,7 @@
             rebootEscrow.storeKey(escrowKey.getKeyBytes());
             armedRebootEscrow = true;
             Slog.i(TAG, "Reboot escrow key stored with RebootEscrow HAL");
-        } catch (RemoteException e) {
+        } catch (RemoteException | ServiceSpecificException e) {
             Slog.e(TAG, "Failed escrow secret to RebootEscrow HAL", e);
         }
 
diff --git a/services/core/java/com/android/server/media/BluetoothRouteProvider.java b/services/core/java/com/android/server/media/BluetoothRouteProvider.java
index 2461b0c..c7575d4 100644
--- a/services/core/java/com/android/server/media/BluetoothRouteProvider.java
+++ b/services/core/java/com/android/server/media/BluetoothRouteProvider.java
@@ -48,6 +48,7 @@
 
 class BluetoothRouteProvider {
     private static final String TAG = "BTRouteProvider";
+    private static final String HEARING_AID_ROUTE_ID_PREFIX = "HEARING_AID_";
     private static BluetoothRouteProvider sInstance;
 
     @SuppressWarnings("WeakerAccess") /* synthetic access */
@@ -179,9 +180,16 @@
 
     @NonNull
     List<MediaRoute2Info> getAllBluetoothRoutes() {
-        ArrayList<MediaRoute2Info> routes = new ArrayList<>();
+        List<MediaRoute2Info> routes = new ArrayList<>();
+        List<String> routeIds = new ArrayList<>();
+
         for (BluetoothRouteInfo btRoute : mBluetoothRoutes.values()) {
+            // A pair of hearing aid devices or the same hardware address
+            if (routeIds.contains(btRoute.route.getId())) {
+                continue;
+            }
             routes.add(btRoute.route);
+            routeIds.add(btRoute.route.getId());
         }
         return routes;
     }
@@ -222,8 +230,8 @@
     private BluetoothRouteInfo createBluetoothRoute(BluetoothDevice device) {
         BluetoothRouteInfo newBtRoute = new BluetoothRouteInfo();
         newBtRoute.btDevice = device;
-        // Current volume will be set when connected.
-        // TODO: Is there any BT device which has fixed volume?
+
+        String routeId = device.getAddress();
         String deviceName = device.getName();
         if (TextUtils.isEmpty(deviceName)) {
             deviceName = mContext.getResources().getText(R.string.unknownName).toString();
@@ -236,10 +244,13 @@
         if (mHearingAidProfile != null
                 && mHearingAidProfile.getConnectedDevices().contains(device)) {
             newBtRoute.connectedProfiles.put(BluetoothProfile.HEARING_AID, true);
+            // Intentionally assign the same ID for a pair of devices to publish only one of them.
+            routeId = HEARING_AID_ROUTE_ID_PREFIX + mHearingAidProfile.getHiSyncId(device);
             type = MediaRoute2Info.TYPE_HEARING_AID;
         }
 
-        newBtRoute.route = new MediaRoute2Info.Builder(device.getAddress(), deviceName)
+        // Current volume will be set when connected.
+        newBtRoute.route = new MediaRoute2Info.Builder(routeId, deviceName)
                 .addFeature(MediaRoute2Info.FEATURE_LIVE_AUDIO)
                 .setConnectionState(MediaRoute2Info.CONNECTION_STATE_DISCONNECTED)
                 .setDescription(mContext.getResources().getText(
@@ -247,6 +258,7 @@
                 .setType(type)
                 .setVolumeHandling(MediaRoute2Info.PLAYBACK_VOLUME_VARIABLE)
                 .setVolumeMax(mAudioManager.getStreamMaxVolume(AudioManager.STREAM_MUSIC))
+                .setAddress(device.getAddress())
                 .build();
         return newBtRoute;
     }
diff --git a/services/core/java/com/android/server/media/MediaKeyDispatcher.java b/services/core/java/com/android/server/media/MediaKeyDispatcher.java
index 176ec3f..5933723 100644
--- a/services/core/java/com/android/server/media/MediaKeyDispatcher.java
+++ b/services/core/java/com/android/server/media/MediaKeyDispatcher.java
@@ -71,6 +71,9 @@
         mOverriddenKeyEvents.put(KeyEvent.KEYCODE_MEDIA_STOP, 0);
         mOverriddenKeyEvents.put(KeyEvent.KEYCODE_MEDIA_NEXT, 0);
         mOverriddenKeyEvents.put(KeyEvent.KEYCODE_MEDIA_PREVIOUS, 0);
+        mOverriddenKeyEvents.put(KeyEvent.KEYCODE_VOLUME_DOWN, 0);
+        mOverriddenKeyEvents.put(KeyEvent.KEYCODE_VOLUME_UP, 0);
+        mOverriddenKeyEvents.put(KeyEvent.KEYCODE_VOLUME_MUTE, 0);
     }
 
     // TODO: Move this method into SessionPolicyProvider.java for better readability.
@@ -126,6 +129,9 @@
      * <li> {@link KeyEvent#KEYCODE_MEDIA_STOP}
      * <li> {@link KeyEvent#KEYCODE_MEDIA_NEXT}
      * <li> {@link KeyEvent#KEYCODE_MEDIA_PREVIOUS}
+     * <li> {@link KeyEvent#KEYCODE_VOLUME_UP}
+     * <li> {@link KeyEvent#KEYCODE_VOLUME_DOWN}
+     * <li> {@link KeyEvent#KEYCODE_VOLUME_MUTE}
      * </ul>
      * @see {@link KeyEvent#isMediaSessionKey(int)}
      */
@@ -164,6 +170,9 @@
      * <li> {@link KeyEvent#KEYCODE_MEDIA_STOP}
      * <li> {@link KeyEvent#KEYCODE_MEDIA_NEXT}
      * <li> {@link KeyEvent#KEYCODE_MEDIA_PREVIOUS}
+     * <li> {@link KeyEvent#KEYCODE_VOLUME_DOWN}
+     * <li> {@link KeyEvent#KEYCODE_VOLUME_UP}
+     * <li> {@link KeyEvent#KEYCODE_VOLUME_MUTE}
      * </ul>
      * @see {@link KeyEvent#isMediaSessionKey(int)}
      * @param keyCode
diff --git a/services/core/java/com/android/server/media/MediaRouter2ServiceImpl.java b/services/core/java/com/android/server/media/MediaRouter2ServiceImpl.java
index 0e99715..93a27f2 100644
--- a/services/core/java/com/android/server/media/MediaRouter2ServiceImpl.java
+++ b/services/core/java/com/android/server/media/MediaRouter2ServiceImpl.java
@@ -567,7 +567,8 @@
             boolean hasModifyAudioRoutingPermission) {
         final IBinder binder = router.asBinder();
         if (mAllRouterRecords.get(binder) != null) {
-            Slog.w(TAG, "Same router already exists. packageName=" + packageName);
+            Slog.w(TAG, "registerRouter2Locked: Same router already exists. packageName="
+                    + packageName);
             return;
         }
 
@@ -597,6 +598,10 @@
 
         UserRecord userRecord = routerRecord.mUserRecord;
         userRecord.mRouterRecords.remove(routerRecord);
+        routerRecord.mUserRecord.mHandler.sendMessage(
+                obtainMessage(UserHandler::notifyPreferredFeaturesChangedToManagers,
+                        routerRecord.mUserRecord.mHandler,
+                        routerRecord.mPackageName, /* preferredFeatures=*/ null));
         userRecord.mHandler.sendMessage(
                 obtainMessage(UserHandler::updateDiscoveryPreferenceOnHandler,
                         userRecord.mHandler));
@@ -612,7 +617,9 @@
         routerRecord.mDiscoveryPreference = discoveryRequest;
         routerRecord.mUserRecord.mHandler.sendMessage(
                 obtainMessage(UserHandler::notifyPreferredFeaturesChangedToManagers,
-                        routerRecord.mUserRecord.mHandler, routerRecord));
+                        routerRecord.mUserRecord.mHandler,
+                        routerRecord.mPackageName,
+                        routerRecord.mDiscoveryPreference.getPreferredFeatures()));
         routerRecord.mUserRecord.mHandler.sendMessage(
                 obtainMessage(UserHandler::updateDiscoveryPreferenceOnHandler,
                         routerRecord.mUserRecord.mHandler));
@@ -665,8 +672,7 @@
         final RouterRecord routerRecord = mAllRouterRecords.get(binder);
 
         if (routerRecord == null) {
-            Slog.w(TAG, "requestCreateSessionWithRouter2ByManagerRequestLocked: "
-                    + "Ignoring unknown router.");
+            Slog.w(TAG, "notifySessionHintsForCreatingSessionLocked: Ignoring unknown router.");
             return;
         }
 
@@ -789,7 +795,8 @@
         ManagerRecord managerRecord = mAllManagerRecords.get(binder);
 
         if (managerRecord != null) {
-            Slog.w(TAG, "Same manager already exists. packageName=" + packageName);
+            Slog.w(TAG, "registerManagerLocked: Same manager already exists. packageName="
+                    + packageName);
             return;
         }
 
@@ -854,7 +861,8 @@
 
         RouterRecord routerRecord = managerRecord.mUserRecord.findRouterRecordLocked(packageName);
         if (routerRecord == null) {
-            Slog.w(TAG, "Ignoring session creation for unknown router.");
+            Slog.w(TAG, "requestCreateSessionWithManagerLocked: Ignoring session creation for "
+                    + "unknown router.");
             return;
         }
 
@@ -1231,7 +1239,8 @@
 
                 for (MediaRoute2Info route : currentRoutes) {
                     if (!route.isValid()) {
-                        Slog.w(TAG, "Ignoring invalid route : " + route);
+                        Slog.w(TAG, "onProviderStateChangedOnHandler: Ignoring invalid route : "
+                                + route);
                         continue;
                     }
                     MediaRoute2Info prevRoute = prevInfo.getRoute(route.getOriginalId());
@@ -1309,8 +1318,8 @@
             try {
                 routerRecord.mRouter.getSessionHintsForCreatingSession(uniqueRequestId, route);
             } catch (RemoteException ex) {
-                Slog.w(TAG, "requestGetSessionHintsOnHandler: "
-                        + "Failed to request. Router probably died.");
+                Slog.w(TAG, "getSessionHintsForCreatingSessionOnHandler: "
+                        + "Failed to request. Router probably died.", ex);
                 mSessionCreationRequests.remove(request);
                 notifyRequestFailedToManager(managerRecord.mManager,
                         toOriginalRequestId(uniqueRequestId), REASON_UNKNOWN_ERROR);
@@ -1323,8 +1332,8 @@
 
             final MediaRoute2Provider provider = findProvider(route.getProviderId());
             if (provider == null) {
-                Slog.w(TAG, "Ignoring session creation request since no provider found for"
-                        + " given route=" + route);
+                Slog.w(TAG, "requestCreateSessionWithRouter2OnHandler: Ignoring session "
+                        + "creation request since no provider found for given route=" + route);
                 notifySessionCreationFailedToRouter(routerRecord,
                         toOriginalRequestId(uniqueRequestId));
                 return;
@@ -1349,22 +1358,21 @@
                 }
             }
             if (matchingRequest == null) {
-                Slog.w(TAG, "requestCreateSessionWithKnownRequestOnHandler: "
-                        + "Ignoring an unknown request.");
+                Slog.w(TAG, "requestCreateSessionWithManagerOnHandler: "
+                        + "Ignoring an unknown session creation request.");
                 return;
             }
 
             if (!TextUtils.equals(matchingRequest.mRoute.getId(), route.getId())) {
-                Slog.w(TAG, "requestCreateSessionWithKnownRequestOnHandler: "
+                Slog.w(TAG, "requestCreateSessionWithManagerOnHandler: "
                         + "The given route is different from the requested route.");
                 return;
             }
 
             final MediaRoute2Provider provider = findProvider(route.getProviderId());
             if (provider == null) {
-                Slog.w(TAG, "Ignoring session creation request since no provider found for"
-                        + " given route=" + route);
-
+                Slog.w(TAG, "requestCreateSessionWithManagerOnHandler: Ignoring session "
+                        + "creation request since no provider found for given route=" + route);
                 mSessionCreationRequests.remove(matchingRequest);
                 notifyRequestFailedToManager(matchingRequest.mRequestedManagerRecord.mManager,
                         toOriginalRequestId(uniqueRequestId), REASON_ROUTE_NOT_AVAILABLE);
@@ -1468,7 +1476,7 @@
                 int volume) {
             final MediaRoute2Provider provider = findProvider(route.getProviderId());
             if (provider == null) {
-                Slog.w(TAG, "setRouteVolume: couldn't find provider for route=" + route);
+                Slog.w(TAG, "setRouteVolumeOnHandler: Couldn't find provider for route=" + route);
                 return;
             }
             provider.setRouteVolume(uniqueRequestId, route.getOriginalId(), volume);
@@ -1478,8 +1486,8 @@
                 @NonNull String uniqueSessionId, int volume) {
             final MediaRoute2Provider provider = findProvider(getProviderId(uniqueSessionId));
             if (provider == null) {
-                Slog.w(TAG, "setSessionVolume: couldn't find provider for session "
-                        + "id=" + uniqueSessionId);
+                Slog.w(TAG, "setSessionVolumeOnHandler: Couldn't find provider for session id="
+                        + uniqueSessionId);
                 return;
             }
             provider.setSessionVolume(uniqueRequestId, getOriginalId(uniqueSessionId), volume);
@@ -1583,7 +1591,7 @@
         private void onSessionInfoChangedOnHandler(@NonNull MediaRoute2Provider provider,
                 @NonNull RoutingSessionInfo sessionInfo) {
             List<IMediaRouter2Manager> managers = getManagers();
-            notifySessionInfoChangedToManagers(managers, sessionInfo);
+            notifySessionUpdatedToManagers(managers, sessionInfo);
 
             // For system provider, notify all routers.
             if (provider == mSystemProvider) {
@@ -1599,7 +1607,8 @@
 
             RouterRecord routerRecord = mSessionToRouterMap.get(sessionInfo.getId());
             if (routerRecord == null) {
-                Slog.w(TAG, "No matching router found for session=" + sessionInfo);
+                Slog.w(TAG, "onSessionInfoChangedOnHandler: No matching router found for session="
+                        + sessionInfo);
                 return;
             }
             notifySessionInfoChangedToRouter(routerRecord, sessionInfo);
@@ -1608,11 +1617,12 @@
         private void onSessionReleasedOnHandler(@NonNull MediaRoute2Provider provider,
                 @NonNull RoutingSessionInfo sessionInfo) {
             List<IMediaRouter2Manager> managers = getManagers();
-            notifySessionInfoChangedToManagers(managers, sessionInfo);
+            notifySessionReleasedToManagers(managers, sessionInfo);
 
             RouterRecord routerRecord = mSessionToRouterMap.get(sessionInfo.getId());
             if (routerRecord == null) {
-                Slog.w(TAG, "No matching router found for session=" + sessionInfo);
+                Slog.w(TAG, "onSessionReleasedOnHandler: No matching router found for session="
+                        + sessionInfo);
                 return;
             }
             notifySessionReleasedToRouter(routerRecord, sessionInfo);
@@ -1789,7 +1799,7 @@
                     currentRoutes.addAll(systemProviderInfo.getRoutes());
                 } else {
                     // This shouldn't happen.
-                    Slog.w(TAG, "notifyRoutesToRouter: System route provider not found.");
+                    Slog.wtf(TAG, "System route provider not found.");
                 }
                 currentSystemSessionInfo = mSystemProvider.getSessionInfos().get(0);
             } else {
@@ -1913,15 +1923,28 @@
             }
         }
 
-        private void notifySessionInfoChangedToManagers(
+        private void notifySessionUpdatedToManagers(
                 @NonNull List<IMediaRouter2Manager> managers,
                 @NonNull RoutingSessionInfo sessionInfo) {
             for (IMediaRouter2Manager manager : managers) {
                 try {
                     manager.notifySessionUpdated(sessionInfo);
                 } catch (RemoteException ex) {
-                    Slog.w(TAG, "notifySessionInfosChangedToManagers: "
-                            + "failed to notify. Manager probably died.", ex);
+                    Slog.w(TAG, "notifySessionUpdatedToManagers: "
+                            + "Failed to notify. Manager probably died.", ex);
+                }
+            }
+        }
+
+        private void notifySessionReleasedToManagers(
+                @NonNull List<IMediaRouter2Manager> managers,
+                @NonNull RoutingSessionInfo sessionInfo) {
+            for (IMediaRouter2Manager manager : managers) {
+                try {
+                    manager.notifySessionReleased(sessionInfo);
+                } catch (RemoteException ex) {
+                    Slog.w(TAG, "notifySessionReleasedToManagers: "
+                            + "Failed to notify. Manager probably died.", ex);
                 }
             }
         }
@@ -1937,7 +1960,8 @@
             }
         }
 
-        private void notifyPreferredFeaturesChangedToManagers(@NonNull RouterRecord routerRecord) {
+        private void notifyPreferredFeaturesChangedToManagers(@NonNull String routerPackageName,
+                @Nullable List<String> preferredFeatures) {
             MediaRouter2ServiceImpl service = mServiceRef.get();
             if (service == null) {
                 return;
@@ -1950,8 +1974,7 @@
             }
             for (IMediaRouter2Manager manager : managers) {
                 try {
-                    manager.notifyPreferredFeaturesChanged(routerRecord.mPackageName,
-                            routerRecord.mDiscoveryPreference.getPreferredFeatures());
+                    manager.notifyPreferredFeaturesChanged(routerPackageName, preferredFeatures);
                 } catch (RemoteException ex) {
                     Slog.w(TAG, "Failed to notify preferred features changed."
                             + " Manager probably died.", ex);
diff --git a/services/core/java/com/android/server/media/MediaRouterService.java b/services/core/java/com/android/server/media/MediaRouterService.java
index bf2cc5e..3337b48 100644
--- a/services/core/java/com/android/server/media/MediaRouterService.java
+++ b/services/core/java/com/android/server/media/MediaRouterService.java
@@ -891,8 +891,24 @@
             if (intent.getAction().equals(BluetoothA2dp.ACTION_ACTIVE_DEVICE_CHANGED)) {
                 BluetoothDevice btDevice = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
                 synchronized (mLock) {
+                    boolean wasA2dpOn = mGlobalBluetoothA2dpOn;
                     mActiveBluetoothDevice = btDevice;
                     mGlobalBluetoothA2dpOn = btDevice != null;
+                    if (wasA2dpOn != mGlobalBluetoothA2dpOn) {
+                        UserRecord userRecord = mUserRecords.get(mCurrentUserId);
+                        if (userRecord != null) {
+                            for (ClientRecord cr : userRecord.mClientRecords) {
+                                // mSelectedRouteId will be null for BT and phone speaker.
+                                if (cr.mSelectedRouteId == null) {
+                                    try {
+                                        cr.mClient.onGlobalA2dpChanged(mGlobalBluetoothA2dpOn);
+                                    } catch (RemoteException e) {
+                                        // Ignore exception
+                                    }
+                                }
+                            }
+                        }
+                    }
                 }
             }
         }
diff --git a/services/core/java/com/android/server/media/MediaSessionService.java b/services/core/java/com/android/server/media/MediaSessionService.java
index afae20d..9625041 100644
--- a/services/core/java/com/android/server/media/MediaSessionService.java
+++ b/services/core/java/com/android/server/media/MediaSessionService.java
@@ -830,9 +830,6 @@
 
         private IOnVolumeKeyLongPressListener mOnVolumeKeyLongPressListener;
         private int mOnVolumeKeyLongPressListenerUid;
-        private KeyEvent mInitialDownVolumeKeyEvent;
-        private int mInitialDownVolumeStream;
-        private boolean mInitialDownMusicOnly;
 
         private IOnMediaKeyListener mOnMediaKeyListener;
         private int mOnMediaKeyListenerUid;
@@ -1104,12 +1101,10 @@
                 "android.media.AudioService.WAKELOCK_ACQUIRED";
         private static final int WAKELOCK_RELEASE_ON_FINISHED = 1980; // magic number
 
-        private KeyEvent mTrackingFirstDownKeyEvent = null;
-        private boolean mIsLongPressing = false;
-        private Runnable mLongPressTimeoutRunnable = null;
-        private int mMultiTapCount = 0;
-        private int mMultiTapKeyCode = 0;
-        private Runnable mMultiTapTimeoutRunnable = null;
+        private KeyEventHandler mMediaKeyEventHandler =
+                new KeyEventHandler(KeyEventHandler.KEY_TYPE_MEDIA);
+        private KeyEventHandler mVolumeKeyEventHandler =
+                new KeyEventHandler(KeyEventHandler.KEY_TYPE_VOLUME);
 
         @Override
         public void onShellCommand(FileDescriptor in, FileDescriptor out, FileDescriptor err,
@@ -1387,8 +1382,8 @@
                         dispatchMediaKeyEventLocked(packageName, pid, uid, asSystemService,
                                 keyEvent, needWakeLock);
                     } else {
-                        handleKeyEventLocked(packageName, pid, uid, asSystemService, keyEvent,
-                                needWakeLock);
+                        mMediaKeyEventHandler.handleMediaKeyEventLocked(packageName, pid, uid,
+                                asSystemService, keyEvent, needWakeLock);
                     }
                 }
             } finally {
@@ -1710,53 +1705,14 @@
 
             try {
                 synchronized (mLock) {
-                    if (isGlobalPriorityActiveLocked()
-                            || mCurrentFullUserRecord.mOnVolumeKeyLongPressListener == null) {
+                    if (isGlobalPriorityActiveLocked()) {
                         dispatchVolumeKeyEventLocked(packageName, opPackageName, pid, uid,
                                 asSystemService, keyEvent, stream, musicOnly);
                     } else {
                         // TODO: Consider the case when both volume up and down keys are pressed
                         //       at the same time.
-                        if (keyEvent.getAction() == KeyEvent.ACTION_DOWN) {
-                            if (keyEvent.getRepeatCount() == 0) {
-                                // Keeps the copy of the KeyEvent because it can be reused.
-                                mCurrentFullUserRecord.mInitialDownVolumeKeyEvent =
-                                        KeyEvent.obtain(keyEvent);
-                                mCurrentFullUserRecord.mInitialDownVolumeStream = stream;
-                                mCurrentFullUserRecord.mInitialDownMusicOnly = musicOnly;
-                                mHandler.sendMessageDelayed(
-                                        mHandler.obtainMessage(
-                                                MessageHandler.MSG_VOLUME_INITIAL_DOWN,
-                                                mCurrentFullUserRecord.mFullUserId, 0),
-                                        LONG_PRESS_TIMEOUT);
-                            }
-                            if (keyEvent.getRepeatCount() > 0 || keyEvent.isLongPress()) {
-                                mHandler.removeMessages(MessageHandler.MSG_VOLUME_INITIAL_DOWN);
-                                if (mCurrentFullUserRecord.mInitialDownVolumeKeyEvent != null) {
-                                    dispatchVolumeKeyLongPressLocked(
-                                            mCurrentFullUserRecord.mInitialDownVolumeKeyEvent);
-                                    // Mark that the key is already handled.
-                                    mCurrentFullUserRecord.mInitialDownVolumeKeyEvent = null;
-                                }
-                                dispatchVolumeKeyLongPressLocked(keyEvent);
-                            }
-                        } else { // if up
-                            mHandler.removeMessages(MessageHandler.MSG_VOLUME_INITIAL_DOWN);
-                            if (mCurrentFullUserRecord.mInitialDownVolumeKeyEvent != null
-                                    && mCurrentFullUserRecord.mInitialDownVolumeKeyEvent
-                                    .getDownTime() == keyEvent.getDownTime()) {
-                                // Short-press. Should change volume.
-                                dispatchVolumeKeyEventLocked(packageName, opPackageName, pid, uid,
-                                        asSystemService,
-                                        mCurrentFullUserRecord.mInitialDownVolumeKeyEvent,
-                                        mCurrentFullUserRecord.mInitialDownVolumeStream,
-                                        mCurrentFullUserRecord.mInitialDownMusicOnly);
-                                dispatchVolumeKeyEventLocked(packageName, opPackageName, pid, uid,
-                                        asSystemService, keyEvent, stream, musicOnly);
-                            } else {
-                                dispatchVolumeKeyLongPressLocked(keyEvent);
-                            }
-                        }
+                        mVolumeKeyEventHandler.handleVolumeKeyEventLocked(packageName, pid, uid,
+                                asSystemService, keyEvent, opPackageName, stream, musicOnly);
                     }
                 }
             } finally {
@@ -2136,266 +2092,6 @@
             }
         }
 
-        // A long press is determined by:
-        // 1) A KeyEvent.ACTION_DOWN KeyEvent and repeat count of 0, followed by
-        // 2) A KeyEvent.ACTION_DOWN KeyEvent with the same key code, a repeat count of 1, and
-        //    FLAG_LONG_PRESS received within ViewConfiguration.getLongPressTimeout().
-        // A tap is determined by:
-        // 1) A KeyEvent.ACTION_DOWN KeyEvent followed by
-        // 2) A KeyEvent.ACTION_UP KeyEvent with the same key code.
-        private void handleKeyEventLocked(String packageName, int pid, int uid,
-                boolean asSystemService, KeyEvent keyEvent, boolean needWakeLock) {
-            if (keyEvent.isCanceled()) {
-                return;
-            }
-
-            int overriddenKeyEvents = (mCustomMediaKeyDispatcher == null) ? 0
-                    : mCustomMediaKeyDispatcher.getOverriddenKeyEvents().get(keyEvent.getKeyCode());
-            cancelTrackingIfNeeded(packageName, pid, uid, asSystemService, keyEvent, needWakeLock,
-                    overriddenKeyEvents);
-            if (!needTracking(keyEvent, overriddenKeyEvents)) {
-                dispatchMediaKeyEventLocked(packageName, pid, uid, asSystemService, keyEvent,
-                        needWakeLock);
-                return;
-            }
-
-            if (isFirstDownKeyEvent(keyEvent)) {
-                mTrackingFirstDownKeyEvent = keyEvent;
-                mIsLongPressing = false;
-                return;
-            }
-
-            // Long press is always overridden here, otherwise the key event would have been already
-            // handled
-            if (isFirstLongPressKeyEvent(keyEvent)) {
-                mIsLongPressing = true;
-            }
-            if (mIsLongPressing) {
-                handleLongPressLocked(keyEvent, needWakeLock, overriddenKeyEvents);
-                return;
-            }
-
-            if (keyEvent.getAction() == KeyEvent.ACTION_UP) {
-                mTrackingFirstDownKeyEvent = null;
-                if (shouldTrackForMultipleTapsLocked(overriddenKeyEvents)) {
-                    if (mMultiTapCount == 0) {
-                        mMultiTapTimeoutRunnable = createSingleTapRunnable(packageName, pid, uid,
-                                asSystemService, keyEvent, needWakeLock,
-                                isSingleTapOverridden(overriddenKeyEvents));
-                        if (isSingleTapOverridden(overriddenKeyEvents)
-                                && !isDoubleTapOverridden(overriddenKeyEvents)
-                                && !isTripleTapOverridden(overriddenKeyEvents)) {
-                            mMultiTapTimeoutRunnable.run();
-                        } else {
-                            mHandler.postDelayed(mMultiTapTimeoutRunnable,
-                                    MULTI_TAP_TIMEOUT);
-                            mMultiTapCount = 1;
-                            mMultiTapKeyCode = keyEvent.getKeyCode();
-                        }
-                    } else if (mMultiTapCount == 1) {
-                        mHandler.removeCallbacks(mMultiTapTimeoutRunnable);
-                        mMultiTapTimeoutRunnable = createDoubleTapRunnable(packageName, pid, uid,
-                                asSystemService, keyEvent, needWakeLock,
-                                isSingleTapOverridden(overriddenKeyEvents),
-                                isDoubleTapOverridden(overriddenKeyEvents));
-                        if (isTripleTapOverridden(overriddenKeyEvents)) {
-                            mHandler.postDelayed(mMultiTapTimeoutRunnable, MULTI_TAP_TIMEOUT);
-                            mMultiTapCount = 2;
-                        } else {
-                            mMultiTapTimeoutRunnable.run();
-                        }
-                    } else if (mMultiTapCount == 2) {
-                        mHandler.removeCallbacks(mMultiTapTimeoutRunnable);
-                        onTripleTap(keyEvent);
-                    }
-                } else {
-                    dispatchDownAndUpKeyEventsLocked(packageName, pid, uid, asSystemService,
-                            keyEvent, needWakeLock);
-                }
-            }
-        }
-
-        private boolean shouldTrackForMultipleTapsLocked(int overriddenKeyEvents) {
-            return isSingleTapOverridden(overriddenKeyEvents)
-                    || isDoubleTapOverridden(overriddenKeyEvents)
-                    || isTripleTapOverridden(overriddenKeyEvents);
-        }
-
-        private void cancelTrackingIfNeeded(String packageName, int pid, int uid,
-                boolean asSystemService, KeyEvent keyEvent, boolean needWakeLock,
-                int overriddenKeyEvents) {
-            if (mTrackingFirstDownKeyEvent == null && mMultiTapTimeoutRunnable == null) {
-                return;
-            }
-
-            if (isFirstDownKeyEvent(keyEvent)) {
-                if (mLongPressTimeoutRunnable != null) {
-                    mHandler.removeCallbacks(mLongPressTimeoutRunnable);
-                    mLongPressTimeoutRunnable.run();
-                }
-                if (mMultiTapTimeoutRunnable != null && keyEvent.getKeyCode() != mMultiTapKeyCode) {
-                    runExistingMultiTapRunnableLocked();
-                }
-                resetLongPressTracking();
-                return;
-            }
-
-            if (mTrackingFirstDownKeyEvent != null
-                    && mTrackingFirstDownKeyEvent.getDownTime() == keyEvent.getDownTime()
-                    && mTrackingFirstDownKeyEvent.getKeyCode() == keyEvent.getKeyCode()
-                    && keyEvent.getAction() == KeyEvent.ACTION_DOWN) {
-                if (isFirstLongPressKeyEvent(keyEvent)) {
-                    if (mMultiTapTimeoutRunnable != null) {
-                        runExistingMultiTapRunnableLocked();
-                    }
-                    if ((overriddenKeyEvents & KEY_EVENT_LONG_PRESS) == 0
-                            && !isVoiceKey(keyEvent.getKeyCode())) {
-                        dispatchMediaKeyEventLocked(packageName, pid, uid, asSystemService,
-                                mTrackingFirstDownKeyEvent, needWakeLock);
-                        mTrackingFirstDownKeyEvent = null;
-                    }
-                } else if (keyEvent.getRepeatCount() > 1 && !mIsLongPressing) {
-                    resetLongPressTracking();
-                }
-            }
-        }
-
-        private boolean needTracking(KeyEvent keyEvent, int overriddenKeyEvents) {
-            if (!isFirstDownKeyEvent(keyEvent)) {
-                if (mTrackingFirstDownKeyEvent == null) {
-                    return false;
-                } else if (mTrackingFirstDownKeyEvent.getDownTime() != keyEvent.getDownTime()
-                        || mTrackingFirstDownKeyEvent.getKeyCode() != keyEvent.getKeyCode()) {
-                    return false;
-                }
-            }
-            if (overriddenKeyEvents == 0 && !isVoiceKey(keyEvent.getKeyCode())) {
-                return false;
-            }
-            return true;
-        }
-
-        private void runExistingMultiTapRunnableLocked() {
-            mHandler.removeCallbacks(mMultiTapTimeoutRunnable);
-            mMultiTapTimeoutRunnable.run();
-        }
-
-        private void resetMultiTapTrackingLocked() {
-            mMultiTapCount = 0;
-            mMultiTapTimeoutRunnable = null;
-            mMultiTapKeyCode = 0;
-        }
-
-        private void handleLongPressLocked(KeyEvent keyEvent, boolean needWakeLock,
-                int overriddenKeyEvents) {
-            if (mCustomMediaKeyDispatcher != null
-                    && isLongPressOverridden(overriddenKeyEvents)) {
-                mCustomMediaKeyDispatcher.onLongPress(keyEvent);
-
-                if (mLongPressTimeoutRunnable != null) {
-                    mHandler.removeCallbacks(mLongPressTimeoutRunnable);
-                }
-                if (keyEvent.getAction() == KeyEvent.ACTION_DOWN) {
-                    if (mLongPressTimeoutRunnable == null) {
-                        mLongPressTimeoutRunnable = createLongPressTimeoutRunnable(keyEvent);
-                    }
-                    mHandler.postDelayed(mLongPressTimeoutRunnable, LONG_PRESS_TIMEOUT);
-                } else {
-                    resetLongPressTracking();
-                }
-            } else if (isFirstLongPressKeyEvent(keyEvent) && isVoiceKey(keyEvent.getKeyCode())) {
-                // Default implementation
-                startVoiceInput(needWakeLock);
-                resetLongPressTracking();
-            }
-        }
-
-        private Runnable createLongPressTimeoutRunnable(KeyEvent keyEvent) {
-            return new Runnable() {
-                @Override
-                public void run() {
-                    if (mCustomMediaKeyDispatcher != null) {
-                        mCustomMediaKeyDispatcher.onLongPress(createCanceledKeyEvent(keyEvent));
-                    }
-                    resetLongPressTracking();
-                }
-            };
-        }
-
-        private void resetLongPressTracking() {
-            mTrackingFirstDownKeyEvent = null;
-            mIsLongPressing = false;
-            mLongPressTimeoutRunnable = null;
-        }
-
-        private KeyEvent createCanceledKeyEvent(KeyEvent keyEvent) {
-            KeyEvent upEvent = KeyEvent.changeAction(keyEvent, KeyEvent.ACTION_UP);
-            return KeyEvent.changeTimeRepeat(upEvent, System.currentTimeMillis(), 0,
-                    KeyEvent.FLAG_CANCELED);
-        }
-
-        private boolean isFirstLongPressKeyEvent(KeyEvent keyEvent) {
-            return ((keyEvent.getFlags() & KeyEvent.FLAG_LONG_PRESS) != 0)
-                    && keyEvent.getRepeatCount() == 1;
-        }
-
-        private boolean isFirstDownKeyEvent(KeyEvent keyEvent) {
-            return keyEvent.getAction() == KeyEvent.ACTION_DOWN && keyEvent.getRepeatCount() == 0;
-        }
-
-        private void dispatchDownAndUpKeyEventsLocked(String packageName, int pid, int uid,
-                boolean asSystemService, KeyEvent keyEvent, boolean needWakeLock) {
-            KeyEvent downEvent = KeyEvent.changeAction(keyEvent, KeyEvent.ACTION_DOWN);
-            dispatchMediaKeyEventLocked(packageName, pid, uid, asSystemService,
-                    downEvent, needWakeLock);
-            dispatchMediaKeyEventLocked(packageName, pid, uid, asSystemService,
-                    keyEvent, needWakeLock);
-        }
-
-        Runnable createSingleTapRunnable(String packageName, int pid, int uid,
-                boolean asSystemService, KeyEvent keyEvent, boolean needWakeLock,
-                boolean overridden) {
-            return new Runnable() {
-                @Override
-                public void run() {
-                    resetMultiTapTrackingLocked();
-                    if (overridden) {
-                        mCustomMediaKeyDispatcher.onSingleTap(keyEvent);
-                    } else {
-                        dispatchDownAndUpKeyEventsLocked(packageName, pid, uid, asSystemService,
-                                keyEvent, needWakeLock);
-                    }
-                }
-            };
-        };
-
-        Runnable createDoubleTapRunnable(String packageName, int pid, int uid,
-                boolean asSystemService, KeyEvent keyEvent, boolean needWakeLock,
-                boolean singleTapOverridden, boolean doubleTapOverridden) {
-            return new Runnable() {
-                @Override
-                public void run() {
-                    resetMultiTapTrackingLocked();
-                    if (doubleTapOverridden) {
-                        mCustomMediaKeyDispatcher.onDoubleTap(keyEvent);
-                    } else if (singleTapOverridden) {
-                        mCustomMediaKeyDispatcher.onSingleTap(keyEvent);
-                        mCustomMediaKeyDispatcher.onSingleTap(keyEvent);
-                    } else {
-                        dispatchDownAndUpKeyEventsLocked(packageName, pid, uid, asSystemService,
-                                keyEvent, needWakeLock);
-                        dispatchDownAndUpKeyEventsLocked(packageName, pid, uid, asSystemService,
-                                keyEvent, needWakeLock);
-                    }
-                }
-            };
-        };
-
-        private void onTripleTap(KeyEvent keyEvent) {
-            resetMultiTapTrackingLocked();
-            mCustomMediaKeyDispatcher.onTripleTap(keyEvent);
-        }
-
         private void dispatchMediaKeyEventLocked(String packageName, int pid, int uid,
                 boolean asSystemService, KeyEvent keyEvent, boolean needWakeLock) {
             if (mCurrentFullUserRecord.getMediaButtonSessionLocked()
@@ -2579,8 +2275,8 @@
                         dispatchMediaKeyEventLocked(mPackageName, mPid, mUid, mAsSystemService,
                                 mKeyEvent, mNeedWakeLock);
                     } else {
-                        handleKeyEventLocked(mPackageName, mPid, mUid, mAsSystemService,
-                                mKeyEvent, mNeedWakeLock);
+                        mMediaKeyEventHandler.handleMediaKeyEventLocked(mPackageName, mPid, mUid,
+                                mAsSystemService, mKeyEvent, mNeedWakeLock);
                     }
                 }
             }
@@ -2655,12 +2351,338 @@
                 onReceiveResult(resultCode, null);
             }
         };
+
+        // A long press is determined by:
+        // 1) A KeyEvent.ACTION_DOWN KeyEvent and repeat count of 0, followed by
+        // 2) A KeyEvent.ACTION_DOWN KeyEvent with the same key code, a repeat count of 1, and
+        //    FLAG_LONG_PRESS received within ViewConfiguration.getLongPressTimeout().
+        // A tap is determined by:
+        // 1) A KeyEvent.ACTION_DOWN KeyEvent followed by
+        // 2) A KeyEvent.ACTION_UP KeyEvent with the same key code.
+        class KeyEventHandler {
+            private static final int KEY_TYPE_MEDIA = 0;
+            private static final int KEY_TYPE_VOLUME = 1;
+
+            private KeyEvent mTrackingFirstDownKeyEvent;
+            private boolean mIsLongPressing;
+            private Runnable mLongPressTimeoutRunnable;
+            private int mMultiTapCount;
+            private Runnable mMultiTapTimeoutRunnable;
+            private int mMultiTapKeyCode;
+            private int mKeyType;
+
+            KeyEventHandler(int keyType) {
+                mKeyType = keyType;
+            }
+
+            void handleMediaKeyEventLocked(String packageName, int pid, int uid,
+                    boolean asSystemService, KeyEvent keyEvent, boolean needWakeLock) {
+                handleKeyEventLocked(packageName, pid, uid, asSystemService, keyEvent, needWakeLock,
+                        null, 0, false);
+            }
+
+            void handleVolumeKeyEventLocked(String packageName, int pid, int uid,
+                    boolean asSystemService, KeyEvent keyEvent, String opPackageName, int stream,
+                    boolean musicOnly) {
+                handleKeyEventLocked(packageName, pid, uid, asSystemService, keyEvent, false,
+                        opPackageName, stream, musicOnly);
+            }
+
+            void handleKeyEventLocked(String packageName, int pid, int uid,
+                    boolean asSystemService, KeyEvent keyEvent, boolean needWakeLock,
+                    String opPackageName, int stream, boolean musicOnly) {
+                if (keyEvent.isCanceled()) {
+                    return;
+                }
+
+                int overriddenKeyEvents = (mCustomMediaKeyDispatcher == null) ? 0
+                        : mCustomMediaKeyDispatcher.getOverriddenKeyEvents()
+                                .get(keyEvent.getKeyCode());
+                cancelTrackingIfNeeded(packageName, pid, uid, asSystemService, keyEvent,
+                        needWakeLock, opPackageName, stream, musicOnly, overriddenKeyEvents);
+                if (!needTracking(keyEvent, overriddenKeyEvents)) {
+                    if (mKeyType == KEY_TYPE_VOLUME) {
+                        dispatchVolumeKeyEventLocked(packageName, opPackageName, pid, uid,
+                                asSystemService, keyEvent, stream, musicOnly);
+                    } else {
+                        dispatchMediaKeyEventLocked(packageName, pid, uid, asSystemService,
+                                keyEvent, needWakeLock);
+                    }
+                    return;
+                }
+
+                if (isFirstDownKeyEvent(keyEvent)) {
+                    mTrackingFirstDownKeyEvent = keyEvent;
+                    mIsLongPressing = false;
+                    return;
+                }
+
+                // Long press is always overridden here, otherwise the key event would have been
+                // already handled
+                if (isFirstLongPressKeyEvent(keyEvent)) {
+                    mIsLongPressing = true;
+                }
+                if (mIsLongPressing) {
+                    handleLongPressLocked(keyEvent, needWakeLock, overriddenKeyEvents);
+                    return;
+                }
+
+                if (keyEvent.getAction() == KeyEvent.ACTION_UP) {
+                    mTrackingFirstDownKeyEvent = null;
+                    if (shouldTrackForMultipleTapsLocked(overriddenKeyEvents)) {
+                        if (mMultiTapCount == 0) {
+                            mMultiTapTimeoutRunnable = createSingleTapRunnable(packageName, pid,
+                                    uid, asSystemService, keyEvent, needWakeLock,
+                                    opPackageName, stream, musicOnly,
+                                    isSingleTapOverridden(overriddenKeyEvents));
+                            if (isSingleTapOverridden(overriddenKeyEvents)
+                                    && !isDoubleTapOverridden(overriddenKeyEvents)
+                                    && !isTripleTapOverridden(overriddenKeyEvents)) {
+                                mMultiTapTimeoutRunnable.run();
+                            } else {
+                                mHandler.postDelayed(mMultiTapTimeoutRunnable,
+                                        MULTI_TAP_TIMEOUT);
+                                mMultiTapCount = 1;
+                                mMultiTapKeyCode = keyEvent.getKeyCode();
+                            }
+                        } else if (mMultiTapCount == 1) {
+                            mHandler.removeCallbacks(mMultiTapTimeoutRunnable);
+                            mMultiTapTimeoutRunnable = createDoubleTapRunnable(packageName, pid,
+                                    uid, asSystemService, keyEvent, needWakeLock, opPackageName,
+                                    stream, musicOnly, isSingleTapOverridden(overriddenKeyEvents),
+                                    isDoubleTapOverridden(overriddenKeyEvents));
+                            if (isTripleTapOverridden(overriddenKeyEvents)) {
+                                mHandler.postDelayed(mMultiTapTimeoutRunnable, MULTI_TAP_TIMEOUT);
+                                mMultiTapCount = 2;
+                            } else {
+                                mMultiTapTimeoutRunnable.run();
+                            }
+                        } else if (mMultiTapCount == 2) {
+                            mHandler.removeCallbacks(mMultiTapTimeoutRunnable);
+                            onTripleTap(keyEvent);
+                        }
+                    } else {
+                        dispatchDownAndUpKeyEventsLocked(packageName, pid, uid, asSystemService,
+                                keyEvent, needWakeLock, opPackageName, stream, musicOnly);
+                    }
+                }
+            }
+
+            private boolean shouldTrackForMultipleTapsLocked(int overriddenKeyEvents) {
+                return isSingleTapOverridden(overriddenKeyEvents)
+                        || isDoubleTapOverridden(overriddenKeyEvents)
+                        || isTripleTapOverridden(overriddenKeyEvents);
+            }
+
+            private void cancelTrackingIfNeeded(String packageName, int pid, int uid,
+                    boolean asSystemService, KeyEvent keyEvent, boolean needWakeLock,
+                    String opPackageName, int stream, boolean musicOnly, int overriddenKeyEvents) {
+                if (mTrackingFirstDownKeyEvent == null && mMultiTapTimeoutRunnable == null) {
+                    return;
+                }
+
+                if (isFirstDownKeyEvent(keyEvent)) {
+                    if (mLongPressTimeoutRunnable != null) {
+                        mHandler.removeCallbacks(mLongPressTimeoutRunnable);
+                        mLongPressTimeoutRunnable.run();
+                    }
+                    if (mMultiTapTimeoutRunnable != null
+                            && keyEvent.getKeyCode() != mMultiTapKeyCode) {
+                        runExistingMultiTapRunnableLocked();
+                    }
+                    resetLongPressTracking();
+                    return;
+                }
+
+                if (mTrackingFirstDownKeyEvent != null
+                        && mTrackingFirstDownKeyEvent.getDownTime() == keyEvent.getDownTime()
+                        && mTrackingFirstDownKeyEvent.getKeyCode() == keyEvent.getKeyCode()
+                        && keyEvent.getAction() == KeyEvent.ACTION_DOWN) {
+                    if (isFirstLongPressKeyEvent(keyEvent)) {
+                        if (mMultiTapTimeoutRunnable != null) {
+                            runExistingMultiTapRunnableLocked();
+                        }
+                        if ((overriddenKeyEvents & KEY_EVENT_LONG_PRESS) == 0) {
+                            if (mKeyType == KEY_TYPE_VOLUME) {
+                                if (mCurrentFullUserRecord.mOnVolumeKeyLongPressListener == null) {
+                                    dispatchVolumeKeyEventLocked(packageName, opPackageName, pid,
+                                            uid, asSystemService, keyEvent, stream, musicOnly);
+                                    mTrackingFirstDownKeyEvent = null;
+                                }
+                            } else if (!isVoiceKey(keyEvent.getKeyCode())) {
+                                dispatchMediaKeyEventLocked(packageName, pid, uid, asSystemService,
+                                        keyEvent, needWakeLock);
+                                mTrackingFirstDownKeyEvent = null;
+                            }
+                        }
+                    } else if (keyEvent.getRepeatCount() > 1 && !mIsLongPressing) {
+                        resetLongPressTracking();
+                    }
+                }
+            }
+
+            private boolean needTracking(KeyEvent keyEvent, int overriddenKeyEvents) {
+                if (!isFirstDownKeyEvent(keyEvent)) {
+                    if (mTrackingFirstDownKeyEvent == null) {
+                        return false;
+                    } else if (mTrackingFirstDownKeyEvent.getDownTime() != keyEvent.getDownTime()
+                            || mTrackingFirstDownKeyEvent.getKeyCode() != keyEvent.getKeyCode()) {
+                        return false;
+                    }
+                }
+                if (overriddenKeyEvents == 0) {
+                    if (mKeyType == KEY_TYPE_VOLUME) {
+                        if (mCurrentFullUserRecord.mOnVolumeKeyLongPressListener == null) {
+                            return false;
+                        }
+                    } else if (!isVoiceKey(keyEvent.getKeyCode())) {
+                        return false;
+                    }
+                }
+                return true;
+            }
+
+            private void runExistingMultiTapRunnableLocked() {
+                mHandler.removeCallbacks(mMultiTapTimeoutRunnable);
+                mMultiTapTimeoutRunnable.run();
+            }
+
+            private void resetMultiTapTrackingLocked() {
+                mMultiTapCount = 0;
+                mMultiTapTimeoutRunnable = null;
+                mMultiTapKeyCode = 0;
+            }
+
+            private void handleLongPressLocked(KeyEvent keyEvent, boolean needWakeLock,
+                    int overriddenKeyEvents) {
+                if (mCustomMediaKeyDispatcher != null
+                        && isLongPressOverridden(overriddenKeyEvents)) {
+                    mCustomMediaKeyDispatcher.onLongPress(keyEvent);
+
+                    if (mLongPressTimeoutRunnable != null) {
+                        mHandler.removeCallbacks(mLongPressTimeoutRunnable);
+                    }
+                    if (keyEvent.getAction() == KeyEvent.ACTION_DOWN) {
+                        if (mLongPressTimeoutRunnable == null) {
+                            mLongPressTimeoutRunnable = createLongPressTimeoutRunnable(keyEvent);
+                        }
+                        mHandler.postDelayed(mLongPressTimeoutRunnable, LONG_PRESS_TIMEOUT);
+                    } else {
+                        resetLongPressTracking();
+                    }
+                } else {
+                    if (mKeyType == KEY_TYPE_VOLUME) {
+                        dispatchVolumeKeyLongPressLocked(keyEvent);
+                    } else if (isFirstLongPressKeyEvent(keyEvent)
+                            && isVoiceKey(keyEvent.getKeyCode())) {
+                        // Default implementation
+                        startVoiceInput(needWakeLock);
+                        resetLongPressTracking();
+                    }
+                }
+            }
+
+            private Runnable createLongPressTimeoutRunnable(KeyEvent keyEvent) {
+                return new Runnable() {
+                    @Override
+                    public void run() {
+                        if (mCustomMediaKeyDispatcher != null) {
+                            mCustomMediaKeyDispatcher.onLongPress(createCanceledKeyEvent(keyEvent));
+                        }
+                        resetLongPressTracking();
+                    }
+                };
+            }
+
+            private void resetLongPressTracking() {
+                mTrackingFirstDownKeyEvent = null;
+                mIsLongPressing = false;
+                mLongPressTimeoutRunnable = null;
+            }
+
+            private KeyEvent createCanceledKeyEvent(KeyEvent keyEvent) {
+                KeyEvent upEvent = KeyEvent.changeAction(keyEvent, KeyEvent.ACTION_UP);
+                return KeyEvent.changeTimeRepeat(upEvent, System.currentTimeMillis(), 0,
+                        KeyEvent.FLAG_CANCELED);
+            }
+
+            private boolean isFirstLongPressKeyEvent(KeyEvent keyEvent) {
+                return ((keyEvent.getFlags() & KeyEvent.FLAG_LONG_PRESS) != 0)
+                        && keyEvent.getRepeatCount() == 1;
+            }
+
+            private boolean isFirstDownKeyEvent(KeyEvent keyEvent) {
+                return keyEvent.getAction() == KeyEvent.ACTION_DOWN
+                        && keyEvent.getRepeatCount() == 0;
+            }
+
+            private void dispatchDownAndUpKeyEventsLocked(String packageName, int pid, int uid,
+                    boolean asSystemService, KeyEvent keyEvent, boolean needWakeLock,
+                    String opPackageName, int stream, boolean musicOnly) {
+                KeyEvent downEvent = KeyEvent.changeAction(keyEvent, KeyEvent.ACTION_DOWN);
+                if (mKeyType == KEY_TYPE_VOLUME) {
+                    dispatchVolumeKeyEventLocked(packageName, opPackageName, pid, uid,
+                            asSystemService, downEvent, stream, musicOnly);
+                    dispatchVolumeKeyEventLocked(packageName, opPackageName, pid, uid,
+                            asSystemService, keyEvent, stream, musicOnly);
+                } else {
+                    dispatchMediaKeyEventLocked(packageName, pid, uid, asSystemService, downEvent,
+                            needWakeLock);
+                    dispatchMediaKeyEventLocked(packageName, pid, uid, asSystemService, keyEvent,
+                            needWakeLock);
+                }
+            }
+
+            Runnable createSingleTapRunnable(String packageName, int pid, int uid,
+                    boolean asSystemService, KeyEvent keyEvent, boolean needWakeLock,
+                    String opPackageName, int stream, boolean musicOnly, boolean overridden) {
+                return new Runnable() {
+                    @Override
+                    public void run() {
+                        resetMultiTapTrackingLocked();
+                        if (overridden) {
+                            mCustomMediaKeyDispatcher.onSingleTap(keyEvent);
+                        } else {
+                            dispatchDownAndUpKeyEventsLocked(packageName, pid, uid, asSystemService,
+                                    keyEvent, needWakeLock, opPackageName, stream, musicOnly);
+                        }
+                    }
+                };
+            };
+
+            Runnable createDoubleTapRunnable(String packageName, int pid, int uid,
+                    boolean asSystemService, KeyEvent keyEvent, boolean needWakeLock,
+                    String opPackageName, int stream, boolean musicOnly,
+                    boolean singleTapOverridden, boolean doubleTapOverridden) {
+                return new Runnable() {
+                    @Override
+                    public void run() {
+                        resetMultiTapTrackingLocked();
+                        if (doubleTapOverridden) {
+                            mCustomMediaKeyDispatcher.onDoubleTap(keyEvent);
+                        } else if (singleTapOverridden) {
+                            mCustomMediaKeyDispatcher.onSingleTap(keyEvent);
+                            mCustomMediaKeyDispatcher.onSingleTap(keyEvent);
+                        } else {
+                            dispatchDownAndUpKeyEventsLocked(packageName, pid, uid, asSystemService,
+                                    keyEvent, needWakeLock, opPackageName, stream, musicOnly);
+                            dispatchDownAndUpKeyEventsLocked(packageName, pid, uid, asSystemService,
+                                    keyEvent, needWakeLock, opPackageName, stream, musicOnly);
+                        }
+                    }
+                };
+            };
+
+            private void onTripleTap(KeyEvent keyEvent) {
+                resetMultiTapTrackingLocked();
+                mCustomMediaKeyDispatcher.onTripleTap(keyEvent);
+            }
+        }
     }
 
     final class MessageHandler extends Handler {
         private static final int MSG_SESSIONS_1_CHANGED = 1;
         private static final int MSG_SESSIONS_2_CHANGED = 2;
-        private static final int MSG_VOLUME_INITIAL_DOWN = 3;
         private final SparseArray<Integer> mIntegerCache = new SparseArray<>();
 
         @Override
@@ -2672,16 +2694,6 @@
                 case MSG_SESSIONS_2_CHANGED:
                     pushSession2Changed((int) msg.obj);
                     break;
-                case MSG_VOLUME_INITIAL_DOWN:
-                    synchronized (mLock) {
-                        FullUserRecord user = mUserRecords.get((int) msg.arg1);
-                        if (user != null && user.mInitialDownVolumeKeyEvent != null) {
-                            dispatchVolumeKeyLongPressLocked(user.mInitialDownVolumeKeyEvent);
-                            // Mark that the key is already handled.
-                            user.mInitialDownVolumeKeyEvent = null;
-                        }
-                    }
-                    break;
             }
         }
 
diff --git a/services/core/java/com/android/server/net/NetworkStatsSubscriptionsMonitor.java b/services/core/java/com/android/server/net/NetworkStatsSubscriptionsMonitor.java
index 0bdf3f2..a0ab5ea 100644
--- a/services/core/java/com/android/server/net/NetworkStatsSubscriptionsMonitor.java
+++ b/services/core/java/com/android/server/net/NetworkStatsSubscriptionsMonitor.java
@@ -28,6 +28,7 @@
 import android.text.TextUtils;
 import android.util.Log;
 
+import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.util.CollectionUtils;
 
 import java.util.ArrayList;
@@ -38,8 +39,6 @@
 /**
  * Helper class that watches for events that are triggered per subscription.
  */
-// TODO (b/152176562): Write tests to verify subscription changes generate corresponding
-//  register/unregister calls.
 public class NetworkStatsSubscriptionsMonitor extends
         SubscriptionManager.OnSubscriptionsChangedListener {
 
@@ -207,5 +206,10 @@
             mLastCollapsedRatType = collapsedRatType;
             mMonitor.mDelegate.onCollapsedRatTypeChanged(mSubscriberId, mLastCollapsedRatType);
         }
+
+        @VisibleForTesting
+        public int getSubId() {
+            return mSubId;
+        }
     }
 }
diff --git a/services/core/java/com/android/server/notification/CalendarTracker.java b/services/core/java/com/android/server/notification/CalendarTracker.java
index 3829b65..cfcf6eb 100644
--- a/services/core/java/com/android/server/notification/CalendarTracker.java
+++ b/services/core/java/com/android/server/notification/CalendarTracker.java
@@ -21,6 +21,7 @@
 import android.content.Context;
 import android.database.ContentObserver;
 import android.database.Cursor;
+import android.database.sqlite.SQLiteException;
 import android.net.Uri;
 import android.provider.CalendarContract.Attendees;
 import android.provider.CalendarContract.Calendars;
@@ -102,6 +103,8 @@
             while (cursor != null && cursor.moveToNext()) {
                 rt.add(cursor.getLong(0));
             }
+        } catch (SQLiteException e) {
+            Slog.w(TAG, "error querying calendar content provider", e);
         } finally {
             if (cursor != null) {
                 cursor.close();
@@ -118,11 +121,12 @@
         ContentUris.appendId(uriBuilder, time);
         ContentUris.appendId(uriBuilder, time + EVENT_CHECK_LOOKAHEAD);
         final Uri uri = uriBuilder.build();
-        final Cursor cursor = mUserContext.getContentResolver().query(uri, INSTANCE_PROJECTION,
-                null, null, INSTANCE_ORDER_BY);
+        Cursor cursor = null;
         final CheckEventResult result = new CheckEventResult();
         result.recheckAt = time + EVENT_CHECK_LOOKAHEAD;
         try {
+            cursor = mUserContext.getContentResolver().query(uri, INSTANCE_PROJECTION,
+                    null, null, INSTANCE_ORDER_BY);
             final ArraySet<Long> calendars = getCalendarsWithAccess();
             while (cursor != null && cursor.moveToNext()) {
                 final long begin = cursor.getLong(0);
@@ -183,9 +187,10 @@
             selection = null;
             selectionArgs = null;
         }
-        final Cursor cursor = mUserContext.getContentResolver().query(Attendees.CONTENT_URI,
-                ATTENDEE_PROJECTION, selection, selectionArgs, null);
+        Cursor cursor = null;
         try {
+            cursor = mUserContext.getContentResolver().query(Attendees.CONTENT_URI,
+                    ATTENDEE_PROJECTION, selection, selectionArgs, null);
             if (cursor == null || cursor.getCount() == 0) {
                 if (DEBUG) Log.d(TAG, "No attendees found");
                 return true;
@@ -205,6 +210,9 @@
                 rt |= eventMeets;
             }
             return rt;
+        } catch (SQLiteException e) {
+            Slog.w(TAG, "error querying attendees content provider", e);
+            return false;
         } finally {
             if (cursor != null) {
                 cursor.close();
diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java
index 5585e98..b64e991 100755
--- a/services/core/java/com/android/server/notification/NotificationManagerService.java
+++ b/services/core/java/com/android/server/notification/NotificationManagerService.java
@@ -92,6 +92,7 @@
 import static android.service.notification.NotificationListenerService.TRIM_LIGHT;
 import static android.view.WindowManager.LayoutParams.TYPE_TOAST;
 
+import static com.android.internal.util.FrameworkStatsLog.DND_MODE_RULE;
 import static com.android.internal.util.FrameworkStatsLog.PACKAGE_NOTIFICATION_CHANNEL_GROUP_PREFERENCES;
 import static com.android.internal.util.FrameworkStatsLog.PACKAGE_NOTIFICATION_CHANNEL_PREFERENCES;
 import static com.android.internal.util.FrameworkStatsLog.PACKAGE_NOTIFICATION_PREFERENCES;
@@ -1906,7 +1907,8 @@
         mMetricsLogger = new MetricsLogger();
         mRankingHandler = rankingHandler;
         mConditionProviders = conditionProviders;
-        mZenModeHelper = new ZenModeHelper(getContext(), mHandler.getLooper(), mConditionProviders);
+        mZenModeHelper = new ZenModeHelper(getContext(), mHandler.getLooper(), mConditionProviders,
+                new SysUiStatsEvent.BuilderFactory());
         mZenModeHelper.addCallback(new ZenModeHelper.Callback() {
             @Override
             public void onConfigChanged() {
@@ -2046,12 +2048,15 @@
         mStripRemoteViewsSizeBytes = getContext().getResources().getInteger(
                 com.android.internal.R.integer.config_notificationStripRemoteViewSizeBytes);
 
-        mMsgPkgsAllowedAsConvos = Set.of(
-                getContext().getResources().getStringArray(
-                        com.android.internal.R.array.config_notificationMsgPkgsAllowedAsConvos));
+        mMsgPkgsAllowedAsConvos = Set.of(getStringArrayResource(
+                com.android.internal.R.array.config_notificationMsgPkgsAllowedAsConvos));
         mStatsManager = statsManager;
     }
 
+    protected String[] getStringArrayResource(int key) {
+        return getContext().getResources().getStringArray(key);
+    }
+
     @Override
     public void onStart() {
         SnoozeHelper snoozeHelper = new SnoozeHelper(getContext(), (userId, r, muteOnReturn) -> {
@@ -2189,6 +2194,12 @@
                 ConcurrentUtils.DIRECT_EXECUTOR,
                 mPullAtomCallback
         );
+        mStatsManager.setPullAtomCallback(
+                DND_MODE_RULE,
+                null, // use default PullAtomMetadata values
+                BackgroundThread.getExecutor(),
+                mPullAtomCallback
+        );
     }
 
     private class StatsPullAtomCallbackImpl implements StatsManager.StatsPullAtomCallback {
@@ -2198,6 +2209,7 @@
                 case PACKAGE_NOTIFICATION_PREFERENCES:
                 case PACKAGE_NOTIFICATION_CHANNEL_PREFERENCES:
                 case PACKAGE_NOTIFICATION_CHANNEL_GROUP_PREFERENCES:
+                case DND_MODE_RULE:
                     return pullNotificationStates(atomTag, data);
                 default:
                     throw new UnsupportedOperationException("Unknown tagId=" + atomTag);
@@ -2216,6 +2228,9 @@
             case PACKAGE_NOTIFICATION_CHANNEL_GROUP_PREFERENCES:
                 mPreferencesHelper.pullPackageChannelGroupPreferencesStats(data);
                 break;
+            case DND_MODE_RULE:
+                mZenModeHelper.pullRules(data);
+                break;
         }
         return StatsManager.PULL_SUCCESS;
     }
@@ -2729,10 +2744,7 @@
     }
 
     protected void maybeRegisterMessageSent(NotificationRecord r) {
-        Context appContext = r.getSbn().getPackageContext(getContext());
-        Notification.Builder nb =
-                Notification.Builder.recoverBuilder(appContext, r.getNotification());
-        if (nb.getStyle() instanceof Notification.MessagingStyle) {
+        if (r.isConversation()) {
             if (r.getShortcutInfo() != null) {
                 if (mPreferencesHelper.setValidMessageSent(
                         r.getSbn().getPackageName(), r.getUid())) {
@@ -4015,7 +4027,7 @@
         private void cancelNotificationFromListenerLocked(ManagedServiceInfo info,
                 int callingUid, int callingPid, String pkg, String tag, int id, int userId) {
             cancelNotification(callingUid, callingPid, pkg, tag, id, 0,
-                    FLAG_ONGOING_EVENT | FLAG_FOREGROUND_SERVICE | FLAG_BUBBLE,
+                    FLAG_ONGOING_EVENT | FLAG_FOREGROUND_SERVICE,
                     true,
                     userId, REASON_LISTENER_CANCEL, info);
         }
@@ -6248,6 +6260,13 @@
                         mUsageStats.registerClickedByUser(r);
                     }
 
+                    if (mReason == REASON_LISTENER_CANCEL
+                        && (r.getNotification().flags & FLAG_BUBBLE) != 0) {
+                        mNotificationDelegate.onBubbleNotificationSuppressionChanged(
+                            r.getKey(), /* suppressed */ true);
+                        return;
+                    }
+
                     if ((r.getNotification().flags & mMustHaveFlags) != mMustHaveFlags) {
                         return;
                     }
diff --git a/services/core/java/com/android/server/notification/SysUiStatsEvent.java b/services/core/java/com/android/server/notification/SysUiStatsEvent.java
index 9bc2346..90737bd 100644
--- a/services/core/java/com/android/server/notification/SysUiStatsEvent.java
+++ b/services/core/java/com/android/server/notification/SysUiStatsEvent.java
@@ -58,6 +58,11 @@
             mBuilder.writeBoolean(value);
             return this;
         }
+
+        public Builder writeByteArray(byte[] value) {
+            mBuilder.writeByteArray(value);
+            return this;
+        }
     }
 
     static class BuilderFactory {
diff --git a/services/core/java/com/android/server/notification/ZenModeHelper.java b/services/core/java/com/android/server/notification/ZenModeHelper.java
index a490b9c..4931d3f 100644
--- a/services/core/java/com/android/server/notification/ZenModeHelper.java
+++ b/services/core/java/com/android/server/notification/ZenModeHelper.java
@@ -20,6 +20,10 @@
 import static android.app.NotificationManager.AUTOMATIC_RULE_STATUS_ENABLED;
 import static android.app.NotificationManager.AUTOMATIC_RULE_STATUS_REMOVED;
 import static android.app.NotificationManager.Policy.PRIORITY_SENDERS_ANY;
+import static android.service.notification.DNDModeProto.ROOT_CONFIG;
+
+import static com.android.internal.util.FrameworkStatsLog.ANNOTATION_ID_IS_UID;
+import static com.android.internal.util.FrameworkStatsLog.DND_MODE_RULE;
 
 import android.app.AppOpsManager;
 import android.app.AutomaticZenRule;
@@ -67,6 +71,7 @@
 import android.util.Log;
 import android.util.Slog;
 import android.util.SparseArray;
+import android.util.StatsEvent;
 import android.util.proto.ProtoOutputStream;
 
 import com.android.internal.R;
@@ -103,6 +108,7 @@
     private final SettingsObserver mSettingsObserver;
     private final AppOpsManager mAppOps;
     @VisibleForTesting protected final NotificationManager mNotificationManager;
+    private final SysUiStatsEvent.BuilderFactory mStatsEventBuilderFactory;
     @VisibleForTesting protected ZenModeConfig mDefaultConfig;
     private final ArrayList<Callback> mCallbacks = new ArrayList<Callback>();
     private final ZenModeFiltering mFiltering;
@@ -130,7 +136,8 @@
 
     private String[] mPriorityOnlyDndExemptPackages;
 
-    public ZenModeHelper(Context context, Looper looper, ConditionProviders conditionProviders) {
+    public ZenModeHelper(Context context, Looper looper, ConditionProviders conditionProviders,
+            SysUiStatsEvent.BuilderFactory statsEventBuilderFactory) {
         mContext = context;
         mHandler = new H(looper);
         addCallback(mMetrics);
@@ -148,6 +155,7 @@
         mFiltering = new ZenModeFiltering(mContext);
         mConditions = new ZenModeConditions(this, conditionProviders);
         mServiceConfig = conditionProviders.getConfig();
+        mStatsEventBuilderFactory = statsEventBuilderFactory;
     }
 
     public Looper getLooper() {
@@ -1170,6 +1178,72 @@
         }
     }
 
+    /**
+     * Generate pulled atoms about do not disturb configurations.
+     */
+    public void pullRules(List<StatsEvent> events) {
+        synchronized (mConfig) {
+            final int numConfigs = mConfigs.size();
+            int id = 0;
+            for (int i = 0; i < numConfigs; i++) {
+                final int user = mConfigs.keyAt(i);
+                final ZenModeConfig config = mConfigs.valueAt(i);
+                SysUiStatsEvent.Builder data = mStatsEventBuilderFactory.newBuilder()
+                        .setAtomId(DND_MODE_RULE)
+                        .writeInt(user)
+                        .writeBoolean(config.manualRule != null) // enabled
+                        .writeBoolean(config.areChannelsBypassingDnd)
+                        .writeInt(ROOT_CONFIG)
+                        .writeString("") // name, empty for root config
+                        .writeInt(Process.SYSTEM_UID) // system owns root config
+                        .addBooleanAnnotation(ANNOTATION_ID_IS_UID, true)
+                        .writeByteArray(config.toZenPolicy().toProto());
+                events.add(data.build());
+                if (config.manualRule != null && config.manualRule.enabler != null) {
+                    ruleToProto(user, config.manualRule, events);
+                }
+                for (ZenRule rule : config.automaticRules.values()) {
+                    ruleToProto(user, rule, events);
+                }
+            }
+        }
+    }
+
+    private void ruleToProto(int user, ZenRule rule, List<StatsEvent> events) {
+        // Make the ID safe.
+        String id = rule.id == null ? "" : rule.id;
+        if (!ZenModeConfig.DEFAULT_RULE_IDS.contains(id)) {
+            id = "";
+        }
+
+        // Look for packages and enablers, enablers get priority.
+        String pkg = rule.pkg == null ? "" : rule.pkg;
+        if (rule.enabler != null) {
+            pkg = rule.enabler;
+            id = ZenModeConfig.MANUAL_RULE_ID;
+        }
+
+        // TODO: fetch the uid from the package manager
+        int uid = "android".equals(pkg) ? Process.SYSTEM_UID : 0;
+
+        SysUiStatsEvent.Builder data;
+        data = mStatsEventBuilderFactory.newBuilder()
+                .setAtomId(DND_MODE_RULE)
+                .writeInt(user)
+                .writeBoolean(rule.enabled)
+                .writeBoolean(false) // channels_bypassing unused for rules
+                .writeInt(rule.zenMode)
+                .writeString(id)
+                .writeInt(uid)
+                .addBooleanAnnotation(ANNOTATION_ID_IS_UID, true);
+        byte[] policyProto = new byte[]{};
+        if (rule.zenPolicy != null) {
+            policyProto = rule.zenPolicy.toProto();
+        }
+        data.writeByteArray(policyProto);
+        events.add(data.build());
+    }
+
     @VisibleForTesting
     protected final class RingerModeDelegate implements AudioManagerInternal.RingerModeDelegate {
         @Override
diff --git a/services/core/java/com/android/server/pm/AppsFilter.java b/services/core/java/com/android/server/pm/AppsFilter.java
index 4b6ee71..5b9db64 100644
--- a/services/core/java/com/android/server/pm/AppsFilter.java
+++ b/services/core/java/com/android/server/pm/AppsFilter.java
@@ -32,7 +32,6 @@
 import android.content.pm.parsing.component.ParsedIntentInfo;
 import android.content.pm.parsing.component.ParsedMainComponent;
 import android.content.pm.parsing.component.ParsedProvider;
-import android.os.Binder;
 import android.os.Process;
 import android.os.Trace;
 import android.os.UserHandle;
@@ -239,20 +238,13 @@
         }
 
         private void updateEnabledState(AndroidPackage pkg) {
-            final long token = Binder.clearCallingIdentity();
-            try {
-                // TODO(b/135203078): Do not use toAppInfo
-                final boolean enabled =
-                        mInjector.getCompatibility().isChangeEnabled(
-                                PackageManager.FILTER_APPLICATION_QUERY,
-                                pkg.toAppInfoWithoutState());
-                if (enabled) {
-                    mDisabledPackages.remove(pkg.getPackageName());
-                } else {
-                    mDisabledPackages.add(pkg.getPackageName());
-                }
-            } finally {
-                Binder.restoreCallingIdentity(token);
+            // TODO(b/135203078): Do not use toAppInfo
+            final boolean enabled = mInjector.getCompatibility().isChangeEnabledInternal(
+                    PackageManager.FILTER_APPLICATION_QUERY, pkg.toAppInfoWithoutState());
+            if (enabled) {
+                mDisabledPackages.remove(pkg.getPackageName());
+            } else {
+                mDisabledPackages.add(pkg.getPackageName());
             }
         }
 
diff --git a/services/core/java/com/android/server/pm/PackageAbiHelperImpl.java b/services/core/java/com/android/server/pm/PackageAbiHelperImpl.java
index 0bd8b28..fc58968 100644
--- a/services/core/java/com/android/server/pm/PackageAbiHelperImpl.java
+++ b/services/core/java/com/android/server/pm/PackageAbiHelperImpl.java
@@ -133,8 +133,10 @@
     @Override
     public NativeLibraryPaths getNativeLibraryPaths(AndroidPackage pkg, PackageSetting pkgSetting,
             File appLib32InstallDir) {
-        return getNativeLibraryPaths(new Abis(pkg, pkgSetting), appLib32InstallDir,
-                pkg.getCodePath(), pkg.getBaseCodePath(), pkg.isSystem(),
+        // Trying to derive the paths, thus need the raw ABI info from the parsed package, and the
+        // current state in PackageSetting is irrelevant.
+        return getNativeLibraryPaths(new Abis(pkg.getPrimaryCpuAbi(), pkg.getSecondaryCpuAbi()),
+                appLib32InstallDir, pkg.getCodePath(), pkg.getBaseCodePath(), pkg.isSystem(),
                 pkgSetting.getPkgState().isUpdatedSystemApp());
     }
 
diff --git a/services/core/java/com/android/server/pm/PackageInstallerSession.java b/services/core/java/com/android/server/pm/PackageInstallerSession.java
index 7ab05c4..de8ad6b 100644
--- a/services/core/java/com/android/server/pm/PackageInstallerSession.java
+++ b/services/core/java/com/android/server/pm/PackageInstallerSession.java
@@ -2108,6 +2108,7 @@
                 baseApk = apk;
             }
 
+            // Validate and add Dex Metadata (.dm).
             final File dexMetadataFile = DexMetadataHelper.findDexMetadataForFile(addedFile);
             if (dexMetadataFile != null) {
                 if (!FileUtils.isValidExtFilename(dexMetadataFile.getName())) {
@@ -2295,6 +2296,13 @@
             throw new PackageManagerException(INSTALL_FAILED_MISSING_SPLIT,
                     "Missing split for " + mPackageName);
         }
+
+        final boolean isInstallerShell = (mInstallerUid == Process.SHELL_UID);
+        if (isInstallerShell && isIncrementalInstallation() && mIncrementalFileStorages != null) {
+            if (!baseApk.debuggable && !baseApk.profilableByShell) {
+                mIncrementalFileStorages.disableReadLogs();
+            }
+        }
     }
 
     private void resolveAndStageFile(File origFile, File targetFile)
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index 766fae6..ae8b3a0 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -10713,6 +10713,20 @@
         return resultList;
     }
 
+    private int getVendorPartitionVersion() {
+        final String version = SystemProperties.get("ro.vndk.version");
+        if (!version.isEmpty()) {
+            try {
+                return Integer.parseInt(version);
+            } catch (NumberFormatException ignore) {
+                if (ArrayUtils.contains(Build.VERSION.ACTIVE_CODENAMES, version)) {
+                    return Build.VERSION_CODES.CUR_DEVELOPMENT;
+                }
+            }
+        }
+        return Build.VERSION_CODES.P;
+    }
+
     @GuardedBy({"mInstallLock", "mLock"})
     private ScanResult scanPackageTracedLI(ParsedPackage parsedPackage,
             final @ParseFlags int parseFlags, @ScanFlags int scanFlags, long currentTime,
@@ -10894,7 +10908,7 @@
 
         // Scan as privileged apps that share a user with a priv-app.
         final boolean skipVendorPrivilegeScan = ((scanFlags & SCAN_AS_VENDOR) != 0)
-                && SystemProperties.getInt("ro.vndk.version", 28) < 28;
+                && getVendorPartitionVersion() < 28;
         if (((scanFlags & SCAN_AS_PRIVILEGED) == 0)
                 && !pkg.isPrivileged()
                 && (pkg.getSharedUserId() != null)
@@ -11053,7 +11067,7 @@
         } else {
             pkgSetting = result.pkgSetting;
             if (originalPkgSetting != null) {
-                mSettings.addRenamedPackageLPw(parsedPackage.getPackageName(),
+                mSettings.addRenamedPackageLPw(parsedPackage.getRealPackage(),
                         originalPkgSetting.name);
                 mTransferredPackages.add(originalPkgSetting.name);
             }
@@ -11162,7 +11176,7 @@
     @GuardedBy("mLock")
     private @Nullable PackageSetting getOriginalPackageLocked(@NonNull AndroidPackage pkg,
             @Nullable String renamedPkgName) {
-        if (!isPackageRenamed(pkg, renamedPkgName)) {
+        if (isPackageRenamed(pkg, renamedPkgName)) {
             return null;
         }
         for (int i = ArrayUtils.size(pkg.getOriginalPackages()) - 1; i >= 0; --i) {
@@ -12070,6 +12084,20 @@
                                     + pkg.getPackageName()
                                     + " is static and cannot be upgraded.");
                         }
+                    } else {
+                        if ((scanFlags & SCAN_AS_VENDOR) != 0) {
+                            if (pkg.getTargetSdkVersion() < getVendorPartitionVersion()) {
+                                Slog.w(TAG, "System overlay " + pkg.getPackageName()
+                                        + " targets an SDK below the required SDK level of vendor"
+                                        + " overlays (" + getVendorPartitionVersion() + ")."
+                                        + " This will become an install error in a future release");
+                            }
+                        } else if (pkg.getTargetSdkVersion() < Build.VERSION.SDK_INT) {
+                            Slog.w(TAG, "System overlay " + pkg.getPackageName()
+                                    + " targets an SDK below the required SDK level of system"
+                                    + " overlays (" + Build.VERSION.SDK_INT + ")."
+                                    + " This will become an install error in a future release");
+                        }
                     }
                 } else {
                     // A non-preloaded overlay packages must have targetSdkVersion >= Q, or be
@@ -13490,6 +13518,17 @@
         removeSuspensionsBySuspendingPackage(allPackages, suspendingPackage::equals, userId);
     }
 
+    boolean isSuspendingAnyPackages(String suspendingPackage, int userId) {
+        synchronized (mLock) {
+            for (final PackageSetting ps : mSettings.mPackages.values()) {
+                if (ps.isSuspendedBy(suspendingPackage, userId)) {
+                    return true;
+                }
+            }
+        }
+        return false;
+    }
+
     /**
      * Removes any suspensions on given packages that were added by packages that pass the given
      * predicate.
@@ -23885,7 +23924,6 @@
                     callingUid);
         }
 
-
         @Override
         public boolean isPlatformSigned(String packageName) {
             PackageSetting packageSetting = mSettings.mPackages.get(packageName);
@@ -24990,6 +25028,16 @@
                 mSettings.writePackageRestrictionsLPr(userId);
             }
         }
+
+        @Override
+        public void unsuspendForSuspendingPackage(final String packageName, int affectedUser) {
+            PackageManagerService.this.unsuspendForSuspendingPackage(packageName, affectedUser);
+        }
+
+        @Override
+        public boolean isSuspendingAnyPackages(String suspendingPackage, int userId) {
+            return PackageManagerService.this.isSuspendingAnyPackages(suspendingPackage, userId);
+        }
     }
 
     @GuardedBy("mLock")
diff --git a/services/core/java/com/android/server/pm/PackageSettingBase.java b/services/core/java/com/android/server/pm/PackageSettingBase.java
index 00a5fe76..834303c 100644
--- a/services/core/java/com/android/server/pm/PackageSettingBase.java
+++ b/services/core/java/com/android/server/pm/PackageSettingBase.java
@@ -422,6 +422,11 @@
         return readUserState(userId).suspended;
     }
 
+    boolean isSuspendedBy(String suspendingPackage, int userId) {
+        final PackageUserState state = readUserState(userId);
+        return state.suspendParams != null && state.suspendParams.containsKey(suspendingPackage);
+    }
+
     void addOrUpdateSuspension(String suspendingPackage, SuspendDialogInfo dialogInfo,
             PersistableBundle appExtras, PersistableBundle launcherExtras, int userId) {
         final PackageUserState existingUserState = modifyUserState(userId);
diff --git a/services/core/java/com/android/server/pm/SELinuxMMAC.java b/services/core/java/com/android/server/pm/SELinuxMMAC.java
index 67e1994..fdd9636 100644
--- a/services/core/java/com/android/server/pm/SELinuxMMAC.java
+++ b/services/core/java/com/android/server/pm/SELinuxMMAC.java
@@ -349,7 +349,8 @@
         if ((sharedUserSetting != null) && (sharedUserSetting.packages.size() != 0)) {
             return sharedUserSetting.seInfoTargetSdkVersion;
         }
-        if (compatibility.isChangeEnabled(SELINUX_LATEST_CHANGES, pkg.toAppInfoWithoutState())) {
+        if (compatibility.isChangeEnabledInternal(SELINUX_LATEST_CHANGES,
+                pkg.toAppInfoWithoutState())) {
             return android.os.Build.VERSION_CODES.R;
         }
 
diff --git a/services/core/java/com/android/server/pm/StagingManager.java b/services/core/java/com/android/server/pm/StagingManager.java
index 8ccf837..515225b 100644
--- a/services/core/java/com/android/server/pm/StagingManager.java
+++ b/services/core/java/com/android/server/pm/StagingManager.java
@@ -53,6 +53,7 @@
 import android.os.PowerManager;
 import android.os.RemoteException;
 import android.os.ServiceManager;
+import android.os.SystemProperties;
 import android.os.UserHandle;
 import android.os.UserManagerInternal;
 import android.os.storage.IStorageManager;
@@ -1155,6 +1156,11 @@
     }
 
     private void checkStateAndResume(@NonNull PackageInstallerSession session) {
+        // Do not resume session if boot completed already
+        if (SystemProperties.getBoolean("sys.boot_completed", false)) {
+            return;
+        }
+
         if (!session.isCommitted()) {
             // Session hasn't been committed yet, ignore.
             return;
diff --git a/services/core/java/com/android/server/pm/TEST_MAPPING b/services/core/java/com/android/server/pm/TEST_MAPPING
index 2614076..eb51cc3 100644
--- a/services/core/java/com/android/server/pm/TEST_MAPPING
+++ b/services/core/java/com/android/server/pm/TEST_MAPPING
@@ -69,6 +69,9 @@
             "exclude-annotation": "androidx.test.filters.Suppress"
         }
       ]
+    },
+    {
+      "name": "PackageManagerServiceHostTests"
     }
   ],
   "postsubmit": [
diff --git a/services/core/java/com/android/server/pm/UserManagerService.java b/services/core/java/com/android/server/pm/UserManagerService.java
index 40fa798..2a6997c 100644
--- a/services/core/java/com/android/server/pm/UserManagerService.java
+++ b/services/core/java/com/android/server/pm/UserManagerService.java
@@ -989,6 +989,15 @@
 
         ensureCanModifyQuietMode(
                 callingPackage, Binder.getCallingUid(), userId, target != null, dontAskCredential);
+
+        if (onlyIfCredentialNotRequired && callingPackage.equals(
+                getPackageManagerInternal().getSystemUiServiceComponent().getPackageName())) {
+            // This is to prevent SysUI from accidentally allowing the profile to turned on
+            // without password when keyguard is still locked.
+            throw new SecurityException("SystemUI is not allowed to set "
+                    + "QUIET_MODE_DISABLE_ONLY_IF_CREDENTIAL_NOT_REQUIRED");
+        }
+
         final long identity = Binder.clearCallingIdentity();
         try {
             if (enableQuietMode) {
@@ -996,7 +1005,17 @@
                         userId, true /* enableQuietMode */, target, callingPackage);
                 return true;
             }
-            mLockPatternUtils.tryUnlockWithCachedUnifiedChallenge(userId);
+            if (mLockPatternUtils.isManagedProfileWithUnifiedChallenge(userId)) {
+                KeyguardManager km = mContext.getSystemService(KeyguardManager.class);
+                // Normally only attempt to auto-unlock unified challenge if keyguard is not showing
+                // (to stop turning profile on automatically via the QS tile), except when we
+                // are called with QUIET_MODE_DISABLE_ONLY_IF_CREDENTIAL_NOT_REQUIRED, in which
+                // case always attempt to auto-unlock.
+                if (!km.isDeviceLocked(mLocalService.getProfileParentId(userId))
+                        || onlyIfCredentialNotRequired) {
+                    mLockPatternUtils.tryUnlockWithCachedUnifiedChallenge(userId);
+                }
+            }
             final boolean needToShowConfirmCredential = !dontAskCredential
                     && mLockPatternUtils.isSecure(userId)
                     && !StorageManager.isUserKeyUnlocked(userId);
@@ -1029,6 +1048,8 @@
      */
     private void ensureCanModifyQuietMode(String callingPackage, int callingUid,
             @UserIdInt int targetUserId, boolean startIntent, boolean dontAskCredential) {
+        verifyCallingPackage(callingPackage, callingUid);
+
         if (hasManageUsersPermission()) {
             return;
         }
@@ -1050,7 +1071,6 @@
             return;
         }
 
-        verifyCallingPackage(callingPackage, callingUid);
         final ShortcutServiceInternal shortcutInternal =
                 LocalServices.getService(ShortcutServiceInternal.class);
         if (shortcutInternal != null) {
diff --git a/services/core/java/com/android/server/pm/UserSystemPackageInstaller.java b/services/core/java/com/android/server/pm/UserSystemPackageInstaller.java
index 58732b4..492b84a 100644
--- a/services/core/java/com/android/server/pm/UserSystemPackageInstaller.java
+++ b/services/core/java/com/android/server/pm/UserSystemPackageInstaller.java
@@ -96,6 +96,8 @@
 class UserSystemPackageInstaller {
     private static final String TAG = "UserManagerService";
 
+    private static final boolean DEBUG = false;
+
     /**
      * System Property whether to only install system packages on a user if they're whitelisted for
      * that user type. These are flags and can be freely combined.
@@ -328,12 +330,15 @@
         // Check whether all whitelisted packages are indeed on the system.
         final String notPresentFmt = "%s is whitelisted but not present.";
         final String notSystemFmt = "%s is whitelisted and present but not a system package.";
+        final String overlayPackageFmt = "%s is whitelisted but it's auto-generated RRO package.";
         for (String pkgName : allWhitelistedPackages) {
             final AndroidPackage pkg = pmInt.getPackage(pkgName);
             if (pkg == null) {
                 warnings.add(String.format(notPresentFmt, pkgName));
             } else if (!pkg.isSystem()) {
                 warnings.add(String.format(notSystemFmt, pkgName));
+            } else if (isAutoGeneratedRRO(pkg)) {
+                warnings.add(String.format(overlayPackageFmt, pkgName));
             }
         }
         return warnings;
@@ -358,7 +363,8 @@
         pmInt.forEachPackage(pkg -> {
             if (!pkg.isSystem()) return;
             final String pkgName = pkg.getManifestPackageName();
-            if (!allWhitelistedPackages.contains(pkgName)) {
+            if (!allWhitelistedPackages.contains(pkgName)
+                    && !isAutoGeneratedRRO(pmInt.getPackage(pkgName))) {
                 errors.add(String.format(logMessageFmt, pkgName));
             }
         });
@@ -407,6 +413,23 @@
         return isImplicitWhitelistSystemMode(getWhitelistMode());
     }
 
+    /**
+     * Whether package name has auto-generated RRO package name suffix.
+     */
+    @VisibleForTesting
+    static boolean hasAutoGeneratedRROSuffix(String name) {
+        return name.endsWith(".auto_generated_rro_product__")
+                || name.endsWith(".auto_generated_rro_vendor__");
+    }
+
+    /**
+     * Whether the package is auto-generated RRO package.
+     */
+    private static boolean isAutoGeneratedRRO(AndroidPackage pkg) {
+        return pkg.isOverlay()
+                && (hasAutoGeneratedRROSuffix(pkg.getManifestPackageName()));
+    }
+
     /** See {@link #isEnforceMode()}. */
     private static boolean isEnforceMode(int whitelistMode) {
         return (whitelistMode & USER_TYPE_PACKAGE_WHITELIST_MODE_ENFORCE) != 0;
@@ -518,7 +541,18 @@
     static boolean shouldInstallPackage(AndroidPackage sysPkg,
             @NonNull ArrayMap<String, Long> userTypeWhitelist,
             @NonNull Set<String> userWhitelist, boolean implicitlyWhitelist) {
-        final String pkgName = sysPkg.getManifestPackageName();
+        final String pkgName;
+        if (isAutoGeneratedRRO(sysPkg)) {
+            pkgName = sysPkg.getOverlayTarget();
+            if (DEBUG) {
+                Slog.i(TAG, "shouldInstallPackage(): " + sysPkg.getManifestPackageName()
+                        + " is auto-generated RRO package, will look for overlay system package: "
+                        + pkgName);
+            }
+        } else {
+            pkgName = sysPkg.getManifestPackageName();
+        }
+
         return (implicitlyWhitelist && !userTypeWhitelist.containsKey(pkgName))
                 || userWhitelist.contains(pkgName);
     }
diff --git a/services/core/java/com/android/server/pm/dex/ArtManagerService.java b/services/core/java/com/android/server/pm/dex/ArtManagerService.java
index 51e07faf..8000c63 100644
--- a/services/core/java/com/android/server/pm/dex/ArtManagerService.java
+++ b/services/core/java/com/android/server/pm/dex/ArtManagerService.java
@@ -63,6 +63,10 @@
 
 import java.io.File;
 import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
 import java.util.Objects;
 
 /**
@@ -557,6 +561,20 @@
     private static final int TRON_COMPILATION_FILTER_FAKE_RUN_FROM_APK = 12;
     private static final int TRON_COMPILATION_FILTER_FAKE_RUN_FROM_APK_FALLBACK = 13;
     private static final int TRON_COMPILATION_FILTER_FAKE_RUN_FROM_VDEX_FALLBACK = 14;
+    // Filter with IORap
+    private static final int TRON_COMPILATION_FILTER_ASSUMED_VERIFIED_IORAP = 15;
+    private static final int TRON_COMPILATION_FILTER_EXTRACT_IORAP = 16;
+    private static final int TRON_COMPILATION_FILTER_VERIFY_IORAP = 17;
+    private static final int TRON_COMPILATION_FILTER_QUICKEN_IORAP = 18;
+    private static final int TRON_COMPILATION_FILTER_SPACE_PROFILE_IORAP = 19;
+    private static final int TRON_COMPILATION_FILTER_SPACE_IORAP = 20;
+    private static final int TRON_COMPILATION_FILTER_SPEED_PROFILE_IORAP = 21;
+    private static final int TRON_COMPILATION_FILTER_SPEED_IORAP = 22;
+    private static final int TRON_COMPILATION_FILTER_EVERYTHING_PROFILE_IORAP = 23;
+    private static final int TRON_COMPILATION_FILTER_EVERYTHING_IORAP = 24;
+    private static final int TRON_COMPILATION_FILTER_FAKE_RUN_FROM_APK_IORAP = 25;
+    private static final int TRON_COMPILATION_FILTER_FAKE_RUN_FROM_APK_FALLBACK_IORAP = 26;
+    private static final int TRON_COMPILATION_FILTER_FAKE_RUN_FROM_VDEX_FALLBACK_IORAP = 27;
 
     // Constants used for logging compilation reason to TRON.
     // DO NOT CHANGE existing values.
@@ -623,6 +641,22 @@
                 return TRON_COMPILATION_FILTER_FAKE_RUN_FROM_APK_FALLBACK;
             case "run-from-vdex-fallback" :
                 return TRON_COMPILATION_FILTER_FAKE_RUN_FROM_VDEX_FALLBACK;
+            case "assume-verified-iorap" : return TRON_COMPILATION_FILTER_ASSUMED_VERIFIED_IORAP;
+            case "extract-iorap" : return TRON_COMPILATION_FILTER_EXTRACT_IORAP;
+            case "verify-iorap" : return TRON_COMPILATION_FILTER_VERIFY_IORAP;
+            case "quicken-iorap" : return TRON_COMPILATION_FILTER_QUICKEN_IORAP;
+            case "space-profile-iorap" : return TRON_COMPILATION_FILTER_SPACE_PROFILE_IORAP;
+            case "space-iorap" : return TRON_COMPILATION_FILTER_SPACE_IORAP;
+            case "speed-profile-iorap" : return TRON_COMPILATION_FILTER_SPEED_PROFILE_IORAP;
+            case "speed-iorap" : return TRON_COMPILATION_FILTER_SPEED_IORAP;
+            case "everything-profile-iorap" :
+                return TRON_COMPILATION_FILTER_EVERYTHING_PROFILE_IORAP;
+            case "everything-iorap" : return TRON_COMPILATION_FILTER_EVERYTHING_IORAP;
+            case "run-from-apk-iorap" : return TRON_COMPILATION_FILTER_FAKE_RUN_FROM_APK_IORAP;
+            case "run-from-apk-fallback-iorap" :
+                return TRON_COMPILATION_FILTER_FAKE_RUN_FROM_APK_FALLBACK_IORAP;
+            case "run-from-vdex-fallback-iorap" :
+                return TRON_COMPILATION_FILTER_FAKE_RUN_FROM_VDEX_FALLBACK_IORAP;
             default: return TRON_COMPILATION_FILTER_UNKNOWN;
         }
     }
@@ -640,9 +674,12 @@
     }
 
     private class ArtManagerInternalImpl extends ArtManagerInternal {
+        private static final String IORAP_DIR = "/data/misc/iorapd";
+        private static final String TAG = "ArtManagerInternalImpl";
+
         @Override
         public PackageOptimizationInfo getPackageOptimizationInfo(
-                ApplicationInfo info, String abi) {
+                ApplicationInfo info, String abi, String activityName) {
             String compilationReason;
             String compilationFilter;
             try {
@@ -662,11 +699,45 @@
                 compilationReason = "error";
             }
 
+            if (checkIorapCompiledTrace(info.packageName, activityName, info.longVersionCode)) {
+                compilationFilter = compilationFilter + "-iorap";
+            }
+
             int compilationFilterTronValue = getCompilationFilterTronValue(compilationFilter);
             int compilationReasonTronValue = getCompilationReasonTronValue(compilationReason);
 
             return new PackageOptimizationInfo(
                     compilationFilterTronValue, compilationReasonTronValue);
         }
+
+        /*
+         * Checks the existence of IORap compiled trace for an app.
+         *
+         * @return true if the compiled trace exists and the size is greater than 1kb.
+         */
+        private boolean checkIorapCompiledTrace(
+                String packageName, String activityName, long version) {
+            // For example: /data/misc/iorapd/com.google.android.GoogleCamera/
+            // 60092239/com.android.camera.CameraLauncher/compiled_traces/compiled_trace.pb
+            Path tracePath = Paths.get(IORAP_DIR,
+                                       packageName,
+                                       Long.toString(version),
+                                       activityName,
+                                       "compiled_traces",
+                                       "compiled_trace.pb");
+            try {
+                boolean exists =  Files.exists(tracePath);
+                Log.d(TAG, tracePath.toString() + (exists? " exists" : " doesn't exist"));
+                if (exists) {
+                    long bytes = Files.size(tracePath);
+                    Log.d(TAG, tracePath.toString() + " size is " + Long.toString(bytes));
+                    return bytes > 0L;
+                }
+                return exists;
+            } catch (IOException e) {
+                Log.d(TAG, e.getMessage());
+                return false;
+            }
+        }
     }
 }
diff --git a/services/core/java/com/android/server/power/Notifier.java b/services/core/java/com/android/server/power/Notifier.java
index 0b95be1..8f0fd60 100644
--- a/services/core/java/com/android/server/power/Notifier.java
+++ b/services/core/java/com/android/server/power/Notifier.java
@@ -616,6 +616,7 @@
         } catch (RemoteException ex) {
             // Ignore
         }
+        FrameworkStatsLog.write(FrameworkStatsLog.DISPLAY_WAKE_REPORTED, reason);
     }
 
     /**
diff --git a/services/core/java/com/android/server/power/PreRebootLogger.java b/services/core/java/com/android/server/power/PreRebootLogger.java
index cda00b4..c9e81ed 100644
--- a/services/core/java/com/android/server/power/PreRebootLogger.java
+++ b/services/core/java/com/android/server/power/PreRebootLogger.java
@@ -16,6 +16,7 @@
 
 package com.android.server.power;
 
+import android.annotation.DurationMillisLong;
 import android.annotation.NonNull;
 import android.content.Context;
 import android.os.Environment;
@@ -23,7 +24,7 @@
 import android.os.ParcelFileDescriptor;
 import android.os.RemoteException;
 import android.os.ServiceManager;
-import android.provider.Settings;
+import android.provider.Settings.Global;
 import android.util.Slog;
 
 import com.android.internal.annotations.GuardedBy;
@@ -34,6 +35,8 @@
 import java.io.FileNotFoundException;
 import java.io.FileWriter;
 import java.io.IOException;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.AtomicBoolean;
 
 /**
  * Provides utils to dump/wipe pre-reboot information.
@@ -46,10 +49,12 @@
     private static final String[] SERVICES_TO_DUMP = {Context.ROLLBACK_SERVICE, "package"};
 
     private static final Object sLock = new Object();
+    private static final long MAX_DUMP_TIME = TimeUnit.SECONDS.toMillis(20);
 
     /**
      * Process pre-reboot information. Dump pre-reboot information to {@link #PREREBOOT_DIR} if
-     * enabled {@link Settings.Global#ADB_ENABLED}; wipe dumped information otherwise.
+     * enabled {@link Settings.Global#ADB_ENABLED} and having active staged session; wipe dumped
+     * information otherwise.
      */
     static void log(Context context) {
         log(context, getDumpDir());
@@ -57,28 +62,49 @@
 
     @VisibleForTesting
     static void log(Context context, @NonNull File dumpDir) {
-        if (Settings.Global.getInt(
-                context.getContentResolver(), Settings.Global.ADB_ENABLED, 0) == 1) {
-            Slog.d(TAG, "Dumping pre-reboot information...");
-            dump(dumpDir);
+        if (needDump(context)) {
+            dump(dumpDir, MAX_DUMP_TIME);
         } else {
-            Slog.d(TAG, "Wiping pre-reboot information...");
             wipe(dumpDir);
         }
     }
 
-    private static void dump(@NonNull File dumpDir) {
-        synchronized (sLock) {
-            for (String buffer : BUFFERS_TO_DUMP) {
-                dumpLogsLocked(dumpDir, buffer);
+    private static boolean needDump(Context context) {
+        return Global.getInt(context.getContentResolver(), Global.ADB_ENABLED, 0) == 1
+                && !context.getPackageManager().getPackageInstaller()
+                        .getActiveStagedSessions().isEmpty();
+    }
+
+    @VisibleForTesting
+    static void dump(@NonNull File dumpDir, @DurationMillisLong long maxWaitTime) {
+        Slog.d(TAG, "Dumping pre-reboot information...");
+        final AtomicBoolean done = new AtomicBoolean(false);
+        final Thread t = new Thread(() -> {
+            synchronized (sLock) {
+                for (String buffer : BUFFERS_TO_DUMP) {
+                    dumpLogsLocked(dumpDir, buffer);
+                }
+                for (String service : SERVICES_TO_DUMP) {
+                    dumpServiceLocked(dumpDir, service);
+                }
             }
-            for (String service : SERVICES_TO_DUMP) {
-                dumpServiceLocked(dumpDir, service);
-            }
+            done.set(true);
+        });
+        t.start();
+
+        try {
+            t.join(maxWaitTime);
+        } catch (InterruptedException e) {
+            Slog.e(TAG, "Failed to dump pre-reboot information due to interrupted", e);
+        }
+
+        if (!done.get()) {
+            Slog.w(TAG, "Failed to dump pre-reboot information due to timeout");
         }
     }
 
     private static void wipe(@NonNull File dumpDir) {
+        Slog.d(TAG, "Wiping pre-reboot information...");
         synchronized (sLock) {
             for (File file : dumpDir.listFiles()) {
                 file.delete();
@@ -109,7 +135,7 @@
                     {"logcat", "-d", "-b", buffer, "-f", dumpFile.getAbsolutePath()};
             Runtime.getRuntime().exec(cmdline).waitFor();
         } catch (IOException | InterruptedException e) {
-            Slog.d(TAG, "Dump system log buffer before reboot fail", e);
+            Slog.e(TAG, "Failed to dump system log buffer before reboot", e);
         }
     }
 
@@ -127,7 +153,7 @@
                             | ParcelFileDescriptor.MODE_WRITE_ONLY);
             binder.dump(fd.getFileDescriptor(), ArrayUtils.emptyArray(String.class));
         } catch (FileNotFoundException | RemoteException e) {
-            Slog.d(TAG, String.format("Dump %s service before reboot fail", serviceName), e);
+            Slog.e(TAG, String.format("Failed to dump %s service before reboot", serviceName), e);
         }
     }
 }
diff --git a/services/core/java/com/android/server/slice/SliceClientPermissions.java b/services/core/java/com/android/server/slice/SliceClientPermissions.java
index ab94a59..e241205 100644
--- a/services/core/java/com/android/server/slice/SliceClientPermissions.java
+++ b/services/core/java/com/android/server/slice/SliceClientPermissions.java
@@ -160,6 +160,9 @@
         // Get to the beginning of the provider.
         while (parser.getEventType() != XmlPullParser.START_TAG
                 || !TAG_CLIENT.equals(parser.getName())) {
+            if (parser.getEventType() == XmlPullParser.END_DOCUMENT) {
+                throw new XmlPullParserException("Can't find client tag in xml");
+            }
             parser.next();
         }
         int depth = parser.getDepth();
@@ -173,6 +176,9 @@
         parser.next();
 
         while (parser.getDepth() > depth) {
+            if (parser.getEventType() == XmlPullParser.END_DOCUMENT) {
+                return provider;
+            }
             if (parser.getEventType() == XmlPullParser.START_TAG
                     && TAG_AUTHORITY.equals(parser.getName())) {
                 try {
diff --git a/services/core/java/com/android/server/slice/SlicePermissionManager.java b/services/core/java/com/android/server/slice/SlicePermissionManager.java
index 1d1c28f..343d2e3 100644
--- a/services/core/java/com/android/server/slice/SlicePermissionManager.java
+++ b/services/core/java/com/android/server/slice/SlicePermissionManager.java
@@ -130,7 +130,7 @@
         }
         SliceClientPermissions client = getClient(pkgUser);
         client.clear();
-        mHandler.obtainMessage(H.MSG_REMOVE, pkgUser);
+        mHandler.obtainMessage(H.MSG_REMOVE, pkgUser).sendToTarget();
     }
 
     public String[] getAllPackagesGranted(String pkg) {
diff --git a/services/core/java/com/android/server/soundtrigger_middleware/SoundTriggerModule.java b/services/core/java/com/android/server/soundtrigger_middleware/SoundTriggerModule.java
index 2f963b7..522e5e1 100644
--- a/services/core/java/com/android/server/soundtrigger_middleware/SoundTriggerModule.java
+++ b/services/core/java/com/android/server/soundtrigger_middleware/SoundTriggerModule.java
@@ -20,8 +20,6 @@
 import android.annotation.Nullable;
 import android.hardware.soundtrigger.V2_1.ISoundTriggerHwCallback;
 import android.hardware.soundtrigger.V2_2.ISoundTriggerHw;
-import android.media.audio.common.AudioConfig;
-import android.media.audio.common.AudioOffloadInfo;
 import android.media.soundtrigger_middleware.ISoundTriggerCallback;
 import android.media.soundtrigger_middleware.ISoundTriggerModule;
 import android.media.soundtrigger_middleware.ModelParameterRange;
@@ -30,6 +28,7 @@
 import android.media.soundtrigger_middleware.PhraseSoundModel;
 import android.media.soundtrigger_middleware.RecognitionConfig;
 import android.media.soundtrigger_middleware.RecognitionEvent;
+import android.media.soundtrigger_middleware.RecognitionStatus;
 import android.media.soundtrigger_middleware.SoundModel;
 import android.media.soundtrigger_middleware.SoundModelType;
 import android.media.soundtrigger_middleware.SoundTriggerModuleProperties;
@@ -579,7 +578,7 @@
                     @NonNull ISoundTriggerHwCallback.RecognitionEvent recognitionEvent,
                     int cookie) {
                 synchronized (SoundTriggerModule.this) {
-                    android.media.soundtrigger_middleware.RecognitionEvent aidlEvent =
+                    RecognitionEvent aidlEvent =
                             ConversionUtil.hidl2aidlRecognitionEvent(recognitionEvent);
                     aidlEvent.captureSession = mSession.mSessionHandle;
                     try {
@@ -589,8 +588,7 @@
                         // In any case, client callbacks are considered best effort.
                         Log.e(TAG, "Client callback execption.", e);
                     }
-                    if (aidlEvent.status
-                            != android.media.soundtrigger_middleware.RecognitionStatus.FORCED) {
+                    if (aidlEvent.status != RecognitionStatus.FORCED) {
                         setState(ModelState.LOADED);
                     }
                 }
@@ -601,7 +599,7 @@
                     @NonNull ISoundTriggerHwCallback.PhraseRecognitionEvent phraseRecognitionEvent,
                     int cookie) {
                 synchronized (SoundTriggerModule.this) {
-                    android.media.soundtrigger_middleware.PhraseRecognitionEvent aidlEvent =
+                    PhraseRecognitionEvent aidlEvent =
                             ConversionUtil.hidl2aidlPhraseRecognitionEvent(phraseRecognitionEvent);
                     aidlEvent.common.captureSession = mSession.mSessionHandle;
                     try {
@@ -611,8 +609,7 @@
                         // In any case, client callbacks are considered best effort.
                         Log.e(TAG, "Client callback execption.", e);
                     }
-                    if (aidlEvent.common.status
-                            != android.media.soundtrigger_middleware.RecognitionStatus.FORCED) {
+                    if (aidlEvent.common.status != RecognitionStatus.FORCED) {
                         setState(ModelState.LOADED);
                     }
                 }
@@ -623,15 +620,13 @@
     /**
      * Creates a default-initialized recognition event.
      *
-     * Object fields are default constructed.
-     * Array fields are initialized to 0 length.
+     * Non-nullable object fields are default constructed.
+     * Non-nullable array fields are initialized to 0 length.
      *
      * @return The event.
      */
     private static RecognitionEvent newEmptyRecognitionEvent() {
         RecognitionEvent result = new RecognitionEvent();
-        result.audioConfig = new AudioConfig();
-        result.audioConfig.offloadInfo = new AudioOffloadInfo();
         result.data = new byte[0];
         return result;
     }
@@ -639,8 +634,8 @@
     /**
      * Creates a default-initialized phrase recognition event.
      *
-     * Object fields are default constructed.
-     * Array fields are initialized to 0 length.
+     * Non-nullable object fields are default constructed.
+     * Non-nullable array fields are initialized to 0 length.
      *
      * @return The event.
      */
diff --git a/services/core/java/com/android/server/stats/pull/StatsPullAtomService.java b/services/core/java/com/android/server/stats/pull/StatsPullAtomService.java
index c0c9b32..7fe21e32 100644
--- a/services/core/java/com/android/server/stats/pull/StatsPullAtomService.java
+++ b/services/core/java/com/android/server/stats/pull/StatsPullAtomService.java
@@ -191,7 +191,6 @@
 import java.util.Set;
 import java.util.UUID;
 import java.util.concurrent.CompletableFuture;
-import java.util.concurrent.CopyOnWriteArrayList;
 import java.util.concurrent.Executor;
 import java.util.concurrent.ThreadLocalRandom;
 import java.util.concurrent.TimeUnit;
@@ -210,14 +209,6 @@
     // Random seed stable for StatsPullAtomService life cycle - can be used for stable sampling
     private static final int RANDOM_SEED = new Random().nextInt();
 
-    /**
-     * Lowest available uid for apps.
-     *
-     * <p>Used to quickly discard memory snapshots of the zygote forks from native process
-     * measurements.
-     */
-    private static final int MIN_APP_UID = 10_000;
-
     private static final int DIMENSION_KEY_SIZE_HARD_LIMIT = 800;
     private static final int DIMENSION_KEY_SIZE_SOFT_LIMIT = 500;
     private static final long APP_OPS_SAMPLING_INITIALIZATION_DELAY_MILLIS = 45000;
@@ -257,21 +248,17 @@
     @GuardedBy("mNotificationStatsLock")
     private INotificationManager mNotificationManagerService;
 
-    private final Object mProcessStatsLock = new Object();
-    @GuardedBy("mProcessStatsLock")
+    @GuardedBy("mProcStatsLock")
     private IProcessStats mProcessStatsService;
 
-    private final Object mCpuTrackerLock = new Object();
-    @GuardedBy("mCpuTrackerLock")
+    @GuardedBy("mProcessCpuTimeLock")
     private ProcessCpuTracker mProcessCpuTracker;
 
-    private final Object mDebugElapsedClockLock = new Object();
     @GuardedBy("mDebugElapsedClockLock")
     private long mDebugElapsedClockPreviousValue = 0;
     @GuardedBy("mDebugElapsedClockLock")
     private long mDebugElapsedClockPullCount = 0;
 
-    private final Object mDebugFailingElapsedClockLock = new Object();
     @GuardedBy("mDebugFailingElapsedClockLock")
     private long mDebugFailingElapsedClockPreviousValue = 0;
     @GuardedBy("mDebugFailingElapsedClockLock")
@@ -284,26 +271,40 @@
     private TelephonyManager mTelephony;
     private SubscriptionManager mSubscriptionManager;
 
+    @GuardedBy("mKernelWakelockLock")
     private KernelWakelockReader mKernelWakelockReader;
+    @GuardedBy("mKernelWakelockLock")
     private KernelWakelockStats mTmpWakelockStats;
 
+    @GuardedBy("mDiskIoLock")
     private StoragedUidIoStatsReader mStoragedUidIoStatsReader;
 
+    @GuardedBy("mCpuTimePerFreqLock")
     private KernelCpuSpeedReader[] mKernelCpuSpeedReaders;
     // Disables throttler on CPU time readers.
+    @GuardedBy("mCpuTimePerUidLock")
     private KernelCpuUidUserSysTimeReader mCpuUidUserSysTimeReader;
+    @GuardedBy("mCpuTimePerUidFreqLock")
     private KernelCpuUidFreqTimeReader mCpuUidFreqTimeReader;
+    @GuardedBy("mCpuActiveTimeLock")
     private KernelCpuUidActiveTimeReader mCpuUidActiveTimeReader;
+    @GuardedBy("mClusterTimeLock")
     private KernelCpuUidClusterTimeReader mCpuUidClusterTimeReader;
 
+    @GuardedBy("mProcStatsLock")
     private File mBaseDir;
 
+    @GuardedBy("mHealthHalLock")
     private BatteryService.HealthServiceWrapper mHealthService;
 
     @Nullable
+    @GuardedBy("mCpuTimePerThreadFreqLock")
     private KernelCpuThreadReaderDiff mKernelCpuThreadReader;
 
+    private final Object mBatteryStatsHelperLock = new Object();
+    @GuardedBy("mBatteryStatsHelperLock")
     private BatteryStatsHelper mBatteryStatsHelper = null;
+    @GuardedBy("mBatteryStatsHelperLock")
     private long mBatteryStatsHelperTimestampMs = -MAX_BATTERY_STATS_HELPER_FREQUENCY_MS;
 
     private StatsPullAtomCallbackImpl mStatsCallbackImpl;
@@ -311,19 +312,75 @@
     private final Object mAppOpsSamplingRateLock = new Object();
     @GuardedBy("mAppOpsSamplingRateLock")
     private int mAppOpsSamplingRate = 0;
+    private final Object mDangerousAppOpsListLock = new Object();
+    @GuardedBy("mDangerousAppOpsListLock")
     private final ArraySet<Integer> mDangerousAppOpsList = new ArraySet<>();
 
     // Baselines that stores list of NetworkStats right after initializing, with associated
-    // information. This is used to calculate difference when pulling
-    // {Mobile|Wifi}BytesTransfer* atoms. Note that this is not thread-safe, and must
-    // only be accessed on the background thread.
+    // information. This is used to calculate difference when pulling BytesTransfer atoms.
     @NonNull
-    private final List<NetworkStatsExt> mNetworkStatsBaselines = new ArrayList<>();
+    @GuardedBy("mDataBytesTransferLock")
+    private final ArrayList<NetworkStatsExt> mNetworkStatsBaselines = new ArrayList<>();
 
     // Listener for monitoring subscriptions changed event.
     private StatsSubscriptionsListener mStatsSubscriptionsListener;
     // List that stores SubInfo of subscriptions that ever appeared since boot.
-    private final CopyOnWriteArrayList<SubInfo> mHistoricalSubs = new CopyOnWriteArrayList<>();
+    @GuardedBy("mDataBytesTransferLock")
+    private final ArrayList<SubInfo> mHistoricalSubs = new ArrayList<>();
+
+    // Puller locks
+    private final Object mDataBytesTransferLock = new Object();
+    private final Object mBluetoothBytesTransferLock = new Object();
+    private final Object mKernelWakelockLock = new Object();
+    private final Object mCpuTimePerFreqLock = new Object();
+    private final Object mCpuTimePerUidLock = new Object();
+    private final Object mCpuTimePerUidFreqLock = new Object();
+    private final Object mCpuActiveTimeLock = new Object();
+    private final Object mCpuClusterTimeLock = new Object();
+    private final Object mWifiActivityInfoLock = new Object();
+    private final Object mModemActivityInfoLock = new Object();
+    private final Object mBluetoothActivityInfoLock = new Object();
+    private final Object mSystemElapsedRealtimeLock = new Object();
+    private final Object mSystemUptimeLock = new Object();
+    private final Object mProcessMemoryStateLock = new Object();
+    private final Object mProcessMemoryHighWaterMarkLock = new Object();
+    private final Object mProcessMemorySnapshotLock = new Object();
+    private final Object mSystemIonHeapSizeLock = new Object();
+    private final Object mIonHeapSizeLock = new Object();
+    private final Object mProcessSystemIonHeapSizeLock = new Object();
+    private final Object mTemperatureLock = new Object();
+    private final Object mCooldownDeviceLock = new Object();
+    private final Object mBinderCallsStatsLock = new Object();
+    private final Object mBinderCallsStatsExceptionsLock = new Object();
+    private final Object mLooperStatsLock = new Object();
+    private final Object mDiskStatsLock = new Object();
+    private final Object mDirectoryUsageLock = new Object();
+    private final Object mAppSizeLock = new Object();
+    private final Object mCategorySizeLock = new Object();
+    private final Object mNumBiometricsEnrolledLock = new Object();
+    private final Object mProcStatsLock = new Object();
+    private final Object mDiskIoLock = new Object();
+    private final Object mPowerProfileLock = new Object();
+    private final Object mProcessCpuTimeLock = new Object();
+    private final Object mCpuTimePerThreadFreqLock = new Object();
+    private final Object mDeviceCalculatedPowerUseLock = new Object();
+    private final Object mDeviceCalculatedPowerBlameUidLock = new Object();
+    private final Object mDeviceCalculatedPowerBlameOtherLock = new Object();
+    private final Object mDebugElapsedClockLock = new Object();
+    private final Object mDebugFailingElapsedClockLock = new Object();
+    private final Object mBuildInformationLock = new Object();
+    private final Object mRoleHolderLock = new Object();
+    private final Object mTimeZoneDataInfoLock = new Object();
+    private final Object mExternalStorageInfoLock = new Object();
+    private final Object mAppsOnExternalStorageInfoLock = new Object();
+    private final Object mFaceSettingsLock = new Object();
+    private final Object mAppOpsLock = new Object();
+    private final Object mRuntimeAppOpAccessMessageLock = new Object();
+    private final Object mNotificationRemoteViewsLock = new Object();
+    private final Object mDangerousPermissionStateLock = new Object();
+    private final Object mHealthHalLock = new Object();
+    private final Object mAttributedAppOpsLock = new Object();
+    private final Object mSettingsStatsLock = new Object();
 
     public StatsPullAtomService(Context context) {
         super(context);
@@ -353,123 +410,229 @@
                     case FrameworkStatsLog.MOBILE_BYTES_TRANSFER_BY_FG_BG:
                     case FrameworkStatsLog.BYTES_TRANSFER_BY_TAG_AND_METERED:
                     case FrameworkStatsLog.DATA_USAGE_BYTES_TRANSFER:
-                        return pullDataBytesTransfer(atomTag, data);
+                        synchronized (mDataBytesTransferLock) {
+                            return pullDataBytesTransferLocked(atomTag, data);
+                        }
                     case FrameworkStatsLog.BLUETOOTH_BYTES_TRANSFER:
-                        return pullBluetoothBytesTransfer(atomTag, data);
+                        synchronized (mBluetoothBytesTransferLock) {
+                            return pullBluetoothBytesTransferLocked(atomTag, data);
+                        }
                     case FrameworkStatsLog.KERNEL_WAKELOCK:
-                        return pullKernelWakelock(atomTag, data);
+                        synchronized (mKernelWakelockLock) {
+                            return pullKernelWakelockLocked(atomTag, data);
+                        }
                     case FrameworkStatsLog.CPU_TIME_PER_FREQ:
-                        return pullCpuTimePerFreq(atomTag, data);
+                        synchronized (mCpuTimePerFreqLock) {
+                            return pullCpuTimePerFreqLocked(atomTag, data);
+                        }
                     case FrameworkStatsLog.CPU_TIME_PER_UID:
-                        return pullCpuTimePerUid(atomTag, data);
+                        synchronized (mCpuTimePerUidLock) {
+                            return pullCpuTimePerUidLocked(atomTag, data);
+                        }
                     case FrameworkStatsLog.CPU_TIME_PER_UID_FREQ:
-                        return pullCpuTimeperUidFreq(atomTag, data);
+                        synchronized (mCpuTimePerUidFreqLock) {
+                            return pullCpuTimePerUidFreqLocked(atomTag, data);
+                        }
                     case FrameworkStatsLog.CPU_ACTIVE_TIME:
-                        return pullCpuActiveTime(atomTag, data);
+                        synchronized (mCpuActiveTimeLock) {
+                            return pullCpuActiveTimeLocked(atomTag, data);
+                        }
                     case FrameworkStatsLog.CPU_CLUSTER_TIME:
-                        return pullCpuClusterTime(atomTag, data);
+                        synchronized (mCpuClusterTimeLock) {
+                            return pullCpuClusterTimeLocked(atomTag, data);
+                        }
                     case FrameworkStatsLog.WIFI_ACTIVITY_INFO:
-                        return pullWifiActivityInfo(atomTag, data);
+                        synchronized (mWifiActivityInfoLock) {
+                            return pullWifiActivityInfoLocked(atomTag, data);
+                        }
                     case FrameworkStatsLog.MODEM_ACTIVITY_INFO:
-                        return pullModemActivityInfo(atomTag, data);
+                        synchronized (mModemActivityInfoLock) {
+                            return pullModemActivityInfoLocked(atomTag, data);
+                        }
                     case FrameworkStatsLog.BLUETOOTH_ACTIVITY_INFO:
-                        return pullBluetoothActivityInfo(atomTag, data);
+                        synchronized (mBluetoothActivityInfoLock) {
+                            return pullBluetoothActivityInfoLocked(atomTag, data);
+                        }
                     case FrameworkStatsLog.SYSTEM_ELAPSED_REALTIME:
-                        return pullSystemElapsedRealtime(atomTag, data);
+                        synchronized (mSystemElapsedRealtimeLock) {
+                            return pullSystemElapsedRealtimeLocked(atomTag, data);
+                        }
                     case FrameworkStatsLog.SYSTEM_UPTIME:
-                        return pullSystemUptime(atomTag, data);
+                        synchronized (mSystemUptimeLock) {
+                            return pullSystemUptimeLocked(atomTag, data);
+                        }
                     case FrameworkStatsLog.PROCESS_MEMORY_STATE:
-                        return pullProcessMemoryState(atomTag, data);
+                        synchronized (mProcessMemoryStateLock) {
+                            return pullProcessMemoryStateLocked(atomTag, data);
+                        }
                     case FrameworkStatsLog.PROCESS_MEMORY_HIGH_WATER_MARK:
-                        return pullProcessMemoryHighWaterMark(atomTag, data);
+                        synchronized (mProcessMemoryHighWaterMarkLock) {
+                            return pullProcessMemoryHighWaterMarkLocked(atomTag, data);
+                        }
                     case FrameworkStatsLog.PROCESS_MEMORY_SNAPSHOT:
-                        return pullProcessMemorySnapshot(atomTag, data);
+                        synchronized (mProcessMemorySnapshotLock) {
+                            return pullProcessMemorySnapshotLocked(atomTag, data);
+                        }
                     case FrameworkStatsLog.SYSTEM_ION_HEAP_SIZE:
-                        return pullSystemIonHeapSize(atomTag, data);
+                        synchronized (mSystemIonHeapSizeLock) {
+                            return pullSystemIonHeapSizeLocked(atomTag, data);
+                        }
                     case FrameworkStatsLog.ION_HEAP_SIZE:
-                        return pullIonHeapSize(atomTag, data);
+                        synchronized (mIonHeapSizeLock) {
+                            return pullIonHeapSizeLocked(atomTag, data);
+                        }
                     case FrameworkStatsLog.PROCESS_SYSTEM_ION_HEAP_SIZE:
-                        return pullProcessSystemIonHeapSize(atomTag, data);
+                        synchronized (mProcessSystemIonHeapSizeLock) {
+                            return pullProcessSystemIonHeapSizeLocked(atomTag, data);
+                        }
                     case FrameworkStatsLog.TEMPERATURE:
-                        return pullTemperature(atomTag, data);
+                        synchronized (mTemperatureLock) {
+                            return pullTemperatureLocked(atomTag, data);
+                        }
                     case FrameworkStatsLog.COOLING_DEVICE:
-                        return pullCooldownDevice(atomTag, data);
+                        synchronized (mCooldownDeviceLock) {
+                            return pullCooldownDeviceLocked(atomTag, data);
+                        }
                     case FrameworkStatsLog.BINDER_CALLS:
-                        return pullBinderCallsStats(atomTag, data);
+                        synchronized (mBinderCallsStatsLock) {
+                            return pullBinderCallsStatsLocked(atomTag, data);
+                        }
                     case FrameworkStatsLog.BINDER_CALLS_EXCEPTIONS:
-                        return pullBinderCallsStatsExceptions(atomTag, data);
+                        synchronized (mBinderCallsStatsExceptionsLock) {
+                            return pullBinderCallsStatsExceptionsLocked(atomTag, data);
+                        }
                     case FrameworkStatsLog.LOOPER_STATS:
-                        return pullLooperStats(atomTag, data);
+                        synchronized (mLooperStatsLock) {
+                            return pullLooperStatsLocked(atomTag, data);
+                        }
                     case FrameworkStatsLog.DISK_STATS:
-                        return pullDiskStats(atomTag, data);
+                        synchronized (mDiskStatsLock) {
+                            return pullDiskStatsLocked(atomTag, data);
+                        }
                     case FrameworkStatsLog.DIRECTORY_USAGE:
-                        return pullDirectoryUsage(atomTag, data);
+                        synchronized (mDirectoryUsageLock) {
+                            return pullDirectoryUsageLocked(atomTag, data);
+                        }
                     case FrameworkStatsLog.APP_SIZE:
-                        return pullAppSize(atomTag, data);
+                        synchronized (mAppSizeLock) {
+                            return pullAppSizeLocked(atomTag, data);
+                        }
                     case FrameworkStatsLog.CATEGORY_SIZE:
-                        return pullCategorySize(atomTag, data);
+                        synchronized (mCategorySizeLock) {
+                            return pullCategorySizeLocked(atomTag, data);
+                        }
                     case FrameworkStatsLog.NUM_FINGERPRINTS_ENROLLED:
-                        return pullNumBiometricsEnrolled(
-                                BiometricsProtoEnums.MODALITY_FINGERPRINT, atomTag, data);
+                        synchronized (mNumBiometricsEnrolledLock) {
+                            return pullNumBiometricsEnrolledLocked(
+                                    BiometricsProtoEnums.MODALITY_FINGERPRINT, atomTag, data);
+                        }
                     case FrameworkStatsLog.NUM_FACES_ENROLLED:
-                        return pullNumBiometricsEnrolled(
-                                BiometricsProtoEnums.MODALITY_FACE, atomTag, data);
+                        synchronized (mNumBiometricsEnrolledLock) {
+                            return pullNumBiometricsEnrolledLocked(
+                                    BiometricsProtoEnums.MODALITY_FACE, atomTag, data);
+                        }
                     case FrameworkStatsLog.PROC_STATS:
-                        return pullProcStats(ProcessStats.REPORT_ALL, atomTag, data);
+                        synchronized (mProcStatsLock) {
+                            return pullProcStatsLocked(ProcessStats.REPORT_ALL, atomTag, data);
+                        }
                     case FrameworkStatsLog.PROC_STATS_PKG_PROC:
-                        return pullProcStats(ProcessStats.REPORT_PKG_PROC_STATS, atomTag, data);
+                        synchronized (mProcStatsLock) {
+                            return pullProcStatsLocked(ProcessStats.REPORT_PKG_PROC_STATS, atomTag,
+                                    data);
+                        }
                     case FrameworkStatsLog.DISK_IO:
-                        return pullDiskIO(atomTag, data);
+                        synchronized (mDiskIoLock) {
+                            return pullDiskIOLocked(atomTag, data);
+                        }
                     case FrameworkStatsLog.POWER_PROFILE:
-                        return pullPowerProfile(atomTag, data);
+                        synchronized (mPowerProfileLock) {
+                            return pullPowerProfileLocked(atomTag, data);
+                        }
                     case FrameworkStatsLog.PROCESS_CPU_TIME:
-                        return pullProcessCpuTime(atomTag, data);
+                        synchronized (mProcessCpuTimeLock) {
+                            return pullProcessCpuTimeLocked(atomTag, data);
+                        }
                     case FrameworkStatsLog.CPU_TIME_PER_THREAD_FREQ:
-                        return pullCpuTimePerThreadFreq(atomTag, data);
+                        synchronized (mCpuTimePerThreadFreqLock) {
+                            return pullCpuTimePerThreadFreqLocked(atomTag, data);
+                        }
                     case FrameworkStatsLog.DEVICE_CALCULATED_POWER_USE:
-                        return pullDeviceCalculatedPowerUse(atomTag, data);
+                        synchronized (mDeviceCalculatedPowerUseLock) {
+                            return pullDeviceCalculatedPowerUseLocked(atomTag, data);
+                        }
                     case FrameworkStatsLog.DEVICE_CALCULATED_POWER_BLAME_UID:
-                        return pullDeviceCalculatedPowerBlameUid(atomTag, data);
+                        synchronized (mDeviceCalculatedPowerBlameUidLock) {
+                            return pullDeviceCalculatedPowerBlameUidLocked(atomTag, data);
+                        }
                     case FrameworkStatsLog.DEVICE_CALCULATED_POWER_BLAME_OTHER:
-                        return pullDeviceCalculatedPowerBlameOther(atomTag, data);
+                        synchronized (mDeviceCalculatedPowerBlameOtherLock) {
+                            return pullDeviceCalculatedPowerBlameOtherLocked(atomTag, data);
+                        }
                     case FrameworkStatsLog.DEBUG_ELAPSED_CLOCK:
-                        return pullDebugElapsedClock(atomTag, data);
+                        synchronized (mDebugElapsedClockLock) {
+                            return pullDebugElapsedClockLocked(atomTag, data);
+                        }
                     case FrameworkStatsLog.DEBUG_FAILING_ELAPSED_CLOCK:
-                        return pullDebugFailingElapsedClock(atomTag, data);
+                        synchronized (mDebugFailingElapsedClockLock) {
+                            return pullDebugFailingElapsedClockLocked(atomTag, data);
+                        }
                     case FrameworkStatsLog.BUILD_INFORMATION:
-                        return pullBuildInformation(atomTag, data);
+                        synchronized (mBuildInformationLock) {
+                            return pullBuildInformationLocked(atomTag, data);
+                        }
                     case FrameworkStatsLog.ROLE_HOLDER:
-                        return pullRoleHolder(atomTag, data);
+                        synchronized (mRoleHolderLock) {
+                            return pullRoleHolderLocked(atomTag, data);
+                        }
                     case FrameworkStatsLog.DANGEROUS_PERMISSION_STATE:
-                        return pullDangerousPermissionState(atomTag, data);
-                    case FrameworkStatsLog.TIME_ZONE_DATA_INFO:
-                        return pullTimeZoneDataInfo(atomTag, data);
-                    case FrameworkStatsLog.EXTERNAL_STORAGE_INFO:
-                        return pullExternalStorageInfo(atomTag, data);
-                    case FrameworkStatsLog.APPS_ON_EXTERNAL_STORAGE_INFO:
-                        return pullAppsOnExternalStorageInfo(atomTag, data);
-                    case FrameworkStatsLog.FACE_SETTINGS:
-                        return pullFaceSettings(atomTag, data);
-                    case FrameworkStatsLog.APP_OPS:
-                        return pullAppOps(atomTag, data);
-                    case FrameworkStatsLog.RUNTIME_APP_OP_ACCESS:
-                        return pullRuntimeAppOpAccessMessage(atomTag, data);
-                    case FrameworkStatsLog.NOTIFICATION_REMOTE_VIEWS:
-                        return pullNotificationRemoteViews(atomTag, data);
                     case FrameworkStatsLog.DANGEROUS_PERMISSION_STATE_SAMPLED:
-                        return pullDangerousPermissionState(atomTag, data);
+                        synchronized (mDangerousPermissionStateLock) {
+                            return pullDangerousPermissionStateLocked(atomTag, data);
+                        }
+                    case FrameworkStatsLog.TIME_ZONE_DATA_INFO:
+                        synchronized (mTimeZoneDataInfoLock) {
+                            return pullTimeZoneDataInfoLocked(atomTag, data);
+                        }
+                    case FrameworkStatsLog.EXTERNAL_STORAGE_INFO:
+                        synchronized (mExternalStorageInfoLock) {
+                            return pullExternalStorageInfoLocked(atomTag, data);
+                        }
+                    case FrameworkStatsLog.APPS_ON_EXTERNAL_STORAGE_INFO:
+                        synchronized (mAppsOnExternalStorageInfoLock) {
+                            return pullAppsOnExternalStorageInfoLocked(atomTag, data);
+                        }
+                    case FrameworkStatsLog.FACE_SETTINGS:
+                        synchronized (mFaceSettingsLock) {
+                            return pullFaceSettingsLocked(atomTag, data);
+                        }
+                    case FrameworkStatsLog.APP_OPS:
+                        synchronized (mAppOpsLock) {
+                            return pullAppOpsLocked(atomTag, data);
+                        }
+                    case FrameworkStatsLog.RUNTIME_APP_OP_ACCESS:
+                        synchronized (mRuntimeAppOpAccessMessageLock) {
+                            return pullRuntimeAppOpAccessMessageLocked(atomTag, data);
+                        }
+                    case FrameworkStatsLog.NOTIFICATION_REMOTE_VIEWS:
+                        synchronized (mNotificationRemoteViewsLock) {
+                            return pullNotificationRemoteViewsLocked(atomTag, data);
+                        }
                     case FrameworkStatsLog.BATTERY_LEVEL:
                     case FrameworkStatsLog.REMAINING_BATTERY_CAPACITY:
                     case FrameworkStatsLog.FULL_BATTERY_CAPACITY:
                     case FrameworkStatsLog.BATTERY_VOLTAGE:
                     case FrameworkStatsLog.BATTERY_CYCLE_COUNT:
-                        return pullHealthHal(atomTag, data);
+                        synchronized (mHealthHalLock) {
+                            return pullHealthHalLocked(atomTag, data);
+                        }
                     case FrameworkStatsLog.ATTRIBUTED_APP_OPS:
-                        return pullAttributedAppOps(atomTag, data);
+                        synchronized (mAttributedAppOpsLock) {
+                            return pullAttributedAppOpsLocked(atomTag, data);
+                        }
                     case FrameworkStatsLog.SETTING_SNAPSHOT:
-                        return pullSettingsStats(atomTag, data);
-                    case FrameworkStatsLog.DISPLAY_WAKE_REASON:
-                        return pullDisplayWakeStats(atomTag, data);
+                        synchronized (mSettingsStatsLock) {
+                            return pullSettingsStatsLocked(atomTag, data);
+                        }
                     default:
                         throw new UnsupportedOperationException("Unknown tagId=" + atomTag);
                 }
@@ -500,6 +663,8 @@
         }
     }
 
+    // We do not hold locks within this function because it is guaranteed to be called before the
+    // pullers are ever run, as the pullers are not yet registered with statsd.
     void initializePullersState() {
         // Get Context Managers
         mStatsManager = (StatsManager) mContext.getSystemService(Context.STATS_MANAGER);
@@ -515,6 +680,7 @@
 
         // Initialize PROC_STATS
         mBaseDir = new File(SystemServiceManager.ensureSystemDir(), "stats_pull");
+        mBaseDir.mkdirs();
 
         // Disables throttler on CPU time readers.
         mCpuUidUserSysTimeReader = new KernelCpuUidUserSysTimeReader(false);
@@ -542,9 +708,6 @@
         mKernelCpuThreadReader =
                 KernelCpuThreadReaderSettingsObserver.getSettingsModifiedReader(mContext);
 
-        // Used by PROC_STATS and PROC_STATS_PKG_PROC atoms
-        mBaseDir.mkdirs();
-
         // Initialize HealthService
         mHealthService = new BatteryService.HealthServiceWrapper();
         try {
@@ -656,7 +819,6 @@
         registerBatteryVoltage();
         registerBatteryCycleCount();
         registerSettingsStats();
-        registerDisplayWakeStats();
     }
 
     private void initAndRegisterNetworkStatsPullers() {
@@ -783,7 +945,7 @@
     }
 
     private IProcessStats getIProcessStatsService() {
-        synchronized (mProcessStatsLock) {
+        synchronized (mProcStatsLock) {
             if (mProcessStatsService == null) {
                 mProcessStatsService = IProcessStats.Stub.asInterface(
                         ServiceManager.getService(ProcessStats.SERVICE_NAME));
@@ -791,7 +953,7 @@
             if (mProcessStatsService != null) {
                 try {
                     mProcessStatsService.asBinder().linkToDeath(() -> {
-                        synchronized (mProcessStatsLock) {
+                        synchronized (mProcStatsLock) {
                             mProcessStatsService = null;
                         }
                     }, /* flags */ 0);
@@ -882,8 +1044,7 @@
         return ret;
     }
 
-    private int pullDataBytesTransfer(
-            int atomTag, @NonNull List<StatsEvent> pulledData) {
+    private int pullDataBytesTransferLocked(int atomTag, @NonNull List<StatsEvent> pulledData) {
         final List<NetworkStatsExt> current = collectNetworkStatsSnapshotForAtom(atomTag);
 
         if (current == null) {
@@ -1237,12 +1398,11 @@
         return null;
     }
 
-    private synchronized BluetoothActivityEnergyInfo fetchBluetoothData() {
-        // TODO: Investigate whether the synchronized keyword is needed.
+    private BluetoothActivityEnergyInfo fetchBluetoothData() {
         final BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
         if (adapter != null) {
-            SynchronousResultReceiver bluetoothReceiver = new SynchronousResultReceiver(
-                    "bluetooth");
+            SynchronousResultReceiver bluetoothReceiver =
+                    new SynchronousResultReceiver("bluetooth");
             adapter.requestControllerActivityEnergyInfo(bluetoothReceiver);
             return awaitControllerInfo(bluetoothReceiver);
         } else {
@@ -1251,7 +1411,7 @@
         }
     }
 
-    int pullBluetoothBytesTransfer(int atomTag, List<StatsEvent> pulledData) {
+    int pullBluetoothBytesTransferLocked(int atomTag, List<StatsEvent> pulledData) {
         BluetoothActivityEnergyInfo info = fetchBluetoothData();
         if (info == null || info.getUidTraffic() == null) {
             return StatsManager.PULL_SKIP;
@@ -1279,7 +1439,7 @@
         );
     }
 
-    int pullKernelWakelock(int atomTag, List<StatsEvent> pulledData) {
+    int pullKernelWakelockLocked(int atomTag, List<StatsEvent> pulledData) {
         final KernelWakelockStats wakelockStats =
                 mKernelWakelockReader.readKernelWakelockStats(mTmpWakelockStats);
         for (Map.Entry<String, KernelWakelockStats.Entry> ent : wakelockStats.entrySet()) {
@@ -1310,7 +1470,7 @@
         );
     }
 
-    int pullCpuTimePerFreq(int atomTag, List<StatsEvent> pulledData) {
+    int pullCpuTimePerFreqLocked(int atomTag, List<StatsEvent> pulledData) {
         for (int cluster = 0; cluster < mKernelCpuSpeedReaders.length; cluster++) {
             long[] clusterTimeMs = mKernelCpuSpeedReaders[cluster].readAbsolute();
             if (clusterTimeMs != null) {
@@ -1341,7 +1501,7 @@
         );
     }
 
-    int pullCpuTimePerUid(int atomTag, List<StatsEvent> pulledData) {
+    int pullCpuTimePerUidLocked(int atomTag, List<StatsEvent> pulledData) {
         mCpuUidUserSysTimeReader.readAbsolute((uid, timesUs) -> {
             long userTimeUs = timesUs[0], systemTimeUs = timesUs[1];
             StatsEvent e = StatsEvent.newBuilder()
@@ -1371,7 +1531,7 @@
         );
     }
 
-    int pullCpuTimeperUidFreq(int atomTag, List<StatsEvent> pulledData) {
+    int pullCpuTimePerUidFreqLocked(int atomTag, List<StatsEvent> pulledData) {
         mCpuUidFreqTimeReader.readAbsolute((uid, cpuFreqTimeMs) -> {
             for (int freqIndex = 0; freqIndex < cpuFreqTimeMs.length; ++freqIndex) {
                 if (cpuFreqTimeMs[freqIndex] != 0) {
@@ -1404,7 +1564,7 @@
         );
     }
 
-    int pullCpuActiveTime(int atomTag, List<StatsEvent> pulledData) {
+    int pullCpuActiveTimeLocked(int atomTag, List<StatsEvent> pulledData) {
         mCpuUidActiveTimeReader.readAbsolute((uid, cpuActiveTimesMs) -> {
             StatsEvent e = StatsEvent.newBuilder()
                     .setAtomId(atomTag)
@@ -1432,7 +1592,7 @@
         );
     }
 
-    int pullCpuClusterTime(int atomTag, List<StatsEvent> pulledData) {
+    int pullCpuClusterTimeLocked(int atomTag, List<StatsEvent> pulledData) {
         mCpuUidClusterTimeReader.readAbsolute((uid, cpuClusterTimesMs) -> {
             for (int i = 0; i < cpuClusterTimesMs.length; i++) {
                 StatsEvent e = StatsEvent.newBuilder()
@@ -1458,7 +1618,7 @@
         );
     }
 
-    int pullWifiActivityInfo(int atomTag, List<StatsEvent> pulledData) {
+    int pullWifiActivityInfoLocked(int atomTag, List<StatsEvent> pulledData) {
         long token = Binder.clearCallingIdentity();
         try {
             SynchronousResultReceiver wifiReceiver = new SynchronousResultReceiver("wifi");
@@ -1510,7 +1670,7 @@
         );
     }
 
-    int pullModemActivityInfo(int atomTag, List<StatsEvent> pulledData) {
+    int pullModemActivityInfoLocked(int atomTag, List<StatsEvent> pulledData) {
         long token = Binder.clearCallingIdentity();
         try {
             SynchronousResultReceiver modemReceiver = new SynchronousResultReceiver("telephony");
@@ -1548,7 +1708,7 @@
         );
     }
 
-    int pullBluetoothActivityInfo(int atomTag, List<StatsEvent> pulledData) {
+    int pullBluetoothActivityInfoLocked(int atomTag, List<StatsEvent> pulledData) {
         BluetoothActivityEnergyInfo info = fetchBluetoothData();
         if (info == null) {
             return StatsManager.PULL_SKIP;
@@ -1580,7 +1740,7 @@
         );
     }
 
-    int pullSystemElapsedRealtime(int atomTag, List<StatsEvent> pulledData) {
+    int pullSystemElapsedRealtimeLocked(int atomTag, List<StatsEvent> pulledData) {
         StatsEvent e = StatsEvent.newBuilder()
                 .setAtomId(atomTag)
                 .writeLong(SystemClock.elapsedRealtime())
@@ -1599,7 +1759,7 @@
         );
     }
 
-    int pullSystemUptime(int atomTag, List<StatsEvent> pulledData) {
+    int pullSystemUptimeLocked(int atomTag, List<StatsEvent> pulledData) {
         StatsEvent e = StatsEvent.newBuilder()
                 .setAtomId(atomTag)
                 .writeLong(SystemClock.uptimeMillis())
@@ -1621,7 +1781,7 @@
         );
     }
 
-    int pullProcessMemoryState(int atomTag, List<StatsEvent> pulledData) {
+    int pullProcessMemoryStateLocked(int atomTag, List<StatsEvent> pulledData) {
         List<ProcessMemoryState> processMemoryStates =
                 LocalServices.getService(ActivityManagerInternal.class)
                         .getMemoryStateForProcesses();
@@ -1651,10 +1811,6 @@
         return StatsManager.PULL_SUCCESS;
     }
 
-    private static boolean isAppUid(int uid) {
-        return uid >= MIN_APP_UID;
-    }
-
     private void registerProcessMemoryHighWaterMark() {
         int tagId = FrameworkStatsLog.PROCESS_MEMORY_HIGH_WATER_MARK;
         mStatsManager.setPullAtomCallback(
@@ -1665,7 +1821,7 @@
         );
     }
 
-    int pullProcessMemoryHighWaterMark(int atomTag, List<StatsEvent> pulledData) {
+    int pullProcessMemoryHighWaterMarkLocked(int atomTag, List<StatsEvent> pulledData) {
         List<ProcessMemoryState> managedProcessList =
                 LocalServices.getService(ActivityManagerInternal.class)
                         .getMemoryStateForProcesses();
@@ -1691,7 +1847,7 @@
         int size = processCmdlines.size();
         for (int i = 0; i < size; ++i) {
             final MemorySnapshot snapshot = readMemorySnapshotFromProcfs(processCmdlines.keyAt(i));
-            if (snapshot == null || isAppUid(snapshot.uid)) {
+            if (snapshot == null) {
                 continue;
             }
             StatsEvent e = StatsEvent.newBuilder()
@@ -1720,7 +1876,7 @@
         );
     }
 
-    int pullProcessMemorySnapshot(int atomTag, List<StatsEvent> pulledData) {
+    int pullProcessMemorySnapshotLocked(int atomTag, List<StatsEvent> pulledData) {
         List<ProcessMemoryState> managedProcessList =
                 LocalServices.getService(ActivityManagerInternal.class)
                         .getMemoryStateForProcesses();
@@ -1752,7 +1908,7 @@
         for (int i = 0; i < size; ++i) {
             int pid = processCmdlines.keyAt(i);
             final MemorySnapshot snapshot = readMemorySnapshotFromProcfs(pid);
-            if (snapshot == null || isAppUid(snapshot.uid)) {
+            if (snapshot == null) {
                 continue;
             }
             StatsEvent e = StatsEvent.newBuilder()
@@ -1782,7 +1938,7 @@
         );
     }
 
-    int pullSystemIonHeapSize(int atomTag, List<StatsEvent> pulledData) {
+    int pullSystemIonHeapSizeLocked(int atomTag, List<StatsEvent> pulledData) {
         final long systemIonHeapSizeInBytes = readSystemIonHeapSizeFromDebugfs();
         StatsEvent e = StatsEvent.newBuilder()
                 .setAtomId(atomTag)
@@ -1805,7 +1961,7 @@
         );
     }
 
-    int pullIonHeapSize(int atomTag, List<StatsEvent> pulledData) {
+    int pullIonHeapSizeLocked(int atomTag, List<StatsEvent> pulledData) {
         int ionHeapSizeInKilobytes = (int) getIonHeapsSizeKb();
         StatsEvent e = StatsEvent.newBuilder()
               .setAtomId(atomTag)
@@ -1825,7 +1981,7 @@
         );
     }
 
-    int pullProcessSystemIonHeapSize(int atomTag, List<StatsEvent> pulledData) {
+    int pullProcessSystemIonHeapSizeLocked(int atomTag, List<StatsEvent> pulledData) {
         List<IonAllocations> result = readProcessSystemIonHeapSizesFromDebugfs();
         for (IonAllocations allocations : result) {
             StatsEvent e = StatsEvent.newBuilder()
@@ -1852,7 +2008,7 @@
         );
     }
 
-    int pullTemperature(int atomTag, List<StatsEvent> pulledData) {
+    int pullTemperatureLocked(int atomTag, List<StatsEvent> pulledData) {
         IThermalService thermalService = getIThermalService();
         if (thermalService == null) {
             return StatsManager.PULL_SKIP;
@@ -1890,7 +2046,7 @@
         );
     }
 
-    int pullCooldownDevice(int atomTag, List<StatsEvent> pulledData) {
+    int pullCooldownDeviceLocked(int atomTag, List<StatsEvent> pulledData) {
         IThermalService thermalService = getIThermalService();
         if (thermalService == null) {
             return StatsManager.PULL_SKIP;
@@ -1930,7 +2086,7 @@
         );
     }
 
-    int pullBinderCallsStats(int atomTag, List<StatsEvent> pulledData) {
+    int pullBinderCallsStatsLocked(int atomTag, List<StatsEvent> pulledData) {
         BinderCallsStatsService.Internal binderStats =
                 LocalServices.getService(BinderCallsStatsService.Internal.class);
         if (binderStats == null) {
@@ -1974,7 +2130,7 @@
         );
     }
 
-    int pullBinderCallsStatsExceptions(int atomTag, List<StatsEvent> pulledData) {
+    int pullBinderCallsStatsExceptionsLocked(int atomTag, List<StatsEvent> pulledData) {
         BinderCallsStatsService.Internal binderStats =
                 LocalServices.getService(BinderCallsStatsService.Internal.class);
         if (binderStats == null) {
@@ -2009,7 +2165,7 @@
         );
     }
 
-    int pullLooperStats(int atomTag, List<StatsEvent> pulledData) {
+    int pullLooperStatsLocked(int atomTag, List<StatsEvent> pulledData) {
         LooperStats looperStats = LocalServices.getService(LooperStats.class);
         if (looperStats == null) {
             return StatsManager.PULL_SKIP;
@@ -2052,7 +2208,7 @@
         );
     }
 
-    int pullDiskStats(int atomTag, List<StatsEvent> pulledData) {
+    int pullDiskStatsLocked(int atomTag, List<StatsEvent> pulledData) {
         // Run a quick-and-dirty performance test: write 512 bytes
         byte[] junk = new byte[512];
         for (int i = 0; i < junk.length; i++) junk[i] = (byte) i;  // Write nonzero bytes
@@ -2118,7 +2274,7 @@
         );
     }
 
-    int pullDirectoryUsage(int atomTag, List<StatsEvent> pulledData) {
+    int pullDirectoryUsageLocked(int atomTag, List<StatsEvent> pulledData) {
         StatFs statFsData = new StatFs(Environment.getDataDirectory().getAbsolutePath());
         StatFs statFsSystem = new StatFs(Environment.getRootDirectory().getAbsolutePath());
         StatFs statFsCache = new StatFs(Environment.getDownloadCacheDirectory().getAbsolutePath());
@@ -2159,7 +2315,7 @@
         );
     }
 
-    int pullAppSize(int atomTag, List<StatsEvent> pulledData) {
+    int pullAppSizeLocked(int atomTag, List<StatsEvent> pulledData) {
         try {
             String jsonStr = IoUtils.readFileAsString(DiskStatsLoggingService.DUMPSYS_CACHE_PATH);
             JSONObject json = new JSONObject(jsonStr);
@@ -2203,7 +2359,7 @@
         );
     }
 
-    int pullCategorySize(int atomTag, List<StatsEvent> pulledData) {
+    int pullCategorySizeLocked(int atomTag, List<StatsEvent> pulledData) {
         try {
             String jsonStr = IoUtils.readFileAsString(DiskStatsLoggingService.DUMPSYS_CACHE_PATH);
             JSONObject json = new JSONObject(jsonStr);
@@ -2317,7 +2473,8 @@
         );
     }
 
-    private int pullNumBiometricsEnrolled(int modality, int atomTag, List<StatsEvent> pulledData) {
+    private int pullNumBiometricsEnrolledLocked(int modality, int atomTag,
+            List<StatsEvent> pulledData) {
         final PackageManager pm = mContext.getPackageManager();
         FingerprintManager fingerprintManager = null;
         FaceManager faceManager = null;
@@ -2385,43 +2542,41 @@
         );
     }
 
-    private int pullProcStats(int section, int atomTag, List<StatsEvent> pulledData) {
+    private int pullProcStatsLocked(int section, int atomTag, List<StatsEvent> pulledData) {
         IProcessStats processStatsService = getIProcessStatsService();
         if (processStatsService == null) {
             return StatsManager.PULL_SKIP;
         }
 
-        synchronized (mProcessStatsLock) {
-            final long token = Binder.clearCallingIdentity();
-            try {
-                // force procstats to flush & combine old files into one store
-                long lastHighWaterMark = readProcStatsHighWaterMark(section);
-                List<ParcelFileDescriptor> statsFiles = new ArrayList<>();
+        final long token = Binder.clearCallingIdentity();
+        try {
+            // force procstats to flush & combine old files into one store
+            long lastHighWaterMark = readProcStatsHighWaterMark(section);
+            List<ParcelFileDescriptor> statsFiles = new ArrayList<>();
 
-                ProcessStats procStats = new ProcessStats(false);
-                long highWaterMark = processStatsService.getCommittedStatsMerged(
-                        lastHighWaterMark, section, true, statsFiles, procStats);
+            ProcessStats procStats = new ProcessStats(false);
+            long highWaterMark = processStatsService.getCommittedStatsMerged(
+                    lastHighWaterMark, section, true, statsFiles, procStats);
 
-                // aggregate the data together for westworld consumption
-                ProtoOutputStream proto = new ProtoOutputStream();
-                procStats.dumpAggregatedProtoForStatsd(proto);
+            // aggregate the data together for westworld consumption
+            ProtoOutputStream proto = new ProtoOutputStream();
+            procStats.dumpAggregatedProtoForStatsd(proto);
 
-                StatsEvent e = StatsEvent.newBuilder()
-                        .setAtomId(atomTag)
-                        .writeByteArray(proto.getBytes())
-                        .build();
-                pulledData.add(e);
+            StatsEvent e = StatsEvent.newBuilder()
+                    .setAtomId(atomTag)
+                    .writeByteArray(proto.getBytes())
+                    .build();
+            pulledData.add(e);
 
-                new File(mBaseDir.getAbsolutePath() + "/" + section + "_" + lastHighWaterMark)
-                        .delete();
-                new File(mBaseDir.getAbsolutePath() + "/" + section + "_" + highWaterMark)
-                        .createNewFile();
-            } catch (RemoteException | IOException e) {
-                Slog.e(TAG, "Getting procstats failed: ", e);
-                return StatsManager.PULL_SKIP;
-            } finally {
-                Binder.restoreCallingIdentity(token);
-            }
+            new File(mBaseDir.getAbsolutePath() + "/" + section + "_" + lastHighWaterMark)
+                    .delete();
+            new File(mBaseDir.getAbsolutePath() + "/" + section + "_" + highWaterMark)
+                    .createNewFile();
+        } catch (RemoteException | IOException e) {
+            Slog.e(TAG, "Getting procstats failed: ", e);
+            return StatsManager.PULL_SKIP;
+        } finally {
+            Binder.restoreCallingIdentity(token);
         }
         return StatsManager.PULL_SUCCESS;
     }
@@ -2461,7 +2616,7 @@
         );
     }
 
-    int pullDiskIO(int atomTag, List<StatsEvent> pulledData) {
+    int pullDiskIOLocked(int atomTag, List<StatsEvent> pulledData) {
         mStoragedUidIoStatsReader.readAbsolute((uid, fgCharsRead, fgCharsWrite, fgBytesRead,
                 fgBytesWrite, bgCharsRead, bgCharsWrite, bgBytesRead, bgBytesWrite,
                 fgFsync, bgFsync) -> {
@@ -2495,7 +2650,7 @@
         );
     }
 
-    int pullPowerProfile(int atomTag, List<StatsEvent> pulledData) {
+    int pullPowerProfileLocked(int atomTag, List<StatsEvent> pulledData) {
         PowerProfile powerProfile = new PowerProfile(mContext);
         ProtoOutputStream proto = new ProtoOutputStream();
         powerProfile.dumpDebug(proto);
@@ -2522,25 +2677,23 @@
         );
     }
 
-    int pullProcessCpuTime(int atomTag, List<StatsEvent> pulledData) {
-        synchronized (mCpuTrackerLock) {
-            if (mProcessCpuTracker == null) {
-                mProcessCpuTracker = new ProcessCpuTracker(false);
-                mProcessCpuTracker.init();
-            }
-            mProcessCpuTracker.update();
-            for (int i = 0; i < mProcessCpuTracker.countStats(); i++) {
-                ProcessCpuTracker.Stats st = mProcessCpuTracker.getStats(i);
-                StatsEvent e = StatsEvent.newBuilder()
-                        .setAtomId(atomTag)
-                        .writeInt(st.uid)
-                        .addBooleanAnnotation(ANNOTATION_ID_IS_UID, true)
-                        .writeString(st.name)
-                        .writeLong(st.base_utime)
-                        .writeLong(st.base_stime)
-                        .build();
-                pulledData.add(e);
-            }
+    int pullProcessCpuTimeLocked(int atomTag, List<StatsEvent> pulledData) {
+        if (mProcessCpuTracker == null) {
+            mProcessCpuTracker = new ProcessCpuTracker(false);
+            mProcessCpuTracker.init();
+        }
+        mProcessCpuTracker.update();
+        for (int i = 0; i < mProcessCpuTracker.countStats(); i++) {
+            ProcessCpuTracker.Stats st = mProcessCpuTracker.getStats(i);
+            StatsEvent e = StatsEvent.newBuilder()
+                    .setAtomId(atomTag)
+                    .writeInt(st.uid)
+                    .addBooleanAnnotation(ANNOTATION_ID_IS_UID, true)
+                    .writeString(st.name)
+                    .writeLong(st.base_utime)
+                    .writeLong(st.base_stime)
+                    .build();
+            pulledData.add(e);
         }
         return StatsManager.PULL_SUCCESS;
     }
@@ -2558,7 +2711,7 @@
         );
     }
 
-    int pullCpuTimePerThreadFreq(int atomTag, List<StatsEvent> pulledData) {
+    int pullCpuTimePerThreadFreqLocked(int atomTag, List<StatsEvent> pulledData) {
         if (this.mKernelCpuThreadReader == null) {
             Slog.e(TAG, "mKernelCpuThreadReader is null");
             return StatsManager.PULL_SKIP;
@@ -2617,23 +2770,27 @@
     }
 
     private BatteryStatsHelper getBatteryStatsHelper() {
-        if (mBatteryStatsHelper == null) {
-            final long callingToken = Binder.clearCallingIdentity();
-            try {
-                // clearCallingIdentity required for BatteryStatsHelper.checkWifiOnly().
-                mBatteryStatsHelper = new BatteryStatsHelper(mContext, false);
-            } finally {
-                Binder.restoreCallingIdentity(callingToken);
+        synchronized (mBatteryStatsHelperLock) {
+            if (mBatteryStatsHelper == null) {
+                final long callingToken = Binder.clearCallingIdentity();
+                try {
+                    // clearCallingIdentity required for BatteryStatsHelper.checkWifiOnly().
+                    mBatteryStatsHelper = new BatteryStatsHelper(mContext, false);
+                } finally {
+                    Binder.restoreCallingIdentity(callingToken);
+                }
+                mBatteryStatsHelper.create((Bundle) null);
             }
-            mBatteryStatsHelper.create((Bundle) null);
-        }
-        long currentTime = SystemClock.elapsedRealtime();
-        if (currentTime - mBatteryStatsHelperTimestampMs >= MAX_BATTERY_STATS_HELPER_FREQUENCY_MS) {
-            // Load BatteryStats and do all the calculations.
-            mBatteryStatsHelper.refreshStats(BatteryStats.STATS_SINCE_CHARGED, UserHandle.USER_ALL);
-            // Calculations are done so we don't need to save the raw BatteryStats data in RAM.
-            mBatteryStatsHelper.clearStats();
-            mBatteryStatsHelperTimestampMs = currentTime;
+            long currentTime = SystemClock.elapsedRealtime();
+            if (currentTime - mBatteryStatsHelperTimestampMs
+                    >= MAX_BATTERY_STATS_HELPER_FREQUENCY_MS) {
+                // Load BatteryStats and do all the calculations.
+                mBatteryStatsHelper.refreshStats(BatteryStats.STATS_SINCE_CHARGED,
+                        UserHandle.USER_ALL);
+                // Calculations are done so we don't need to save the raw BatteryStats data in RAM.
+                mBatteryStatsHelper.clearStats();
+                mBatteryStatsHelperTimestampMs = currentTime;
+            }
         }
         return mBatteryStatsHelper;
     }
@@ -2652,7 +2809,7 @@
         );
     }
 
-    int pullDeviceCalculatedPowerUse(int atomTag, List<StatsEvent> pulledData) {
+    int pullDeviceCalculatedPowerUseLocked(int atomTag, List<StatsEvent> pulledData) {
         BatteryStatsHelper bsHelper = getBatteryStatsHelper();
         StatsEvent e = StatsEvent.newBuilder()
                 .setAtomId(atomTag)
@@ -2672,7 +2829,7 @@
         );
     }
 
-    int pullDeviceCalculatedPowerBlameUid(int atomTag, List<StatsEvent> pulledData) {
+    int pullDeviceCalculatedPowerBlameUidLocked(int atomTag, List<StatsEvent> pulledData) {
         final List<BatterySipper> sippers = getBatteryStatsHelper().getUsageList();
         if (sippers == null) {
             return StatsManager.PULL_SKIP;
@@ -2703,7 +2860,7 @@
         );
     }
 
-    int pullDeviceCalculatedPowerBlameOther(int atomTag, List<StatsEvent> pulledData) {
+    int pullDeviceCalculatedPowerBlameOtherLocked(int atomTag, List<StatsEvent> pulledData) {
         final List<BatterySipper> sippers = getBatteryStatsHelper().getUsageList();
         if (sippers == null) {
             return StatsManager.PULL_SKIP;
@@ -2739,41 +2896,37 @@
         );
     }
 
-    int pullDebugElapsedClock(int atomTag, List<StatsEvent> pulledData) {
+    int pullDebugElapsedClockLocked(int atomTag, List<StatsEvent> pulledData) {
         final long elapsedMillis = SystemClock.elapsedRealtime();
+        final long clockDiffMillis = mDebugElapsedClockPreviousValue == 0
+                ? 0 : elapsedMillis - mDebugElapsedClockPreviousValue;
 
-        synchronized (mDebugElapsedClockLock) {
-            final long clockDiffMillis = mDebugElapsedClockPreviousValue == 0
-                    ? 0 : elapsedMillis - mDebugElapsedClockPreviousValue;
+        StatsEvent e = StatsEvent.newBuilder()
+                .setAtomId(atomTag)
+                .writeLong(mDebugElapsedClockPullCount)
+                .writeLong(elapsedMillis)
+                // Log it twice to be able to test multi-value aggregation from ValueMetric.
+                .writeLong(elapsedMillis)
+                .writeLong(clockDiffMillis)
+                .writeInt(1 /* always set */)
+                .build();
+        pulledData.add(e);
 
-            StatsEvent e = StatsEvent.newBuilder()
+        if (mDebugElapsedClockPullCount % 2 == 1) {
+            StatsEvent e2 = StatsEvent.newBuilder()
                     .setAtomId(atomTag)
                     .writeLong(mDebugElapsedClockPullCount)
                     .writeLong(elapsedMillis)
                     // Log it twice to be able to test multi-value aggregation from ValueMetric.
                     .writeLong(elapsedMillis)
                     .writeLong(clockDiffMillis)
-                    .writeInt(1 /* always set */)
+                    .writeInt(2 /* set on odd pulls */)
                     .build();
-            pulledData.add(e);
-
-            if (mDebugElapsedClockPullCount % 2 == 1) {
-                StatsEvent e2 = StatsEvent.newBuilder()
-                        .setAtomId(atomTag)
-                        .writeLong(mDebugElapsedClockPullCount)
-                        .writeLong(elapsedMillis)
-                        // Log it twice to be able to test multi-value aggregation from ValueMetric.
-                        .writeLong(elapsedMillis)
-                        .writeLong(clockDiffMillis)
-                        .writeInt(2 /* set on odd pulls */)
-                        .build();
-                pulledData.add(e2);
-            }
-
-            mDebugElapsedClockPullCount++;
-            mDebugElapsedClockPreviousValue = elapsedMillis;
+            pulledData.add(e2);
         }
 
+        mDebugElapsedClockPullCount++;
+        mDebugElapsedClockPreviousValue = elapsedMillis;
         return StatsManager.PULL_SUCCESS;
     }
 
@@ -2790,31 +2943,27 @@
         );
     }
 
-    int pullDebugFailingElapsedClock(int atomTag, List<StatsEvent> pulledData) {
+    int pullDebugFailingElapsedClockLocked(int atomTag, List<StatsEvent> pulledData) {
         final long elapsedMillis = SystemClock.elapsedRealtime();
-
-        synchronized (mDebugFailingElapsedClockLock) {
-            // Fails every 5 buckets.
-            if (mDebugFailingElapsedClockPullCount++ % 5 == 0) {
-                mDebugFailingElapsedClockPreviousValue = elapsedMillis;
-                Slog.e(TAG, "Failing debug elapsed clock");
-                return StatsManager.PULL_SKIP;
-            }
-
-            StatsEvent e = StatsEvent.newBuilder()
-                    .setAtomId(atomTag)
-                    .writeLong(mDebugFailingElapsedClockPullCount)
-                    .writeLong(elapsedMillis)
-                    // Log it twice to be able to test multi-value aggregation from ValueMetric.
-                    .writeLong(elapsedMillis)
-                    .writeLong(mDebugFailingElapsedClockPreviousValue == 0
-                            ? 0 : elapsedMillis - mDebugFailingElapsedClockPreviousValue)
-                    .build();
-            pulledData.add(e);
-
+        // Fails every 5 buckets.
+        if (mDebugFailingElapsedClockPullCount++ % 5 == 0) {
             mDebugFailingElapsedClockPreviousValue = elapsedMillis;
+            Slog.e(TAG, "Failing debug elapsed clock");
+            return StatsManager.PULL_SKIP;
         }
 
+        StatsEvent e = StatsEvent.newBuilder()
+                .setAtomId(atomTag)
+                .writeLong(mDebugFailingElapsedClockPullCount)
+                .writeLong(elapsedMillis)
+                // Log it twice to be able to test multi-value aggregation from ValueMetric.
+                .writeLong(elapsedMillis)
+                .writeLong(mDebugFailingElapsedClockPreviousValue == 0
+                        ? 0 : elapsedMillis - mDebugFailingElapsedClockPreviousValue)
+                .build();
+        pulledData.add(e);
+
+        mDebugFailingElapsedClockPreviousValue = elapsedMillis;
         return StatsManager.PULL_SUCCESS;
     }
 
@@ -2828,7 +2977,7 @@
         );
     }
 
-    int pullBuildInformation(int atomTag, List<StatsEvent> pulledData) {
+    int pullBuildInformationLocked(int atomTag, List<StatsEvent> pulledData) {
         StatsEvent e = StatsEvent.newBuilder()
                 .setAtomId(atomTag)
                 .writeString(Build.FINGERPRINT)
@@ -2856,7 +3005,7 @@
     }
 
     // Add a RoleHolder atom for each package that holds a role.
-    int pullRoleHolder(int atomTag, List<StatsEvent> pulledData) {
+    int pullRoleHolderLocked(int atomTag, List<StatsEvent> pulledData) {
         long callingToken = Binder.clearCallingIdentity();
         try {
             PackageManager pm = mContext.getPackageManager();
@@ -2914,7 +3063,7 @@
         );
     }
 
-    int pullDangerousPermissionState(int atomTag, List<StatsEvent> pulledData) {
+    int pullDangerousPermissionStateLocked(int atomTag, List<StatsEvent> pulledData) {
         final long token = Binder.clearCallingIdentity();
         float samplingRate = DeviceConfig.getFloat(DeviceConfig.NAMESPACE_PERMISSIONS,
                 DANGEROUS_PERMISSION_STATE_SAMPLE_RATE, 0.02f);
@@ -3007,7 +3156,7 @@
         );
     }
 
-    int pullTimeZoneDataInfo(int atomTag, List<StatsEvent> pulledData) {
+    int pullTimeZoneDataInfoLocked(int atomTag, List<StatsEvent> pulledData) {
         String tzDbVersion = "Unknown";
         try {
             tzDbVersion = android.icu.util.TimeZone.getTZDataVersion();
@@ -3034,7 +3183,7 @@
         );
     }
 
-    int pullExternalStorageInfo(int atomTag, List<StatsEvent> pulledData) {
+    int pullExternalStorageInfoLocked(int atomTag, List<StatsEvent> pulledData) {
         if (mStorageManager == null) {
             return StatsManager.PULL_SKIP;
         }
@@ -3084,7 +3233,7 @@
         );
     }
 
-    int pullAppsOnExternalStorageInfo(int atomTag, List<StatsEvent> pulledData) {
+    int pullAppsOnExternalStorageInfoLocked(int atomTag, List<StatsEvent> pulledData) {
         if (mStorageManager == null) {
             return StatsManager.PULL_SKIP;
         }
@@ -3140,7 +3289,7 @@
         );
     }
 
-    int pullFaceSettings(int atomTag, List<StatsEvent> pulledData) {
+    int pullFaceSettingsLocked(int atomTag, List<StatsEvent> pulledData) {
         final long callingToken = Binder.clearCallingIdentity();
         try {
             List<UserInfo> users = mContext.getSystemService(UserManager.class).getUsers();
@@ -3222,7 +3371,7 @@
         }
     }
 
-    int pullAppOps(int atomTag, List<StatsEvent> pulledData) {
+    int pullAppOpsLocked(int atomTag, List<StatsEvent> pulledData) {
         final long token = Binder.clearCallingIdentity();
         try {
             AppOpsManager appOps = mContext.getSystemService(AppOpsManager.class);
@@ -3299,7 +3448,7 @@
         );
     }
 
-    int pullAttributedAppOps(int atomTag, List<StatsEvent> pulledData) {
+    int pullAttributedAppOpsLocked(int atomTag, List<StatsEvent> pulledData) {
         final long token = Binder.clearCallingIdentity();
         try {
             AppOpsManager appOps = mContext.getSystemService(AppOpsManager.class);
@@ -3358,7 +3507,7 @@
         CompletableFuture<HistoricalOps> ops = new CompletableFuture<>();
         HistoricalOpsRequest histOpsRequest =
                 new HistoricalOpsRequest.Builder(
-                        Instant.now().minus(1, ChronoUnit.DAYS).toEpochMilli(),
+                        Math.max(Instant.now().minus(1, ChronoUnit.DAYS).toEpochMilli(), 0),
                         Long.MAX_VALUE).setFlags(
                         OP_FLAGS_PULLED).build();
         appOps.getHistoricalOps(histOpsRequest, AsyncTask.THREAD_POOL_EXECUTOR, ops::complete);
@@ -3377,7 +3526,9 @@
         }
         int estimatedSamplingRate = (int) constrain(
                 appOpsTargetCollectionSize * 100 / estimatedSize, 0, 100);
-        mAppOpsSamplingRate = min(mAppOpsSamplingRate, estimatedSamplingRate);
+        synchronized (mAppOpsSamplingRateLock) {
+            mAppOpsSamplingRate = min(mAppOpsSamplingRate, estimatedSamplingRate);
+        }
     }
 
     private List<AppOpEntry> processHistoricalOps(
@@ -3414,13 +3565,22 @@
     private void processHistoricalOp(AppOpsManager.HistoricalOp op,
             List<AppOpEntry> opsList, int uid, int samplingRatio, String packageName,
             @Nullable String attributionTag) {
-        AppOpEntry entry = new AppOpEntry(packageName, attributionTag, op, uid);
+        int firstChar = 0;
+        if (attributionTag != null && attributionTag.startsWith(packageName)) {
+            firstChar = packageName.length();
+            if (firstChar < attributionTag.length() && attributionTag.charAt(firstChar) == '.') {
+                firstChar++;
+            }
+        }
+        AppOpEntry entry = new AppOpEntry(packageName,
+                attributionTag == null ? null : attributionTag.substring(firstChar), op,
+                uid);
         if (entry.mHash < samplingRatio) {
             opsList.add(entry);
         }
     }
 
-    int pullRuntimeAppOpAccessMessage(int atomTag, List<StatsEvent> pulledData) {
+    int pullRuntimeAppOpAccessMessageLocked(int atomTag, List<StatsEvent> pulledData) {
         final long token = Binder.clearCallingIdentity();
         try {
             AppOpsManager appOps = mContext.getSystemService(AppOpsManager.class);
@@ -3507,7 +3667,7 @@
         );
     }
 
-    int pullNotificationRemoteViews(int atomTag, List<StatsEvent> pulledData) {
+    int pullNotificationRemoteViewsLocked(int atomTag, List<StatsEvent> pulledData) {
         INotificationManager notificationManagerService = getINotificationManagerService();
         if (notificationManagerService == null) {
             return StatsManager.PULL_SKIP;
@@ -3601,7 +3761,7 @@
         );
     }
 
-    int pullHealthHal(int atomTag, List<StatsEvent> pulledData) {
+    int pullHealthHalLocked(int atomTag, List<StatsEvent> pulledData) {
         IHealth healthService = mHealthService.getLastService();
         if (healthService == null) {
             return StatsManager.PULL_SKIP;
@@ -3651,7 +3811,7 @@
         );
     }
 
-    int pullSettingsStats(int atomTag, List<StatsEvent> pulledData) {
+    int pullSettingsStatsLocked(int atomTag, List<StatsEvent> pulledData) {
         UserManager userManager = mContext.getSystemService(UserManager.class);
         if (userManager == null) {
             return StatsManager.PULL_SKIP;
@@ -3678,21 +3838,6 @@
         return StatsManager.PULL_SUCCESS;
     }
 
-    private void registerDisplayWakeStats() {
-        int tagId = FrameworkStatsLog.DISPLAY_WAKE_REASON;
-        mStatsManager.setPullAtomCallback(
-                tagId,
-                null, // use default PullAtomMetadata values
-                DIRECT_EXECUTOR,
-                mStatsCallbackImpl
-        );
-    }
-
-    int pullDisplayWakeStats(int atomTag, List<StatsEvent> pulledData) {
-        //TODO: Denny, implement read/write DisplayWakeStats, b/154172964
-        return 0;
-    }
-
     // Thermal event received from vendor thermal management subsystem
     private static final class ThermalEventListener extends IThermalEventListener.Stub {
         @Override
@@ -3749,11 +3894,13 @@
                 final SubInfo subInfo = new SubInfo(subId, sub.getCarrierId(), mcc, mnc,
                         subscriberId, sub.isOpportunistic());
                 Slog.i(TAG, "subId " + subId + " added into historical sub list");
-                mHistoricalSubs.add(subInfo);
 
-                // Since getting snapshot when pulling will also include data before boot,
-                // query stats as baseline to prevent double count is needed.
-                mNetworkStatsBaselines.addAll(getDataUsageBytesTransferSnapshotForSub(subInfo));
+                synchronized (mDataBytesTransferLock) {
+                    mHistoricalSubs.add(subInfo);
+                    // Since getting snapshot when pulling will also include data before boot,
+                    // query stats as baseline to prevent double count is needed.
+                    mNetworkStatsBaselines.addAll(getDataUsageBytesTransferSnapshotForSub(subInfo));
+                }
             }
         }
     }
diff --git a/services/core/java/com/android/server/textclassifier/FixedSizeQueue.java b/services/core/java/com/android/server/textclassifier/FixedSizeQueue.java
new file mode 100644
index 0000000..edb258d
--- /dev/null
+++ b/services/core/java/com/android/server/textclassifier/FixedSizeQueue.java
@@ -0,0 +1,103 @@
+/*
+ * Copyright (C) 2020 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.textclassifier;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.util.Preconditions;
+
+import java.util.ArrayDeque;
+import java.util.Objects;
+import java.util.Queue;
+
+/**
+ * A fixed-size queue which automatically evicts the oldest element from the queue when it is full.
+ *
+ * <p>This class does not accept null element.
+ *
+ * @param <E> the type of elements held in this queue
+ */
+@VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE)
+public final class FixedSizeQueue<E> {
+
+    private final Queue<E> mDelegate;
+
+    @Nullable
+    private final OnEntryEvictedListener<E> mOnEntryEvictedListener;
+
+    private final int mMaxSize;
+
+    public FixedSizeQueue(int maxSize, @Nullable OnEntryEvictedListener<E> onEntryEvictedListener) {
+        Preconditions.checkArgument(maxSize > 0, "maxSize (%s) must > 0", maxSize);
+        mDelegate = new ArrayDeque<>(maxSize);
+        mMaxSize = maxSize;
+        mOnEntryEvictedListener = onEntryEvictedListener;
+    }
+
+    /** Returns the number of items in the queue. */
+    public int size() {
+        return mDelegate.size();
+    }
+
+    /** Adds an element to the queue, evicts the oldest element if it reaches its max capacity. */
+    public boolean add(@NonNull E element) {
+        Objects.requireNonNull(element);
+        if (size() == mMaxSize) {
+            E removed = mDelegate.remove();
+            if (mOnEntryEvictedListener != null) {
+                mOnEntryEvictedListener.onEntryEvicted(removed);
+            }
+        }
+        mDelegate.add(element);
+        return true;
+    }
+
+    /**
+     * Returns and removes the head of the queue, or returns null if this queue is empty.
+     */
+    @Nullable
+    public E poll() {
+        return mDelegate.poll();
+    }
+
+    /**
+     * Removes an element from the queue, returns a boolean to indicate if an element is removed.
+     */
+    public boolean remove(@NonNull E element) {
+        Objects.requireNonNull(element);
+        return mDelegate.remove(element);
+    }
+
+    /** Returns whether the queue is empty. */
+    public boolean isEmpty() {
+        return mDelegate.isEmpty();
+    }
+
+    /**
+     * A listener to get notified when an element is evicted.
+     *
+     * @param <E> the type of element
+     */
+    public interface OnEntryEvictedListener<E> {
+        /**
+         * Notifies that an element is evicted because the queue is reaching its max capacity.
+         */
+        void onEntryEvicted(@NonNull E element);
+    }
+}
diff --git a/services/core/java/com/android/server/textclassifier/TextClassificationManagerService.java b/services/core/java/com/android/server/textclassifier/TextClassificationManagerService.java
index 1c96a2e..1707d95 100644
--- a/services/core/java/com/android/server/textclassifier/TextClassificationManagerService.java
+++ b/services/core/java/com/android/server/textclassifier/TextClassificationManagerService.java
@@ -41,6 +41,7 @@
 import android.service.textclassifier.TextClassifierService.ConnectionState;
 import android.text.TextUtils;
 import android.util.ArrayMap;
+import android.util.LruCache;
 import android.util.Slog;
 import android.util.SparseArray;
 import android.view.textclassifier.ConversationAction;
@@ -68,12 +69,10 @@
 
 import java.io.FileDescriptor;
 import java.io.PrintWriter;
-import java.util.ArrayDeque;
 import java.util.ArrayList;
 import java.util.List;
 import java.util.Map;
 import java.util.Objects;
-import java.util.Queue;
 
 /**
  * A manager for TextClassifier services.
@@ -308,13 +307,15 @@
         Objects.requireNonNull(classificationContext);
         Objects.requireNonNull(classificationContext.getSystemTextClassifierMetadata());
 
+        synchronized (mLock) {
+            mSessionCache.put(sessionId, classificationContext);
+        }
         handleRequest(
                 classificationContext.getSystemTextClassifierMetadata(),
                 /* verifyCallingPackage= */ true,
                 /* attemptToBind= */ false,
                 service -> {
                     service.onCreateTextClassificationSession(classificationContext, sessionId);
-                    mSessionCache.put(sessionId, classificationContext);
                 },
                 "onCreateTextClassificationSession",
                 NO_OP_CALLBACK);
@@ -588,12 +589,14 @@
      * are cleaned up automatically when the client process is dead.
      */
     static final class SessionCache {
+        private static final int MAX_CACHE_SIZE = 100;
+
         @NonNull
         private final Object mLock;
         @NonNull
         @GuardedBy("mLock")
-        private final Map<TextClassificationSessionId, StrippedTextClassificationContext> mCache =
-                new ArrayMap<>();
+        private final LruCache<TextClassificationSessionId, StrippedTextClassificationContext>
+                mCache = new LruCache<>(MAX_CACHE_SIZE);
         @NonNull
         @GuardedBy("mLock")
         private final Map<TextClassificationSessionId, DeathRecipient> mDeathRecipients =
@@ -775,6 +778,8 @@
     }
 
     private final class ServiceState {
+        private static final int MAX_PENDING_REQUESTS = 20;
+
         @UserIdInt
         final int mUserId;
         @NonNull
@@ -786,7 +791,15 @@
         final int mBindServiceFlags;
         @NonNull
         @GuardedBy("mLock")
-        final Queue<PendingRequest> mPendingRequests = new ArrayDeque<>();
+        final FixedSizeQueue<PendingRequest> mPendingRequests =
+                new FixedSizeQueue<>(MAX_PENDING_REQUESTS,
+                        request -> {
+                            Slog.w(LOG_TAG,
+                                    String.format("Pending request[%s] is dropped", request.mName));
+                            if (request.mOnServiceFailure != null) {
+                                request.mOnServiceFailure.run();
+                            }
+                        });
         @Nullable
         @GuardedBy("mLock")
         ITextClassifierService mService;
@@ -910,7 +923,7 @@
                 pw.printPair("bindServiceFlags", mBindServiceFlags);
                 pw.printPair("boundServiceUid", mBoundServiceUid);
                 pw.printPair("binding", mBinding);
-                pw.printPair("numberRequests", mPendingRequests.size());
+                pw.printPair("numOfPendingRequests", mPendingRequests.size());
             }
         }
 
diff --git a/services/core/java/com/android/server/tv/tunerresourcemanager/TunerResourceManagerService.java b/services/core/java/com/android/server/tv/tunerresourcemanager/TunerResourceManagerService.java
index 41aa4ee..7cb59dc 100644
--- a/services/core/java/com/android/server/tv/tunerresourcemanager/TunerResourceManagerService.java
+++ b/services/core/java/com/android/server/tv/tunerresourcemanager/TunerResourceManagerService.java
@@ -21,6 +21,7 @@
 import android.app.ActivityManager;
 import android.app.ActivityManager.RunningAppProcessInfo;
 import android.content.Context;
+import android.media.IResourceManagerService;
 import android.media.tv.TvInputManager;
 import android.media.tv.tunerresourcemanager.CasSessionRequest;
 import android.media.tv.tunerresourcemanager.IResourcesReclaimListener;
@@ -53,7 +54,7 @@
  *
  * @hide
  */
-public class TunerResourceManagerService extends SystemService {
+public class TunerResourceManagerService extends SystemService implements IBinder.DeathRecipient {
     private static final String TAG = "TunerResourceManagerService";
     private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
 
@@ -76,6 +77,7 @@
 
     private TvInputManager mTvInputManager;
     private ActivityManager mActivityManager;
+    private IResourceManagerService mMediaResourceManager;
     private UseCasePriorityHints mPriorityCongfig = new UseCasePriorityHints();
 
     // An internal resource request count to help generate resource handle.
@@ -102,6 +104,22 @@
         mActivityManager =
                 (ActivityManager) getContext().getSystemService(Context.ACTIVITY_SERVICE);
         mPriorityCongfig.parse();
+
+        if (mMediaResourceManager == null) {
+            IBinder mediaResourceManagerBinder = getBinderService("media.resource_manager");
+            if (mediaResourceManagerBinder == null) {
+                Slog.w(TAG, "Resource Manager Service not available.");
+                return;
+            }
+            try {
+                mediaResourceManagerBinder.linkToDeath(this, /*flags*/ 0);
+            } catch (RemoteException e) {
+                Slog.w(TAG, "Could not link to death of native resource manager service.");
+                return;
+            }
+            mMediaResourceManager = IResourceManagerService.Stub.asInterface(
+                    mediaResourceManagerBinder);
+        }
     }
 
     private final class BinderService extends ITunerResourceManager.Stub {
@@ -380,6 +398,19 @@
         }
     }
 
+    /**
+     * Handle the death of the native resource manager service
+     */
+    @Override
+    public void binderDied() {
+        if (DEBUG) {
+            Slog.w(TAG, "Native media resource manager service has died");
+        }
+        synchronized (mLock) {
+            mMediaResourceManager = null;
+        }
+    }
+
     @VisibleForTesting
     protected void registerClientProfileInternal(ResourceClientProfile profile,
             IResourcesReclaimListener listener, int[] clientId) {
@@ -399,6 +430,16 @@
                 ? Binder.getCallingPid() /*callingPid*/
                 : mTvInputManager.getClientPid(profile.getTvInputSessionId()); /*tvAppId*/
 
+        // Update Media Resource Manager with the tvAppId
+        if (profile.getTvInputSessionId() != null && mMediaResourceManager != null) {
+            try {
+                mMediaResourceManager.overridePid(Binder.getCallingPid(), pid);
+            } catch (RemoteException e) {
+                Slog.e(TAG, "Could not overridePid in resourceManagerSercice,"
+                        + " remote exception: " + e);
+            }
+        }
+
         ClientProfile clientProfile = new ClientProfile.Builder(clientId[0])
                                               .tvInputSessionId(profile.getTvInputSessionId())
                                               .useCase(profile.getUseCase())
@@ -415,6 +456,15 @@
             Slog.d(TAG, "unregisterClientProfile(clientId=" + clientId + ")");
         }
         removeClientProfile(clientId);
+        // Remove the Media Resource Manager callingPid to tvAppId mapping
+        if (mMediaResourceManager != null) {
+            try {
+                mMediaResourceManager.overridePid(Binder.getCallingPid(), -1);
+            } catch (RemoteException e) {
+                Slog.e(TAG, "Could not overridePid in resourceManagerSercice when unregister,"
+                        + " remote exception: " + e);
+            }
+        }
     }
 
     @VisibleForTesting
diff --git a/services/core/java/com/android/server/wm/AccessibilityController.java b/services/core/java/com/android/server/wm/AccessibilityController.java
index 34998a0..b9240c7 100644
--- a/services/core/java/com/android/server/wm/AccessibilityController.java
+++ b/services/core/java/com/android/server/wm/AccessibilityController.java
@@ -898,11 +898,16 @@
                         /* ignore */
                     }
                     mSurfaceControl = surfaceControl;
-                    mService.mTransactionFactory.get().setLayer(mSurfaceControl,
-                            mService.mPolicy.getWindowLayerFromTypeLw(TYPE_MAGNIFICATION_OVERLAY)
-                                    * WindowManagerService.TYPE_LAYER_MULTIPLIER)
-                            .setPosition(mSurfaceControl, 0, 0)
-                            .apply();
+
+                    final SurfaceControl.Transaction t = mService.mTransactionFactory.get();
+                    final int layer =
+                            mService.mPolicy.getWindowLayerFromTypeLw(TYPE_MAGNIFICATION_OVERLAY) *
+                                    WindowManagerService.TYPE_LAYER_MULTIPLIER;
+                    t.setLayer(mSurfaceControl, layer).setPosition(mSurfaceControl, 0, 0);
+                    InputMonitor.setTrustedOverlayInputInfo(mSurfaceControl, t,
+                            mDisplayContent.getDisplayId(), "Magnification Overlay");
+                    t.apply();
+
                     mSurface.copyFrom(mSurfaceControl);
 
                     mAnimationController = new AnimationController(context,
diff --git a/services/core/java/com/android/server/wm/ActivityMetricsLogger.java b/services/core/java/com/android/server/wm/ActivityMetricsLogger.java
index fb29f9a..189b21f 100644
--- a/services/core/java/com/android/server/wm/ActivityMetricsLogger.java
+++ b/services/core/java/com/android/server/wm/ActivityMetricsLogger.java
@@ -842,7 +842,8 @@
                 ? PackageOptimizationInfo.createWithNoInfo()
                 : artManagerInternal.getPackageOptimizationInfo(
                         info.applicationInfo,
-                        info.launchedActivityAppRecordRequiredAbi);
+                        info.launchedActivityAppRecordRequiredAbi,
+                        info.launchedActivityName);
         builder.addTaggedData(PACKAGE_OPTIMIZATION_COMPILATION_REASON,
                 packageOptimizationInfo.getCompilationReason());
         builder.addTaggedData(PACKAGE_OPTIMIZATION_COMPILATION_FILTER,
diff --git a/services/core/java/com/android/server/wm/ActivityRecord.java b/services/core/java/com/android/server/wm/ActivityRecord.java
index fe2b144..5668454b 100644
--- a/services/core/java/com/android/server/wm/ActivityRecord.java
+++ b/services/core/java/com/android/server/wm/ActivityRecord.java
@@ -311,7 +311,6 @@
 import com.android.server.wm.ActivityMetricsLogger.TransitionInfoSnapshot;
 import com.android.server.wm.ActivityStack.ActivityState;
 import com.android.server.wm.SurfaceAnimator.AnimationType;
-import com.android.server.wm.SurfaceAnimator.OnAnimationFinishedCallback;
 import com.android.server.wm.WindowManagerService.H;
 import com.android.server.wm.utils.InsetUtils;
 
@@ -2199,10 +2198,13 @@
 
     @Override
     boolean isFocusable() {
+        return super.isFocusable() && (canReceiveKeys() || isAlwaysFocusable());
+    }
+
+    boolean canReceiveKeys() {
         // TODO(156521483): Propagate the state down the hierarchy instead of checking the parent
-        boolean canReceiveKeys = getWindowConfiguration().canReceiveKeys()
-                && getTask().getWindowConfiguration().canReceiveKeys();
-        return super.isFocusable() && (canReceiveKeys || isAlwaysFocusable());
+        return getWindowConfiguration().canReceiveKeys()
+                && (task == null || task.getWindowConfiguration().canReceiveKeys());
     }
 
     boolean isResizeable() {
@@ -2371,10 +2373,10 @@
                 // For the apps below Q, there can be only one app which has the focused window per
                 // process, because legacy apps may not be ready for a multi-focus system.
                 return false;
+
             }
         }
-        return (getWindowConfiguration().canReceiveKeys() || isAlwaysFocusable())
-                && getDisplay() != null;
+        return (canReceiveKeys() || isAlwaysFocusable()) && getDisplay() != null;
     }
 
     /**
@@ -2842,7 +2844,8 @@
                     // their client may have activities.
                     // No longer have activities, so update LRU list and oom adj.
                     app.updateProcessInfo(true /* updateServiceConnectionActivities */,
-                            false /* activityChange */, true /* updateOomAdj */);
+                            false /* activityChange */, true /* updateOomAdj */,
+                            false /* addPendingTopUid */);
                 }
             }
 
@@ -3355,6 +3358,13 @@
 
             final long origId = Binder.clearCallingIdentity();
             try {
+                // Link the fixed rotation transform to this activity since we are transferring the
+                // starting window.
+                if (fromActivity.hasFixedRotationTransform()) {
+                    mDisplayContent.handleTopActivityLaunchingInDifferentOrientation(this,
+                            false /* checkOpening */);
+                }
+
                 // Transfer the starting window over to the new token.
                 mStartingData = fromActivity.mStartingData;
                 startingSurface = fromActivity.startingSurface;
@@ -4165,14 +4175,12 @@
     }
 
     @Override
-    boolean applyAnimation(WindowManager.LayoutParams lp, int transit, boolean enter,
-            boolean isVoiceInteraction,
-            @Nullable OnAnimationFinishedCallback animationFinishedCallback) {
+    boolean applyAnimation(LayoutParams lp, int transit, boolean enter,
+            boolean isVoiceInteraction, @Nullable ArrayList<WindowContainer> sources) {
         if (mUseTransferredAnimation) {
             return false;
         }
-        return super.applyAnimation(lp, transit, enter, isVoiceInteraction,
-                animationFinishedCallback);
+        return super.applyAnimation(lp, transit, enter, isVoiceInteraction, sources);
     }
 
     /**
@@ -7539,7 +7547,7 @@
     public String toString() {
         if (stringName != null) {
             return stringName + " t" + (task == null ? INVALID_TASK_ID : task.mTaskId) +
-                    (finishing ? " f}" : "") + (mIsExiting ? " mIsExiting=" : "") + "}";
+                    (finishing ? " f}" : "") + (mIsExiting ? " isExiting" : "") + "}";
         }
         StringBuilder sb = new StringBuilder(128);
         sb.append("ActivityRecord{");
@@ -7719,24 +7727,25 @@
                     outAppBounds.set(outBounds);
                 }
             } else {
-                outBounds.set(0, 0, mWidth, mHeight);
-                getFrameByOrientation(outAppBounds, orientation);
-                if (orientationRequested && !canChangeOrientation
-                        && (outAppBounds.width() > outAppBounds.height()) != (mWidth > mHeight)) {
-                    // The orientation is mismatched but the display cannot rotate. The bounds will
-                    // fit to the short side of display.
-                    if (orientation == ORIENTATION_LANDSCAPE) {
-                        outAppBounds.bottom = (int) ((float) mWidth * mWidth / mHeight);
-                        outAppBounds.right = mWidth;
-                    } else {
-                        outAppBounds.bottom = mHeight;
-                        outAppBounds.right = (int) ((float) mHeight * mHeight / mWidth);
+                if (orientationRequested) {
+                    getFrameByOrientation(outBounds, orientation);
+                    if ((outBounds.width() > outBounds.height()) != (mWidth > mHeight)) {
+                        // The orientation is mismatched but the display cannot rotate. The bounds
+                        // will fit to the short side of display.
+                        if (orientation == ORIENTATION_LANDSCAPE) {
+                            outBounds.bottom = (int) ((float) mWidth * mWidth / mHeight);
+                            outBounds.right = mWidth;
+                        } else {
+                            outBounds.bottom = mHeight;
+                            outBounds.right = (int) ((float) mHeight * mHeight / mWidth);
+                        }
+                        outBounds.offset(
+                                getHorizontalCenterOffset(mWidth, outBounds.width()), 0 /* dy */);
                     }
-                    outAppBounds.offset(getHorizontalCenterOffset(outBounds.width(),
-                            outAppBounds.width()), 0 /* dy */);
                 } else {
-                    outAppBounds.set(outBounds);
+                    outBounds.set(0, 0, mWidth, mHeight);
                 }
+                outAppBounds.set(outBounds);
             }
 
             if (rotation != ROTATION_UNDEFINED) {
diff --git a/services/core/java/com/android/server/wm/ActivityStack.java b/services/core/java/com/android/server/wm/ActivityStack.java
index 0d5621d..b4bc0f5 100644
--- a/services/core/java/com/android/server/wm/ActivityStack.java
+++ b/services/core/java/com/android/server/wm/ActivityStack.java
@@ -813,7 +813,7 @@
     /** Resume next focusable stack after reparenting to another display. */
     void postReparent() {
         adjustFocusToNextFocusableTask("reparent", true /* allowFocusSelf */,
-                true /* moveParentsToTop */);
+                true /* moveDisplayToTop */);
         mRootWindowContainer.resumeFocusedStacksTopActivities();
         // Update visibility of activities before notifying WM. This way it won't try to resize
         // windows that are no longer visible.
@@ -1682,7 +1682,8 @@
             // happens to be sitting towards the end.
             if (next.attachedToProcess()) {
                 next.app.updateProcessInfo(false /* updateServiceConnectionActivities */,
-                        true /* activityChange */, false /* updateOomAdj */);
+                        true /* activityChange */, false /* updateOomAdj */,
+                        false /* addPendingTopUid */);
             } else if (!next.isProcessRunning()) {
                 // Since the start-process is asynchronous, if we already know the process of next
                 // activity isn't running, we can start the process earlier to save the time to wait
@@ -1839,7 +1840,8 @@
             next.setState(RESUMED, "resumeTopActivityInnerLocked");
 
             next.app.updateProcessInfo(false /* updateServiceConnectionActivities */,
-                    true /* activityChange */, true /* updateOomAdj */);
+                    true /* activityChange */, true /* updateOomAdj */,
+                    true /* addPendingTopUid */);
 
             // Have the window manager re-evaluate the orientation of
             // the screen based on the new activity order.
@@ -3230,22 +3232,22 @@
 
     @Override
     void dump(PrintWriter pw, String prefix, boolean dumpAll) {
-        pw.println(prefix + "mStackId=" + getRootTaskId());
-        pw.println(prefix + "mDeferRemoval=" + mDeferRemoval);
-        pw.println(prefix + "mBounds=" + getRawBounds().toShortString());
-        for (int taskNdx = mChildren.size() - 1; taskNdx >= 0; taskNdx--) {
-            mChildren.get(taskNdx).dump(pw, prefix + "  ", dumpAll);
+        if (mDeferRemoval) {
+            pw.println(prefix + "mDeferRemoval=true");
         }
+        super.dump(pw, prefix, dumpAll);
         if (!mExitingActivities.isEmpty()) {
             pw.println();
-            pw.println("  Exiting application tokens:");
+            pw.println(prefix + "Exiting application tokens:");
+            final String doublePrefix = prefix + "  ";
             for (int i = mExitingActivities.size() - 1; i >= 0; i--) {
                 WindowToken token = mExitingActivities.get(i);
-                pw.print("  Exiting App #"); pw.print(i);
+                pw.print(doublePrefix + "Exiting App #" + i);
                 pw.print(' '); pw.print(token);
                 pw.println(':');
-                token.dump(pw, "    ", dumpAll);
+                token.dump(pw, doublePrefix, dumpAll);
             }
+            pw.println();
         }
         mAnimatingActivityRegistry.dump(pw, "AnimatingApps:", prefix);
     }
diff --git a/services/core/java/com/android/server/wm/ActivityStackSupervisor.java b/services/core/java/com/android/server/wm/ActivityStackSupervisor.java
index b7ca1a9..1f9e860 100644
--- a/services/core/java/com/android/server/wm/ActivityStackSupervisor.java
+++ b/services/core/java/com/android/server/wm/ActivityStackSupervisor.java
@@ -1886,7 +1886,7 @@
     public void dump(PrintWriter pw, String prefix) {
         pw.println();
         pw.println("ActivityStackSupervisor state:");
-        mRootWindowContainer.dump(pw, prefix);
+        mRootWindowContainer.dump(pw, prefix, true /* dumpAll */);
         getKeyguardController().dump(pw, prefix);
         mService.getLockTaskController().dump(pw, prefix);
         pw.print(prefix);
diff --git a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
index 5f591b5..6dd1ea9 100644
--- a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
+++ b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
@@ -1685,6 +1685,11 @@
         final NeededUriGrants resultGrants = collectGrants(resultData, r.resultTo);
 
         synchronized (mGlobalLock) {
+            // Sanity check in case activity was removed before entering global lock.
+            if (!r.isInHistory()) {
+                return true;
+            }
+
             // Keep track of the root activity of the task before we finish it
             final Task tr = r.getTask();
             final ActivityRecord rootR = tr.getRootActivity();
@@ -4873,6 +4878,10 @@
                     return;
                 }
 
+                if (isInPictureInPictureMode(activity)) {
+                    throw new IllegalStateException("Activity is already in PIP mode");
+                }
+
                 final boolean canEnterPictureInPicture = activity.checkEnterPictureInPictureState(
                         "requestPictureInPictureMode", /* beforeStopping */ false);
                 if (!canEnterPictureInPicture) {
diff --git a/services/core/java/com/android/server/wm/AlertWindowNotification.java b/services/core/java/com/android/server/wm/AlertWindowNotification.java
index 7b511ec..fde0369 100644
--- a/services/core/java/com/android/server/wm/AlertWindowNotification.java
+++ b/services/core/java/com/android/server/wm/AlertWindowNotification.java
@@ -18,6 +18,7 @@
 
 import static android.app.NotificationManager.IMPORTANCE_MIN;
 import static android.app.PendingIntent.FLAG_CANCEL_CURRENT;
+import static android.app.PendingIntent.FLAG_IMMUTABLE;
 import static android.content.Context.NOTIFICATION_SERVICE;
 import static android.content.Intent.FLAG_ACTIVITY_CLEAR_TASK;
 import static android.content.Intent.FLAG_ACTIVITY_NEW_TASK;
@@ -139,7 +140,8 @@
                 Uri.fromParts("package", packageName, null));
         intent.setFlags(FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_CLEAR_TASK);
         // Calls into activity manager...
-        return PendingIntent.getActivity(context, mRequestCode, intent, FLAG_CANCEL_CURRENT);
+        return PendingIntent.getActivity(context, mRequestCode, intent,
+                FLAG_CANCEL_CURRENT | FLAG_IMMUTABLE);
     }
 
     private void createNotificationChannel(Context context, String appName) {
diff --git a/services/core/java/com/android/server/wm/AppTransitionController.java b/services/core/java/com/android/server/wm/AppTransitionController.java
index 67fe968..d60d098 100644
--- a/services/core/java/com/android/server/wm/AppTransitionController.java
+++ b/services/core/java/com/android/server/wm/AppTransitionController.java
@@ -49,7 +49,7 @@
 import static com.android.server.wm.AppTransition.isKeyguardGoingAwayTransit;
 import static com.android.server.wm.ProtoLogGroup.WM_DEBUG_APP_TRANSITIONS;
 import static com.android.server.wm.ProtoLogGroup.WM_DEBUG_APP_TRANSITIONS_ANIM;
-import static com.android.server.wm.WindowContainer.AnimationFlags.CHILDREN;
+import static com.android.server.wm.SurfaceAnimator.ANIMATION_TYPE_APP_TRANSITION;
 import static com.android.server.wm.WindowContainer.AnimationFlags.PARENTS;
 import static com.android.server.wm.WindowManagerDebugConfig.SHOW_LIGHT_TRANSACTIONS;
 import static com.android.server.wm.WindowManagerDebugConfig.TAG_WITH_CLASS_NAME;
@@ -75,7 +75,6 @@
 import java.util.LinkedList;
 import java.util.function.Predicate;
 
-
 /**
  * Checks for app transition readiness, resolves animation attributes and performs visibility
  * change for apps that animate as part of an app transition.
@@ -375,18 +374,14 @@
             // triggers WC#onAnimationFinished only on the promoted target. So we need to take care
             // of triggering AR#onAnimationFinished on each ActivityRecord which is a part of the
             // app transition.
-            final ArrayList<ActivityRecord> transitioningDecendants = new ArrayList<>();
+            final ArrayList<ActivityRecord> transitioningDescendants = new ArrayList<>();
             for (int j = 0; j < apps.size(); ++j) {
                 final ActivityRecord app = apps.valueAt(j);
                 if (app.isDescendantOf(wc)) {
-                    transitioningDecendants.add(app);
+                    transitioningDescendants.add(app);
                 }
             }
-            wc.applyAnimation(animLp, transit, visible, voiceInteraction, (type, anim) -> {
-                for (int j = 0; j < transitioningDecendants.size(); ++j) {
-                    transitioningDecendants.get(j).onAnimationFinished(type, anim);
-                }
-            });
+            wc.applyAnimation(animLp, transit, visible, voiceInteraction, transitioningDescendants);
         }
     }
 
@@ -540,7 +535,14 @@
             ProtoLog.v(WM_DEBUG_APP_TRANSITIONS, "Now opening app %s", app);
 
             app.commitVisibility(true /* visible */, false /* performLayout */);
-            if (!app.isAnimating(PARENTS | CHILDREN)) {
+
+            // In case a trampoline activity is used, it can happen that a new ActivityRecord is
+            // added and a new app transition starts before the previous app transition animation
+            // ends. So we cannot simply use app.isAnimating(PARENTS) to determine if the app must
+            // to be added to the list of tokens to be notified of app transition complete.
+            final WindowContainer wc = app.getAnimatingContainer(PARENTS,
+                    ANIMATION_TYPE_APP_TRANSITION);
+            if (wc == null || !wc.getAnimationSources().contains(app)) {
                 // This token isn't going to be animating. Add it to the list of tokens to
                 // be notified of app transition complete since the notification will not be
                 // sent be the app window animator.
@@ -599,8 +601,7 @@
         for (int i = 0; i < appsCount; i++) {
             WindowContainer wc = apps.valueAt(i);
             ProtoLog.v(WM_DEBUG_APP_TRANSITIONS, "Now changing app %s", wc);
-            wc.applyAnimation(null, transit, true, false,
-                    null /* animationFinishedCallback */);
+            wc.applyAnimation(null, transit, true, false, null /* sources */);
         }
     }
 
diff --git a/services/core/java/com/android/server/wm/BarController.java b/services/core/java/com/android/server/wm/BarController.java
index 8b14095..26e0790 100644
--- a/services/core/java/com/android/server/wm/BarController.java
+++ b/services/core/java/com/android/server/wm/BarController.java
@@ -59,6 +59,7 @@
     private final int mTransparentFlag;
     private final int mStatusBarManagerId;
     private final int mTranslucentWmFlag;
+    private final int mWindowType;
     protected final Handler mHandler;
     private final Object mServiceAquireLock = new Object();
     private StatusBarManagerInternal mStatusBarInternal;
@@ -77,13 +78,14 @@
     private OnBarVisibilityChangedListener mVisibilityChangeListener;
 
     BarController(String tag, int displayId, int transientFlag, int unhideFlag, int translucentFlag,
-            int statusBarManagerId, int translucentWmFlag, int transparentFlag) {
+            int statusBarManagerId, int windowType, int translucentWmFlag, int transparentFlag) {
         mTag = "BarController." + tag;
         mDisplayId = displayId;
         mTransientFlag = transientFlag;
         mUnhideFlag = unhideFlag;
         mTranslucentFlag = translucentFlag;
         mStatusBarManagerId = statusBarManagerId;
+        mWindowType = windowType;
         mTranslucentWmFlag = translucentWmFlag;
         mTransparentFlag = transparentFlag;
         mHandler = new BarHandler();
@@ -168,7 +170,12 @@
     }
 
     boolean isTransparentAllowed(WindowState win) {
-        return win == null || win.letterboxNotIntersectsOrFullyContains(mContentFrame);
+        if (win == null) {
+            return true;
+        }
+        final Rect rotatedContentFrame = win.mToken.getFixedRotationBarContentFrame(mWindowType);
+        final Rect contentFrame = rotatedContentFrame != null ? rotatedContentFrame : mContentFrame;
+        return win.letterboxNotIntersectsOrFullyContains(contentFrame);
     }
 
     boolean setBarShowingLw(final boolean show) {
diff --git a/services/core/java/com/android/server/wm/Dimmer.java b/services/core/java/com/android/server/wm/Dimmer.java
index fdcc3f4..d43a7b8 100644
--- a/services/core/java/com/android/server/wm/Dimmer.java
+++ b/services/core/java/com/android/server/wm/Dimmer.java
@@ -22,7 +22,6 @@
 import static com.android.server.wm.AnimationSpecProto.ALPHA;
 import static com.android.server.wm.SurfaceAnimator.ANIMATION_TYPE_DIMMER;
 
-import android.annotation.Nullable;
 import android.graphics.Rect;
 import android.util.Log;
 import android.util.proto.ProtoOutputStream;
@@ -31,7 +30,6 @@
 
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.server.wm.SurfaceAnimator.AnimationType;
-import com.android.server.wm.SurfaceAnimator.OnAnimationFinishedCallback;
 
 import java.io.PrintWriter;
 
@@ -160,8 +158,7 @@
     @VisibleForTesting
     interface SurfaceAnimatorStarter {
         void startAnimation(SurfaceAnimator surfaceAnimator, SurfaceControl.Transaction t,
-                AnimationAdapter anim, boolean hidden, @AnimationType int type,
-                @Nullable OnAnimationFinishedCallback animationFinishedCallback);
+                AnimationAdapter anim, boolean hidden, @AnimationType int type);
     }
 
     Dimmer(WindowContainer host) {
@@ -348,7 +345,7 @@
         mSurfaceAnimatorStarter.startAnimation(animator, t, new LocalAnimationAdapter(
                 new AlphaAnimationSpec(startAlpha, endAlpha, getDimDuration(container)),
                 mHost.mWmService.mSurfaceAnimationRunner), false /* hidden */,
-                ANIMATION_TYPE_DIMMER, null /* animationFinishedCallback */);
+                ANIMATION_TYPE_DIMMER);
     }
 
     private long getDimDuration(WindowContainer container) {
diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java
index a5b94b3..fb60257 100644
--- a/services/core/java/com/android/server/wm/DisplayContent.java
+++ b/services/core/java/com/android/server/wm/DisplayContent.java
@@ -2977,12 +2977,10 @@
         pw.println();
         mWallpaperController.dump(pw, "  ");
 
-        pw.println();
-        pw.print("mSystemGestureExclusion=");
         if (mSystemGestureExclusionListeners.getRegisteredCallbackCount() > 0) {
+            pw.println();
+            pw.print("  mSystemGestureExclusion=");
             pw.println(mSystemGestureExclusion);
-        } else {
-            pw.println("<no lstnrs>");
         }
 
         pw.println();
@@ -3506,22 +3504,21 @@
      * doesn't support IME/system decorations.
      *
      * @param target current IME target.
-     * @return {@link WindowState} that can host IME.
+     * @return {@link InsetsControlTarget} that can host IME.
      */
-    WindowState getImeHostOrFallback(WindowState target) {
+    InsetsControlTarget getImeHostOrFallback(WindowState target) {
         if (target != null && target.getDisplayContent().canShowIme()) {
             return target;
         }
         return getImeFallback();
     }
 
-    WindowState getImeFallback() {
-
+    InsetsControlTarget getImeFallback() {
         // host is in non-default display that doesn't support system decor, default to
-        // default display's StatusBar to control IME.
-        // TODO: (b/148234093)find a better host OR control IME animation/visibility directly
-        //  because it won't work when statusbar isn't available.
-        return mWmService.getDefaultDisplayContentLocked().getDisplayPolicy().getStatusBar();
+        // default display's StatusBar to control IME (when available), else let system control it.
+        WindowState statusBar = 
+                mWmService.getDefaultDisplayContentLocked().getDisplayPolicy().getStatusBar();
+        return statusBar != null ? statusBar : mRemoteInsetsControlTarget;
     }
 
     boolean canShowIme() {
@@ -5650,8 +5647,12 @@
             }
 
             if (animatingRecents != null && animatingRecents == mFixedRotationLaunchingApp) {
-                // Because it won't affect display orientation, just finish the transform.
-                animatingRecents.finishFixedRotationTransform();
+                // The recents activity should be going to be invisible (switch to another app or
+                // return to original top). Only clear the top launching record without finishing
+                // the transform immediately because it won't affect display orientation. And before
+                // the visibility is committed, the recents activity may perform relayout which may
+                // cause unexpected configuration change if the rotated configuration is restored.
+                // The transform will be finished when the transition is done.
                 setFixedRotationLaunchingAppUnchecked(null);
             } else {
                 // If there is already a launching activity that is not the recents, before its
@@ -5674,7 +5675,11 @@
             }
             if (mFixedRotationLaunchingApp != null
                     && mFixedRotationLaunchingApp.hasFixedRotationTransform(r)) {
-                continueUpdateOrientationForDiffOrienLaunchingApp();
+                // Waiting until all of the associated activities have done animation, or the
+                // orientation would be updated too early and cause flickers.
+                if (!mFixedRotationLaunchingApp.hasAnimatingFixedRotationTransition()) {
+                    continueUpdateOrientationForDiffOrienLaunchingApp();
+                }
             } else {
                 r.finishFixedRotationTransform();
             }
diff --git a/services/core/java/com/android/server/wm/DisplayPolicy.java b/services/core/java/com/android/server/wm/DisplayPolicy.java
index e244b55..3c4a9ad 100644
--- a/services/core/java/com/android/server/wm/DisplayPolicy.java
+++ b/services/core/java/com/android/server/wm/DisplayPolicy.java
@@ -151,6 +151,7 @@
 import android.util.Pair;
 import android.util.PrintWriterPrinter;
 import android.util.Slog;
+import android.util.SparseArray;
 import android.view.DisplayCutout;
 import android.view.Gravity;
 import android.view.InputChannel;
@@ -199,6 +200,7 @@
 import com.android.server.wm.utils.InsetUtils;
 
 import java.io.PrintWriter;
+import java.util.function.Consumer;
 
 /**
  * The policy that provides the basic behaviors and states of a display to show UI.
@@ -471,6 +473,7 @@
                 View.NAVIGATION_BAR_UNHIDE,
                 View.NAVIGATION_BAR_TRANSLUCENT,
                 StatusBarManager.WINDOW_NAVIGATION_BAR,
+                TYPE_NAVIGATION_BAR,
                 FLAG_TRANSLUCENT_NAVIGATION,
                 View.NAVIGATION_BAR_TRANSPARENT);
 
@@ -1171,6 +1174,11 @@
                 displayFrames.mDisplayCutoutSafe.top);
     }
 
+    @VisibleForTesting
+    StatusBarController getStatusBarController() {
+        return mStatusBarController;
+    }
+
     WindowState getStatusBar() {
         return mStatusBar;
     }
@@ -1469,13 +1477,16 @@
     }
 
     private void simulateLayoutDecorWindow(WindowState win, DisplayFrames displayFrames,
-            InsetsState insetsState, WindowFrames simulatedWindowFrames, Runnable layout) {
+            InsetsState insetsState, WindowFrames simulatedWindowFrames,
+            SparseArray<Rect> contentFrames, Consumer<Rect> layout) {
         win.setSimulatedWindowFrames(simulatedWindowFrames);
+        final Rect contentFrame = new Rect();
         try {
-            layout.run();
+            layout.accept(contentFrame);
         } finally {
             win.setSimulatedWindowFrames(null);
         }
+        contentFrames.put(win.mAttrs.type, contentFrame);
         mDisplayContent.getInsetsStateController().computeSimulatedState(insetsState, win,
                 displayFrames, simulatedWindowFrames);
     }
@@ -1487,24 +1498,25 @@
      * state and some temporal states. In other words, it doesn't change the window frames used to
      * show on screen.
      */
-    void simulateLayoutDisplay(DisplayFrames displayFrames, InsetsState insetsState, int uiMode) {
+    void simulateLayoutDisplay(DisplayFrames displayFrames, InsetsState insetsState,
+            SparseArray<Rect> barContentFrames) {
         displayFrames.onBeginLayout();
         updateInsetsStateForDisplayCutout(displayFrames, insetsState);
         insetsState.setDisplayFrame(displayFrames.mUnrestricted);
         final WindowFrames simulatedWindowFrames = new WindowFrames();
         if (mNavigationBar != null) {
-            simulateLayoutDecorWindow(
-                    mNavigationBar, displayFrames, insetsState, simulatedWindowFrames,
-                    () -> layoutNavigationBar(displayFrames, uiMode, mLastNavVisible,
+            simulateLayoutDecorWindow(mNavigationBar, displayFrames, insetsState,
+                    simulatedWindowFrames, barContentFrames,
+                    contentFrame -> layoutNavigationBar(displayFrames,
+                            mDisplayContent.getConfiguration().uiMode, mLastNavVisible,
                             mLastNavTranslucent, mLastNavAllowedHidden,
-                            mLastNotificationShadeForcesShowingNavigation,
-                            false /* isRealLayout */));
+                            mLastNotificationShadeForcesShowingNavigation, contentFrame));
         }
         if (mStatusBar != null) {
-            simulateLayoutDecorWindow(
-                    mStatusBar, displayFrames, insetsState, simulatedWindowFrames,
-                    () -> layoutStatusBar(displayFrames, mLastSystemUiFlags,
-                            false /* isRealLayout */));
+            simulateLayoutDecorWindow(mStatusBar, displayFrames, insetsState,
+                    simulatedWindowFrames, barContentFrames,
+                    contentFrame -> layoutStatusBar(displayFrames, mLastSystemUiFlags,
+                            contentFrame));
         }
         layoutScreenDecorWindows(displayFrames, simulatedWindowFrames);
         postAdjustDisplayFrames(displayFrames);
@@ -1556,9 +1568,10 @@
 
         boolean updateSysUiVisibility = layoutNavigationBar(displayFrames, uiMode, navVisible,
                 navTranslucent, navAllowedHidden, notificationShadeForcesShowingNavigation,
-                true /* isRealLayout */);
+                null /* simulatedContentFrame */);
         if (DEBUG_LAYOUT) Slog.i(TAG, "mDock rect:" + displayFrames.mDock);
-        updateSysUiVisibility |= layoutStatusBar(displayFrames, sysui, true /* isRealLayout */);
+        updateSysUiVisibility |= layoutStatusBar(displayFrames, sysui,
+                null /* simulatedContentFrame */);
         if (updateSysUiVisibility) {
             updateSystemUiVisibilityLw();
         }
@@ -1579,10 +1592,9 @@
                 navControlTarget instanceof WindowState ? (WindowState) navControlTarget : null;
         final InsetsState requestedState = navControllingWin != null
                 ? navControllingWin.getRequestedInsetsState() : null;
-        final InsetsSource navSource = requestedState != null
-                ? requestedState.peekSource(ITYPE_NAVIGATION_BAR) : null;
-        final boolean navVisible = navSource != null
-                ? navSource.isVisible() : InsetsState.getDefaultVisibility(ITYPE_NAVIGATION_BAR);
+        final boolean navVisible = requestedState != null
+                ? requestedState.getSourceOrDefaultVisibility(ITYPE_NAVIGATION_BAR)
+                : InsetsState.getDefaultVisibility(ITYPE_NAVIGATION_BAR);
         final boolean showBarsByTouch = navControllingWin != null
                 && navControllingWin.mAttrs.insetsFlags.behavior == BEHAVIOR_SHOW_BARS_BY_TOUCH;
         // When the navigation bar isn't visible, we put up a fake input window to catch all
@@ -1731,7 +1743,8 @@
         displayFrames.mContent.set(dockFrame);
     }
 
-    private boolean layoutStatusBar(DisplayFrames displayFrames, int sysui, boolean isRealLayout) {
+    private boolean layoutStatusBar(DisplayFrames displayFrames, int sysui,
+            Rect simulatedContentFrame) {
         // decide where the status bar goes ahead of time
         if (mStatusBar == null) {
             return false;
@@ -1754,12 +1767,14 @@
         displayFrames.mStable.top = Math.max(displayFrames.mStable.top,
                 displayFrames.mDisplayCutoutSafe.top);
 
-        if (isRealLayout) {
-            // Tell the bar controller where the collapsed status bar content is.
-            sTmpRect.set(windowFrames.mContentFrame);
-            sTmpRect.intersect(displayFrames.mDisplayCutoutSafe);
-            sTmpRect.top = windowFrames.mContentFrame.top; // Ignore top display cutout inset
-            sTmpRect.bottom = displayFrames.mStable.top; // Use collapsed status bar size
+        // Tell the bar controller where the collapsed status bar content is.
+        sTmpRect.set(windowFrames.mContentFrame);
+        sTmpRect.intersect(displayFrames.mDisplayCutoutSafe);
+        sTmpRect.top = windowFrames.mContentFrame.top; // Ignore top display cutout inset
+        sTmpRect.bottom = displayFrames.mStable.top; // Use collapsed status bar size
+        if (simulatedContentFrame != null) {
+            simulatedContentFrame.set(sTmpRect);
+        } else {
             mStatusBarController.setContentFrame(sTmpRect);
         }
 
@@ -1796,7 +1811,7 @@
 
     private boolean layoutNavigationBar(DisplayFrames displayFrames, int uiMode, boolean navVisible,
             boolean navTranslucent, boolean navAllowedHidden,
-            boolean statusBarForcesShowingNavigation, boolean isRealLayout) {
+            boolean statusBarForcesShowingNavigation, Rect simulatedContentFrame) {
         if (mNavigationBar == null) {
             return false;
         }
@@ -1900,7 +1915,9 @@
                 navigationFrame /* visibleFrame */, sTmpRect /* decorFrame */,
                 navigationFrame /* stableFrame */);
         mNavigationBar.computeFrame(displayFrames);
-        if (isRealLayout) {
+        if (simulatedContentFrame != null) {
+            simulatedContentFrame.set(windowFrames.mContentFrame);
+        } else {
             mNavigationBarPosition = navBarPosition;
             mNavigationBarController.setContentFrame(windowFrames.mContentFrame);
         }
@@ -2372,12 +2389,13 @@
         final boolean requestedFullscreen = (fl & FLAG_FULLSCREEN) != 0
                 || (requestedSysUiFl & View.SYSTEM_UI_FLAG_FULLSCREEN) != 0
                 || (ViewRootImpl.sNewInsetsMode == NEW_INSETS_MODE_FULL
-                        && !win.getRequestedInsetsState().getSource(ITYPE_STATUS_BAR).isVisible());
+                        && !win.getRequestedInsetsState().getSourceOrDefaultVisibility(
+                                ITYPE_STATUS_BAR));
         final boolean requestedHideNavigation =
                 (requestedSysUiFl & View.SYSTEM_UI_FLAG_HIDE_NAVIGATION) != 0
                 || (ViewRootImpl.sNewInsetsMode == NEW_INSETS_MODE_FULL
-                        && !win.getRequestedInsetsState().getSource(ITYPE_NAVIGATION_BAR)
-                                .isVisible());
+                        && !win.getRequestedInsetsState().getSourceOrDefaultVisibility(
+                                ITYPE_NAVIGATION_BAR));
 
         // TYPE_BASE_APPLICATION windows are never considered floating here because they don't get
         // cropped / shifted to the displayFrame in WindowState.
@@ -3187,24 +3205,32 @@
             return;
         }
         if (ViewRootImpl.sNewInsetsMode == NEW_INSETS_MODE_FULL) {
-            if (swipeTarget == mNavigationBar
-                    && !getInsetsPolicy().isHidden(ITYPE_NAVIGATION_BAR)) {
-                // Don't show status bar when swiping on already visible navigation bar
-                return;
-            }
             final InsetsSourceProvider provider = swipeTarget.getControllableInsetProvider();
             final InsetsControlTarget controlTarget = provider != null
                     ? provider.getControlTarget() : null;
 
-            // No transient mode on lockscreen (in notification shade window).
             if (controlTarget == null || controlTarget == getNotificationShade()) {
+                // No transient mode on lockscreen (in notification shade window).
                 return;
             }
+
+            if (swipeTarget == mNavigationBar
+                    && !getInsetsPolicy().isHidden(ITYPE_NAVIGATION_BAR)) {
+                // Don't show status bar when swiping on already visible navigation bar.
+                // But restore the position of navigation bar if it has been moved by the control
+                // target.
+                controlTarget.showInsets(Type.navigationBars(), false);
+                return;
+            }
+
+            int insetsTypesToShow = Type.systemBars();
+
             if (controlTarget.canShowTransient()) {
-                mDisplayContent.getInsetsPolicy().showTransient(IntArray.wrap(
+                insetsTypesToShow &= ~mDisplayContent.getInsetsPolicy().showTransient(IntArray.wrap(
                         new int[]{ITYPE_STATUS_BAR, ITYPE_NAVIGATION_BAR}));
-            } else {
-                controlTarget.showInsets(Type.systemBars(), false);
+            }
+            if (insetsTypesToShow != 0) {
+                controlTarget.showInsets(insetsTypesToShow, false);
             }
         } else {
             boolean sb = mStatusBarController.checkShowTransientBarLw();
diff --git a/services/core/java/com/android/server/wm/EmulatorDisplayOverlay.java b/services/core/java/com/android/server/wm/EmulatorDisplayOverlay.java
index 2165b0e..c9cc944 100644
--- a/services/core/java/com/android/server/wm/EmulatorDisplayOverlay.java
+++ b/services/core/java/com/android/server/wm/EmulatorDisplayOverlay.java
@@ -66,6 +66,9 @@
             t.setLayer(ctrl, zOrder);
             t.setPosition(ctrl, 0, 0);
             t.show(ctrl);
+            // Ensure we aren't considered as obscuring for Input purposes.
+            InputMonitor.setTrustedOverlayInputInfo(ctrl, t,
+                    dc.getDisplayId(), "EmulatorDisplayOverlay");
             mSurface.copyFrom(ctrl);
         } catch (OutOfResourcesException e) {
         }
diff --git a/services/core/java/com/android/server/wm/InputMonitor.java b/services/core/java/com/android/server/wm/InputMonitor.java
index efcd61d..8734b5e 100644
--- a/services/core/java/com/android/server/wm/InputMonitor.java
+++ b/services/core/java/com/android/server/wm/InputMonitor.java
@@ -16,13 +16,17 @@
 
 package com.android.server.wm;
 
+import static android.os.Process.myPid;
+import static android.os.Process.myUid;
 import static android.os.Trace.TRACE_TAG_WINDOW_MANAGER;
 import static android.view.WindowManager.INPUT_CONSUMER_NAVIGATION;
 import static android.view.WindowManager.INPUT_CONSUMER_PIP;
 import static android.view.WindowManager.INPUT_CONSUMER_RECENTS_ANIMATION;
 import static android.view.WindowManager.INPUT_CONSUMER_WALLPAPER;
 import static android.view.WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL;
+import static android.view.WindowManager.LayoutParams.INPUT_FEATURE_NO_INPUT_CHANNEL;
 import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_DISABLE_WALLPAPER_TOUCH_EVENTS;
+import static android.view.WindowManager.LayoutParams.TYPE_SECURE_SYSTEM_OVERLAY;
 import static android.view.WindowManager.LayoutParams.TYPE_WALLPAPER;
 
 import static com.android.server.wm.ProtoLogGroup.WM_DEBUG_FOCUS_LIGHT;
@@ -550,4 +554,26 @@
             }
         }
     }
+
+    /**
+     * Helper function to generate an InputInfo with type SECURE_SYSTEM_OVERLAY. This input
+     * info will not have an input channel or be touchable, but is used to omit Surfaces
+     * from occlusion detection, so that System global overlays like the Watermark aren't
+     * counted by the InputDispatcher as occluding applications below.
+     */
+    static void setTrustedOverlayInputInfo(SurfaceControl sc, SurfaceControl.Transaction t,
+            int displayId, String name) {
+        InputWindowHandle inputWindowHandle = new InputWindowHandle(null, displayId);
+        inputWindowHandle.name = name;
+        inputWindowHandle.layoutParamsType = TYPE_SECURE_SYSTEM_OVERLAY;
+        inputWindowHandle.dispatchingTimeoutNanos = -1;
+        inputWindowHandle.visible = true;
+        inputWindowHandle.canReceiveKeys = false;
+        inputWindowHandle.hasFocus = false;
+        inputWindowHandle.ownerPid = myPid();
+        inputWindowHandle.ownerUid = myUid();
+        inputWindowHandle.inputFeatures = INPUT_FEATURE_NO_INPUT_CHANNEL;
+        inputWindowHandle.scaleFactor = 1;
+        t.setInputWindowInfo(sc, inputWindowHandle);
+    }
 }
diff --git a/services/core/java/com/android/server/wm/InsetsPolicy.java b/services/core/java/com/android/server/wm/InsetsPolicy.java
index 035f201..be6e4b7 100644
--- a/services/core/java/com/android/server/wm/InsetsPolicy.java
+++ b/services/core/java/com/android/server/wm/InsetsPolicy.java
@@ -42,6 +42,7 @@
 import android.view.SurfaceControl;
 import android.view.SyncRtSurfaceTransactionApplier;
 import android.view.ViewRootImpl;
+import android.view.WindowInsets.Type.InsetsType;
 import android.view.WindowInsetsAnimation;
 import android.view.WindowInsetsAnimation.Bounds;
 import android.view.WindowInsetsAnimationControlListener;
@@ -127,14 +128,16 @@
         return provider != null && provider.hasWindow() && !provider.getSource().isVisible();
     }
 
-    void showTransient(IntArray types) {
+    @InsetsType int showTransient(IntArray types) {
+        @InsetsType int showingTransientTypes = 0;
         boolean changed = false;
         for (int i = types.size() - 1; i >= 0; i--) {
             final int type = types.get(i);
-            if (mShowingTransientTypes.indexOf(type) != -1) {
+            if (!isHidden(type)) {
                 continue;
             }
-            if (!isHidden(type)) {
+            showingTransientTypes |= InsetsState.toPublicType(type);
+            if (mShowingTransientTypes.indexOf(type) != -1) {
                 continue;
             }
             mShowingTransientTypes.add(type);
@@ -161,6 +164,7 @@
                 }
             });
         }
+        return showingTransientTypes;
     }
 
     void hideTransient() {
@@ -192,18 +196,6 @@
             state = new InsetsState(state);
             state.setSourceVisible(mShowingTransientTypes.get(i), false);
         }
-        if (mFocusedWin != null && getStatusControlTarget(mFocusedWin) == mDummyControlTarget) {
-            if (state == originalState) {
-                state = new InsetsState(state);
-            }
-            state.setSourceVisible(ITYPE_STATUS_BAR, mFocusedWin.getRequestedInsetsState());
-        }
-        if (mFocusedWin != null && getNavControlTarget(mFocusedWin) == mDummyControlTarget) {
-            if (state == originalState) {
-                state = new InsetsState(state);
-            }
-            state.setSourceVisible(ITYPE_NAVIGATION_BAR, mFocusedWin.getRequestedInsetsState());
-        }
         return state;
     }
 
@@ -373,7 +365,7 @@
             final WindowState controllingWin =
                     controlTarget instanceof WindowState ? (WindowState) controlTarget : null;
             setVisible(controllingWin == null
-                    || controllingWin.getRequestedInsetsState().getSource(type).isVisible());
+                    || controllingWin.getRequestedInsetsState().getSourceOrDefaultVisibility(type));
         }
 
         private void setVisible(boolean visible) {
diff --git a/services/core/java/com/android/server/wm/InsetsSourceProvider.java b/services/core/java/com/android/server/wm/InsetsSourceProvider.java
index 6a49759..c8d9fe0 100644
--- a/services/core/java/com/android/server/wm/InsetsSourceProvider.java
+++ b/services/core/java/com/android/server/wm/InsetsSourceProvider.java
@@ -280,7 +280,7 @@
         }
         final Transaction t = mDisplayContent.getPendingTransaction();
         mWin.startAnimation(t, mAdapter, !mClientVisible /* hidden */,
-                ANIMATION_TYPE_INSETS_CONTROL, null /* animationFinishedCallback */);
+                ANIMATION_TYPE_INSETS_CONTROL);
 
         // The leash was just created. We cannot dispatch it until its surface transaction is
         // applied. Otherwise, the client's operation to the leash might be overwritten by us.
diff --git a/services/core/java/com/android/server/wm/InsetsStateController.java b/services/core/java/com/android/server/wm/InsetsStateController.java
index 77bc37f..bf9a784 100644
--- a/services/core/java/com/android/server/wm/InsetsStateController.java
+++ b/services/core/java/com/android/server/wm/InsetsStateController.java
@@ -178,6 +178,7 @@
             if (imeSource != null && imeSource.isVisible()) {
                 imeSource = new InsetsSource(imeSource);
                 imeSource.setVisible(false);
+                imeSource.setFrame(0, 0, 0, 0);
                 state = new InsetsState(state);
                 state.addSource(imeSource);
             }
diff --git a/services/core/java/com/android/server/wm/RecentTasks.java b/services/core/java/com/android/server/wm/RecentTasks.java
index 1cd94b4..24bb7c8 100644
--- a/services/core/java/com/android/server/wm/RecentTasks.java
+++ b/services/core/java/com/android/server/wm/RecentTasks.java
@@ -1341,6 +1341,17 @@
                 break;
         }
 
+        // Tasks managed by/associated with an ActivityView should be excluded from recents.
+        // singleTaskInstance is set on the VirtualDisplay managed by ActivityView
+        // TODO(b/126185105): Find a different signal to use besides isSingleTaskInstance
+        final ActivityStack stack = task.getStack();
+        if (stack != null) {
+            DisplayContent display = stack.getDisplay();
+            if (display != null && display.isSingleTaskInstance()) {
+                return false;
+            }
+        }
+
         // If we're in lock task mode, ignore the root task
         if (task == mService.getLockTaskController().getRootTask()) {
             return false;
diff --git a/services/core/java/com/android/server/wm/RecentsAnimation.java b/services/core/java/com/android/server/wm/RecentsAnimation.java
index bded651..1780820 100644
--- a/services/core/java/com/android/server/wm/RecentsAnimation.java
+++ b/services/core/java/com/android/server/wm/RecentsAnimation.java
@@ -233,6 +233,8 @@
             // duration of the gesture that is driven by the recents component
             targetActivity.mLaunchTaskBehind = true;
             mLaunchedTargetActivity = targetActivity;
+            // TODO(b/156772625): Evaluate to send new intents vs. replacing the intent extras.
+            targetActivity.intent.replaceExtras(mTargetIntent);
 
             // Fetch all the surface controls and pass them to the client to get the animation
             // started. Cancel any existing recents animation running synchronously (do not hold the
diff --git a/services/core/java/com/android/server/wm/RootWindowContainer.java b/services/core/java/com/android/server/wm/RootWindowContainer.java
index ae5adca..583663c 100644
--- a/services/core/java/com/android/server/wm/RootWindowContainer.java
+++ b/services/core/java/com/android/server/wm/RootWindowContainer.java
@@ -3570,12 +3570,14 @@
         }
     }
 
-    public void dump(PrintWriter pw, String prefix) {
+    @Override
+    public void dump(PrintWriter pw, String prefix, boolean dumpAll) {
+        super.dump(pw, prefix, dumpAll);
         pw.print(prefix);
         pw.println("topDisplayFocusedStack=" + getTopDisplayFocusedStack());
         for (int i = getChildCount() - 1; i >= 0; --i) {
             final DisplayContent display = getChildAt(i);
-            display.dump(pw, prefix, true /* dumpAll */);
+            display.dump(pw, prefix, dumpAll);
         }
         pw.println();
     }
diff --git a/services/core/java/com/android/server/wm/ShellRoot.java b/services/core/java/com/android/server/wm/ShellRoot.java
index 7a38bb6..0ae9ca9 100644
--- a/services/core/java/com/android/server/wm/ShellRoot.java
+++ b/services/core/java/com/android/server/wm/ShellRoot.java
@@ -104,7 +104,7 @@
                         0 /* windowCornerRadius */),
                 mDisplayContent.mWmService.mSurfaceAnimationRunner);
         mToken.startAnimation(mToken.getPendingTransaction(), adapter, false /* hidden */,
-                ANIMATION_TYPE_WINDOW_ANIMATION, null /* animationFinishedCallback */);
+                ANIMATION_TYPE_WINDOW_ANIMATION);
     }
 
     WindowInfo getWindowInfo() {
diff --git a/services/core/java/com/android/server/wm/StatusBarController.java b/services/core/java/com/android/server/wm/StatusBarController.java
index cac992a..3564e0b 100644
--- a/services/core/java/com/android/server/wm/StatusBarController.java
+++ b/services/core/java/com/android/server/wm/StatusBarController.java
@@ -17,6 +17,7 @@
 package com.android.server.wm;
 
 import static android.view.WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS;
+import static android.view.WindowManager.LayoutParams.TYPE_STATUS_BAR;
 
 import static com.android.server.wm.WindowManagerInternal.AppTransitionListener;
 
@@ -90,6 +91,7 @@
                 View.STATUS_BAR_UNHIDE,
                 View.STATUS_BAR_TRANSLUCENT,
                 StatusBarManager.WINDOW_STATUS_BAR,
+                TYPE_STATUS_BAR,
                 FLAG_TRANSLUCENT_STATUS,
                 View.STATUS_BAR_TRANSPARENT);
     }
diff --git a/services/core/java/com/android/server/wm/StrictModeFlash.java b/services/core/java/com/android/server/wm/StrictModeFlash.java
index f537005..fa62daa 100644
--- a/services/core/java/com/android/server/wm/StrictModeFlash.java
+++ b/services/core/java/com/android/server/wm/StrictModeFlash.java
@@ -54,6 +54,10 @@
             t.setLayer(ctrl, WindowManagerService.TYPE_LAYER_MULTIPLIER * 101);
             t.setPosition(ctrl, 0, 0);
             t.show(ctrl);
+            // Ensure we aren't considered as obscuring for Input purposes.
+            InputMonitor.setTrustedOverlayInputInfo(ctrl, t, dc.getDisplayId(),
+                    "StrictModeFlash");
+
             mSurface.copyFrom(ctrl);
         } catch (OutOfResourcesException e) {
         }
diff --git a/services/core/java/com/android/server/wm/SurfaceAnimator.java b/services/core/java/com/android/server/wm/SurfaceAnimator.java
index 1b77fd2..0e5d7d9 100644
--- a/services/core/java/com/android/server/wm/SurfaceAnimator.java
+++ b/services/core/java/com/android/server/wm/SurfaceAnimator.java
@@ -428,16 +428,11 @@
 
     void dump(PrintWriter pw, String prefix) {
         pw.print(prefix); pw.print("mLeash="); pw.print(mLeash);
-        if (mAnimationStartDelayed) {
-            pw.print(" mAnimationStartDelayed="); pw.println(mAnimationStartDelayed);
-        } else {
-            pw.println();
-        }
-        pw.print(prefix); pw.println("Animation:");
+        pw.print(" mAnimationType=" + mAnimationType);
+        pw.println(mAnimationStartDelayed ? " mAnimationStartDelayed=true" : "");
+        pw.print(prefix); pw.print("Animation: "); pw.println(mAnimation);
         if (mAnimation != null) {
             mAnimation.dump(pw, prefix + "  ");
-        } else {
-            pw.print(prefix); pw.println("null");
         }
     }
 
diff --git a/services/core/java/com/android/server/wm/Task.java b/services/core/java/com/android/server/wm/Task.java
index 48609e1..c749125 100644
--- a/services/core/java/com/android/server/wm/Task.java
+++ b/services/core/java/com/android/server/wm/Task.java
@@ -85,7 +85,6 @@
 import static com.android.server.wm.IdentifierProto.USER_ID;
 import static com.android.server.wm.ProtoLogGroup.WM_DEBUG_ADD_REMOVE;
 import static com.android.server.wm.ProtoLogGroup.WM_DEBUG_RECENTS_ANIMATIONS;
-import static com.android.server.wm.SurfaceAnimator.OnAnimationFinishedCallback;
 import static com.android.server.wm.WindowContainer.AnimationFlags.CHILDREN;
 import static com.android.server.wm.WindowContainer.AnimationFlags.TRANSITION;
 import static com.android.server.wm.WindowContainerChildProto.TASK;
@@ -1436,15 +1435,6 @@
             mAtmService.getTaskChangeNotificationController().notifyTaskStackChanged();
         }
 
-        final boolean isRootTask = isRootTask();
-        if (isRootTask) {
-            final DisplayContent display = getDisplayContent();
-            if (display.isSingleTaskInstance()) {
-                mAtmService.notifySingleTaskDisplayEmpty(display.mDisplayId);
-            }
-            display.mDisplayContent.setLayoutNeeded();
-        }
-
         if (hasChild()) {
             updateEffectiveIntent();
 
@@ -1465,7 +1455,7 @@
         } else if (!mReuseTask && !mCreatedByOrganizer) {
             // Remove entire task if it doesn't have any activity left and it isn't marked for reuse
             // or created by task organizer.
-            if (!isRootTask) {
+            if (!isRootTask()) {
                 getStack().removeChild(this, reason);
             }
             EventLogTags.writeWmTaskRemoved(mTaskId,
@@ -2648,7 +2638,7 @@
      */
     ActivityStack adjustFocusToNextFocusableTask(String reason) {
         return adjustFocusToNextFocusableTask(reason, false /* allowFocusSelf */,
-                true /* moveParentsToTop */);
+                true /* moveDisplayToTop */);
     }
 
     /** Return the next focusable task by looking from the siblings and parent tasks */
@@ -2671,11 +2661,11 @@
      * Find next proper focusable task and make it focused.
      * @param reason The reason of making the adjustment.
      * @param allowFocusSelf Is the focus allowed to remain on the same task.
-     * @param moveParentsToTop Whether to move parents to top while making the task focused.
+     * @param moveDisplayToTop Whether to move display to top while making the task focused.
      * @return The root task that now got the focus, {@code null} if none found.
      */
     ActivityStack adjustFocusToNextFocusableTask(String reason, boolean allowFocusSelf,
-            boolean moveParentsToTop) {
+            boolean moveDisplayToTop) {
         ActivityStack focusableTask = (ActivityStack) getNextFocusableTask(allowFocusSelf);
         if (focusableTask == null) {
             focusableTask = mRootWindowContainer.getNextFocusableStack((ActivityStack) this,
@@ -2686,10 +2676,17 @@
         }
 
         final ActivityStack rootTask = (ActivityStack) focusableTask.getRootTask();
-        if (!moveParentsToTop) {
-            // Only move the next stack to top in its task container.
+        if (!moveDisplayToTop) {
+            // There may be multiple task layers above this task, so when relocating the task to the
+            // top, we should move this task and each of its parent task that below display area to
+            // the top of each layer.
             WindowContainer parent = focusableTask.getParent();
-            parent.positionChildAt(POSITION_TOP, focusableTask, false /* includingParents */);
+            WindowContainer next = focusableTask;
+            do {
+                parent.positionChildAt(POSITION_TOP, next, false /* includingParents */);
+                next = parent;
+                parent = next.getParent();
+            } while (next.asTask() != null && parent != null);
             return rootTask;
         }
 
@@ -2817,6 +2814,10 @@
         if (DEBUG_STACK) Slog.i(TAG, "removeTask: removing taskId=" + mTaskId);
         EventLogTags.writeWmTaskRemoved(mTaskId, "removeTask");
 
+        if (mDisplayContent != null && mDisplayContent.isSingleTaskInstance()) {
+            mAtmService.notifySingleTaskDisplayEmpty(mDisplayContent.mDisplayId);
+        }
+
         // If applicable let the TaskOrganizer know the Task is vanishing.
         setTaskOrganizer(null);
 
@@ -2923,7 +2924,12 @@
     }
 
     boolean cropWindowsToStackBounds() {
-        return isResizeable();
+        // Don't crop HOME/RECENTS windows to stack bounds. This is because in split-screen
+        // they extend past their stack and sysui uses the stack surface to control cropping.
+        // TODO(b/158242495): get rid of this when drag/drop can use surface bounds.
+        final boolean isTopHomeOrRecents = (isActivityTypeHome() || isActivityTypeRecents())
+                && getRootTask().getTopMostTask() == this;
+        return isResizeable() && !isTopHomeOrRecents;
     }
 
     /**
@@ -3500,7 +3506,7 @@
     @Override
     protected void applyAnimationUnchecked(WindowManager.LayoutParams lp, boolean enter,
             int transit, boolean isVoiceInteraction,
-            @Nullable OnAnimationFinishedCallback finishedCallback) {
+            @Nullable ArrayList<WindowContainer> sources) {
         final RecentsAnimationController control = mWmService.getRecentsAnimationController();
         if (control != null) {
             // We let the transition to be controlled by RecentsAnimation, and callback task's
@@ -3509,30 +3515,31 @@
                 ProtoLog.d(WM_DEBUG_RECENTS_ANIMATIONS,
                         "applyAnimationUnchecked, control: %s, task: %s, transit: %s",
                         control, asTask(), AppTransition.appTransitionToString(transit));
-                control.addTaskToTargets(this, finishedCallback);
+                control.addTaskToTargets(this, (type, anim) -> {
+                    for (int i = 0; i < sources.size(); ++i) {
+                        sources.get(i).onAnimationFinished(type, anim);
+                    }
+                });
             }
         } else {
-            super.applyAnimationUnchecked(lp, enter, transit, isVoiceInteraction, finishedCallback);
+            super.applyAnimationUnchecked(lp, enter, transit, isVoiceInteraction, sources);
         }
     }
 
     @Override
     void dump(PrintWriter pw, String prefix, boolean dumpAll) {
         super.dump(pw, prefix, dumpAll);
+        pw.println(prefix + "bounds=" + getBounds().toShortString());
         final String doublePrefix = prefix + "  ";
-
-        pw.println(prefix + "taskId=" + mTaskId);
-        pw.println(doublePrefix + "mBounds=" + getBounds().toShortString());
-        pw.println(doublePrefix + "appTokens=" + mChildren);
-
-        final String triplePrefix = doublePrefix + "  ";
-        final String quadruplePrefix = triplePrefix + "  ";
-
-        int[] index = { 0 };
-        forAllActivities((r) -> {
-            pw.println(triplePrefix + "Activity #" + index[0]++ + " " + r);
-            r.dump(pw, quadruplePrefix, dumpAll);
-        });
+        for (int i = mChildren.size() - 1; i >= 0; i--) {
+            final WindowContainer<?> child = mChildren.get(i);
+            pw.println(prefix + "* " + child);
+            // Only dump non-activity because full activity info is already printed by
+            // RootWindowContainer#dumpActivities.
+            if (child.asActivityRecord() == null) {
+                child.dump(pw, doublePrefix, dumpAll);
+            }
+        }
     }
 
     /**
diff --git a/services/core/java/com/android/server/wm/TaskDisplayArea.java b/services/core/java/com/android/server/wm/TaskDisplayArea.java
index 22054db..e0568af 100644
--- a/services/core/java/com/android/server/wm/TaskDisplayArea.java
+++ b/services/core/java/com/android/server/wm/TaskDisplayArea.java
@@ -17,6 +17,7 @@
 package com.android.server.wm;
 
 import static android.app.WindowConfiguration.ACTIVITY_TYPE_HOME;
+import static android.app.WindowConfiguration.ACTIVITY_TYPE_RECENTS;
 import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD;
 import static android.app.WindowConfiguration.ACTIVITY_TYPE_UNDEFINED;
 import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM;
@@ -99,6 +100,9 @@
     private ActivityStack mRootPinnedTask;
     private ActivityStack mRootSplitScreenPrimaryTask;
 
+    // TODO(b/159029784): Remove when getStack() behavior is cleaned-up
+    private ActivityStack mRootRecentsTask;
+
     private final ArrayList<ActivityStack> mTmpAlwaysOnTopStacks = new ArrayList<>();
     private final ArrayList<ActivityStack> mTmpNormalStacks = new ArrayList<>();
     private final ArrayList<ActivityStack> mTmpHomeStacks = new ArrayList<>();
@@ -163,6 +167,8 @@
     ActivityStack getStack(int windowingMode, int activityType) {
         if (activityType == ACTIVITY_TYPE_HOME) {
             return mRootHomeTask;
+        } else if (activityType == ACTIVITY_TYPE_RECENTS) {
+            return mRootRecentsTask;
         }
         if (windowingMode == WINDOWING_MODE_PINNED) {
             return mRootPinnedTask;
@@ -199,6 +205,10 @@
         return mRootHomeTask;
     }
 
+    @Nullable ActivityStack getRootRecentsTask() {
+        return mRootRecentsTask;
+    }
+
     ActivityStack getRootPinnedTask() {
         return mRootPinnedTask;
     }
@@ -207,6 +217,15 @@
         return mRootSplitScreenPrimaryTask;
     }
 
+    ActivityStack getRootSplitScreenSecondaryTask() {
+        for (int i = mChildren.size() - 1; i >= 0; --i) {
+            if (mChildren.get(i).inSplitScreenSecondaryWindowingMode()) {
+                return mChildren.get(i);
+            }
+        }
+        return null;
+    }
+
     ArrayList<Task> getVisibleTasks() {
         final ArrayList<Task> visibleTasks = new ArrayList<>();
         forAllTasks(task -> {
@@ -237,6 +256,16 @@
             } else {
                 mRootHomeTask = stack;
             }
+        } else if (stack.isActivityTypeRecents()) {
+            if (mRootRecentsTask != null) {
+                if (!stack.isDescendantOf(mRootRecentsTask)) {
+                    throw new IllegalArgumentException("addStackReferenceIfNeeded: recents stack="
+                            + mRootRecentsTask + " already exist on display=" + this
+                            + " stack=" + stack);
+                }
+            } else {
+                mRootRecentsTask = stack;
+            }
         }
 
         if (!stack.isRootTask()) {
@@ -264,6 +293,8 @@
     void removeStackReferenceIfNeeded(ActivityStack stack) {
         if (stack == mRootHomeTask) {
             mRootHomeTask = null;
+        } else if (stack == mRootRecentsTask) {
+            mRootRecentsTask = null;
         } else if (stack == mRootPinnedTask) {
             mRootPinnedTask = null;
         } else if (stack == mRootSplitScreenPrimaryTask) {
@@ -299,8 +330,17 @@
 
     @Override
     void positionChildAt(int position, ActivityStack child, boolean includingParents) {
-        final boolean moveToTop = (position == POSITION_TOP || position == getChildCount());
+        final boolean moveToTop = position >= getChildCount() - 1;
         final boolean moveToBottom = (position == POSITION_BOTTOM || position == 0);
+
+        // Reset mPreferredTopFocusableStack before positioning to top or {@link
+        // ActivityStackSupervisor#updateTopResumedActivityIfNeeded()} won't update the top
+        // resumed activity.
+        final boolean wasContained = mChildren.contains(child);
+        if (moveToTop && wasContained && child.isFocusable()) {
+            mPreferredTopFocusableStack = null;
+        }
+
         if (child.getWindowConfiguration().isAlwaysOnTop() && !moveToTop) {
             // This stack is always-on-top, override the default behavior.
             Slog.w(TAG_WM, "Ignoring move of always-on-top stack=" + this + " to bottom");
@@ -330,6 +370,17 @@
         child.updateTaskMovement(moveToTop);
 
         mDisplayContent.setLayoutNeeded();
+
+        // The insert position may be adjusted to non-top when there is always-on-top stack. Since
+        // the original position is preferred to be top, the stack should have higher priority when
+        // we are looking for top focusable stack. The condition {@code wasContained} restricts the
+        // preferred stack is set only when moving an existing stack to top instead of adding a new
+        // stack that may be too early (e.g. in the middle of launching or reparenting).
+        if (moveToTop && child.isFocusableAndVisible()) {
+            mPreferredTopFocusableStack = child;
+        } else if (mPreferredTopFocusableStack == child) {
+            mPreferredTopFocusableStack = null;
+        }
     }
 
     /**
@@ -727,29 +778,10 @@
                     "positionStackAt: Can only have one task on display=" + this);
         }
 
-        final boolean movingToTop = wasContained && position >= getStackCount() - 1;
-        // Reset mPreferredTopFocusableStack before positioning to top or {@link
-        // ActivityStackSupervisor#updateTopResumedActivityIfNeeded()} won't update the top
-        // resumed activity.
-        if (movingToTop && stack.isFocusable()) {
-            mPreferredTopFocusableStack = null;
-        }
-
         // Since positionChildAt() is called during the creation process of pinned stacks,
         // ActivityStack#getStack() can be null.
         positionStackAt(position, stack, includingParents);
 
-        // The insert position may be adjusted to non-top when there is always-on-top stack. Since
-        // the original position is preferred to be top, the stack should have higher priority when
-        // we are looking for top focusable stack. The condition {@code wasContained} restricts the
-        // preferred stack is set only when moving an existing stack to top instead of adding a new
-        // stack that may be too early (e.g. in the middle of launching or reparenting).
-        if (movingToTop && stack.isFocusableAndVisible()) {
-            mPreferredTopFocusableStack = stack;
-        } else if (mPreferredTopFocusableStack == stack) {
-            mPreferredTopFocusableStack = null;
-        }
-
         if (updateLastFocusedStackReason != null) {
             final ActivityStack currentFocusedStack = getFocusedStack();
             if (currentFocusedStack != prevFocusedStack) {
@@ -1741,21 +1773,23 @@
         // reparenting stack finished.
         // Keep the order from bottom to top.
         int numStacks = getStackCount();
+
+        final boolean splitScreenActivated = toDisplayArea.isSplitScreenModeActivated();
+        final ActivityStack rootStack = splitScreenActivated ? toDisplayArea
+                .getTopStackInWindowingMode(WINDOWING_MODE_SPLIT_SCREEN_SECONDARY) : null;
         for (int stackNdx = 0; stackNdx < numStacks; stackNdx++) {
             final ActivityStack stack = getStackAt(stackNdx);
             // Always finish non-standard type stacks.
             if (destroyContentOnRemoval || !stack.isActivityTypeStandardOrUndefined()) {
                 stack.finishAllActivitiesImmediately();
             } else {
-                // If default display is in split-window mode, set windowing mode of the
-                // stack to split-screen secondary. Otherwise, set the windowing mode to
-                // undefined by default to let stack inherited the windowing mode from the
-                // new display.
-                final int windowingMode = toDisplayArea.isSplitScreenModeActivated()
-                        ? WINDOWING_MODE_SPLIT_SCREEN_SECONDARY
-                        : WINDOWING_MODE_UNDEFINED;
-                stack.reparent(toDisplayArea, true /* onTop */);
-                stack.setWindowingMode(windowingMode);
+                // Reparent the stack to the root task of secondary-split-screen or display area.
+                stack.reparent(stack.supportsSplitScreenWindowingMode() && rootStack != null
+                        ? rootStack : toDisplayArea, POSITION_TOP);
+
+                // Set the windowing mode to undefined by default to let the stack inherited the
+                // windowing mode.
+                stack.setWindowingMode(WINDOWING_MODE_UNDEFINED);
                 lastReparentedStack = stack;
             }
             // Stacks may be removed from this display. Ensure each stack will be processed
@@ -1763,6 +1797,17 @@
             stackNdx -= numStacks - getStackCount();
             numStacks = getStackCount();
         }
+        if (lastReparentedStack != null && splitScreenActivated) {
+            if (!lastReparentedStack.supportsSplitScreenWindowingMode()) {
+                mAtmService.getTaskChangeNotificationController()
+                        .notifyActivityDismissingDockedStack();
+                toDisplayArea.onSplitScreenModeDismissed(lastReparentedStack);
+            } else if (rootStack != null) {
+                // update focus
+                rootStack.moveToFront("display-removed");
+            }
+        }
+
         mRemoved = true;
 
         return lastReparentedStack;
@@ -1772,16 +1817,20 @@
     @Override
     void dump(PrintWriter pw, String prefix, boolean dumpAll) {
         pw.println(prefix + "TaskDisplayArea " + getName());
+        super.dump(pw, prefix, dumpAll);
         if (mPreferredTopFocusableStack != null) {
             pw.println(prefix + "  mPreferredTopFocusableStack=" + mPreferredTopFocusableStack);
         }
         if (mLastFocusedStack != null) {
             pw.println(prefix + "  mLastFocusedStack=" + mLastFocusedStack);
         }
-        pw.println(prefix + "  Application tokens in top down Z order:");
+        final String doublePrefix = prefix + "  ";
+        final String triplePrefix = doublePrefix + "  ";
+        pw.println(doublePrefix + "Application tokens in top down Z order:");
         for (int stackNdx = getChildCount() - 1; stackNdx >= 0; --stackNdx) {
             final ActivityStack stack = getChildAt(stackNdx);
-            stack.dump(pw, prefix + "    ", dumpAll);
+            pw.println(doublePrefix + "* " + stack);
+            stack.dump(pw, triplePrefix, dumpAll);
         }
     }
 }
diff --git a/services/core/java/com/android/server/wm/Watermark.java b/services/core/java/com/android/server/wm/Watermark.java
index 4e1b217..3d49ebe 100644
--- a/services/core/java/com/android/server/wm/Watermark.java
+++ b/services/core/java/com/android/server/wm/Watermark.java
@@ -29,6 +29,7 @@
 import android.util.Log;
 import android.util.TypedValue;
 import android.view.Display;
+import android.view.InputWindowHandle;
 import android.view.Surface;
 import android.view.Surface.OutOfResourcesException;
 import android.view.SurfaceControl;
@@ -124,6 +125,8 @@
             t.setLayer(ctrl, WindowManagerService.TYPE_LAYER_MULTIPLIER * 100)
                     .setPosition(ctrl, 0, 0)
                     .show(ctrl);
+            // Ensure we aren't considered as obscuring for Input purposes.
+            InputMonitor.setTrustedOverlayInputInfo(ctrl, t, dc.getDisplayId(), "Watermark");
             mSurface.copyFrom(ctrl);
         } catch (OutOfResourcesException e) {
         }
diff --git a/services/core/java/com/android/server/wm/WindowContainer.java b/services/core/java/com/android/server/wm/WindowContainer.java
index 90156fd..6406f0ae 100644
--- a/services/core/java/com/android/server/wm/WindowContainer.java
+++ b/services/core/java/com/android/server/wm/WindowContainer.java
@@ -64,6 +64,7 @@
 import android.os.Debug;
 import android.os.IBinder;
 import android.os.Trace;
+import android.util.ArraySet;
 import android.util.Pair;
 import android.util.Pools;
 import android.util.Slog;
@@ -181,6 +182,14 @@
     final SurfaceFreezer mSurfaceFreezer;
     protected final WindowManagerService mWmService;
 
+    /**
+     * Sources which triggered a surface animation on this container. An animation target can be
+     * promoted to higher level, for example, from a set of {@link ActivityRecord}s to
+     * {@link ActivityStack}. In this case, {@link ActivityRecord}s are set on this variable while
+     * the animation is running, and reset after finishing it.
+     */
+    private final ArraySet<WindowContainer> mSurfaceAnimationSources = new ArraySet<>();
+
     private final Point mTmpPos = new Point();
     protected final Point mLastSurfacePosition = new Point();
 
@@ -193,8 +202,6 @@
      */
     private boolean mCommittedReparentToAnimationLeash;
 
-    private final Configuration mTmpConfig = new Configuration();
-
     /** Interface for {@link #isAnimating} to check which cases for the container is animating. */
     public interface AnimationFlags {
         /**
@@ -872,29 +879,8 @@
      * @see AnimationFlags#PARENTS
      * @see AnimationFlags#CHILDREN
      */
-    boolean isAnimating(int flags, int typesToCheck) {
-        int animationType = mSurfaceAnimator.getAnimationType();
-        if (mSurfaceAnimator.isAnimating() && (animationType & typesToCheck) > 0) {
-            return true;
-        }
-        if ((flags & TRANSITION) != 0 && isWaitingForTransitionStart()) {
-            return true;
-        }
-        if ((flags & PARENTS) != 0) {
-            final WindowContainer parent = getParent();
-            if (parent != null && parent.isAnimating(flags & ~CHILDREN, typesToCheck)) {
-                return true;
-            }
-        }
-        if ((flags & CHILDREN) != 0) {
-            for (int i = 0; i < mChildren.size(); ++i) {
-                final WindowContainer wc = mChildren.get(i);
-                if (wc.isAnimating(flags & ~PARENTS, typesToCheck)) {
-                    return true;
-                }
-            }
-        }
-        return false;
+    final boolean isAnimating(int flags, int typesToCheck) {
+        return getAnimatingContainer(flags, typesToCheck) != null;
     }
 
     /**
@@ -904,16 +890,20 @@
      *              checking animating status.
      * @param typesToExclude The combination of bitmask {@link AnimationType} to exclude when
      *                     checking if animating.
+     *
+     * @deprecated Use {@link #isAnimating(int, int)}
      */
-    boolean isAnimatingExcluding(int flags, int typesToExclude) {
+    @Deprecated
+    final boolean isAnimatingExcluding(int flags, int typesToExclude) {
         return isAnimating(flags, ANIMATION_TYPE_ALL & ~typesToExclude);
     }
 
     /**
-     * @see #isAnimating(int, int)
+     * @deprecated Use {@link #isAnimating(int, int)}
      * TODO (b/152333373): Migrate calls to use isAnimating with specified animation type
      */
-    boolean isAnimating(int flags) {
+    @Deprecated
+    final boolean isAnimating(int flags) {
         return isAnimating(flags, ANIMATION_TYPE_ALL);
     }
 
@@ -2107,10 +2097,15 @@
     }
 
     void cancelAnimation() {
+        doAnimationFinished(mSurfaceAnimator.getAnimationType(), mSurfaceAnimator.getAnimation());
         mSurfaceAnimator.cancelAnimation();
         mSurfaceFreezer.unfreeze(getPendingTransaction());
     }
 
+    ArraySet<WindowContainer> getAnimationSources() {
+        return mSurfaceAnimationSources;
+    }
+
     @Override
     public SurfaceControl getFreezeSnapshotTarget() {
         return null;
@@ -2156,6 +2151,7 @@
      * @param transit The app transition type indicates what kind of transition to be applied.
      * @param enter Whether the app transition is entering transition or not.
      * @param isVoiceInteraction Whether the container is participating in voice interaction or not.
+     * @param sources {@link ActivityRecord}s which causes this app transition animation.
      *
      * @return {@code true} when the container applied the app transition, {@code false} if the
      *         app transition is disabled or skipped.
@@ -2163,7 +2159,7 @@
      * @see #getAnimationAdapter
      */
     boolean applyAnimation(WindowManager.LayoutParams lp, int transit, boolean enter,
-            boolean isVoiceInteraction, @Nullable OnAnimationFinishedCallback finishedCallback) {
+            boolean isVoiceInteraction, @Nullable ArrayList<WindowContainer> sources) {
         if (mWmService.mDisableTransitionAnimation) {
             ProtoLog.v(WM_DEBUG_APP_TRANSITIONS_ANIM,
                     "applyAnimation: transition animation is disabled or skipped. "
@@ -2178,7 +2174,7 @@
         try {
             Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "WC#applyAnimation");
             if (okToAnimate()) {
-                applyAnimationUnchecked(lp, enter, transit, isVoiceInteraction, finishedCallback);
+                applyAnimationUnchecked(lp, enter, transit, isVoiceInteraction, sources);
             } else {
                 cancelAnimation();
             }
@@ -2276,14 +2272,17 @@
 
     protected void applyAnimationUnchecked(WindowManager.LayoutParams lp, boolean enter,
             int transit, boolean isVoiceInteraction,
-            @Nullable OnAnimationFinishedCallback finishedCallback) {
+            @Nullable ArrayList<WindowContainer> sources) {
         final Pair<AnimationAdapter, AnimationAdapter> adapters = getAnimationAdapter(lp,
                 transit, enter, isVoiceInteraction);
         AnimationAdapter adapter = adapters.first;
         AnimationAdapter thumbnailAdapter = adapters.second;
         if (adapter != null) {
+            if (sources != null) {
+                mSurfaceAnimationSources.addAll(sources);
+            }
             startAnimation(getPendingTransaction(), adapter, !isVisible(),
-                    ANIMATION_TYPE_APP_TRANSITION, finishedCallback);
+                    ANIMATION_TYPE_APP_TRANSITION);
             if (adapter.getShowWallpaper()) {
                 getDisplayContent().pendingLayoutChanges |= FINISH_LAYOUT_REDO_WALLPAPER;
             }
@@ -2411,10 +2410,18 @@
         updateSurfacePosition(t);
     }
 
+    private void doAnimationFinished(@AnimationType int type, AnimationAdapter anim) {
+        for (int i = 0; i < mSurfaceAnimationSources.size(); ++i) {
+            mSurfaceAnimationSources.valueAt(i).onAnimationFinished(type, anim);
+        }
+        mSurfaceAnimationSources.clear();
+    }
+
     /**
      * Called when an animation has finished running.
      */
     protected void onAnimationFinished(@AnimationType int type, AnimationAdapter anim) {
+        doAnimationFinished(type, anim);
         mWmService.onAnimationFinished();
     }
 
@@ -2428,16 +2435,66 @@
     /**
      * @return The {@link WindowContainer} which is running an animation.
      *
-     * It traverses from the current container to its parents recursively. If nothing is animating,
-     * it will return {@code null}.
+     * By default this only checks if this container itself is actually running an animation, but
+     * you can extend the check target over its relatives, or relax the condition so that this can
+     * return {@code WindowContainer} if an animation starts soon by giving a combination
+     * of {@link AnimationFlags}.
+     *
+     * Note that you can give a combination of bitmask flags to specify targets and condition for
+     * checking animating status.
+     * e.g. {@code isAnimating(TRANSITION | PARENT)} returns {@code true} if either this
+     * container itself or one of its parents is running an animation or waiting for an app
+     * transition.
+     *
+     * Note that TRANSITION propagates to parents and children as well.
+     *
+     * @param flags The combination of bitmask flags to specify targets and condition for
+     *              checking animating status.
+     * @param typesToCheck The combination of bitmask {@link AnimationType} to compare when
+     *                     determining if animating.
+     *
+     * @see AnimationFlags#TRANSITION
+     * @see AnimationFlags#PARENTS
+     * @see AnimationFlags#CHILDREN
      */
     @Nullable
-    WindowContainer getAnimatingContainer() {
-        if (isAnimating()) {
+    WindowContainer getAnimatingContainer(int flags, int typesToCheck) {
+        int animationType = mSurfaceAnimator.getAnimationType();
+        if (mSurfaceAnimator.isAnimating() && (animationType & typesToCheck) > 0) {
             return this;
         }
-        final WindowContainer parent = getParent();
-        return (parent != null) ? parent.getAnimatingContainer() : null;
+        if ((flags & TRANSITION) != 0 && isWaitingForTransitionStart()) {
+            return this;
+        }
+        if ((flags & PARENTS) != 0) {
+            final WindowContainer parent = getParent();
+            if (parent != null) {
+                final WindowContainer wc = parent.getAnimatingContainer(
+                        flags & ~CHILDREN, typesToCheck);
+                if (wc != null) {
+                    return wc;
+                }
+            }
+        }
+        if ((flags & CHILDREN) != 0) {
+            for (int i = 0; i < mChildren.size(); ++i) {
+                final WindowContainer wc = mChildren.get(i).getAnimatingContainer(
+                        flags & ~PARENTS, typesToCheck);
+                if (wc != null) {
+                    return wc;
+                }
+            }
+        }
+        return null;
+    }
+
+    /**
+     * @deprecated Use {@link #getAnimatingContainer(int, int)} instead.
+     */
+    @Nullable
+    @Deprecated
+    final WindowContainer getAnimatingContainer() {
+        return getAnimatingContainer(PARENTS, ANIMATION_TYPE_ALL);
     }
 
     /**
diff --git a/services/core/java/com/android/server/wm/WindowContainerThumbnail.java b/services/core/java/com/android/server/wm/WindowContainerThumbnail.java
index a27a112..126154b 100644
--- a/services/core/java/com/android/server/wm/WindowContainerThumbnail.java
+++ b/services/core/java/com/android/server/wm/WindowContainerThumbnail.java
@@ -133,15 +133,14 @@
                         mWindowContainer.getDisplayContent().mAppTransition.canSkipFirstFrame(),
                         mWindowContainer.getDisplayContent().getWindowCornerRadius()),
                 mWindowContainer.mWmService.mSurfaceAnimationRunner), false /* hidden */,
-                ANIMATION_TYPE_RECENTS, null /* animationFinishedCallback */);
+                ANIMATION_TYPE_RECENTS);
     }
 
     /**
      * Start animation with existing adapter.
      */
     void startAnimation(Transaction t, AnimationAdapter anim, boolean hidden) {
-        mSurfaceAnimator.startAnimation(t, anim, hidden, ANIMATION_TYPE_RECENTS,
-                null /* animationFinishedCallback */);
+        mSurfaceAnimator.startAnimation(t, anim, hidden, ANIMATION_TYPE_RECENTS);
     }
 
     private void onAnimationFinished(@AnimationType int type, AnimationAdapter anim) {
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index d1366bd..0590288 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -5616,11 +5616,6 @@
         mLatencyTracker.onActionStart(ACTION_ROTATE_SCREEN);
         mExitAnimId = exitAnim;
         mEnterAnimId = enterAnim;
-        ScreenRotationAnimation screenRotationAnimation =
-                displayContent.getRotationAnimation();
-        if (screenRotationAnimation != null) {
-            screenRotationAnimation.kill();
-        }
 
         displayContent.updateDisplayInfo();
         final int originalRotation = overrideOriginalRotation != ROTATION_UNDEFINED
@@ -7628,8 +7623,12 @@
                 if (imeTarget == null) {
                     return;
                 }
-                imeTarget = imeTarget.getImeControlTarget();
-                imeTarget.getDisplayContent().getInsetsStateController().getImeSourceProvider()
+                imeTarget = imeTarget.getImeControlTarget().getWindow();
+                // If InsetsControlTarget doesn't have a window, its using remoteControlTarget which
+                // is controlled by default display
+                final DisplayContent dc = imeTarget != null
+                        ? imeTarget.getDisplayContent() : getDefaultDisplayContentLocked();
+                dc.getInsetsStateController().getImeSourceProvider()
                         .scheduleShowImePostLayout(imeTarget);
             }
         }
@@ -7642,7 +7641,9 @@
                     // The target window no longer exists.
                     return;
                 }
-                final DisplayContent dc = imeTarget.getImeControlTarget().getDisplayContent();
+                imeTarget = imeTarget.getImeControlTarget().getWindow();
+                final DisplayContent dc = imeTarget != null
+                        ? imeTarget.getDisplayContent() : getDefaultDisplayContentLocked();
                 // If there was a pending IME show(), reset it as IME has been
                 // requested to be hidden.
                 dc.getInsetsStateController().getImeSourceProvider().abortShowImePostLayout();
diff --git a/services/core/java/com/android/server/wm/WindowProcessController.java b/services/core/java/com/android/server/wm/WindowProcessController.java
index 2ec6df5..29cf177 100644
--- a/services/core/java/com/android/server/wm/WindowProcessController.java
+++ b/services/core/java/com/android/server/wm/WindowProcessController.java
@@ -1007,8 +1007,11 @@
     }
 
     void updateProcessInfo(boolean updateServiceConnectionActivities, boolean activityChange,
-            boolean updateOomAdj) {
+            boolean updateOomAdj, boolean addPendingTopUid) {
         if (mListener == null) return;
+        if (addPendingTopUid) {
+            mAtm.mAmInternal.addPendingTopUid(mUid, mPid);
+        }
         // Posting on handler so WM lock isn't held when we call into AM.
         final Message m = PooledLambda.obtainMessage(WindowProcessListener::updateProcessInfo,
                 mListener, updateServiceConnectionActivities, activityChange, updateOomAdj);
@@ -1068,7 +1071,7 @@
         }
         // update ActivityManagerService.PendingStartActivityUids list.
         if (topProcessState == ActivityManager.PROCESS_STATE_TOP) {
-            mAtm.mAmInternal.updatePendingTopUid(mUid, true);
+            mAtm.mAmInternal.addPendingTopUid(mUid, mPid);
         }
         // Posting the message at the front of queue so WM lock isn't held when we call into AM,
         // and the process state of starting activity can be updated quicker which will give it a
diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java
index 36232e1..5ea1bbb 100644
--- a/services/core/java/com/android/server/wm/WindowState.java
+++ b/services/core/java/com/android/server/wm/WindowState.java
@@ -1529,6 +1529,29 @@
     }
 
     /**
+     * This is a form of rectangle "difference". It cut off each dimension of rect by the amount
+     * that toRemove is "pushing into" it from the outside. Any dimension that fully contains
+     * toRemove won't change.
+     */
+    private void cutRect(Rect rect, Rect toRemove) {
+        if (toRemove.isEmpty()) return;
+        if (toRemove.top < rect.bottom && toRemove.bottom > rect.top) {
+            if (toRemove.right >= rect.right && toRemove.left >= rect.left) {
+                rect.right = toRemove.left;
+            } else if (toRemove.left <= rect.left && toRemove.right <= rect.right) {
+                rect.left = toRemove.right;
+            }
+        }
+        if (toRemove.left < rect.right && toRemove.right > rect.left) {
+            if (toRemove.bottom >= rect.bottom && toRemove.top >= rect.top) {
+                rect.bottom = toRemove.top;
+            } else if (toRemove.top <= rect.top && toRemove.bottom <= rect.bottom) {
+                rect.top = toRemove.bottom;
+            }
+        }
+    }
+
+    /**
      * Retrieves the visible bounds of the window.
      * @param bounds The rect which gets the bounds.
      */
@@ -1544,6 +1567,20 @@
             } else {
                 intersectWithStackBounds = false;
             }
+            if (inSplitScreenPrimaryWindowingMode()) {
+                // If this is in the primary split and the home stack is the top visible task in
+                // the secondary split, it means this is "minimized" and thus must prevent
+                // overlapping with home.
+                // TODO(b/158242495): get rid of this when drag/drop can use surface bounds.
+                final ActivityStack rootSecondary =
+                        task.getDisplayArea().getRootSplitScreenSecondaryTask();
+                if (rootSecondary.isActivityTypeHome() || rootSecondary.isActivityTypeRecents()) {
+                    final WindowContainer topTask = rootSecondary.getTopChild();
+                    if (topTask.isVisible()) {
+                        cutRect(mTmpRect, topTask.getBounds());
+                    }
+                }
+            }
         }
 
         bounds.set(mWindowFrames.mVisibleFrame);
@@ -3576,6 +3613,9 @@
     @Override
     public void notifyInsetsControlChanged() {
         ProtoLog.d(WM_DEBUG_IME, "notifyInsetsControlChanged for %s ", this);
+        if (mAppDied || mRemoved) {
+            return;
+        }
         final InsetsStateController stateController =
                 getDisplayContent().getInsetsStateController();
         try {
@@ -5049,16 +5089,13 @@
         mWindowFrames.updateLastInsetValues();
     }
 
+    @Nullable
     @Override
-    boolean isAnimating(int flags, int typesToCheck) {
-
-        // If we are an inset provider, all our animations are driven by the inset client, so we
-        // aren't really animating.
-        // TODO: Replace this with a proper animation type system.
+    WindowContainer<WindowState> getAnimatingContainer(int flags, int typesToCheck) {
         if (mControllableInsetProvider != null) {
-            return false;
+            return null;
         }
-        return super.isAnimating(flags, typesToCheck);
+        return super.getAnimatingContainer(flags, typesToCheck);
     }
 
     void startAnimation(Animation anim) {
@@ -5101,8 +5138,7 @@
     }
 
     private void startAnimation(Transaction t, AnimationAdapter adapter) {
-        startAnimation(t, adapter, mWinAnimator.mLastHidden, ANIMATION_TYPE_WINDOW_ANIMATION,
-                null /* animationFinishedCallback */);
+        startAnimation(t, adapter, mWinAnimator.mLastHidden, ANIMATION_TYPE_WINDOW_ANIMATION);
     }
 
     @Override
@@ -5390,6 +5426,7 @@
             final WindowState imeTarget = getDisplayContent().mInputMethodTarget;
             boolean inTokenWithAndAboveImeTarget = imeTarget != null && imeTarget != this
                     && imeTarget.mToken == mToken
+                    && mAttrs.type != TYPE_APPLICATION_STARTING
                     && getParent() != null
                     && imeTarget.compareTo(this) <= 0;
             return inTokenWithAndAboveImeTarget;
@@ -5404,10 +5441,10 @@
      * {@link android.view.inputmethod.InputMethodManager#showSoftInput(View, int)} is unknown,
      * use {@link DisplayContent#getImeControlTarget()} instead.
      *
-     * @return {@link WindowState} of host that controls the IME.
+     * @return {@link InsetsControlTarget} of host that controls the IME.
      *         When window is doesn't have a parent, it is returned as-is.
      */
-    WindowState getImeControlTarget() {
+    InsetsControlTarget getImeControlTarget() {
         final DisplayContent dc = getDisplayContent();
         final WindowState parentWindow = dc.getParentWindow();
 
diff --git a/services/core/java/com/android/server/wm/WindowStateAnimator.java b/services/core/java/com/android/server/wm/WindowStateAnimator.java
index c025236..8115ac8c 100644
--- a/services/core/java/com/android/server/wm/WindowStateAnimator.java
+++ b/services/core/java/com/android/server/wm/WindowStateAnimator.java
@@ -247,10 +247,6 @@
     private final SurfaceControl.Transaction mPostDrawTransaction =
             new SurfaceControl.Transaction();
 
-    // Used to track whether we have called detach children on the way to invisibility, in which
-    // case we need to give the client a new Surface if it lays back out to a visible state.
-    boolean mChildrenDetached = false;
-
     // Set to true after the first frame of the Pinned stack animation
     // and reset after the last to ensure we only reset mForceScaleUntilResize
     // once per animation.
@@ -425,7 +421,8 @@
         // transparent to the app.
         // If the children are detached, we don't want to reparent them to the new surface.
         // Instead let the children get removed when the old surface is deleted.
-        if (mSurfaceController != null && mPendingDestroySurface != null && !mChildrenDetached
+        if (mSurfaceController != null && mPendingDestroySurface != null
+                && !mPendingDestroySurface.mChildrenDetached
                 && (mWin.mActivityRecord == null || !mWin.mActivityRecord.isRelaunching())) {
             mPostDrawTransaction.reparentChildren(
                     mPendingDestroySurface.getClientViewRootSurface(),
@@ -461,7 +458,6 @@
         if (mSurfaceController != null) {
             return mSurfaceController;
         }
-        mChildrenDetached = false;
 
         if ((mWin.mAttrs.privateFlags & PRIVATE_FLAG_IS_ROUNDED_CORNERS_OVERLAY) != 0) {
             windowType = SurfaceControl.WINDOW_TYPE_DONT_SCREENSHOT;
@@ -1365,7 +1361,7 @@
             mPostDrawTransaction.reparent(pendingSurfaceControl, null);
             // If the children are detached, we don't want to reparent them to the new surface.
             // Instead let the children get removed when the old surface is deleted.
-            if (!mChildrenDetached) {
+            if (!mPendingDestroySurface.mChildrenDetached) {
                 mPostDrawTransaction.reparentChildren(
                         mPendingDestroySurface.getClientViewRootSurface(),
                         mSurfaceController.mSurfaceControl);
@@ -1596,7 +1592,6 @@
         if (mSurfaceController != null) {
             mSurfaceController.detachChildren();
         }
-        mChildrenDetached = true;
         // If the children are detached, it means the app is exiting. We don't want to tear the
         // content down too early, otherwise we could end up with a flicker. By preserving the
         // current surface, we ensure the content remains on screen until the window is completely
diff --git a/services/core/java/com/android/server/wm/WindowSurfaceController.java b/services/core/java/com/android/server/wm/WindowSurfaceController.java
index 0a7ca5a..b2bfcdc 100644
--- a/services/core/java/com/android/server/wm/WindowSurfaceController.java
+++ b/services/core/java/com/android/server/wm/WindowSurfaceController.java
@@ -90,6 +90,9 @@
 
     private final SurfaceControl.Transaction mTmpTransaction;
 
+    // Used to track whether we have called detach children on the way to invisibility.
+    boolean mChildrenDetached;
+
     WindowSurfaceController(String name, int w, int h, int format,
             int flags, WindowStateAnimator animator, int windowType, int ownerUid) {
         mAnimator = animator;
@@ -144,6 +147,7 @@
 
     void detachChildren() {
         ProtoLog.i(WM_SHOW_TRANSACTIONS, "SEVER CHILDREN");
+        mChildrenDetached = true;
         if (mSurfaceControl != null) {
             mSurfaceControl.detachChildren();
         }
diff --git a/services/core/java/com/android/server/wm/WindowToken.java b/services/core/java/com/android/server/wm/WindowToken.java
index d257002..86aacf3 100644
--- a/services/core/java/com/android/server/wm/WindowToken.java
+++ b/services/core/java/com/android/server/wm/WindowToken.java
@@ -48,6 +48,7 @@
 import android.os.IBinder;
 import android.os.RemoteException;
 import android.util.Slog;
+import android.util.SparseArray;
 import android.util.proto.ProtoOutputStream;
 import android.view.DisplayAdjustments.FixedRotationAdjustments;
 import android.view.DisplayInfo;
@@ -124,7 +125,7 @@
     private static class FixedRotationTransformState {
         final DisplayInfo mDisplayInfo;
         final DisplayFrames mDisplayFrames;
-        final InsetsState mInsetsState;
+        final InsetsState mInsetsState = new InsetsState();
         final Configuration mRotatedOverrideConfiguration;
         final SeamlessRotator mRotator;
         /**
@@ -133,14 +134,14 @@
          */
         final ArrayList<WindowToken> mAssociatedTokens = new ArrayList<>(3);
         final ArrayList<WindowContainer<?>> mRotatedContainers = new ArrayList<>(3);
+        final SparseArray<Rect> mBarContentFrames = new SparseArray<>();
         boolean mIsTransforming = true;
 
         FixedRotationTransformState(DisplayInfo rotatedDisplayInfo,
-                DisplayFrames rotatedDisplayFrames, InsetsState rotatedInsetsState,
-                Configuration rotatedConfig, int currentRotation) {
+                DisplayFrames rotatedDisplayFrames, Configuration rotatedConfig,
+                int currentRotation) {
             mDisplayInfo = rotatedDisplayInfo;
             mDisplayFrames = rotatedDisplayFrames;
-            mInsetsState = rotatedInsetsState;
             mRotatedOverrideConfiguration = rotatedConfig;
             // This will use unrotate as rotate, so the new and old rotation are inverted.
             mRotator = new SeamlessRotator(rotatedDisplayInfo.rotation, currentRotation,
@@ -516,6 +517,12 @@
                 : null;
     }
 
+    Rect getFixedRotationBarContentFrame(int windowType) {
+        return isFixedRotationTransforming()
+                ? mFixedRotationTransformState.mBarContentFrames.get(windowType)
+                : null;
+    }
+
     InsetsState getFixedRotationTransformInsetsState() {
         return isFixedRotationTransforming() ? mFixedRotationTransformState.mInsetsState : null;
     }
@@ -526,12 +533,12 @@
         if (mFixedRotationTransformState != null) {
             return;
         }
-        final InsetsState insetsState = new InsetsState();
-        mDisplayContent.getDisplayPolicy().simulateLayoutDisplay(displayFrames, insetsState,
-                mDisplayContent.getConfiguration().uiMode);
         mFixedRotationTransformState = new FixedRotationTransformState(info, displayFrames,
-                insetsState, new Configuration(config), mDisplayContent.getRotation());
+                new Configuration(config), mDisplayContent.getRotation());
         mFixedRotationTransformState.mAssociatedTokens.add(this);
+        mDisplayContent.getDisplayPolicy().simulateLayoutDisplay(displayFrames,
+                mFixedRotationTransformState.mInsetsState,
+                mFixedRotationTransformState.mBarContentFrames);
         onConfigurationChanged(getParent().getConfiguration());
         notifyFixedRotationTransform(true /* enabled */);
     }
@@ -554,6 +561,25 @@
         notifyFixedRotationTransform(true /* enabled */);
     }
 
+    /**
+     * Return {@code true} if one of the associated activity is still animating. Otherwise,
+     * return {@code false}.
+     */
+    boolean hasAnimatingFixedRotationTransition() {
+        if (mFixedRotationTransformState == null) {
+            return false;
+        }
+
+        for (int i = mFixedRotationTransformState.mAssociatedTokens.size() - 1; i >= 0; i--) {
+            final ActivityRecord r =
+                    mFixedRotationTransformState.mAssociatedTokens.get(i).asActivityRecord();
+            if (r != null && r.isAnimating(TRANSITION | PARENTS)) {
+                return true;
+            }
+        }
+        return false;
+    }
+
     void finishFixedRotationTransform() {
         finishFixedRotationTransform(null /* applyDisplayRotation */);
     }
diff --git a/services/core/jni/com_android_server_tv_TvInputHal.cpp b/services/core/jni/com_android_server_tv_TvInputHal.cpp
index 098b2ef..4e1a234 100644
--- a/services/core/jni/com_android_server_tv_TvInputHal.cpp
+++ b/services/core/jni/com_android_server_tv_TvInputHal.cpp
@@ -301,6 +301,7 @@
     JTvInputHal(JNIEnv* env, jobject thiz, sp<ITvInput> tvInput, const sp<Looper>& looper);
 
     Mutex mLock;
+    Mutex mStreamLock;
     jweak mThiz;
     sp<Looper> mLooper;
 
@@ -338,6 +339,7 @@
 }
 
 int JTvInputHal::addOrUpdateStream(int deviceId, int streamId, const sp<Surface>& surface) {
+    Mutex::Autolock autoLock(&mStreamLock);
     KeyedVector<int, Connection>& connections = mConnections.editValueFor(deviceId);
     if (connections.indexOfKey(streamId) < 0) {
         connections.add(streamId, Connection());
@@ -412,6 +414,7 @@
 }
 
 int JTvInputHal::removeStream(int deviceId, int streamId) {
+    Mutex::Autolock autoLock(&mStreamLock);
     KeyedVector<int, Connection>& connections = mConnections.editValueFor(deviceId);
     if (connections.indexOfKey(streamId) < 0) {
         return BAD_VALUE;
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
index f1064d1..401649a 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
@@ -631,7 +631,7 @@
 
     /**
      * Whether or not device admin feature is supported. If it isn't return defaults for all
-     * public methods.
+     * public methods, unless the caller has the appropriate permission for a particular method.
      */
     final boolean mHasFeature;
 
@@ -2616,6 +2616,8 @@
         mSetupContentObserver = new SetupContentObserver(mHandler);
 
         mUserManagerInternal.addUserRestrictionsListener(new RestrictionsListener(mContext));
+
+        loadOwners();
     }
 
     /**
@@ -2676,12 +2678,23 @@
         }
     }
 
+    /**
+     * Load information about device and profile owners of the device, populating mOwners and
+     * pushing owner info to other system services. This is called at a fairly early stage of
+     * system server initialiation (via DevicePolicyManagerService's ctor), so care should to
+     * be taken to not interact with system services that are initialiated after DPMS.
+     * onLockSettingsReady() is a safer place to do initialization work not critical during
+     * the first boot stage.
+     * Note this only loads the list of owners, and not their actual policy (DevicePolicyData).
+     * The policy is normally loaded lazily when it's first accessed. In several occasions
+     * the list of owners is necessary for providing callers with aggregated policies across
+     * multiple owners, hence the owner list is loaded as part of DPMS's construction here.
+     */
     void loadOwners() {
         synchronized (getLockObject()) {
             mOwners.load();
             setDeviceOwnershipSystemPropertyLocked();
             findOwnerComponentIfNecessaryLocked();
-            migrateUserRestrictionsIfNecessaryLocked();
 
             // TODO PO may not have a class name either due to b/17652534.  Address that too.
             updateDeviceOwnerLocked();
@@ -2742,7 +2755,8 @@
         Slog.i(LOG_TAG, "Giving the PO additional power...");
         markProfileOwnerOnOrganizationOwnedDeviceUncheckedLocked(poAdminComponent, poUserId);
         Slog.i(LOG_TAG, "Migrating DO policies to PO...");
-        moveDoPoliciesToProfileParentAdmin(doAdmin, poAdmin.getParentActiveAdmin());
+        moveDoPoliciesToProfileParentAdminLocked(doAdmin, poAdmin.getParentActiveAdmin());
+        migratePersonalAppSuspensionLocked(doUserId, poUserId, poAdmin);
         saveSettingsLocked(poUserId);
         Slog.i(LOG_TAG, "Clearing the DO...");
         final ComponentName doAdminReceiver = doAdmin.info.getComponent();
@@ -2762,6 +2776,25 @@
                 .write();
     }
 
+    @GuardedBy("getLockObject()")
+    private void migratePersonalAppSuspensionLocked(
+            int doUserId, int poUserId, ActiveAdmin poAdmin) {
+        final PackageManagerInternal pmi = mInjector.getPackageManagerInternal();
+        if (!pmi.isSuspendingAnyPackages(PLATFORM_PACKAGE_NAME, doUserId)) {
+            Slog.i(LOG_TAG, "DO is not suspending any apps.");
+            return;
+        }
+
+        if (getTargetSdk(poAdmin.info.getPackageName(), poUserId) >= Build.VERSION_CODES.R) {
+            Slog.i(LOG_TAG, "PO is targeting R+, keeping personal apps suspended.");
+            getUserData(doUserId).mAppsSuspended = true;
+            poAdmin.mSuspendPersonalApps = true;
+        } else {
+            Slog.i(LOG_TAG, "PO isn't targeting R+, unsuspending personal apps.");
+            pmi.unsuspendForSuspendingPackage(PLATFORM_PACKAGE_NAME, doUserId);
+        }
+    }
+
     private void uninstallOrDisablePackage(String packageName, int userHandle) {
         final ApplicationInfo appInfo;
         try {
@@ -2803,7 +2836,9 @@
         pi.uninstall(packageName, 0 /* flags */, new IntentSender((IIntentSender) mLocalSender));
     }
 
-    private void moveDoPoliciesToProfileParentAdmin(ActiveAdmin doAdmin, ActiveAdmin parentAdmin) {
+    @GuardedBy("getLockObject()")
+    private void moveDoPoliciesToProfileParentAdminLocked(
+            ActiveAdmin doAdmin, ActiveAdmin parentAdmin) {
         // The following policies can be already controlled via parent instance, skip if so.
         if (parentAdmin.mPasswordPolicy.quality == PASSWORD_QUALITY_UNSPECIFIED) {
             parentAdmin.mPasswordPolicy = doAdmin.mPasswordPolicy;
@@ -4104,8 +4139,10 @@
     }
 
     private void onLockSettingsReady() {
+        synchronized (getLockObject()) {
+            migrateUserRestrictionsIfNecessaryLocked();
+        }
         getUserData(UserHandle.USER_SYSTEM);
-        loadOwners();
         cleanUpOldUsers();
         maybeSetDefaultProfileOwnerUserRestrictions();
         handleStartUser(UserHandle.USER_SYSTEM);
@@ -5995,7 +6032,8 @@
 
     @Override
     public void lockNow(int flags, boolean parent) {
-        if (!mHasFeature) {
+        if (!mHasFeature && mContext.checkCallingPermission(android.Manifest.permission.LOCK_DEVICE)
+                != PackageManager.PERMISSION_GRANTED) {
             return;
         }
 
@@ -12674,7 +12712,8 @@
                 for (ResolveInfo receiver : receivers) {
                     final String packageName = receiver.getComponentInfo().packageName;
                     if (checkCrossProfilePackagePermissions(packageName, userId,
-                            requiresPermission)) {
+                            requiresPermission)
+                            || checkModifyQuietModePermission(packageName, userId)) {
                         Slog.i(LOG_TAG,
                                 String.format("Sending %s broadcast to %s.", intent.getAction(),
                                         packageName));
@@ -12692,6 +12731,27 @@
         }
 
         /**
+         * Checks whether the package {@code packageName} has the {@code MODIFY_QUIET_MODE}
+         * permission granted for the user {@code userId}.
+         */
+        private boolean checkModifyQuietModePermission(String packageName, @UserIdInt int userId) {
+            try {
+                final int uid = Objects.requireNonNull(
+                        mInjector.getPackageManager().getApplicationInfoAsUser(
+                                Objects.requireNonNull(packageName), /* flags= */ 0, userId)).uid;
+                return PackageManager.PERMISSION_GRANTED
+                        == ActivityManager.checkComponentPermission(
+                        android.Manifest.permission.MODIFY_QUIET_MODE, uid, /* owningUid= */
+                        -1, /* exported= */ true);
+            } catch (NameNotFoundException ex) {
+                Slog.w(LOG_TAG,
+                        String.format("Cannot find the package %s to check for permissions.",
+                                packageName));
+                return false;
+            }
+        }
+
+        /**
          * Checks whether the package {@code packageName} has the required permissions to receive
          * cross-profile broadcasts on behalf of the user {@code userId}.
          */
@@ -16132,25 +16192,34 @@
         }
         Slog.i(LOG_TAG, String.format("%s personal apps for user %d",
                 suspended ? "Suspending" : "Unsuspending", userId));
+
+        if (suspended) {
+            suspendPersonalAppsInPackageManager(userId);
+        } else {
+            mInjector.getPackageManagerInternal().unsuspendForSuspendingPackage(
+                    PLATFORM_PACKAGE_NAME, userId);
+        }
+
+        synchronized (getLockObject()) {
+            getUserData(userId).mAppsSuspended = suspended;
+            saveSettingsLocked(userId);
+        }
+    }
+
+    private void suspendPersonalAppsInPackageManager(int userId) {
         mInjector.binderWithCleanCallingIdentity(() -> {
             try {
                 final String[] appsToSuspend = mInjector.getPersonalAppsForSuspension(userId);
-                final String[] failedPackages = mIPackageManager.setPackagesSuspendedAsUser(
-                        appsToSuspend, suspended, null, null, null, PLATFORM_PACKAGE_NAME, userId);
-                if (!ArrayUtils.isEmpty(failedPackages)) {
-                    Slog.wtf(LOG_TAG, String.format("Failed to %s packages: %s",
-                            suspended ? "suspend" : "unsuspend", String.join(",", failedPackages)));
+                final String[] failedApps = mIPackageManager.setPackagesSuspendedAsUser(
+                        appsToSuspend, true, null, null, null, PLATFORM_PACKAGE_NAME, userId);
+                if (!ArrayUtils.isEmpty(failedApps)) {
+                    Slog.wtf(LOG_TAG, "Failed to suspend apps: " + String.join(",", failedApps));
                 }
             } catch (RemoteException re) {
                 // Shouldn't happen.
                 Slog.e(LOG_TAG, "Failed talking to the package manager", re);
             }
         });
-
-        synchronized (getLockObject()) {
-            getUserData(userId).mAppsSuspended = suspended;
-            saveSettingsLocked(userId);
-        }
     }
 
     @GuardedBy("getLockObject()")
diff --git a/services/incremental/BinderIncrementalService.cpp b/services/incremental/BinderIncrementalService.cpp
index e790a19..7132706c 100644
--- a/services/incremental/BinderIncrementalService.cpp
+++ b/services/incremental/BinderIncrementalService.cpp
@@ -165,6 +165,11 @@
     return ok();
 }
 
+binder::Status BinderIncrementalService::disableReadLogs(int32_t storageId) {
+    mImpl.disableReadLogs(storageId);
+    return ok();
+}
+
 binder::Status BinderIncrementalService::makeDirectory(int32_t storageId, const std::string& path,
                                                        int32_t* _aidl_return) {
     *_aidl_return = mImpl.makeDir(storageId, path);
diff --git a/services/incremental/BinderIncrementalService.h b/services/incremental/BinderIncrementalService.h
index 68549f5..1015494 100644
--- a/services/incremental/BinderIncrementalService.h
+++ b/services/incremental/BinderIncrementalService.h
@@ -74,7 +74,7 @@
                                    std::vector<uint8_t>* _aidl_return) final;
     binder::Status startLoading(int32_t storageId, bool* _aidl_return) final;
     binder::Status deleteStorage(int32_t storageId) final;
-
+    binder::Status disableReadLogs(int32_t storageId) final;
     binder::Status configureNativeBinaries(int32_t storageId, const std::string& apkFullPath,
                                            const std::string& libDirRelativePath,
                                            const std::string& abi, bool extractNativeLibs,
diff --git a/services/incremental/IncrementalService.cpp b/services/incremental/IncrementalService.cpp
index 885f4d2..3450c3ae 100644
--- a/services/incremental/IncrementalService.cpp
+++ b/services/incremental/IncrementalService.cpp
@@ -60,6 +60,7 @@
     static constexpr auto storagePrefix = "st"sv;
     static constexpr auto mountpointMdPrefix = ".mountpoint."sv;
     static constexpr auto infoMdName = ".info"sv;
+    static constexpr auto readLogsDisabledMarkerName = ".readlogs_disabled"sv;
     static constexpr auto libDir = "lib"sv;
     static constexpr auto libSuffix = ".so"sv;
     static constexpr auto blockSize = 4096;
@@ -172,6 +173,13 @@
 
     return name;
 }
+
+static bool checkReadLogsDisabledMarker(std::string_view root) {
+    const auto markerPath = path::c_str(path::join(root, constants().readLogsDisabledMarkerName));
+    struct stat st;
+    return (::stat(markerPath, &st) == 0);
+}
+
 } // namespace
 
 IncrementalService::IncFsMount::~IncFsMount() {
@@ -618,6 +626,32 @@
     return it->second->second.storage;
 }
 
+void IncrementalService::disableReadLogs(StorageId storageId) {
+    std::unique_lock l(mLock);
+    const auto ifs = getIfsLocked(storageId);
+    if (!ifs) {
+        LOG(ERROR) << "disableReadLogs failed, invalid storageId: " << storageId;
+        return;
+    }
+    if (!ifs->readLogsEnabled()) {
+        return;
+    }
+    ifs->disableReadLogs();
+    l.unlock();
+
+    const auto metadata = constants().readLogsDisabledMarkerName;
+    if (auto err = mIncFs->makeFile(ifs->control,
+                                    path::join(ifs->root, constants().mount,
+                                               constants().readLogsDisabledMarkerName),
+                                    0777, idFromMetadata(metadata), {})) {
+        //{.metadata = {metadata.data(), (IncFsSize)metadata.size()}})) {
+        LOG(ERROR) << "Failed to make marker file for storageId: " << storageId;
+        return;
+    }
+
+    setStorageParams(storageId, /*enableReadLogs=*/false);
+}
+
 int IncrementalService::setStorageParams(StorageId storageId, bool enableReadLogs) {
     const auto ifs = getIfs(storageId);
     if (!ifs) {
@@ -627,6 +661,11 @@
 
     const auto& params = ifs->dataLoaderStub->params();
     if (enableReadLogs) {
+        if (!ifs->readLogsEnabled()) {
+            LOG(ERROR) << "setStorageParams failed, readlogs disabled for storageId: " << storageId;
+            return -EPERM;
+        }
+
         if (auto status = mAppOpsManager->checkPermission(kDataUsageStats, kOpUsage,
                                                           params.packageName.c_str());
             !status.isOk()) {
@@ -1072,6 +1111,11 @@
                                                 std::move(control), *this);
         cleanupFiles.release(); // ifs will take care of that now
 
+        // Check if marker file present.
+        if (checkReadLogsDisabledMarker(root)) {
+            ifs->disableReadLogs();
+        }
+
         std::vector<std::pair<std::string, metadata::BindPoint>> permanentBindPoints;
         auto d = openDir(root);
         while (auto e = ::readdir(d.get())) {
@@ -1243,6 +1287,11 @@
     ifs->mountId = mount.storage().id();
     mNextId = std::max(mNextId, ifs->mountId + 1);
 
+    // Check if marker file present.
+    if (checkReadLogsDisabledMarker(mountTarget)) {
+        ifs->disableReadLogs();
+    }
+
     // DataLoader params
     DataLoaderParamsParcel dataLoaderParams;
     {
diff --git a/services/incremental/IncrementalService.h b/services/incremental/IncrementalService.h
index 918531b..a6cc946 100644
--- a/services/incremental/IncrementalService.h
+++ b/services/incremental/IncrementalService.h
@@ -94,6 +94,10 @@
         Permanent = 1,
     };
 
+    enum StorageFlags {
+        ReadLogsEnabled = 1,
+    };
+
     static FileId idFromMetadata(std::span<const uint8_t> metadata);
     static inline FileId idFromMetadata(std::span<const char> metadata) {
         return idFromMetadata({(const uint8_t*)metadata.data(), metadata.size()});
@@ -116,6 +120,7 @@
     int unbind(StorageId storage, std::string_view target);
     void deleteStorage(StorageId storage);
 
+    void disableReadLogs(StorageId storage);
     int setStorageParams(StorageId storage, bool enableReadLogs);
 
     int makeFile(StorageId storage, std::string_view path, int mode, FileId id,
@@ -264,6 +269,7 @@
         const std::string root;
         Control control;
         /*const*/ MountId mountId;
+        int32_t flags = StorageFlags::ReadLogsEnabled;
         StorageMap storages;
         BindMap bindPoints;
         DataLoaderStubPtr dataLoaderStub;
@@ -282,6 +288,9 @@
 
         StorageMap::iterator makeStorage(StorageId id);
 
+        void disableReadLogs() { flags &= ~StorageFlags::ReadLogsEnabled; }
+        int32_t readLogsEnabled() const { return (flags & StorageFlags::ReadLogsEnabled); }
+
         static void cleanupFilesystem(std::string_view root);
     };
 
diff --git a/services/incremental/test/IncrementalServiceTest.cpp b/services/incremental/test/IncrementalServiceTest.cpp
index 26b5094..1ae9e25 100644
--- a/services/incremental/test/IncrementalServiceTest.cpp
+++ b/services/incremental/test/IncrementalServiceTest.cpp
@@ -929,6 +929,34 @@
     ASSERT_GE(mDataLoader->setStorageParams(true), 0);
 }
 
+TEST_F(IncrementalServiceTest, testSetIncFsMountOptionsSuccessAndDisabled) {
+    mVold->mountIncFsSuccess();
+    mIncFs->makeFileSuccess();
+    mVold->bindMountSuccess();
+    mVold->setIncFsMountOptionsSuccess();
+    mDataLoaderManager->bindToDataLoaderSuccess();
+    mDataLoaderManager->getDataLoaderSuccess();
+    mAppOpsManager->checkPermissionSuccess();
+    EXPECT_CALL(*mDataLoaderManager, unbindFromDataLoader(_));
+    EXPECT_CALL(*mVold, unmountIncFs(_)).Times(2);
+    // Enabling and then disabling readlogs.
+    EXPECT_CALL(*mVold, setIncFsMountOptions(_, true)).Times(1);
+    EXPECT_CALL(*mVold, setIncFsMountOptions(_, false)).Times(1);
+    // After setIncFsMountOptions succeeded expecting to start watching.
+    EXPECT_CALL(*mAppOpsManager, startWatchingMode(_, _, _)).Times(1);
+    // Not expecting callback removal.
+    EXPECT_CALL(*mAppOpsManager, stopWatchingMode(_)).Times(0);
+    TemporaryDir tempDir;
+    int storageId = mIncrementalService->createStorage(tempDir.path, std::move(mDataLoaderParcel),
+                                                       IncrementalService::CreateOptions::CreateNew,
+                                                       {}, {}, {});
+    ASSERT_GE(storageId, 0);
+    ASSERT_GE(mDataLoader->setStorageParams(true), 0);
+    // Now disable.
+    mIncrementalService->disableReadLogs(storageId);
+    ASSERT_EQ(mDataLoader->setStorageParams(true), -EPERM);
+}
+
 TEST_F(IncrementalServiceTest, testSetIncFsMountOptionsSuccessAndPermissionChanged) {
     mVold->mountIncFsSuccess();
     mIncFs->makeFileSuccess();
diff --git a/services/net/java/android/net/ip/IpClientCallbacks.java b/services/net/java/android/net/ip/IpClientCallbacks.java
index c93e5c5..b172c4b 100644
--- a/services/net/java/android/net/ip/IpClientCallbacks.java
+++ b/services/net/java/android/net/ip/IpClientCallbacks.java
@@ -16,7 +16,6 @@
 
 package android.net.ip;
 
-import android.net.DhcpResults;
 import android.net.DhcpResultsParcelable;
 import android.net.Layer2PacketParcelable;
 import android.net.LinkProperties;
@@ -67,19 +66,15 @@
      * <p>DHCPv4 or static IPv4 configuration failure or success can be determined by whether or not
      * the passed-in DhcpResults object is null.
      */
-    public void onNewDhcpResults(DhcpResults dhcpResults) {}
-
-    /**
-     * Callback called when new DHCP results are available.
-     *
-     * <p>This is purely advisory and not an indication of provisioning success or failure.  This is
-     * only here for callers that want to expose DHCPv4 results to other APIs
-     * (e.g., WifiInfo#setInetAddress).
-     *
-     * <p>DHCPv4 or static IPv4 configuration failure or success can be determined by whether or not
-     * the passed-in DhcpResults object is null.
-     */
-    public void onNewDhcpResults(DhcpResultsParcelable dhcpResults) {}
+    public void onNewDhcpResults(DhcpResultsParcelable dhcpResults) {
+        // In general callbacks would not use a parcelable directly (DhcpResultsParcelable), and
+        // would use a wrapper instead. But there are already two classes in the tree for DHCP
+        // information: DhcpInfo and DhcpResults, and each of them do not expose an appropriate API
+        // (they are bags of mutable fields and can't be changed because they are public API and
+        // @UnsupportedAppUsage). Adding a third class would cost more than the gain considering
+        // that the only client of this callback is WiFi, which will end up converting the results
+        // to DhcpInfo anyway.
+    }
 
     /**
      * Indicates that provisioning was successful.
diff --git a/services/net/java/android/net/ip/IpClientUtil.java b/services/net/java/android/net/ip/IpClientUtil.java
index b329aee..426614e 100644
--- a/services/net/java/android/net/ip/IpClientUtil.java
+++ b/services/net/java/android/net/ip/IpClientUtil.java
@@ -16,8 +16,6 @@
 
 package android.net.ip;
 
-import static android.net.shared.IpConfigurationParcelableUtil.fromStableParcelable;
-
 import android.content.Context;
 import android.net.DhcpResultsParcelable;
 import android.net.Layer2PacketParcelable;
@@ -118,7 +116,6 @@
         // null or not.
         @Override
         public void onNewDhcpResults(DhcpResultsParcelable dhcpResults) {
-            mCb.onNewDhcpResults(fromStableParcelable(dhcpResults));
             mCb.onNewDhcpResults(dhcpResults);
         }
 
diff --git a/services/net/java/android/net/util/DhcpResultsCompatUtil.java b/services/net/java/android/net/util/DhcpResultsCompatUtil.java
new file mode 100644
index 0000000..fce0834
--- /dev/null
+++ b/services/net/java/android/net/util/DhcpResultsCompatUtil.java
@@ -0,0 +1,54 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.net.util;
+
+import static android.net.shared.IpConfigurationParcelableUtil.unparcelAddress;
+
+import android.annotation.Nullable;
+import android.net.DhcpResults;
+import android.net.DhcpResultsParcelable;
+
+import java.net.Inet4Address;
+
+/**
+ * Compatibility utility for code that still uses DhcpResults.
+ *
+ * TODO: remove this class when all usages of DhcpResults (including Wifi in AOSP) are removed.
+ */
+public class DhcpResultsCompatUtil {
+
+    /**
+     * Convert a DhcpResultsParcelable to DhcpResults.
+     *
+     * contract {
+     *     returns(null) implies p == null
+     *     returnsNotNull() implies p != null
+     * }
+     */
+    @Nullable
+    public static DhcpResults fromStableParcelable(@Nullable DhcpResultsParcelable p) {
+        if (p == null) return null;
+        final DhcpResults results = new DhcpResults(p.baseConfiguration);
+        results.leaseDuration = p.leaseDuration;
+        results.mtu = p.mtu;
+        results.serverAddress = (Inet4Address) unparcelAddress(p.serverAddress);
+        results.vendorInfo = p.vendorInfo;
+        results.serverHostName = p.serverHostName;
+        results.captivePortalApiUrl = p.captivePortalApiUrl;
+        return results;
+    }
+}
diff --git a/services/people/java/com/android/server/people/prediction/ShareTargetPredictor.java b/services/people/java/com/android/server/people/prediction/ShareTargetPredictor.java
index 2e60f2a..236ac84 100644
--- a/services/people/java/com/android/server/people/prediction/ShareTargetPredictor.java
+++ b/services/people/java/com/android/server/people/prediction/ShareTargetPredictor.java
@@ -16,6 +16,8 @@
 
 package com.android.server.people.prediction;
 
+import static java.util.Collections.reverseOrder;
+
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.annotation.UserIdInt;
@@ -39,6 +41,7 @@
 
 import java.util.ArrayList;
 import java.util.Collections;
+import java.util.Comparator;
 import java.util.List;
 import java.util.function.Consumer;
 
@@ -85,7 +88,9 @@
         List<ShareTarget> shareTargets = getDirectShareTargets();
         SharesheetModelScorer.computeScore(shareTargets, getShareEventType(mIntentFilter),
                 System.currentTimeMillis());
-        Collections.sort(shareTargets, (t1, t2) -> -Float.compare(t1.getScore(), t2.getScore()));
+        Collections.sort(shareTargets,
+                Comparator.comparing(ShareTarget::getScore, reverseOrder())
+                        .thenComparing(t -> t.getAppTarget().getRank()));
         List<AppTarget> res = new ArrayList<>();
         for (int i = 0; i < Math.min(getPredictionContext().getPredictedTargetCount(),
                 shareTargets.size()); i++) {
@@ -135,6 +140,7 @@
                     new AppTargetId(shortcutInfo.getId()),
                     shortcutInfo)
                     .setClassName(shareShortcut.getTargetComponent().getClassName())
+                    .setRank(shortcutInfo.getRank())
                     .build();
             String packageName = shortcutInfo.getPackage();
             int userId = shortcutInfo.getUserId();
diff --git a/services/tests/PackageManagerServiceTests/host/Android.bp b/services/tests/PackageManagerServiceTests/host/Android.bp
new file mode 100644
index 0000000..dad001b
--- /dev/null
+++ b/services/tests/PackageManagerServiceTests/host/Android.bp
@@ -0,0 +1,33 @@
+// Copyright (C) 2020 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.
+
+java_test_host {
+    name: "PackageManagerServiceHostTests",
+    srcs: ["src/**/*.kt"],
+    libs: [
+        "tradefed",
+        "junit",
+        "truth-prebuilt",
+    ],
+    static_libs: [
+        "frameworks-base-hostutils",
+    ],
+    test_suites: ["general-tests"],
+    java_resources: [
+        ":PackageManagerDummyAppVersion1",
+        ":PackageManagerDummyAppVersion2",
+        ":PackageManagerDummyAppVersion3",
+        ":PackageManagerDummyAppOriginalOverride",
+    ]
+}
diff --git a/services/tests/PackageManagerServiceTests/host/AndroidTest.xml b/services/tests/PackageManagerServiceTests/host/AndroidTest.xml
new file mode 100644
index 0000000..dc8c811
--- /dev/null
+++ b/services/tests/PackageManagerServiceTests/host/AndroidTest.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright (C) 2020 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.
+  -->
+
+<configuration description="Test module config for PackageManagerServiceHostTests">
+    <option name="test-tag" value="PackageManagerServiceHostTests" />
+
+    <target_preparer class="com.android.tradefed.targetprep.RootTargetPreparer"/>
+
+    <test class="com.android.tradefed.testtype.HostTest">
+        <option name="jar" value="PackageManagerServiceHostTests.jar" />
+    </test>
+</configuration>
diff --git a/services/tests/PackageManagerServiceTests/host/src/com/android/server/pm/test/HostUtils.kt b/services/tests/PackageManagerServiceTests/host/src/com/android/server/pm/test/HostUtils.kt
new file mode 100644
index 0000000..4927c45
--- /dev/null
+++ b/services/tests/PackageManagerServiceTests/host/src/com/android/server/pm/test/HostUtils.kt
@@ -0,0 +1,46 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.pm.test
+
+import com.android.internal.util.test.SystemPreparer
+import com.android.tradefed.device.ITestDevice
+import java.io.File
+
+internal fun SystemPreparer.pushApk(file: String, partition: Partition) =
+        pushResourceFile(file, HostUtils.makePathForApk(file, partition))
+
+internal fun SystemPreparer.deleteApk(file: String, partition: Partition) =
+        deleteFile(partition.baseFolder.resolve(file.removeSuffix(".apk")).toString())
+
+internal object HostUtils {
+
+    fun getDataDir(device: ITestDevice, pkgName: String) =
+            device.executeShellCommand("dumpsys package $pkgName")
+                    .lineSequence()
+                    .map(String::trim)
+                    .single { it.startsWith("dataDir=") }
+                    .removePrefix("dataDir=")
+
+    fun makePathForApk(fileName: String, partition: Partition) =
+            makePathForApk(File(fileName), partition)
+
+    fun makePathForApk(file: File, partition: Partition) =
+            partition.baseFolder
+                    .resolve(file.nameWithoutExtension)
+                    .resolve(file.name)
+                    .toString()
+}
diff --git a/services/tests/PackageManagerServiceTests/host/src/com/android/server/pm/test/OriginalPackageMigrationTest.kt b/services/tests/PackageManagerServiceTests/host/src/com/android/server/pm/test/OriginalPackageMigrationTest.kt
new file mode 100644
index 0000000..90494c5
--- /dev/null
+++ b/services/tests/PackageManagerServiceTests/host/src/com/android/server/pm/test/OriginalPackageMigrationTest.kt
@@ -0,0 +1,98 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.pm.test
+
+import com.android.internal.util.test.SystemPreparer
+import com.android.tradefed.testtype.DeviceJUnit4ClassRunner
+import com.android.tradefed.testtype.junit4.BaseHostJUnit4Test
+import com.google.common.truth.Truth.assertThat
+import org.junit.ClassRule
+import org.junit.Rule
+import org.junit.Test
+import org.junit.rules.RuleChain
+import org.junit.rules.TemporaryFolder
+import org.junit.runner.RunWith
+
+@RunWith(DeviceJUnit4ClassRunner::class)
+class OriginalPackageMigrationTest : BaseHostJUnit4Test() {
+
+    companion object {
+        private const val TEST_PKG_NAME = "com.android.server.pm.test.dummy_app"
+        private const val VERSION_ONE = "PackageManagerDummyAppVersion1.apk"
+        private const val VERSION_TWO = "PackageManagerDummyAppVersion2.apk"
+        private const val VERSION_THREE = "PackageManagerDummyAppVersion3.apk"
+        private const val NEW_PKG = "PackageManagerDummyAppOriginalOverride.apk"
+
+        @get:ClassRule
+        val deviceRebootRule = SystemPreparer.TestRuleDelegate(true)
+    }
+
+    private val tempFolder = TemporaryFolder()
+    private val preparer: SystemPreparer = SystemPreparer(tempFolder,
+            SystemPreparer.RebootStrategy.START_STOP, deviceRebootRule) { this.device }
+
+    @get:Rule
+    val rules = RuleChain.outerRule(tempFolder).around(preparer)!!
+
+    @Test
+    fun lowerVersion() {
+        runForApk(VERSION_ONE)
+    }
+
+    @Test
+    fun sameVersion() {
+        runForApk(VERSION_TWO)
+    }
+
+    @Test
+    fun higherVersion() {
+        runForApk(VERSION_THREE)
+    }
+
+    // A bug was found where renamed the package during parsing was leading to an invalid version
+    // code check at scan time. A lower version package was being dropped after reboot. To test
+    // this, the override APK is defined as versionCode 2 and the original package is given
+    // versionCode 1, 2, and 3 from the other methods.
+    private fun runForApk(apk: String) {
+        preparer.pushApk(apk, Partition.SYSTEM)
+                .reboot()
+
+        device.getAppPackageInfo(TEST_PKG_NAME).run {
+            assertThat(codePath).contains(apk.removeSuffix(".apk"))
+        }
+
+        // Ensure data is preserved by writing to the original dataDir
+        val file = tempFolder.newFile().apply { writeText("Test") }
+        device.pushFile(file, "${HostUtils.getDataDir(device, TEST_PKG_NAME)}/files/test.txt")
+
+        preparer.deleteApk(apk, Partition.SYSTEM)
+                .pushApk(NEW_PKG, Partition.SYSTEM)
+                .reboot()
+
+        device.getAppPackageInfo(TEST_PKG_NAME)
+                .run {
+                    assertThat(this.toString()).isNotEmpty()
+                    assertThat(codePath)
+                            .contains(NEW_PKG.removeSuffix(".apk"))
+                }
+
+        // And then reading the data contents back
+        assertThat(device.pullFileContents(
+                "${HostUtils.getDataDir(device, TEST_PKG_NAME)}/files/test.txt"))
+                .isEqualTo("Test")
+    }
+}
diff --git a/services/tests/PackageManagerServiceTests/host/src/com/android/server/pm/test/Partition.kt b/services/tests/PackageManagerServiceTests/host/src/com/android/server/pm/test/Partition.kt
new file mode 100644
index 0000000..35192a7
--- /dev/null
+++ b/services/tests/PackageManagerServiceTests/host/src/com/android/server/pm/test/Partition.kt
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.pm.test
+
+import java.nio.file.Path
+import java.nio.file.Paths
+
+// Unfortunately no easy way to access PMS SystemPartitions, so mock them here
+internal enum class Partition(val baseFolder: Path) {
+    SYSTEM("/system/app"),
+    VENDOR("/vendor/app"),
+    PRODUCT("/product/app"),
+    SYSTEM_EXT("/system_ext/app")
+    ;
+
+    constructor(baseFolder: String) : this(Paths.get(baseFolder))
+}
diff --git a/services/tests/PackageManagerServiceTests/host/test-apps/Android.bp b/services/tests/PackageManagerServiceTests/host/test-apps/Android.bp
new file mode 100644
index 0000000..9568faa
--- /dev/null
+++ b/services/tests/PackageManagerServiceTests/host/test-apps/Android.bp
@@ -0,0 +1,33 @@
+// Copyright (C) 2020 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.
+
+android_test_helper_app {
+    name: "PackageManagerDummyAppVersion1",
+    manifest: "AndroidManifestVersion1.xml"
+}
+
+android_test_helper_app {
+    name: "PackageManagerDummyAppVersion2",
+    manifest: "AndroidManifestVersion2.xml"
+}
+
+android_test_helper_app {
+    name: "PackageManagerDummyAppVersion3",
+    manifest: "AndroidManifestVersion3.xml"
+}
+
+android_test_helper_app {
+    name: "PackageManagerDummyAppOriginalOverride",
+    manifest: "AndroidManifestOriginalOverride.xml"
+}
diff --git a/packages/SystemUI/res/color/qs_user_detail_avatar_tint.xml b/services/tests/PackageManagerServiceTests/host/test-apps/AndroidManifestOriginalOverride.xml
similarity index 62%
copy from packages/SystemUI/res/color/qs_user_detail_avatar_tint.xml
copy to services/tests/PackageManagerServiceTests/host/test-apps/AndroidManifestOriginalOverride.xml
index 696e9b1..f16e1bc 100644
--- a/packages/SystemUI/res/color/qs_user_detail_avatar_tint.xml
+++ b/services/tests/PackageManagerServiceTests/host/test-apps/AndroidManifestOriginalOverride.xml
@@ -1,7 +1,6 @@
 <?xml version="1.0" encoding="utf-8"?>
-
 <!--
-  ~ Copyright (C) 2016 The Android Open Source Project
+  ~ Copyright (C) 2020 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.
@@ -13,10 +12,14 @@
   ~ 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
+  ~ limitations under the License.
   -->
+<manifest
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    package="com.android.server.pm.test.dummy_app.override"
+    android:versionCode="2"
+    >
 
-<selector xmlns:android="http://schemas.android.com/apk/res/android">
-    <item android:state_enabled="false" android:color="?android:attr/textColorPrimary" />
-    <item android:color="@android:color/transparent" />
-</selector>
+    <original-package android:name="com.android.server.pm.test.dummy_app"/>
+
+</manifest>
diff --git a/packages/SystemUI/res/color/qs_user_detail_avatar_tint.xml b/services/tests/PackageManagerServiceTests/host/test-apps/AndroidManifestVersion1.xml
similarity index 64%
copy from packages/SystemUI/res/color/qs_user_detail_avatar_tint.xml
copy to services/tests/PackageManagerServiceTests/host/test-apps/AndroidManifestVersion1.xml
index 696e9b1..d772050 100644
--- a/packages/SystemUI/res/color/qs_user_detail_avatar_tint.xml
+++ b/services/tests/PackageManagerServiceTests/host/test-apps/AndroidManifestVersion1.xml
@@ -1,7 +1,6 @@
 <?xml version="1.0" encoding="utf-8"?>
-
 <!--
-  ~ Copyright (C) 2016 The Android Open Source Project
+  ~ Copyright (C) 2020 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.
@@ -13,10 +12,10 @@
   ~ 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
+  ~ limitations under the License.
   -->
-
-<selector xmlns:android="http://schemas.android.com/apk/res/android">
-    <item android:state_enabled="false" android:color="?android:attr/textColorPrimary" />
-    <item android:color="@android:color/transparent" />
-</selector>
+<manifest
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    package="com.android.server.pm.test.dummy_app"
+    android:versionCode="1"
+    />
diff --git a/packages/SystemUI/res/color/qs_user_detail_avatar_tint.xml b/services/tests/PackageManagerServiceTests/host/test-apps/AndroidManifestVersion2.xml
similarity index 64%
copy from packages/SystemUI/res/color/qs_user_detail_avatar_tint.xml
copy to services/tests/PackageManagerServiceTests/host/test-apps/AndroidManifestVersion2.xml
index 696e9b1..53f836b 100644
--- a/packages/SystemUI/res/color/qs_user_detail_avatar_tint.xml
+++ b/services/tests/PackageManagerServiceTests/host/test-apps/AndroidManifestVersion2.xml
@@ -1,7 +1,6 @@
 <?xml version="1.0" encoding="utf-8"?>
-
 <!--
-  ~ Copyright (C) 2016 The Android Open Source Project
+  ~ Copyright (C) 2020 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.
@@ -13,10 +12,10 @@
   ~ 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
+  ~ limitations under the License.
   -->
-
-<selector xmlns:android="http://schemas.android.com/apk/res/android">
-    <item android:state_enabled="false" android:color="?android:attr/textColorPrimary" />
-    <item android:color="@android:color/transparent" />
-</selector>
+<manifest
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    package="com.android.server.pm.test.dummy_app"
+    android:versionCode="2"
+    />
diff --git a/packages/SystemUI/res/color/qs_user_detail_avatar_tint.xml b/services/tests/PackageManagerServiceTests/host/test-apps/AndroidManifestVersion3.xml
similarity index 64%
copy from packages/SystemUI/res/color/qs_user_detail_avatar_tint.xml
copy to services/tests/PackageManagerServiceTests/host/test-apps/AndroidManifestVersion3.xml
index 696e9b1..90ca9d0 100644
--- a/packages/SystemUI/res/color/qs_user_detail_avatar_tint.xml
+++ b/services/tests/PackageManagerServiceTests/host/test-apps/AndroidManifestVersion3.xml
@@ -1,7 +1,6 @@
 <?xml version="1.0" encoding="utf-8"?>
-
 <!--
-  ~ Copyright (C) 2016 The Android Open Source Project
+  ~ Copyright (C) 2020 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.
@@ -13,10 +12,10 @@
   ~ 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
+  ~ limitations under the License.
   -->
-
-<selector xmlns:android="http://schemas.android.com/apk/res/android">
-    <item android:state_enabled="false" android:color="?android:attr/textColorPrimary" />
-    <item android:color="@android:color/transparent" />
-</selector>
+<manifest
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    package="com.android.server.pm.test.dummy_app"
+    android:versionCode="3"
+    />
diff --git a/services/tests/mockingservicestests/Android.bp b/services/tests/mockingservicestests/Android.bp
index ff34ebd..b4e0f10 100644
--- a/services/tests/mockingservicestests/Android.bp
+++ b/services/tests/mockingservicestests/Android.bp
@@ -21,7 +21,7 @@
         "services.core",
         "services.net",
         "service-jobscheduler",
-        "service-permission",
+        "service-permission.impl",
         "service-blobstore",
         "androidx.test.runner",
         "androidx.test.ext.truth",
diff --git a/services/tests/mockingservicestests/src/com/android/server/am/MockingOomAdjusterTests.java b/services/tests/mockingservicestests/src/com/android/server/am/MockingOomAdjusterTests.java
index fde40aa..cdafd32 100644
--- a/services/tests/mockingservicestests/src/com/android/server/am/MockingOomAdjusterTests.java
+++ b/services/tests/mockingservicestests/src/com/android/server/am/MockingOomAdjusterTests.java
@@ -63,6 +63,7 @@
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertTrue;
 import static org.mockito.AdditionalAnswers.answer;
+import static org.mockito.ArgumentMatchers.eq;
 import static org.mockito.Mockito.any;
 import static org.mockito.Mockito.anyInt;
 import static org.mockito.Mockito.anyLong;
@@ -170,6 +171,7 @@
                 mock(OomAdjProfiler.class));
         doReturn(new ActivityManagerService.ProcessChangeItem()).when(sService)
                 .enqueueProcessChangeItemLocked(anyInt(), anyInt());
+        doReturn(true).when(sService).containsTopUiOrRunningRemoteAnimOrEmptyLocked(any());
         sService.mOomAdjuster = new OomAdjuster(sService, sService.mProcessList,
                 mock(ActiveUids.class));
         sService.mOomAdjuster.mAdjSeq = 10000;
@@ -266,6 +268,21 @@
 
     @SuppressWarnings("GuardedBy")
     @Test
+    public void testUpdateOomAdj_DoOne_TopApp_PreemptedByTopUi() {
+        ProcessRecord app = spy(makeDefaultProcessRecord(MOCKAPP_PID, MOCKAPP_UID,
+                MOCKAPP_PROCESSNAME, MOCKAPP_PACKAGENAME, true));
+        doReturn(PROCESS_STATE_TOP).when(sService.mAtmInternal).getTopProcessState();
+        doReturn(app).when(sService).getTopAppLocked();
+        doReturn(false).when(sService).containsTopUiOrRunningRemoteAnimOrEmptyLocked(eq(app));
+        sService.mWakefulness = PowerManagerInternal.WAKEFULNESS_AWAKE;
+        sService.mOomAdjuster.updateOomAdjLocked(app, false, OomAdjuster.OOM_ADJ_REASON_NONE);
+        doReturn(null).when(sService).getTopAppLocked();
+
+        assertProcStates(app, PROCESS_STATE_TOP, FOREGROUND_APP_ADJ, SCHED_GROUP_DEFAULT);
+    }
+
+    @SuppressWarnings("GuardedBy")
+    @Test
     public void testUpdateOomAdj_DoOne_RunningInstrumentation() {
         ProcessRecord app = spy(makeDefaultProcessRecord(MOCKAPP_PID, MOCKAPP_UID,
                 MOCKAPP_PROCESSNAME, MOCKAPP_PACKAGENAME, true));
diff --git a/services/tests/servicestests/Android.bp b/services/tests/servicestests/Android.bp
index 40a1706..979f4e1 100644
--- a/services/tests/servicestests/Android.bp
+++ b/services/tests/servicestests/Android.bp
@@ -44,7 +44,7 @@
         "hamcrest-library",
         "servicestests-utils",
         "service-jobscheduler",
-        "service-permission",
+        "service-permission.impl",
         // TODO: remove once Android migrates to JUnit 4.12,
         // which provides assertThrows
         "testng",
diff --git a/services/tests/servicestests/AndroidManifest.xml b/services/tests/servicestests/AndroidManifest.xml
index 3b38d94..6db3233 100644
--- a/services/tests/servicestests/AndroidManifest.xml
+++ b/services/tests/servicestests/AndroidManifest.xml
@@ -80,6 +80,7 @@
     <uses-permission android:name="android.permission.WRITE_DREAM_STATE"/>
     <uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS"/>
     <uses-permission android:name="android.permission.MODIFY_DAY_NIGHT_MODE"/>
+    <uses-permission android:name="android.permission.MEDIA_RESOURCE_OVERRIDE_PID"/>
 
     <!-- Uses API introduced in O (26) -->
     <uses-sdk android:minSdkVersion="1"
diff --git a/services/tests/servicestests/assets/AppIntegrityManagerServiceImplTest/SourceStampTestApk.apk b/services/tests/servicestests/assets/AppIntegrityManagerServiceImplTest/SourceStampTestApk.apk
index 8056e0b..211e064 100644
--- a/services/tests/servicestests/assets/AppIntegrityManagerServiceImplTest/SourceStampTestApk.apk
+++ b/services/tests/servicestests/assets/AppIntegrityManagerServiceImplTest/SourceStampTestApk.apk
Binary files differ
diff --git a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerServiceMigrationTest.java b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerServiceMigrationTest.java
index a0b9d9d..3167820 100644
--- a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerServiceMigrationTest.java
+++ b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerServiceMigrationTest.java
@@ -18,17 +18,24 @@
 import static android.os.UserHandle.USER_SYSTEM;
 
 import static com.android.server.devicepolicy.DpmTestUtils.writeInputStreamToFile;
+import static com.android.server.pm.PackageManagerService.PLATFORM_PACKAGE_NAME;
 
 import static org.junit.Assert.assertArrayEquals;
+import static org.mockito.ArgumentMatchers.anyBoolean;
 import static org.mockito.Matchers.any;
 import static org.mockito.Matchers.anyInt;
 import static org.mockito.Matchers.eq;
 import static org.mockito.Mockito.doAnswer;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
 
+import android.app.admin.DevicePolicyManager;
 import android.app.admin.DevicePolicyManagerInternal;
 import android.content.ComponentName;
+import android.content.Intent;
 import android.content.pm.PackageManager;
+import android.os.Build;
 import android.os.Bundle;
 import android.os.UserHandle;
 import android.os.UserManager;
@@ -354,8 +361,7 @@
         prepareAdmin1AsDo();
         prepareAdminAnotherPackageAsPo(COPE_PROFILE_USER_ID);
 
-        final DevicePolicyManagerServiceTestable dpms;
-        dpms = bootDpmsUp();
+        final DevicePolicyManagerServiceTestable dpms = bootDpmsUp();
 
         // DO should still be DO since no migration should happen.
         assertTrue(dpms.mOwners.hasDeviceOwner());
@@ -364,13 +370,12 @@
     @SmallTest
     public void testCompMigrationAffiliated() throws Exception {
         prepareAdmin1AsDo();
-        prepareAdmin1AsPo(COPE_PROFILE_USER_ID);
+        prepareAdmin1AsPo(COPE_PROFILE_USER_ID, Build.VERSION_CODES.R);
 
         // Secure lock screen is needed for password policy APIs to work.
         when(getServices().lockPatternUtils.hasSecureLockScreen()).thenReturn(true);
 
-        final DevicePolicyManagerServiceTestable dpms;
-        dpms = bootDpmsUp();
+        final DevicePolicyManagerServiceTestable dpms = bootDpmsUp();
 
         // DO should cease to be DO.
         assertFalse(dpms.mOwners.hasDeviceOwner());
@@ -408,6 +413,66 @@
                     dpms.getProfileOwnerAdminLocked(COPE_PROFILE_USER_ID)
                             .getEffectiveRestrictions()
                             .containsKey(UserManager.DISALLOW_CONFIG_DATE_TIME));
+            assertEquals("Personal apps suspension wasn't migrated",
+                    DevicePolicyManager.PERSONAL_APPS_NOT_SUSPENDED,
+                    dpm.getPersonalAppsSuspendedReasons(admin1));
+        });
+    }
+
+    @SmallTest
+    public void testCompMigration_keepSuspendedAppsWhenDpcIsRPlus() throws Exception {
+        prepareAdmin1AsDo();
+        prepareAdmin1AsPo(COPE_PROFILE_USER_ID, Build.VERSION_CODES.R);
+
+        // Pretend some packages are suspended.
+        when(getServices().packageManagerInternal.isSuspendingAnyPackages(
+                PLATFORM_PACKAGE_NAME, USER_SYSTEM)).thenReturn(true);
+
+        final DevicePolicyManagerServiceTestable dpms = bootDpmsUp();
+
+        verify(getServices().packageManagerInternal, never())
+                .unsuspendForSuspendingPackage(PLATFORM_PACKAGE_NAME, USER_SYSTEM);
+
+        sendBroadcastWithUser(dpms, Intent.ACTION_USER_STARTED, USER_SYSTEM);
+
+        // Verify that actual package suspension state is not modified after user start
+        verify(getServices().packageManagerInternal, never())
+                .unsuspendForSuspendingPackage(PLATFORM_PACKAGE_NAME, USER_SYSTEM);
+        verify(getServices().ipackageManager, never()).setPackagesSuspendedAsUser(
+                any(), anyBoolean(), any(), any(), any(), any(), anyInt());
+
+        final DpmMockContext poContext = new DpmMockContext(getServices(), mRealTestContext);
+        poContext.binder.callingUid = UserHandle.getUid(COPE_PROFILE_USER_ID, COPE_ADMIN1_APP_ID);
+
+        runAsCaller(poContext, dpms, dpm -> {
+            assertEquals("Personal apps suspension wasn't migrated",
+                    DevicePolicyManager.PERSONAL_APPS_SUSPENDED_EXPLICITLY,
+                    dpm.getPersonalAppsSuspendedReasons(admin1));
+        });
+    }
+
+    @SmallTest
+    public void testCompMigration_unsuspendAppsWhenDpcNotRPlus() throws Exception {
+        prepareAdmin1AsDo();
+        prepareAdmin1AsPo(COPE_PROFILE_USER_ID, Build.VERSION_CODES.Q);
+
+        // Pretend some packages are suspended.
+        when(getServices().packageManagerInternal.isSuspendingAnyPackages(
+                PLATFORM_PACKAGE_NAME, USER_SYSTEM)).thenReturn(true);
+
+        final DevicePolicyManagerServiceTestable dpms = bootDpmsUp();
+
+        // Verify that apps get unsuspended.
+        verify(getServices().packageManagerInternal)
+                .unsuspendForSuspendingPackage(PLATFORM_PACKAGE_NAME, USER_SYSTEM);
+
+        final DpmMockContext poContext = new DpmMockContext(getServices(), mRealTestContext);
+        poContext.binder.callingUid = UserHandle.getUid(COPE_PROFILE_USER_ID, COPE_ADMIN1_APP_ID);
+
+        runAsCaller(poContext, dpms, dpm -> {
+            assertEquals("Personal apps weren't unsuspended",
+                    DevicePolicyManager.PERSONAL_APPS_NOT_SUSPENDED,
+                    dpm.getPersonalAppsSuspendedReasons(admin1));
         });
     }
 
@@ -439,22 +504,23 @@
                         .getAbsoluteFile());
     }
 
-    private void prepareAdmin1AsPo(int profileUserId) throws Exception {
+    private void prepareAdmin1AsPo(int profileUserId, int targetSdk) throws Exception {
         preparePo(profileUserId, admin1, R.raw.comp_profile_owner_same_package,
-                R.raw.comp_policies_profile_same_package, COPE_ADMIN1_APP_ID);
+                R.raw.comp_policies_profile_same_package, COPE_ADMIN1_APP_ID, targetSdk);
     }
 
     private void prepareAdminAnotherPackageAsPo(int profileUserId) throws Exception {
         preparePo(profileUserId, adminAnotherPackage, R.raw.comp_profile_owner_another_package,
-                R.raw.comp_policies_profile_another_package, COPE_ANOTHER_ADMIN_APP_ID);
+                R.raw.comp_policies_profile_another_package, COPE_ANOTHER_ADMIN_APP_ID,
+                Build.VERSION.SDK_INT);
     }
 
     private void preparePo(int profileUserId, ComponentName admin, int profileOwnerXmlResId,
-            int policyXmlResId, int adminAppId) throws Exception {
+            int policyXmlResId, int adminAppId, int targetSdk) throws Exception {
         final File profileDir = getServices().addUser(profileUserId, 0,
                 UserManager.USER_TYPE_PROFILE_MANAGED, USER_SYSTEM /* profile group */);
-        setUpPackageManagerForFakeAdmin(
-                admin, UserHandle.getUid(profileUserId, adminAppId), admin1);
+        setUpPackageManagerForFakeAdmin(admin, UserHandle.getUid(profileUserId, adminAppId),
+                /* enabledSetting =*/ null, targetSdk, admin1);
         writeInputStreamToFile(getRawStream(policyXmlResId),
                 (new File(profileDir, "device_policies.xml")).getAbsoluteFile());
         writeInputStreamToFile(getRawStream(profileOwnerXmlResId),
diff --git a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java
index 4a77489..daaabf8 100644
--- a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java
+++ b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java
@@ -254,7 +254,7 @@
 
     @Override
     protected void tearDown() throws Exception {
-        flushTasks();
+        flushTasks(dpms);
         getMockTransferMetadataManager().deleteMetadataFile();
         super.tearDown();
     }
@@ -4961,7 +4961,7 @@
 
         // CertificateMonitor.updateInstalledCertificates is called on the background thread,
         // let it finish with system uid, otherwise it will throw and crash.
-        flushTasks();
+        flushTasks(dpms);
 
         mContext.binder.restoreCallingIdentity(ident);
     }
@@ -5459,7 +5459,7 @@
         getServices().injectBroadcast(mServiceContext, new Intent(KeyChain.ACTION_TRUST_STORE_CHANGED)
                 .putExtra(Intent.EXTRA_USER_HANDLE, callerUser.getIdentifier()),
                 callerUser.getIdentifier());
-        flushTasks();
+        flushTasks(dpms);
 
         final List<String> ownerInstalledCaCerts = new ArrayList<>();
 
@@ -5486,7 +5486,7 @@
         getServices().injectBroadcast(mServiceContext, new Intent(KeyChain.ACTION_TRUST_STORE_CHANGED)
                 .putExtra(Intent.EXTRA_USER_HANDLE, callerUser.getIdentifier()),
                 callerUser.getIdentifier());
-        flushTasks();
+        flushTasks(dpms);
 
         // Verify that the CA cert is no longer reported as installed by the Device Owner / Profile
         // Owner.
@@ -5530,7 +5530,7 @@
         getServices().injectBroadcast(mServiceContext, new Intent(KeyChain.ACTION_TRUST_STORE_CHANGED)
                 .putExtra(Intent.EXTRA_USER_HANDLE, callerUser.getIdentifier()),
                 callerUser.getIdentifier());
-        flushTasks();
+        flushTasks(dpms);
 
         // Removing the Profile Owner should clear the information on which CA certs were installed
         runAsCaller(admin1Context, dpms, dpm -> dpm.clearProfileOwner(admin1));
@@ -6311,7 +6311,7 @@
         clearInvocations(getServices().alarmManager);
 
         setUserUnlocked(CALLER_USER_HANDLE, false);
-        sendBroadcastWithUser(Intent.ACTION_USER_STOPPED, CALLER_USER_HANDLE);
+        sendBroadcastWithUser(dpms, Intent.ACTION_USER_STOPPED, CALLER_USER_HANDLE);
 
         // Verify the alarm was scheduled for time when the warning should be shown.
         verify(getServices().alarmManager, times(1))
@@ -6325,7 +6325,7 @@
 
         // Pretend the alarm went off.
         dpms.mMockInjector.setSystemCurrentTimeMillis(PROFILE_OFF_WARNING_TIME + 10);
-        sendBroadcastWithUser(ACTION_PROFILE_OFF_DEADLINE, CALLER_USER_HANDLE);
+        sendBroadcastWithUser(dpms, ACTION_PROFILE_OFF_DEADLINE, CALLER_USER_HANDLE);
 
         // Verify the alarm was scheduled for the actual deadline this time.
         verify(getServices().alarmManager, times(1)).set(anyInt(), eq(PROFILE_OFF_DEADLINE), any());
@@ -6340,7 +6340,7 @@
 
         // Pretend the alarm went off.
         dpms.mMockInjector.setSystemCurrentTimeMillis(PROFILE_OFF_DEADLINE + 10);
-        sendBroadcastWithUser(ACTION_PROFILE_OFF_DEADLINE, CALLER_USER_HANDLE);
+        sendBroadcastWithUser(dpms, ACTION_PROFILE_OFF_DEADLINE, CALLER_USER_HANDLE);
 
         // Verify the alarm was not set.
         verifyZeroInteractions(getServices().alarmManager);
@@ -6364,10 +6364,10 @@
 
         mContext.binder.callingUid = DpmMockContext.SYSTEM_UID;
         setUserUnlocked(CALLER_USER_HANDLE, false);
-        sendBroadcastWithUser(Intent.ACTION_USER_STOPPED, CALLER_USER_HANDLE);
+        sendBroadcastWithUser(dpms, Intent.ACTION_USER_STOPPED, CALLER_USER_HANDLE);
         clearInvocations(getServices().alarmManager);
         setUserUnlocked(CALLER_USER_HANDLE, true);
-        sendBroadcastWithUser(Intent.ACTION_USER_UNLOCKED, CALLER_USER_HANDLE);
+        sendBroadcastWithUser(dpms, Intent.ACTION_USER_UNLOCKED, CALLER_USER_HANDLE);
 
         // Verify that the alarm got discharged.
         verify(getServices().alarmManager, times(1)).cancel((PendingIntent) null);
@@ -6384,16 +6384,16 @@
 
         mContext.binder.callingUid = DpmMockContext.SYSTEM_UID;
         setUserUnlocked(CALLER_USER_HANDLE, false);
-        sendBroadcastWithUser(Intent.ACTION_USER_STOPPED, CALLER_USER_HANDLE);
+        sendBroadcastWithUser(dpms, Intent.ACTION_USER_STOPPED, CALLER_USER_HANDLE);
 
         // Pretend the alarm went off.
         dpms.mMockInjector.setSystemCurrentTimeMillis(PROFILE_OFF_WARNING_TIME + 10);
-        sendBroadcastWithUser(ACTION_PROFILE_OFF_DEADLINE, CALLER_USER_HANDLE);
+        sendBroadcastWithUser(dpms, ACTION_PROFILE_OFF_DEADLINE, CALLER_USER_HANDLE);
 
         clearInvocations(getServices().alarmManager);
         clearInvocations(getServices().notificationManager);
         setUserUnlocked(CALLER_USER_HANDLE, true);
-        sendBroadcastWithUser(Intent.ACTION_USER_UNLOCKED, CALLER_USER_HANDLE);
+        sendBroadcastWithUser(dpms, Intent.ACTION_USER_UNLOCKED, CALLER_USER_HANDLE);
 
         // Verify that the alarm got discharged.
         verify(getServices().alarmManager, times(1)).cancel((PendingIntent) null);
@@ -6413,24 +6413,24 @@
 
         mContext.binder.callingUid = DpmMockContext.SYSTEM_UID;
         setUserUnlocked(CALLER_USER_HANDLE, false);
-        sendBroadcastWithUser(Intent.ACTION_USER_STOPPED, CALLER_USER_HANDLE);
+        sendBroadcastWithUser(dpms, Intent.ACTION_USER_STOPPED, CALLER_USER_HANDLE);
 
         // Pretend the alarm went off after the deadline.
         dpms.mMockInjector.setSystemCurrentTimeMillis(PROFILE_OFF_DEADLINE + 10);
-        sendBroadcastWithUser(ACTION_PROFILE_OFF_DEADLINE, CALLER_USER_HANDLE);
+        sendBroadcastWithUser(dpms, ACTION_PROFILE_OFF_DEADLINE, CALLER_USER_HANDLE);
 
         clearInvocations(getServices().alarmManager);
         clearInvocations(getServices().notificationManager);
         clearInvocations(getServices().ipackageManager);
 
         // Pretend the user clicked on the "apps suspended" notification to turn the profile on.
-        sendBroadcastWithUser(ACTION_TURN_PROFILE_ON_NOTIFICATION, CALLER_USER_HANDLE);
+        sendBroadcastWithUser(dpms, ACTION_TURN_PROFILE_ON_NOTIFICATION, CALLER_USER_HANDLE);
         // Verify that the profile is turned on.
         verify(getServices().userManager, times(1))
                 .requestQuietModeEnabled(eq(false), eq(UserHandle.of(CALLER_USER_HANDLE)));
 
         setUserUnlocked(CALLER_USER_HANDLE, true);
-        sendBroadcastWithUser(Intent.ACTION_USER_UNLOCKED, CALLER_USER_HANDLE);
+        sendBroadcastWithUser(dpms, Intent.ACTION_USER_UNLOCKED, CALLER_USER_HANDLE);
 
         // Verify that the notification is removed (at this point DPC should show it).
         verify(getServices().notificationManager, times(1))
@@ -6454,13 +6454,6 @@
                 .isEqualTo(DevicePolicyManager.PERSONAL_APPS_SUSPENDED_PROFILE_TIMEOUT);
     }
 
-    private void sendBroadcastWithUser(String action, int userHandle) throws Exception {
-        final Intent intent = new Intent(action);
-        intent.putExtra(Intent.EXTRA_USER_HANDLE, userHandle);
-        getServices().injectBroadcast(mServiceContext, intent, userHandle);
-        flushTasks();
-    }
-
     private void setUserUnlocked(int userHandle, boolean unlocked) {
         when(getServices().userManager.isUserUnlocked(eq(userHandle))).thenReturn(unlocked);
     }
@@ -6471,10 +6464,6 @@
 
         when(getServices().userManager.isUserUnlocked()).thenReturn(true);
 
-        // Pretend our admin handles CHECK_POLICY_COMPLIANCE intent.
-        final Intent intent = new Intent(ACTION_CHECK_POLICY_COMPLIANCE);
-        intent.setPackage(admin1.getPackageName());
-
         doReturn(Collections.singletonList(new ResolveInfo()))
                 .when(getServices().packageManager).queryIntentActivitiesAsUser(
                         any(Intent.class), anyInt(), eq(CALLER_USER_HANDLE));
@@ -6674,12 +6663,4 @@
         return new StringParceledListSlice(Arrays.asList(s));
     }
 
-    private void flushTasks() throws Exception {
-        dpms.mHandler.runWithScissors(() -> {}, 0 /*now*/);
-        dpms.mBackgroundHandler.runWithScissors(() -> {}, 0 /*now*/);
-
-        // We can't let exceptions happen on the background thread. Throw them here if they happen
-        // so they still cause the test to fail despite being suppressed.
-        getServices().rethrowBackgroundBroadcastExceptions();
-    }
 }
diff --git a/services/tests/servicestests/src/com/android/server/devicepolicy/DpmTestBase.java b/services/tests/servicestests/src/com/android/server/devicepolicy/DpmTestBase.java
index 9a1a5fb..41d54e9 100644
--- a/services/tests/servicestests/src/com/android/server/devicepolicy/DpmTestBase.java
+++ b/services/tests/servicestests/src/com/android/server/devicepolicy/DpmTestBase.java
@@ -83,6 +83,23 @@
         return mServices;
     }
 
+    protected void sendBroadcastWithUser(DevicePolicyManagerServiceTestable dpms, String action,
+            int userHandle) throws Exception {
+        final Intent intent = new Intent(action);
+        intent.putExtra(Intent.EXTRA_USER_HANDLE, userHandle);
+        getServices().injectBroadcast(getContext(), intent, userHandle);
+        flushTasks(dpms);
+    }
+
+    protected void flushTasks(DevicePolicyManagerServiceTestable dpms) throws Exception {
+        dpms.mHandler.runWithScissors(() -> { }, 0 /*now*/);
+        dpms.mBackgroundHandler.runWithScissors(() -> { }, 0 /*now*/);
+
+        // We can't let exceptions happen on the background thread. Throw them here if they happen
+        // so they still cause the test to fail despite being suppressed.
+        getServices().rethrowBackgroundBroadcastExceptions();
+    }
+
     protected interface DpmRunnable {
         void run(DevicePolicyManager dpm) throws Exception;
     }
@@ -180,7 +197,7 @@
      * @param copyFromAdmin package information for {@code admin} will be built based on this
      *    component's information.
      */
-    private void setUpPackageManagerForFakeAdmin(ComponentName admin, int packageUid,
+    protected void setUpPackageManagerForFakeAdmin(ComponentName admin, int packageUid,
             Integer enabledSetting, Integer appTargetSdk, ComponentName copyFromAdmin)
             throws Exception {
 
diff --git a/services/tests/servicestests/src/com/android/server/integrity/AppIntegrityManagerServiceImplTest.java b/services/tests/servicestests/src/com/android/server/integrity/AppIntegrityManagerServiceImplTest.java
index 53c9bb2..9ca84d3 100644
--- a/services/tests/servicestests/src/com/android/server/integrity/AppIntegrityManagerServiceImplTest.java
+++ b/services/tests/servicestests/src/com/android/server/integrity/AppIntegrityManagerServiceImplTest.java
@@ -121,7 +121,7 @@
     private static final String INSTALLER_SHA256 =
             "30F41A7CBF96EE736A54DD6DF759B50ED3CC126ABCEF694E167C324F5976C227";
     private static final String SOURCE_STAMP_CERTIFICATE_HASH =
-            "681B0E56A796350C08647352A4DB800CC44B2ADC8F4C72FA350BD05D4D50264D";
+            "C6E737809CEF2B08CC6694892215F82A5E8FBC3C2A0F6212770310B90622D2D9";
 
     private static final String DUMMY_APP_TWO_CERTS_CERT_1 =
             "C0369C2A1096632429DFA8433068AECEAD00BAC337CA92A175036D39CC9AFE94";
diff --git a/services/tests/servicestests/src/com/android/server/locksettings/RebootEscrowManagerTests.java b/services/tests/servicestests/src/com/android/server/locksettings/RebootEscrowManagerTests.java
index 4127fec..c4d1211 100644
--- a/services/tests/servicestests/src/com/android/server/locksettings/RebootEscrowManagerTests.java
+++ b/services/tests/servicestests/src/com/android/server/locksettings/RebootEscrowManagerTests.java
@@ -43,6 +43,7 @@
 import android.content.pm.UserInfo;
 import android.hardware.rebootescrow.IRebootEscrow;
 import android.os.RemoteException;
+import android.os.ServiceSpecificException;
 import android.os.UserManager;
 import android.platform.test.annotations.Presubmit;
 
@@ -178,6 +179,13 @@
     }
 
     @Test
+    public void clearCredentials_HalFailure_NonFatal() throws Exception {
+        doThrow(ServiceSpecificException.class).when(mRebootEscrow).storeKey(any());
+        mService.clearRebootEscrow();
+        verify(mRebootEscrow).storeKey(eq(new byte[32]));
+    }
+
+    @Test
     public void armService_Success() throws Exception {
         RebootEscrowListener mockListener = mock(RebootEscrowListener.class);
         mService.setRebootEscrowListener(mockListener);
@@ -200,6 +208,24 @@
     }
 
     @Test
+    public void armService_HalFailure_NonFatal() throws Exception {
+        RebootEscrowListener mockListener = mock(RebootEscrowListener.class);
+        mService.setRebootEscrowListener(mockListener);
+        mService.prepareRebootEscrow();
+
+        clearInvocations(mRebootEscrow);
+        mService.callToRebootEscrowIfNeeded(PRIMARY_USER_ID, FAKE_SP_VERSION, FAKE_AUTH_TOKEN);
+        verify(mockListener).onPreparedForReboot(eq(true));
+        verify(mRebootEscrow, never()).storeKey(any());
+
+        assertNull(
+                mStorage.getString(RebootEscrowManager.REBOOT_ESCROW_ARMED_KEY, null, USER_SYSTEM));
+        doThrow(ServiceSpecificException.class).when(mRebootEscrow).storeKey(any());
+        assertFalse(mService.armRebootEscrowIfNeeded());
+        verify(mRebootEscrow).storeKey(any());
+    }
+
+    @Test
     public void armService_MultipleUsers_Success() throws Exception {
         RebootEscrowListener mockListener = mock(RebootEscrowListener.class);
         mService.setRebootEscrowListener(mockListener);
diff --git a/services/tests/servicestests/src/com/android/server/people/prediction/ShareTargetPredictorTest.java b/services/tests/servicestests/src/com/android/server/people/prediction/ShareTargetPredictorTest.java
index 60104d3..b09a3c3 100644
--- a/services/tests/servicestests/src/com/android/server/people/prediction/ShareTargetPredictorTest.java
+++ b/services/tests/servicestests/src/com/android/server/people/prediction/ShareTargetPredictorTest.java
@@ -117,10 +117,10 @@
 
     @Test
     public void testPredictTargets() {
-        mShareShortcuts.add(buildShareShortcut(PACKAGE_1, CLASS_1, "sc1"));
-        mShareShortcuts.add(buildShareShortcut(PACKAGE_1, CLASS_1, "sc2"));
-        mShareShortcuts.add(buildShareShortcut(PACKAGE_2, CLASS_2, "sc3"));
-        mShareShortcuts.add(buildShareShortcut(PACKAGE_2, CLASS_2, "sc4"));
+        mShareShortcuts.add(buildShareShortcut(PACKAGE_1, CLASS_1, "sc1", 0));
+        mShareShortcuts.add(buildShareShortcut(PACKAGE_1, CLASS_1, "sc2", 0));
+        mShareShortcuts.add(buildShareShortcut(PACKAGE_2, CLASS_2, "sc3", 0));
+        mShareShortcuts.add(buildShareShortcut(PACKAGE_2, CLASS_2, "sc4", 0));
 
         when(mPackageData1.getConversationInfo("sc1")).thenReturn(mock(ConversationInfo.class));
         when(mPackageData1.getConversationInfo("sc2")).thenReturn(mock(ConversationInfo.class));
@@ -165,12 +165,12 @@
 
     @Test
     public void testPredictTargets_reachTargetsLimit() {
-        mShareShortcuts.add(buildShareShortcut(PACKAGE_1, CLASS_1, "sc1"));
-        mShareShortcuts.add(buildShareShortcut(PACKAGE_1, CLASS_1, "sc2"));
-        mShareShortcuts.add(buildShareShortcut(PACKAGE_2, CLASS_2, "sc3"));
-        mShareShortcuts.add(buildShareShortcut(PACKAGE_2, CLASS_2, "sc4"));
-        mShareShortcuts.add(buildShareShortcut(PACKAGE_1, CLASS_1, "sc5"));
-        mShareShortcuts.add(buildShareShortcut(PACKAGE_2, CLASS_2, "sc6"));
+        mShareShortcuts.add(buildShareShortcut(PACKAGE_1, CLASS_1, "sc1", 0));
+        mShareShortcuts.add(buildShareShortcut(PACKAGE_1, CLASS_1, "sc2", 0));
+        mShareShortcuts.add(buildShareShortcut(PACKAGE_2, CLASS_2, "sc3", 0));
+        mShareShortcuts.add(buildShareShortcut(PACKAGE_2, CLASS_2, "sc4", 0));
+        mShareShortcuts.add(buildShareShortcut(PACKAGE_1, CLASS_1, "sc5", 0));
+        mShareShortcuts.add(buildShareShortcut(PACKAGE_2, CLASS_2, "sc6", 0));
 
         when(mPackageData1.getConversationInfo("sc1")).thenReturn(mock(ConversationInfo.class));
         when(mPackageData1.getConversationInfo("sc2")).thenReturn(mock(ConversationInfo.class));
@@ -250,6 +250,41 @@
     }
 
     @Test
+    public void testPredictTargets_noSharingHistoryRankedByShortcutRank() {
+        mShareShortcuts.add(buildShareShortcut(PACKAGE_1, CLASS_1, "sc1", 3));
+        mShareShortcuts.add(buildShareShortcut(PACKAGE_1, CLASS_1, "sc2", 2));
+        mShareShortcuts.add(buildShareShortcut(PACKAGE_2, CLASS_2, "sc3", 1));
+        mShareShortcuts.add(buildShareShortcut(PACKAGE_2, CLASS_2, "sc4", 0));
+
+        when(mPackageData1.getConversationInfo("sc1")).thenReturn(mock(ConversationInfo.class));
+        when(mPackageData1.getConversationInfo("sc2")).thenReturn(mock(ConversationInfo.class));
+        when(mPackageData2.getConversationInfo("sc3")).thenReturn(mock(ConversationInfo.class));
+        // "sc4" does not have a ConversationInfo.
+
+        mPredictor.predictTargets();
+
+        verify(mUpdatePredictionsMethod).accept(mAppTargetCaptor.capture());
+        List<AppTarget> res = mAppTargetCaptor.getValue();
+        assertEquals(4, res.size());
+
+        assertEquals("sc4", res.get(0).getId().getId());
+        assertEquals(CLASS_2, res.get(0).getClassName());
+        assertEquals(PACKAGE_2, res.get(0).getPackageName());
+
+        assertEquals("sc3", res.get(1).getId().getId());
+        assertEquals(CLASS_2, res.get(1).getClassName());
+        assertEquals(PACKAGE_2, res.get(1).getPackageName());
+
+        assertEquals("sc2", res.get(2).getId().getId());
+        assertEquals(CLASS_1, res.get(2).getClassName());
+        assertEquals(PACKAGE_1, res.get(2).getPackageName());
+
+        assertEquals("sc1", res.get(3).getId().getId());
+        assertEquals(CLASS_1, res.get(3).getClassName());
+        assertEquals(PACKAGE_1, res.get(3).getPackageName());
+    }
+
+    @Test
     public void testSortTargets() {
         AppTarget appTarget1 = new AppTarget.Builder(
                 new AppTargetId("cls1#pkg1"), PACKAGE_1, UserHandle.of(USER_ID))
@@ -348,19 +383,20 @@
     }
 
     private static ShareShortcutInfo buildShareShortcut(
-            String packageName, String className, String shortcutId) {
-        ShortcutInfo shortcutInfo = buildShortcut(packageName, shortcutId);
+            String packageName, String className, String shortcutId, int rank) {
+        ShortcutInfo shortcutInfo = buildShortcut(packageName, shortcutId, rank);
         ComponentName componentName = new ComponentName(packageName, className);
         return new ShareShortcutInfo(shortcutInfo, componentName);
     }
 
-    private static ShortcutInfo buildShortcut(String packageName, String shortcutId) {
+    private static ShortcutInfo buildShortcut(String packageName, String shortcutId, int rank) {
         Context mockContext = mock(Context.class);
         when(mockContext.getPackageName()).thenReturn(packageName);
         when(mockContext.getUserId()).thenReturn(USER_ID);
         when(mockContext.getUser()).thenReturn(UserHandle.of(USER_ID));
         ShortcutInfo.Builder builder = new ShortcutInfo.Builder(mockContext, shortcutId)
                 .setShortLabel(shortcutId)
+                .setRank(rank)
                 .setIntent(new Intent("TestIntent"));
         return builder.build();
     }
diff --git a/services/tests/servicestests/src/com/android/server/pm/SELinuxMMACTest.java b/services/tests/servicestests/src/com/android/server/pm/SELinuxMMACTest.java
index efc1c05..a550b27 100644
--- a/services/tests/servicestests/src/com/android/server/pm/SELinuxMMACTest.java
+++ b/services/tests/servicestests/src/com/android/server/pm/SELinuxMMACTest.java
@@ -52,7 +52,7 @@
     @Test
     public void getSeInfoOptInToLatest() {
         AndroidPackage pkg = makePackage(Build.VERSION_CODES.P);
-        when(mMockCompatibility.isChangeEnabled(eq(SELinuxMMAC.SELINUX_LATEST_CHANGES),
+        when(mMockCompatibility.isChangeEnabledInternal(eq(SELinuxMMAC.SELINUX_LATEST_CHANGES),
                 argThat(argument -> argument.packageName.equals(pkg.getPackageName()))))
                 .thenReturn(true);
         assertThat(SELinuxMMAC.getSeInfo(pkg, null, mMockCompatibility),
@@ -62,7 +62,7 @@
     @Test
     public void getSeInfoNoOptIn() {
         AndroidPackage pkg = makePackage(Build.VERSION_CODES.P);
-        when(mMockCompatibility.isChangeEnabled(eq(SELinuxMMAC.SELINUX_LATEST_CHANGES),
+        when(mMockCompatibility.isChangeEnabledInternal(eq(SELinuxMMAC.SELINUX_LATEST_CHANGES),
                 argThat(argument -> argument.packageName.equals(pkg.getPackageName()))))
                 .thenReturn(false);
         assertThat(SELinuxMMAC.getSeInfo(pkg, null, mMockCompatibility),
@@ -72,7 +72,7 @@
     @Test
     public void getSeInfoNoOptInButAlreadyR() {
         AndroidPackage pkg = makePackage(OPT_IN_VERSION);
-        when(mMockCompatibility.isChangeEnabled(eq(SELinuxMMAC.SELINUX_LATEST_CHANGES),
+        when(mMockCompatibility.isChangeEnabledInternal(eq(SELinuxMMAC.SELINUX_LATEST_CHANGES),
                 argThat(argument -> argument.packageName.equals(pkg.getPackageName()))))
                 .thenReturn(false);
         assertThat(SELinuxMMAC.getSeInfo(pkg, null, mMockCompatibility),
diff --git a/services/tests/servicestests/src/com/android/server/pm/UserSystemPackageInstallerTest.java b/services/tests/servicestests/src/com/android/server/pm/UserSystemPackageInstallerTest.java
index c55df51..87979fb 100644
--- a/services/tests/servicestests/src/com/android/server/pm/UserSystemPackageInstallerTest.java
+++ b/services/tests/servicestests/src/com/android/server/pm/UserSystemPackageInstallerTest.java
@@ -366,9 +366,75 @@
         for (PackageInfo p : packageInfos) {
             actualPackages.add(p.packageName);
         }
+
+        // Add auto-generated RRO package to expectedPackages since they are not (supposed to be)
+        // in the whitelist but they should be installed.
+        for (PackageInfo p : packageInfos) {
+            if (p.isOverlayPackage()
+                        && UserSystemPackageInstaller.hasAutoGeneratedRROSuffix(p.packageName)
+                        && expectedPackages.contains(p.overlayTarget)) {
+                expectedPackages.add(p.packageName);
+            }
+        }
         checkPackageDifferences(expectedPackages, actualPackages);
     }
 
+    @Test
+    public void testAutoGeneratedRROMatchesSuffix() {
+        final List<PackageInfo> packageInfos = mContext.getPackageManager()
+                .getInstalledPackages(PackageManager.GET_UNINSTALLED_PACKAGES);
+
+        Log.v(TAG, "Found total packages: " + packageInfos.size());
+
+        for (PackageInfo p : packageInfos) {
+            if (p.packageName.contains(".auto_generated_rro_")) {
+                assertTrue("Auto-generated RRO package name does not match the suffix: "
+                        + p.packageName,
+                        UserSystemPackageInstaller.hasAutoGeneratedRROSuffix(p.packageName));
+            }
+        }
+    }
+
+    /**
+     * Test that overlay package not in whitelist should be installed for all user at Explicit mode.
+     */
+    @Test
+    public void testInstallOverlayPackagesExplicitMode() {
+        setUserTypePackageWhitelistMode(USER_TYPE_PACKAGE_WHITELIST_MODE_ENFORCE);
+
+        final String[] userTypes = new String[]{"type"};
+        final long maskOfType = 0b0001L;
+
+        final String packageName1 = "whitelistedPkg";
+        final String packageName2 = "nonWhitelistedPkg";
+        final String overlayName1 = String.format("%s.auto_generated_rro_product__", packageName1);
+        final String overlayName2 = String.format("%s.auto_generated_rro_product__", packageName2);
+
+        final AndroidPackage overlayPackage1 = ((ParsedPackage) PackageImpl.forTesting(overlayName1)
+                .setOverlay(true)
+                .setOverlayTarget(packageName1)
+                .hideAsParsed())
+                .hideAsFinal();
+
+        final AndroidPackage overlayPackage2 = ((ParsedPackage) PackageImpl.forTesting(overlayName2)
+                .setOverlay(true)
+                .setOverlayTarget(packageName2)
+                .hideAsParsed())
+                .hideAsFinal();
+
+        final ArrayMap<String, Long> userTypeWhitelist = new ArrayMap<>();
+        userTypeWhitelist.put(packageName1, maskOfType);
+
+        final Set<String> userWhitelist = new ArraySet<>();
+        userWhitelist.add(packageName1);
+
+        boolean implicit = false;
+        assertTrue("Overlay for package1 should be installed", UserSystemPackageInstaller
+                .shouldInstallPackage(overlayPackage1, userTypeWhitelist, userWhitelist, implicit));
+        assertFalse("Overlay for package2 should not be installed", UserSystemPackageInstaller
+                .shouldInstallPackage(overlayPackage2, userTypeWhitelist, userWhitelist, implicit));
+    }
+
     /** Asserts that actual is a subset of expected. */
     private void checkPackageDifferences(Set<String> expected, Set<String> actual) {
         final Set<String> uniqueToExpected = new ArraySet<>(expected);
diff --git a/services/tests/servicestests/src/com/android/server/power/PreRebootLoggerTest.java b/services/tests/servicestests/src/com/android/server/power/PreRebootLoggerTest.java
index a138234..45574fc 100644
--- a/services/tests/servicestests/src/com/android/server/power/PreRebootLoggerTest.java
+++ b/services/tests/servicestests/src/com/android/server/power/PreRebootLoggerTest.java
@@ -23,6 +23,9 @@
 import static org.mockito.Mockito.when;
 
 import android.content.Context;
+import android.content.pm.PackageInstaller;
+import android.content.pm.PackageInstaller.SessionInfo;
+import android.content.pm.PackageManager;
 import android.provider.Settings;
 import android.test.mock.MockContentResolver;
 
@@ -36,12 +39,15 @@
 import org.junit.AfterClass;
 import org.junit.Before;
 import org.junit.BeforeClass;
+import org.junit.Rule;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.mockito.Mock;
-import org.mockito.MockitoAnnotations;
+import org.mockito.junit.MockitoJUnit;
+import org.mockito.junit.MockitoRule;
 
 import java.io.File;
+import java.util.List;
 
 /**
  * Tests for {@link PreRebootLogger}
@@ -49,7 +55,11 @@
 @SmallTest
 @RunWith(AndroidJUnit4.class)
 public class PreRebootLoggerTest {
+    @Rule public final MockitoRule mocks = MockitoJUnit.rule();
     @Mock Context mContext;
+    @Mock PackageManager mPackageManager;
+    @Mock PackageInstaller mPackageInstaller;
+    @Mock List<SessionInfo> mSessions;
     private MockContentResolver mContentResolver;
     private File mDumpDir;
 
@@ -64,29 +74,53 @@
     }
 
     @Before
-    public void setup() {
-        MockitoAnnotations.initMocks(this);
+    public void enableAdbConfig() {
         mContentResolver = new MockContentResolver(getInstrumentation().getTargetContext());
         when(mContext.getContentResolver()).thenReturn(mContentResolver);
         mContentResolver.addProvider(Settings.AUTHORITY, new FakeSettingsProvider());
+        Settings.Global.putInt(mContentResolver, Settings.Global.ADB_ENABLED, 1);
+    }
 
+    @Before
+    public void prepareActiveStagedSessions() {
+        when(mContext.getPackageManager()).thenReturn(mPackageManager);
+        when(mPackageManager.getPackageInstaller()).thenReturn(mPackageInstaller);
+        when(mPackageInstaller.getActiveStagedSessions()).thenReturn(mSessions);
+        when(mSessions.isEmpty()).thenReturn(false);
+    }
+
+    @Before
+    public void setupDumpDir() {
         mDumpDir = Files.createTempDir();
-        mDumpDir.mkdir();
         mDumpDir.deleteOnExit();
     }
 
     @Test
-    public void log_adbEnabled_dumpsInformationProperly() {
-        Settings.Global.putInt(mContentResolver, Settings.Global.ADB_ENABLED, 1);
-
+    public void log_dumpsInformationProperly() {
         PreRebootLogger.log(mContext, mDumpDir);
 
         assertThat(mDumpDir.list()).asList().containsExactly("system", "package", "rollback");
     }
 
     @Test
+    public void dump_exceedTimeout_wontBlockCurrentThread() {
+        PreRebootLogger.dump(mDumpDir, 1 /* maxWaitTime */);
+
+        assertThat(mDumpDir.listFiles()).asList().containsNoneOf("system", "package", "rollback");
+    }
+
+    @Test
+    public void log_noActiveStagedSession_wipesDumpedInformation() {
+        PreRebootLogger.log(mContext, mDumpDir);
+        when(mSessions.isEmpty()).thenReturn(true);
+
+        PreRebootLogger.log(mContext, mDumpDir);
+
+        assertThat(mDumpDir.listFiles()).isEmpty();
+    }
+
+    @Test
     public void log_adbDisabled_wipesDumpedInformation() {
-        Settings.Global.putInt(mContentResolver, Settings.Global.ADB_ENABLED, 1);
         PreRebootLogger.log(mContext, mDumpDir);
         Settings.Global.putInt(mContentResolver, Settings.Global.ADB_ENABLED, 0);
 
diff --git a/services/tests/servicestests/src/com/android/server/textclassifier/FixedSizeQueueTest.java b/services/tests/servicestests/src/com/android/server/textclassifier/FixedSizeQueueTest.java
new file mode 100644
index 0000000..90527b8
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/textclassifier/FixedSizeQueueTest.java
@@ -0,0 +1,109 @@
+/*
+ * Copyright (C) 2020 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.textclassifier;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import org.junit.Test;
+
+import java.util.ArrayList;
+import java.util.List;
+
+public class FixedSizeQueueTest {
+
+    @Test
+    public void add_belowMaxCapacity() {
+        FixedSizeQueue<Integer> queue = new FixedSizeQueue<>(1, /* onEntryEvictedListener= */ null);
+        assertThat(queue.size()).isEqualTo(0);
+
+        queue.add(1);
+
+        assertThat(queue.size()).isEqualTo(1);
+        assertThat(queue.poll()).isEqualTo(1);
+    }
+
+    @Test
+    public void add_exceedMaxCapacity() {
+        FixedSizeQueue<Integer> queue = new FixedSizeQueue<>(2, /* onEntryEvictedListener= */ null);
+
+        queue.add(1);
+        queue.add(2);
+        queue.add(3);
+
+        assertThat(queue.size()).isEqualTo(2);
+        assertThat(queue.poll()).isEqualTo(2);
+        assertThat(queue.poll()).isEqualTo(3);
+    }
+
+    @Test
+    public void poll() {
+        FixedSizeQueue<Integer> queue = new FixedSizeQueue<>(1, /* onEntryEvictedListener= */ null);
+
+        queue.add(1);
+
+        assertThat(queue.poll()).isEqualTo(1);
+        assertThat(queue.poll()).isNull();
+    }
+
+    @Test
+    public void remove() {
+        FixedSizeQueue<Integer> queue = new FixedSizeQueue<>(1, /* onEntryEvictedListener= */ null);
+
+        queue.add(1);
+
+        assertThat(queue.remove(1)).isTrue();
+        assertThat(queue.isEmpty()).isTrue();
+    }
+
+    @Test
+    public void remove_noSuchElement() {
+        FixedSizeQueue<Integer> queue = new FixedSizeQueue<>(1, /* onEntryEvictedListener= */ null);
+
+        queue.add(1);
+
+        assertThat(queue.remove(2)).isFalse();
+    }
+
+    @Test
+    public void isEmpty_true() {
+        FixedSizeQueue<Integer> queue = new FixedSizeQueue<>(1, /* onEntryEvictedListener= */ null);
+
+        assertThat(queue.isEmpty()).isTrue();
+    }
+
+    @Test
+    public void isEmpty_false() {
+        FixedSizeQueue<Integer> queue = new FixedSizeQueue<>(1, /* onEntryEvictedListener= */ null);
+
+        queue.add(1);
+
+        assertThat(queue.isEmpty()).isFalse();
+    }
+
+    @Test
+    public void onEntryEvicted() {
+        List<Integer> onEntryEvictedElements = new ArrayList<>();
+        FixedSizeQueue<Integer> queue =
+                new FixedSizeQueue<>(1, onEntryEvictedElements::add);
+
+        queue.add(1);
+        queue.add(2);
+        queue.add(3);
+
+        assertThat(onEntryEvictedElements).containsExactly(1, 2).inOrder();
+    }
+}
diff --git a/services/tests/uiservicestests/src/com/android/server/UiModeManagerServiceTest.java b/services/tests/uiservicestests/src/com/android/server/UiModeManagerServiceTest.java
index 3062584..b100c84 100644
--- a/services/tests/uiservicestests/src/com/android/server/UiModeManagerServiceTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/UiModeManagerServiceTest.java
@@ -31,9 +31,10 @@
 import android.os.PowerManagerInternal;
 import android.os.PowerSaveState;
 import android.os.RemoteException;
-import android.provider.Settings;
 import android.testing.AndroidTestingRunner;
 import android.testing.TestableLooper;
+
+import com.android.server.twilight.TwilightListener;
 import com.android.server.twilight.TwilightManager;
 import com.android.server.twilight.TwilightState;
 import com.android.server.wm.WindowManagerInternal;
@@ -55,7 +56,6 @@
 import static junit.framework.TestCase.assertTrue;
 import static org.junit.Assert.assertEquals;
 import static org.mockito.ArgumentMatchers.any;
-import static org.mockito.ArgumentMatchers.anyBoolean;
 import static org.mockito.ArgumentMatchers.anyInt;
 import static org.mockito.ArgumentMatchers.anyLong;
 import static org.mockito.ArgumentMatchers.anyString;
@@ -65,6 +65,7 @@
 import static org.mockito.Mockito.atLeast;
 import static org.mockito.Mockito.atLeastOnce;
 import static org.mockito.Mockito.doAnswer;
+import static org.mockito.Mockito.doReturn;
 import static org.mockito.Mockito.times;
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
@@ -100,6 +101,7 @@
     private BroadcastReceiver mTimeChangedCallback;
     private AlarmManager.OnAlarmListener mCustomListener;
     private Consumer<PowerSaveState> mPowerSaveConsumer;
+    private TwilightListener mTwilightListener;
 
     @Before
     public void setUp() {
@@ -107,6 +109,10 @@
         when(mContext.checkCallingOrSelfPermission(anyString()))
                 .thenReturn(PackageManager.PERMISSION_GRANTED);
         doAnswer(inv -> {
+            mTwilightListener = (TwilightListener) inv.getArgument(0);
+            return null;
+        }).when(mTwilightManager).registerListener(any(), any());
+        doAnswer(inv -> {
             mPowerSaveConsumer = (Consumer<PowerSaveState>) inv.getArgument(1);
             return null;
         }).when(mLocalPowerManager).registerLowPowerModeObserver(anyInt(), any());
@@ -160,6 +166,37 @@
     }
 
     @Test
+    public void setNightMoveActivated_overridesFunctionCorrectly() throws RemoteException {
+        // set up
+        when(mPowerManager.isInteractive()).thenReturn(false);
+        mService.setNightMode(MODE_NIGHT_NO);
+        assertFalse(mUiManagerService.getConfiguration().isNightModeActive());
+
+        // assume it is day time
+        doReturn(false).when(mTwilightState).isNight();
+
+        // set mode to auto
+        mService.setNightMode(MODE_NIGHT_AUTO);
+
+        // set night mode on overriding current config
+        mService.setNightModeActivated(true);
+
+        assertTrue(mUiManagerService.getConfiguration().isNightModeActive());
+
+        // now it is night time
+        doReturn(true).when(mTwilightState).isNight();
+        mTwilightListener.onTwilightStateChanged(mTwilightState);
+
+        assertTrue(mUiManagerService.getConfiguration().isNightModeActive());
+
+        // now it is next day mid day
+        doReturn(false).when(mTwilightState).isNight();
+        mTwilightListener.onTwilightStateChanged(mTwilightState);
+
+        assertFalse(mUiManagerService.getConfiguration().isNightModeActive());
+    }
+
+    @Test
     public void setAutoMode_screenOffRegistered() throws RemoteException {
         try {
             mService.setNightMode(MODE_NIGHT_NO);
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 de9b77c..ef4d5db 100755
--- a/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
@@ -178,6 +178,7 @@
 
 import org.junit.After;
 import org.junit.Before;
+import org.junit.Ignore;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.mockito.ArgumentCaptor;
@@ -347,6 +348,11 @@
             super.setNotificationAssistantAccessGrantedForUserInternal(assistant, userId, granted);
         }
 
+        @Override
+        protected String[] getStringArrayResource(int key) {
+            return new String[] {PKG_O};
+        }
+
         private void setNotificationAssistantAccessGrantedCallback(
                 @Nullable NotificationAssistantAccessGrantedCallback callback) {
             this.mNotificationAssistantAccessGrantedCallback = callback;
@@ -434,7 +440,8 @@
 
         // Setup managed services
         mListener = mListeners.new ManagedServiceInfo(
-                null, new ComponentName(PKG, "test_class"), mUid, true, null, 0);
+                null, new ComponentName(PKG, "test_class"),
+                UserHandle.getUserId(mUid), true, null, 0);
         ComponentName defaultComponent = ComponentName.unflattenFromString("config/device");
         ArraySet<ComponentName> components = new ArraySet<>();
         components.add(defaultComponent);
@@ -444,7 +451,7 @@
         when(mAssistants.getDefaultComponents()).thenReturn(components);
         when(mAssistants.queryPackageForServices(
                 anyString(), anyInt(), anyInt())).thenReturn(components);
-        when(mListeners.checkServiceTokenLocked(any())).thenReturn(mListener);
+        when(mListeners.checkServiceTokenLocked(null)).thenReturn(mListener);
         ManagedServices.Config listenerConfig = new ManagedServices.Config();
         listenerConfig.xmlTag = NotificationListeners.TAG_ENABLED_NOTIFICATION_LISTENERS;
         when(mListeners.getConfig()).thenReturn(listenerConfig);
@@ -497,6 +504,10 @@
 
         mBinderService.createNotificationChannels(
                 PKG, new ParceledListSlice(Arrays.asList(mTestNotificationChannel)));
+        mBinderService.createNotificationChannels(
+                PKG_P, new ParceledListSlice(Arrays.asList(mTestNotificationChannel)));
+        mBinderService.createNotificationChannels(
+                PKG_O, new ParceledListSlice(Arrays.asList(mTestNotificationChannel)));
         assertNotNull(mBinderService.getNotificationChannel(
                 PKG, mContext.getUserId(), PKG, TEST_CHANNEL_ID));
         clearInvocations(mRankingHandler);
@@ -583,7 +594,7 @@
                 .setGroupSummary(isSummary);
         StatusBarNotification sbn = new StatusBarNotification(PKG, PKG, id,
                 "tag" + System.currentTimeMillis(), mUid, 0,
-                nb.build(), new UserHandle(mUid), null, 0);
+                nb.build(), UserHandle.getUserHandleForUid(mUid), null, 0);
         return new NotificationRecord(mContext, sbn, channel);
     }
 
@@ -603,7 +614,7 @@
             nb.extend(extender);
         }
         StatusBarNotification sbn = new StatusBarNotification(PKG, PKG, 8, "tag", mUid, 0,
-                nb.build(), new UserHandle(mUid), null, 0);
+                nb.build(), UserHandle.getUserHandleForUid(mUid), null, 0);
         return new NotificationRecord(mContext, sbn, channel);
     }
 
@@ -635,7 +646,7 @@
         Notification.Builder nb = getMessageStyleNotifBuilder(addMetadata, groupKey, isSummary);
         StatusBarNotification sbn = new StatusBarNotification(PKG, PKG, id,
                 tag, mUid, 0,
-                nb.build(), new UserHandle(mUid), null, 0);
+                nb.build(), UserHandle.getUserHandleForUid(mUid), null, 0);
         return new NotificationRecord(mContext, sbn, channel);
     }
 
@@ -1328,6 +1339,7 @@
     }
 
     @Test
+    @Ignore
     public void testPostCancelPostNotifiesListeners() throws Exception {
         // WHEN a notification is posted
         final StatusBarNotification sbn = generateNotificationRecord(null).getSbn();
@@ -1687,7 +1699,7 @@
                         .setSmallIcon(android.R.drawable.sym_def_app_icon)
                         .build();
         StatusBarNotification sbn = new StatusBarNotification("a", "a", 0, null, mUid, 0,
-                n, new UserHandle(mUid), null, 0);
+                n, UserHandle.getUserHandleForUid(mUid), null, 0);
         sbn.getNotification().flags |= FLAG_FOREGROUND_SERVICE;
         mBinderService.enqueueNotificationWithTag(PKG, PKG, null,
                 sbn.getId(), sbn.getNotification(), sbn.getUserId());
@@ -2191,7 +2203,8 @@
     public void testCreateChannelNotifyListener() throws Exception {
         List<String> associations = new ArrayList<>();
         associations.add("a");
-        when(mCompanionMgr.getAssociations(PKG, mUid)).thenReturn(associations);
+        when(mCompanionMgr.getAssociations(PKG, UserHandle.getUserId(mUid)))
+                .thenReturn(associations);
         mService.setPreferencesHelper(mPreferencesHelper);
         when(mPreferencesHelper.getNotificationChannel(eq(PKG), anyInt(),
                 eq(mTestNotificationChannel.getId()), anyBoolean()))
@@ -2219,7 +2232,8 @@
     public void testCreateChannelGroupNotifyListener() throws Exception {
         List<String> associations = new ArrayList<>();
         associations.add("a");
-        when(mCompanionMgr.getAssociations(PKG, mUid)).thenReturn(associations);
+        when(mCompanionMgr.getAssociations(PKG, UserHandle.getUserId(mUid)))
+                .thenReturn(associations);
         mService.setPreferencesHelper(mPreferencesHelper);
         NotificationChannelGroup group1 = new NotificationChannelGroup("a", "b");
         NotificationChannelGroup group2 = new NotificationChannelGroup("n", "m");
@@ -2239,7 +2253,8 @@
     public void testUpdateChannelNotifyListener() throws Exception {
         List<String> associations = new ArrayList<>();
         associations.add("a");
-        when(mCompanionMgr.getAssociations(PKG, mUid)).thenReturn(associations);
+        when(mCompanionMgr.getAssociations(PKG, UserHandle.getUserId(mUid)))
+                .thenReturn(associations);
         mService.setPreferencesHelper(mPreferencesHelper);
         mTestNotificationChannel.setLightColor(Color.CYAN);
         when(mPreferencesHelper.getNotificationChannel(eq(PKG), anyInt(),
@@ -2257,7 +2272,8 @@
     public void testDeleteChannelNotifyListener() throws Exception {
         List<String> associations = new ArrayList<>();
         associations.add("a");
-        when(mCompanionMgr.getAssociations(PKG, mUid)).thenReturn(associations);
+        when(mCompanionMgr.getAssociations(PKG, UserHandle.getUserId(mUid)))
+                .thenReturn(associations);
         mService.setPreferencesHelper(mPreferencesHelper);
         when(mPreferencesHelper.getNotificationChannel(eq(PKG), anyInt(),
                 eq(mTestNotificationChannel.getId()), anyBoolean()))
@@ -2273,7 +2289,8 @@
     public void testDeleteChannelGroupNotifyListener() throws Exception {
         List<String> associations = new ArrayList<>();
         associations.add("a");
-        when(mCompanionMgr.getAssociations(PKG, mUid)).thenReturn(associations);
+        when(mCompanionMgr.getAssociations(PKG, UserHandle.getUserId(mUid)))
+                .thenReturn(associations);
         NotificationChannelGroup ncg = new NotificationChannelGroup("a", "b/c");
         mService.setPreferencesHelper(mPreferencesHelper);
         when(mPreferencesHelper.getNotificationChannelGroup(eq(ncg.getId()), eq(PKG), anyInt()))
@@ -2290,7 +2307,8 @@
         mService.setPreferencesHelper(mPreferencesHelper);
         List<String> associations = new ArrayList<>();
         associations.add("a");
-        when(mCompanionMgr.getAssociations(PKG, mUid)).thenReturn(associations);
+        when(mCompanionMgr.getAssociations(PKG, UserHandle.getUserId(mUid)))
+                .thenReturn(associations);
         when(mPreferencesHelper.getNotificationChannel(eq(PKG), anyInt(),
                 eq(mTestNotificationChannel.getId()), anyBoolean()))
                 .thenReturn(mTestNotificationChannel);
@@ -2310,7 +2328,8 @@
     public void testUpdateNotificationChannelFromPrivilegedListener_noAccess() throws Exception {
         mService.setPreferencesHelper(mPreferencesHelper);
         List<String> associations = new ArrayList<>();
-        when(mCompanionMgr.getAssociations(PKG, mUid)).thenReturn(associations);
+        when(mCompanionMgr.getAssociations(PKG, UserHandle.getUserId(mUid)))
+                .thenReturn(associations);
 
         try {
             mBinderService.updateNotificationChannelFromPrivilegedListener(
@@ -2333,7 +2352,8 @@
         mService.setPreferencesHelper(mPreferencesHelper);
         List<String> associations = new ArrayList<>();
         associations.add("a");
-        when(mCompanionMgr.getAssociations(PKG, mUid)).thenReturn(associations);
+        when(mCompanionMgr.getAssociations(PKG, UserHandle.getUserId(mUid)))
+                .thenReturn(associations);
         mListener = mock(ManagedServices.ManagedServiceInfo.class);
         mListener.component = new ComponentName(PKG, PKG);
         when(mListener.enabledAndUserMatches(anyInt())).thenReturn(false);
@@ -2360,7 +2380,8 @@
         mService.setPreferencesHelper(mPreferencesHelper);
         List<String> associations = new ArrayList<>();
         associations.add("a");
-        when(mCompanionMgr.getAssociations(PKG, mUid)).thenReturn(associations);
+        when(mCompanionMgr.getAssociations(PKG, UserHandle.getUserId(mUid)))
+                .thenReturn(associations);
 
         mBinderService.getNotificationChannelsFromPrivilegedListener(
                 null, PKG, Process.myUserHandle());
@@ -2373,7 +2394,8 @@
     public void testGetNotificationChannelFromPrivilegedListener_cdm_noAccess() throws Exception {
         mService.setPreferencesHelper(mPreferencesHelper);
         List<String> associations = new ArrayList<>();
-        when(mCompanionMgr.getAssociations(PKG, mUid)).thenReturn(associations);
+        when(mCompanionMgr.getAssociations(PKG, UserHandle.getUserId(mUid)))
+                .thenReturn(associations);
 
         try {
             mBinderService.getNotificationChannelsFromPrivilegedListener(
@@ -2391,7 +2413,8 @@
     public void testGetNotificationChannelFromPrivilegedListener_assistant_success()
             throws Exception {
         mService.setPreferencesHelper(mPreferencesHelper);
-        when(mCompanionMgr.getAssociations(PKG, mUid)).thenReturn(new ArrayList<>());
+        when(mCompanionMgr.getAssociations(PKG, UserHandle.getUserId(mUid)))
+                .thenReturn(new ArrayList<>());
         when(mAssistants.isServiceTokenValidLocked(any())).thenReturn(true);
 
         mBinderService.getNotificationChannelsFromPrivilegedListener(
@@ -2405,7 +2428,8 @@
     public void testGetNotificationChannelFromPrivilegedListener_assistant_noAccess()
             throws Exception {
         mService.setPreferencesHelper(mPreferencesHelper);
-        when(mCompanionMgr.getAssociations(PKG, mUid)).thenReturn(new ArrayList<>());
+        when(mCompanionMgr.getAssociations(PKG, UserHandle.getUserId(mUid)))
+                .thenReturn(new ArrayList<>());
         when(mAssistants.isServiceTokenValidLocked(any())).thenReturn(false);
 
         try {
@@ -2425,7 +2449,8 @@
         mService.setPreferencesHelper(mPreferencesHelper);
         List<String> associations = new ArrayList<>();
         associations.add("a");
-        when(mCompanionMgr.getAssociations(PKG, mUid)).thenReturn(associations);
+        when(mCompanionMgr.getAssociations(PKG, UserHandle.getUserId(mUid)))
+                .thenReturn(associations);
         mListener = mock(ManagedServices.ManagedServiceInfo.class);
         when(mListener.enabledAndUserMatches(anyInt())).thenReturn(false);
         when(mListeners.checkServiceTokenLocked(any())).thenReturn(mListener);
@@ -2447,7 +2472,8 @@
         mService.setPreferencesHelper(mPreferencesHelper);
         List<String> associations = new ArrayList<>();
         associations.add("a");
-        when(mCompanionMgr.getAssociations(PKG, mUid)).thenReturn(associations);
+        when(mCompanionMgr.getAssociations(PKG, UserHandle.getUserId(mUid)))
+                .thenReturn(associations);
 
         mBinderService.getNotificationChannelGroupsFromPrivilegedListener(
                 null, PKG, Process.myUserHandle());
@@ -2459,7 +2485,8 @@
     public void testGetNotificationChannelGroupsFromPrivilegedListener_noAccess() throws Exception {
         mService.setPreferencesHelper(mPreferencesHelper);
         List<String> associations = new ArrayList<>();
-        when(mCompanionMgr.getAssociations(PKG, mUid)).thenReturn(associations);
+        when(mCompanionMgr.getAssociations(PKG, UserHandle.getUserId(mUid)))
+                .thenReturn(associations);
 
         try {
             mBinderService.getNotificationChannelGroupsFromPrivilegedListener(
@@ -2476,7 +2503,8 @@
     public void testGetNotificationChannelGroupsFromPrivilegedListener_badUser() throws Exception {
         mService.setPreferencesHelper(mPreferencesHelper);
         List<String> associations = new ArrayList<>();
-        when(mCompanionMgr.getAssociations(PKG, mUid)).thenReturn(associations);
+        when(mCompanionMgr.getAssociations(PKG, UserHandle.getUserId(mUid)))
+                .thenReturn(associations);
         mListener = mock(ManagedServices.ManagedServiceInfo.class);
         when(mListener.enabledAndUserMatches(anyInt())).thenReturn(false);
         when(mListeners.checkServiceTokenLocked(any())).thenReturn(mListener);
@@ -3026,8 +3054,6 @@
         mBinderService.setNotificationAssistantAccessGranted(c, true);
 
         verify(mListeners).migrateToXml();
-        verify(mListeners).notifyNotificationChannelChanged(anyString(), any(), any(),
-                anyInt());
         verify(mConditionProviders).setPackageOrComponentEnabled(
                 anyString(), anyInt(), anyBoolean(), anyBoolean());
         verify(mAssistants).migrateToXml();
@@ -3041,8 +3067,6 @@
         mBinderService.setNotificationPolicyAccessGranted(c.getPackageName(), true);
 
         verify(mListeners).migrateToXml();
-        verify(mListeners).notifyNotificationChannelChanged(anyString(), any(), any(),
-                anyInt());
         verify(mConditionProviders).setPackageOrComponentEnabled(
                 anyString(), anyInt(), anyBoolean(), anyBoolean());
         verify(mAssistants).migrateToXml();
@@ -3178,7 +3202,7 @@
                 .setSmallIcon(android.R.drawable.sym_def_app_icon);
         StatusBarNotification sbn = new StatusBarNotification(PKG, PKG, 1,
                 "testNoFakeColorizedPermission", mUid, 0,
-                nb.build(), new UserHandle(mUid), null, 0);
+                nb.build(), UserHandle.getUserHandleForUid(mUid), null, 0);
         NotificationRecord nr = new NotificationRecord(mContext, sbn, mTestNotificationChannel);
 
         mBinderService.enqueueNotificationWithTag(PKG, PKG, sbn.getTag(),
@@ -3216,7 +3240,7 @@
                 .build();
 
         StatusBarNotification sbn = new StatusBarNotification("a", "a", 0, "tag", mUid, 0,
-                n, new UserHandle(mUid), null, 0);
+                n, UserHandle.getUserHandleForUid(mUid), null, 0);
         NotificationRecord otherPackage =
                 new NotificationRecord(mContext, sbn, mTestNotificationChannel);
         mService.addEnqueuedNotification(otherPackage);
@@ -3224,7 +3248,7 @@
 
         // Same notifications are enqueued as posted, everything counts b/c id and tag don't match
         // anything that's currently enqueued or posted
-        int userId = new UserHandle(mUid).getIdentifier();
+        int userId = UserHandle.getUserId(mUid);
         assertEquals(40,
                 mService.getNotificationCountLocked(PKG, userId, 0, null));
         assertEquals(40,
@@ -3441,8 +3465,8 @@
 
         StatusBarNotification sbn = new StatusBarNotification(preOPkg, preOPkg, 9,
                 "testBumpFGImportance_noChannelChangePreOApp",
-                Binder.getCallingUid(), 0, nb.build(), new UserHandle(Binder.getCallingUid()), null,
-                0);
+                Binder.getCallingUid(), 0, nb.build(),
+                UserHandle.getUserHandleForUid(Binder.getCallingUid()), null, 0);
 
         mBinderService.enqueueNotificationWithTag(sbn.getPackageName(), sbn.getOpPkg(),
                 sbn.getTag(), sbn.getId(), sbn.getNotification(), sbn.getUserId());
@@ -3459,7 +3483,7 @@
 
         sbn = new StatusBarNotification(preOPkg, preOPkg, 9,
                 "testBumpFGImportance_noChannelChangePreOApp", Binder.getCallingUid(),
-                0, nb.build(), new UserHandle(Binder.getCallingUid()), null, 0);
+                0, nb.build(), UserHandle.getUserHandleForUid(Binder.getCallingUid()), null, 0);
 
         mBinderService.enqueueNotificationWithTag(preOPkg, preOPkg,
                 "testBumpFGImportance_noChannelChangePreOApp",
@@ -3813,7 +3837,8 @@
                         .addMessage(message1)
                         .addMessage(message2));
         NotificationRecord recordA = new NotificationRecord(mContext, new StatusBarNotification(
-                PKG, PKG, 0, "tag", mUid, 0, nbA.build(), new UserHandle(mUid), null, 0), c);
+                PKG, PKG, 0, "tag", mUid, 0, nbA.build(), UserHandle.getUserHandleForUid(mUid),
+                null, 0), c);
 
         // First post means we grant access to both
         reset(mUgm);
@@ -3831,7 +3856,8 @@
                 .setSmallIcon(android.R.drawable.sym_def_app_icon)
                 .setStyle(new Notification.MessagingStyle("").addMessage(message2));
         NotificationRecord recordB = new NotificationRecord(mContext, new StatusBarNotification(PKG,
-                PKG, 0, "tag", mUid, 0, nbB.build(), new UserHandle(mUid), null, 0), c);
+                PKG, 0, "tag", mUid, 0, nbB.build(), UserHandle.getUserHandleForUid(mUid), null, 0),
+                c);
 
         // Update means we drop access to first
         reset(mUgmInternal);
@@ -3870,7 +3896,8 @@
                 .setStyle(new Notification.MessagingStyle("")
                         .addMessage(message1));
         NotificationRecord recordA = new NotificationRecord(mContext, new StatusBarNotification(
-                PKG, PKG, 0, "tag", mUid, 0, nbA.build(), new UserHandle(mUid), null, 0), c);
+                PKG, PKG, 0, "tag", mUid, 0, nbA.build(), UserHandle.getUserHandleForUid(mUid),
+                null, 0), c);
 
         doThrow(new SecurityException("no access")).when(mUgm)
                 .grantUriPermissionFromOwner(
@@ -4029,7 +4056,7 @@
         Notification.Builder nb1 = new Notification.Builder(mContext, "")
                 .setContentTitle("foo");
         StatusBarNotification sbn1 = new StatusBarNotification(PKG, PKG, 0, "tag", mUid, 0,
-                nb1.build(), new UserHandle(mUid), null, 0);
+                nb1.build(), UserHandle.getUserHandleForUid(mUid), null, 0);
         NotificationRecord r1 =
                 new NotificationRecord(mContext, sbn1, mock(NotificationChannel.class));
 
@@ -4037,7 +4064,7 @@
                 .setFlag(FLAG_FOREGROUND_SERVICE, true)
                 .setContentTitle("bar");
         StatusBarNotification sbn2 = new StatusBarNotification(PKG, PKG, 0, "tag", mUid, 0,
-                nb2.build(), new UserHandle(mUid), null, 0);
+                nb2.build(), UserHandle.getUserHandleForUid(mUid), null, 0);
         NotificationRecord r2 =
                 new NotificationRecord(mContext, sbn2, mock(NotificationChannel.class));
 
@@ -4049,14 +4076,14 @@
         Notification.Builder nb1 = new Notification.Builder(mContext, "")
                 .setContentTitle("foo");
         StatusBarNotification sbn1 = new StatusBarNotification(PKG, PKG, 0, "tag", mUid, 0,
-                nb1.build(), new UserHandle(mUid), null, 0);
+                nb1.build(), UserHandle.getUserHandleForUid(mUid), null, 0);
         NotificationRecord r1 =
                 new NotificationRecord(mContext, sbn1, mock(NotificationChannel.class));
 
         Notification.Builder nb2 = new Notification.Builder(mContext, "")
                 .setContentTitle("bar");
         StatusBarNotification sbn2 = new StatusBarNotification(PKG, PKG, 0, "tag", mUid, 0,
-                nb2.build(), new UserHandle(mUid), null, 0);
+                nb2.build(), UserHandle.getUserHandleForUid(mUid), null, 0);
         NotificationRecord r2 =
                 new NotificationRecord(mContext, sbn2, mock(NotificationChannel.class));
 
@@ -4069,7 +4096,7 @@
                 .setStyle(new Notification.InboxStyle()
                     .addLine("line1").addLine("line2"));
         StatusBarNotification sbn1 = new StatusBarNotification(PKG, PKG, 0, "tag", mUid, 0,
-                nb1.build(), new UserHandle(mUid), null, 0);
+                nb1.build(), UserHandle.getUserHandleForUid(mUid), null, 0);
         NotificationRecord r1 =
                 new NotificationRecord(mContext, sbn1, mock(NotificationChannel.class));
 
@@ -4077,7 +4104,7 @@
                 .setStyle(new Notification.InboxStyle()
                         .addLine("line1").addLine("line2_changed"));
         StatusBarNotification sbn2 = new StatusBarNotification(PKG, PKG, 0, "tag", mUid, 0,
-                nb2.build(), new UserHandle(mUid), null, 0);
+                nb2.build(), UserHandle.getUserHandleForUid(mUid), null, 0);
         NotificationRecord r2 =
                 new NotificationRecord(mContext, sbn2, mock(NotificationChannel.class));
 
@@ -4087,7 +4114,7 @@
                 .setStyle(new Notification.InboxStyle()
                         .addLine("line1"));
         StatusBarNotification sbn3 = new StatusBarNotification(PKG, PKG, 0, "tag", mUid, 0,
-                nb3.build(), new UserHandle(mUid), null, 0);
+                nb3.build(), UserHandle.getUserHandleForUid(mUid), null, 0);
         NotificationRecord r3 =
                 new NotificationRecord(mContext, sbn3, mock(NotificationChannel.class));
 
@@ -4097,7 +4124,7 @@
                 .setStyle(new Notification.InboxStyle()
                         .addLine("line1").addLine("line2").addLine("line3"));
         StatusBarNotification sbn4 = new StatusBarNotification(PKG, PKG, 0, "tag", mUid, 0,
-                nb4.build(), new UserHandle(mUid), null, 0);
+                nb4.build(), UserHandle.getUserHandleForUid(mUid), null, 0);
         NotificationRecord r4 =
                 new NotificationRecord(mContext, sbn4, mock(NotificationChannel.class));
 
@@ -4106,7 +4133,7 @@
         Notification.Builder nb5 = new Notification.Builder(mContext, "")
             .setContentText("not an inbox");
         StatusBarNotification sbn5 = new StatusBarNotification(PKG, PKG, 0, "tag", mUid, 0,
-                nb5.build(), new UserHandle(mUid), null, 0);
+                nb5.build(), UserHandle.getUserHandleForUid(mUid), null, 0);
         NotificationRecord r5 =
                 new NotificationRecord(mContext, sbn5, mock(NotificationChannel.class));
 
@@ -4118,14 +4145,14 @@
         Notification.Builder nb1 = new Notification.Builder(mContext, "")
                 .setContentText("foo");
         StatusBarNotification sbn1 = new StatusBarNotification(PKG, PKG, 0, "tag", mUid, 0,
-                nb1.build(), new UserHandle(mUid), null, 0);
+                nb1.build(), UserHandle.getUserHandleForUid(mUid), null, 0);
         NotificationRecord r1 =
                 new NotificationRecord(mContext, sbn1, mock(NotificationChannel.class));
 
         Notification.Builder nb2 = new Notification.Builder(mContext, "")
                 .setContentText("bar");
         StatusBarNotification sbn2 = new StatusBarNotification(PKG, PKG, 0, "tag", mUid, 0,
-                nb2.build(), new UserHandle(mUid), null, 0);
+                nb2.build(), UserHandle.getUserHandleForUid(mUid), null, 0);
         NotificationRecord r2 =
                 new NotificationRecord(mContext, sbn2, mock(NotificationChannel.class));
 
@@ -4137,14 +4164,14 @@
         Notification.Builder nb1 = new Notification.Builder(mContext, "")
                 .setContentText("foo");
         StatusBarNotification sbn1 = new StatusBarNotification(PKG, PKG, 0, "tag", mUid, 0,
-                nb1.build(), new UserHandle(mUid), null, 0);
+                nb1.build(), UserHandle.getUserHandleForUid(mUid), null, 0);
         NotificationRecord r1 =
                 new NotificationRecord(mContext, sbn1, mock(NotificationChannel.class));
 
         Notification.Builder nb2 = new Notification.Builder(mContext, "")
                 .setContentText("foo");
         StatusBarNotification sbn2 = new StatusBarNotification(PKG, PKG, 0, "tag", mUid, 0,
-                nb2.build(), new UserHandle(mUid), null, 0);
+                nb2.build(), UserHandle.getUserHandleForUid(mUid), null, 0);
         NotificationRecord r2 =
                 new NotificationRecord(mContext, sbn2, mock(NotificationChannel.class));
 
@@ -4156,14 +4183,14 @@
         Notification.Builder nb1 = new Notification.Builder(mContext, "")
                 .setContentText(Html.fromHtml("<b>foo</b>"));
         StatusBarNotification sbn1 = new StatusBarNotification(PKG, PKG, 0, "tag", mUid, 0,
-                nb1.build(), new UserHandle(mUid), null, 0);
+                nb1.build(), UserHandle.getUserHandleForUid(mUid), null, 0);
         NotificationRecord r1 =
                 new NotificationRecord(mContext, sbn1, mock(NotificationChannel.class));
 
         Notification.Builder nb2 = new Notification.Builder(mContext, "")
                 .setContentText(Html.fromHtml("<b>foo</b>"));
         StatusBarNotification sbn2 = new StatusBarNotification(PKG, PKG, 0, "tag", mUid, 0,
-                nb2.build(), new UserHandle(mUid), null, 0);
+                nb2.build(), UserHandle.getUserHandleForUid(mUid), null, 0);
         NotificationRecord r2 =
                 new NotificationRecord(mContext, sbn2, mock(NotificationChannel.class));
 
@@ -4175,14 +4202,14 @@
         Notification.Builder nb1 = new Notification.Builder(mContext, "")
                 .setContentText(Html.fromHtml("<b>foo</b>"));
         StatusBarNotification sbn1 = new StatusBarNotification(PKG, PKG, 0, "tag", mUid, 0,
-                nb1.build(), new UserHandle(mUid), null, 0);
+                nb1.build(), UserHandle.getUserHandleForUid(mUid), null, 0);
         NotificationRecord r1 =
                 new NotificationRecord(mContext, sbn1, mock(NotificationChannel.class));
 
         Notification.Builder nb2 = new Notification.Builder(mContext, "")
                 .setContentText(Html.fromHtml("<b>bar</b>"));
         StatusBarNotification sbn2 = new StatusBarNotification(PKG, PKG, 0, "tag", mUid, 0,
-                nb2.build(), new UserHandle(mUid), null, 0);
+                nb2.build(), UserHandle.getUserHandleForUid(mUid), null, 0);
         NotificationRecord r2 =
                 new NotificationRecord(mContext, sbn2, mock(NotificationChannel.class));
 
@@ -4194,14 +4221,14 @@
         Notification.Builder nb1 = new Notification.Builder(mContext, "")
                 .setProgress(100, 90, false);
         StatusBarNotification sbn1 = new StatusBarNotification(PKG, PKG, 0, "tag", mUid, 0,
-                nb1.build(), new UserHandle(mUid), null, 0);
+                nb1.build(), UserHandle.getUserHandleForUid(mUid), null, 0);
         NotificationRecord r1 =
                 new NotificationRecord(mContext, sbn1, mock(NotificationChannel.class));
 
         Notification.Builder nb2 = new Notification.Builder(mContext, "")
                 .setProgress(100, 100, false);
         StatusBarNotification sbn2 = new StatusBarNotification(PKG, PKG, 0, "tag", mUid, 0,
-                nb2.build(), new UserHandle(mUid), null, 0);
+                nb2.build(), UserHandle.getUserHandleForUid(mUid), null, 0);
         NotificationRecord r2 =
                 new NotificationRecord(mContext, sbn2, mock(NotificationChannel.class));
 
@@ -4213,14 +4240,14 @@
         Notification.Builder nb1 = new Notification.Builder(mContext, "")
                 .setProgress(100, 90, false);
         StatusBarNotification sbn1 = new StatusBarNotification(PKG, PKG, 0, "tag", mUid, 0,
-                nb1.build(), new UserHandle(mUid), null, 0);
+                nb1.build(), UserHandle.getUserHandleForUid(mUid), null, 0);
         NotificationRecord r1 =
                 new NotificationRecord(mContext, sbn1, mock(NotificationChannel.class));
 
         Notification.Builder nb2 = new Notification.Builder(mContext, "")
                 .setProgress(100, 91, false);
         StatusBarNotification sbn2 = new StatusBarNotification(PKG, PKG, 0, "tag", mUid, 0,
-                nb2.build(), new UserHandle(mUid), null, 0);
+                nb2.build(), UserHandle.getUserHandleForUid(mUid), null, 0);
         NotificationRecord r2 =
                 new NotificationRecord(mContext, sbn2, mock(NotificationChannel.class));
 
@@ -4232,14 +4259,14 @@
         Notification.Builder nb1 = new Notification.Builder(mContext, "")
                 .setProgress(100, 100, false);
         StatusBarNotification sbn1 = new StatusBarNotification(PKG, PKG, 0, "tag", mUid, 0,
-                nb1.build(), new UserHandle(mUid), null, 0);
+                nb1.build(), UserHandle.getUserHandleForUid(mUid), null, 0);
         NotificationRecord r1 =
                 new NotificationRecord(mContext, sbn1, mock(NotificationChannel.class));
 
         Notification.Builder nb2 = new Notification.Builder(mContext, "")
                 .setProgress(100, 100, false);
         StatusBarNotification sbn2 = new StatusBarNotification(PKG, PKG, 0, "tag", mUid, 0,
-                nb2.build(), new UserHandle(mUid), null, 0);
+                nb2.build(), UserHandle.getUserHandleForUid(mUid), null, 0);
         NotificationRecord r2 =
                 new NotificationRecord(mContext, sbn2, mock(NotificationChannel.class));
 
@@ -4253,7 +4280,7 @@
                 .setFlag(Notification.FLAG_GROUP_SUMMARY, true)
                 .setContentText("foo");
         StatusBarNotification sbn1 = new StatusBarNotification(PKG, PKG, 0, "tag", mUid, 0,
-                nb1.build(), new UserHandle(mUid), null, 0);
+                nb1.build(), UserHandle.getUserHandleForUid(mUid), null, 0);
         NotificationRecord r1 =
                 new NotificationRecord(mContext, sbn1, mock(NotificationChannel.class));
 
@@ -4262,7 +4289,7 @@
                 .setFlag(Notification.FLAG_GROUP_SUMMARY, true)
                 .setContentText("bar");
         StatusBarNotification sbn2 = new StatusBarNotification(PKG, PKG, 0, "tag", mUid, 0,
-                nb2.build(), new UserHandle(mUid), null, 0);
+                nb2.build(), UserHandle.getUserHandleForUid(mUid), null, 0);
         NotificationRecord r2 =
                 new NotificationRecord(mContext, sbn2, mock(NotificationChannel.class));
 
@@ -4276,7 +4303,7 @@
                 .setFlag(Notification.FLAG_GROUP_SUMMARY, true)
                 .setContentText("bar");
         StatusBarNotification sbn2 = new StatusBarNotification(PKG, PKG, 0, "tag", mUid, 0,
-                nb2.build(), new UserHandle(mUid), null, 0);
+                nb2.build(), UserHandle.getUserHandleForUid(mUid), null, 0);
         NotificationRecord r2 =
                 new NotificationRecord(mContext, sbn2, mock(NotificationChannel.class));
 
@@ -4694,7 +4721,7 @@
         n.flags |= FLAG_FOREGROUND_SERVICE;
 
         StatusBarNotification sbn = new StatusBarNotification(PKG, PKG, 9, null, mUid, 0,
-                n, new UserHandle(mUid), null, 0);
+                n, UserHandle.getUserHandleForUid(mUid), null, 0);
         NotificationRecord r = new NotificationRecord(mContext, sbn, mTestNotificationChannel);
 
         mService.addEnqueuedNotification(r);
@@ -4713,7 +4740,7 @@
         n.flags |= FLAG_FOREGROUND_SERVICE;
 
         StatusBarNotification sbn = new StatusBarNotification(PKG, PKG, 9, null, mUid, 0,
-                n, new UserHandle(mUid), null, 0);
+                n, UserHandle.getUserHandleForUid(mUid), null, 0);
         NotificationRecord r = new NotificationRecord(mContext, sbn, mTestNotificationChannel);
 
         mService.addNotification(r);
@@ -5026,7 +5053,7 @@
                         .setSmallIcon(android.R.drawable.sym_def_app_icon);
 
         StatusBarNotification sbn = new StatusBarNotification(PKG, "opPkg", 0, "tag", mUid, 0,
-                nb.build(), new UserHandle(mUid), null, 0);
+                nb.build(), UserHandle.getUserHandleForUid(mUid), null, 0);
         NotificationRecord r =  new NotificationRecord(mContext, sbn, mTestNotificationChannel);
 
         mService.reportSeen(r);
@@ -5050,7 +5077,7 @@
         StatusBarNotification sbn = new StatusBarNotification(PKG, PKG, r.getSbn().getId(),
                 r.getSbn().getTag(), mUid, 0,
                 new Notification.Builder(mContext, mTestNotificationChannel.getId()).build(),
-                new UserHandle(mUid), null, 0);
+                UserHandle.getUserHandleForUid(mUid), null, 0);
         NotificationRecord update = new NotificationRecord(mContext, sbn, mTestNotificationChannel);
         mService.addEnqueuedNotification(update);
         assertNull(update.getSbn().getNotification().getSmallIcon());
@@ -5084,7 +5111,7 @@
     }
 
     @Test
-    public void testgetNotificationChannels_crossUser() throws Exception {
+    public void testGetNotificationChannels_crossUser() throws Exception {
         // same user no problem
         mBinderService.getNotificationChannels("src", "target", mContext.getUserId());
 
@@ -5273,7 +5300,7 @@
                 .setSmallIcon(android.R.drawable.sym_def_app_icon)
                 .setBubbleMetadata(getBubbleMetadata());
         StatusBarNotification sbn = new StatusBarNotification(PKG, PKG, 1, "tag", mUid, 0,
-                nb.build(), new UserHandle(mUid), null, 0);
+                nb.build(), UserHandle.getUserHandleForUid(mUid), null, 0);
         NotificationRecord nr = new NotificationRecord(mContext, sbn, mTestNotificationChannel);
 
         // Say we're foreground
@@ -5319,7 +5346,7 @@
         nb.setShortcutId(null);
         StatusBarNotification sbn = new StatusBarNotification(PKG, PKG, 1,
                 null, mUid, 0,
-                nb.build(), new UserHandle(mUid), null, 0);
+                nb.build(), UserHandle.getUserHandleForUid(mUid), null, 0);
 
         mBinderService.enqueueNotificationWithTag(PKG, PKG, sbn.getTag(),
                 sbn.getId(), sbn.getNotification(), sbn.getUserId());
@@ -5363,7 +5390,7 @@
 
         StatusBarNotification sbn = new StatusBarNotification(PKG, PKG, 1,
                 "testFlagBubbleNotifs_noFlag_notBubble", mUid, 0,
-                nb.build(), new UserHandle(mUid), null, 0);
+                nb.build(), UserHandle.getUserHandleForUid(mUid), null, 0);
         NotificationRecord nr = new NotificationRecord(mContext, sbn, mTestNotificationChannel);
 
         // Post the notification
@@ -5455,25 +5482,49 @@
     }
 
     @Test
-    public void testCancelNotificationsFromListener_ignoresBubbles() throws Exception {
-        final NotificationRecord nrNormal = generateNotificationRecord(mTestNotificationChannel);
-        final NotificationRecord nrBubble = generateNotificationRecord(mTestNotificationChannel);
-        nrBubble.getSbn().getNotification().flags |= FLAG_BUBBLE;
+    public void testCancelNotificationsFromListener_cancelsNonBubble() throws Exception {
+        // Add non-bubble notif
+        final NotificationRecord nr = generateNotificationRecord(mTestNotificationChannel);
+        mService.addNotification(nr);
 
-        mService.addNotification(nrNormal);
-        mService.addNotification(nrBubble);
-
-        String[] keys = {nrNormal.getSbn().getKey(), nrBubble.getSbn().getKey()};
+        // Cancel via listener
+        String[] keys = {nr.getSbn().getKey()};
         mService.getBinderService().cancelNotificationsFromListener(null, keys);
         waitForIdle();
 
+        // Notif not active anymore
+        StatusBarNotification[] notifs = mBinderService.getActiveNotifications(PKG);
+        assertEquals(0, notifs.length);
+        assertEquals(0, mService.getNotificationRecordCount());
+        // Cancel event is logged
+        assertEquals(1, mNotificationRecordLogger.numCalls());
+        assertEquals(NotificationRecordLogger.NotificationCancelledEvent
+            .NOTIFICATION_CANCEL_LISTENER_CANCEL, mNotificationRecordLogger.event(0));
+    }
+
+    @Test
+    public void testCancelNotificationsFromListener_suppressesBubble() throws Exception {
+        // Add bubble notif
+        setUpPrefsForBubbles(PKG, mUid,
+            true /* global */,
+            BUBBLE_PREFERENCE_ALL /* app */,
+            true /* channel */);
+        NotificationRecord nr = generateMessageBubbleNotifRecord(mTestNotificationChannel, "tag");
+
+        mBinderService.enqueueNotificationWithTag(PKG, PKG, nr.getSbn().getTag(),
+            nr.getSbn().getId(), nr.getSbn().getNotification(), nr.getSbn().getUserId());
+        waitForIdle();
+
+        // Cancel via listener
+        String[] keys = {nr.getSbn().getKey()};
+        mService.getBinderService().cancelNotificationsFromListener(null, keys);
+        waitForIdle();
+
+        // Bubble notif active and suppressed
         StatusBarNotification[] notifs = mBinderService.getActiveNotifications(PKG);
         assertEquals(1, notifs.length);
         assertEquals(1, mService.getNotificationRecordCount());
-
-        assertEquals(1, mNotificationRecordLogger.numCalls());
-        assertEquals(NotificationRecordLogger.NotificationCancelledEvent
-                .NOTIFICATION_CANCEL_LISTENER_CANCEL, mNotificationRecordLogger.event(0));
+        assertTrue(notifs[0].getNotification().getBubbleMetadata().isNotificationSuppressed());
     }
 
     @Test
@@ -6154,7 +6205,7 @@
         nb.setShortcutId(VALID_CONVO_SHORTCUT_ID);
         nb.setBubbleMetadata(metadata);
         StatusBarNotification sbn = new StatusBarNotification(PKG, PKG, 1,
-                "tag", mUid, 0, nb.build(), new UserHandle(mUid), null, 0);
+                "tag", mUid, 0, nb.build(), UserHandle.getUserHandleForUid(mUid), null, 0);
         NotificationRecord nr = new NotificationRecord(mContext, sbn, mTestNotificationChannel);
 
         // Test: Send the bubble notification
@@ -6179,7 +6230,7 @@
         // Test: Remove the shortcut
         when(mLauncherApps.getShortcuts(any(), any())).thenReturn(null);
         launcherAppsCallback.getValue().onShortcutsChanged(PKG, Collections.emptyList(),
-                new UserHandle(mUid));
+                UserHandle.getUserHandleForUid(mUid));
         waitForIdle();
 
         // Verify:
@@ -6214,7 +6265,7 @@
         nb.setShortcutId(shortcutId);
         nb.setBubbleMetadata(metadata);
         StatusBarNotification sbn = new StatusBarNotification(PKG, PKG, 1,
-                "tag", mUid, 0, nb.build(), new UserHandle(mUid), null, 0);
+                "tag", mUid, 0, nb.build(), UserHandle.getUserHandleForUid(mUid), null, 0);
         NotificationRecord nr = new NotificationRecord(mContext, sbn, mTestNotificationChannel);
 
         // Pretend the shortcut exists
@@ -6662,15 +6713,43 @@
 
     @Test
     public void testRecordMessages_invalidMsg() throws RemoteException {
-        NotificationRecord nr =
-                generateMessageBubbleNotifRecord(mTestNotificationChannel,
-                        "testRecordMessages_invalidMsg");
+        Notification.Builder nb = getMessageStyleNotifBuilder(false /* addDefaultMetadata */,
+                null /* groupKey */, false /* isSummary */);
+        nb.setShortcutId(null);
+        StatusBarNotification sbn = new StatusBarNotification(PKG_P, PKG_P, 1,
+                "testRecordMessages_invalidMsg", mUid, 0, nb.build(),
+                UserHandle.getUserHandleForUid(mUid), null, 0);
+        NotificationRecord nr = new NotificationRecord(mContext, sbn, mTestNotificationChannel);
+
         when(mLauncherApps.getShortcuts(any(), any())).thenReturn(null);
-        mBinderService.enqueueNotificationWithTag(PKG, PKG, nr.getSbn().getTag(),
+        mBinderService.enqueueNotificationWithTag(PKG_P, PKG_P, nr.getSbn().getTag(),
                 nr.getSbn().getId(), nr.getSbn().getNotification(), nr.getSbn().getUserId());
         waitForIdle();
 
-        assertTrue(mBinderService.isInInvalidMsgState(PKG, mUid));
+        assertTrue(mBinderService.isInInvalidMsgState(PKG_P, mUid));
+    }
+
+    @Test
+    public void testRecordMessages_invalidMsg_notMessageStyle() throws RemoteException {
+        Notification.Builder nb = new Notification.Builder(mContext,
+                mTestNotificationChannel.getId())
+                .setContentTitle("foo")
+                .setShortcutId(null)
+                .setSmallIcon(android.R.drawable.sym_def_app_icon)
+                .setCategory(Notification.CATEGORY_MESSAGE);
+        StatusBarNotification sbn = new StatusBarNotification(PKG_O, PKG_O, 1,
+                "testRecordMessages_invalidMsg_notMessageStyle", mUid, 0, nb.build(),
+                UserHandle.getUserHandleForUid(mUid), null, 0);
+        NotificationRecord nr = new NotificationRecord(mContext, sbn, mTestNotificationChannel);
+
+        when(mLauncherApps.getShortcuts(any(), any())).thenReturn(null);
+        mBinderService.enqueueNotificationWithTag(PKG_O, PKG_O, nr.getSbn().getTag(),
+                nr.getSbn().getId(), nr.getSbn().getNotification(), nr.getSbn().getUserId());
+        waitForIdle();
+
+        // PKG_O is allowed to be in conversation space b/c of override in
+        // TestableNotificationManagerService
+        assertTrue(mBinderService.isInInvalidMsgState(PKG_O, mUid));
     }
 
     @Test
@@ -6678,24 +6757,25 @@
         Notification.Builder nb = getMessageStyleNotifBuilder(false /* addDefaultMetadata */,
                 null /* groupKey */, false /* isSummary */);
         nb.setShortcutId(null);
-        StatusBarNotification sbn = new StatusBarNotification(PKG, PKG, 1,
-                "testRecordMessages_validMsg", mUid, 0, nb.build(), new UserHandle(mUid), null, 0);
+        StatusBarNotification sbn = new StatusBarNotification(PKG_P, PKG_P, 1,
+                "testRecordMessages_validMsg", mUid, 0, nb.build(),
+                UserHandle.getUserHandleForUid(mUid), null, 0);
         NotificationRecord nr = new NotificationRecord(mContext, sbn, mTestNotificationChannel);
 
-        mBinderService.enqueueNotificationWithTag(PKG, PKG, nr.getSbn().getTag(),
+        mBinderService.enqueueNotificationWithTag(PKG_P, PKG_P, nr.getSbn().getTag(),
                 nr.getSbn().getId(), nr.getSbn().getNotification(), nr.getSbn().getUserId());
         waitForIdle();
 
-        assertTrue(mBinderService.isInInvalidMsgState(PKG, mUid));
+        assertTrue(mBinderService.isInInvalidMsgState(PKG_P, mUid));
 
         nr = generateMessageBubbleNotifRecord(mTestNotificationChannel,
                 "testRecordMessages_validMsg");
 
-        mBinderService.enqueueNotificationWithTag(PKG, PKG, nr.getSbn().getTag(),
+        mBinderService.enqueueNotificationWithTag(PKG_P, PKG_P, nr.getSbn().getTag(),
                 nr.getSbn().getId(), nr.getSbn().getNotification(), nr.getSbn().getUserId());
         waitForIdle();
 
-        assertFalse(mBinderService.isInInvalidMsgState(PKG, mUid));
+        assertFalse(mBinderService.isInInvalidMsgState(PKG_P, mUid));
     }
 
     @Test
@@ -6715,7 +6795,7 @@
         nb.setShortcutId(null);
         StatusBarNotification sbn = new StatusBarNotification(PKG, PKG, 1,
                 "testRecordMessages_invalidMsg_afterValidMsg_2", mUid, 0, nb.build(),
-                new UserHandle(mUid), null, 0);
+                UserHandle.getUserHandleForUid(mUid), null, 0);
          nr = new NotificationRecord(mContext, sbn, mTestNotificationChannel);
 
         mBinderService.enqueueNotificationWithTag(PKG, PKG, nr.getSbn().getTag(),
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/WrappedSysUiStatsEvent.java b/services/tests/uiservicestests/src/com/android/server/notification/WrappedSysUiStatsEvent.java
index f4f64d7..89adc72 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/WrappedSysUiStatsEvent.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/WrappedSysUiStatsEvent.java
@@ -88,11 +88,21 @@
             return index < mValues.size() ? mValues.get(index) : null;
         }
 
-        /** useful to make assertTrue() statemetns more readable. */
+        /** useful to make assertTrue() statements more readable. */
         public boolean getBoolean(int index) {
             return (Boolean) mValues.get(index);
         }
 
+        /** useful to make assertTrue() statements more readable. */
+        public int getInt(int index) {
+            return (Integer) mValues.get(index);
+        }
+
+        /** useful to make assertTrue() statements more readable. */
+        public String getString(int index) {
+            return (String) mValues.get(index);
+        }
+
         private void addValue(Object value) {
             mLastIndex = mValues.size();
             mValues.add(value);
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/ZenModeConfigTest.java b/services/tests/uiservicestests/src/com/android/server/notification/ZenModeConfigTest.java
index f7b435e..013a994 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/ZenModeConfigTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/ZenModeConfigTest.java
@@ -101,11 +101,39 @@
 
         Policy expectedPolicy = new Policy(priorityCategories, priorityCallSenders,
                 priorityMessageSenders, suppressedVisualEffects, 0, priorityConversationsSenders);
-
         assertEquals(expectedPolicy, config.toNotificationPolicy(zenPolicy));
     }
 
     @Test
+    public void testZenConfigToZenPolicy() {
+        ZenPolicy expected = new ZenPolicy.Builder()
+                .allowAlarms(true)
+                .allowReminders(true)
+                .allowEvents(true)
+                .showLights(false)
+                .showBadges(false)
+                .showInAmbientDisplay(false)
+                .build();
+
+        ZenModeConfig config = getMutedAllConfig();
+        config.allowAlarms = true;
+        config.allowReminders = true;
+        config.allowEvents = true;
+        config.suppressedVisualEffects |= Policy.SUPPRESSED_EFFECT_BADGE;
+        config.suppressedVisualEffects |= Policy.SUPPRESSED_EFFECT_LIGHTS;
+        config.suppressedVisualEffects |= Policy.SUPPRESSED_EFFECT_AMBIENT;
+        ZenPolicy actual = config.toZenPolicy();
+
+        assertEquals(expected.getVisualEffectBadge(), actual.getVisualEffectBadge());
+        assertEquals(expected.getPriorityCategoryAlarms(), actual.getPriorityCategoryAlarms());
+        assertEquals(expected.getPriorityCategoryReminders(),
+                actual.getPriorityCategoryReminders());
+        assertEquals(expected.getPriorityCategoryEvents(), actual.getPriorityCategoryEvents());
+        assertEquals(expected.getVisualEffectLights(), actual.getVisualEffectLights());
+        assertEquals(expected.getVisualEffectAmbient(), actual.getVisualEffectAmbient());
+    }
+
+    @Test
     public void testPriorityOnlyMutingAll() {
         ZenModeConfig config = getMutedAllConfig();
         assertTrue(ZenModeConfig.areAllPriorityOnlyRingerSoundsMuted(config));
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/ZenModeHelperTest.java b/services/tests/uiservicestests/src/com/android/server/notification/ZenModeHelperTest.java
index 108af89..3c7206f 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/ZenModeHelperTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/ZenModeHelperTest.java
@@ -27,16 +27,25 @@
 import static android.app.NotificationManager.Policy.PRIORITY_CATEGORY_REPEAT_CALLERS;
 import static android.app.NotificationManager.Policy.PRIORITY_CATEGORY_SYSTEM;
 import static android.app.NotificationManager.Policy.PRIORITY_SENDERS_ANY;
-import static android.app.NotificationManager.Policy.PRIORITY_SENDERS_CONTACTS;
 import static android.app.NotificationManager.Policy.PRIORITY_SENDERS_STARRED;
 import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_BADGE;
 import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_FULL_SCREEN_INTENT;
 import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_LIGHTS;
 import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_PEEK;
+import static android.provider.Settings.Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS;
+
+import static com.android.internal.util.FrameworkStatsLog.ANNOTATION_ID_IS_UID;
+import static com.android.internal.util.FrameworkStatsLog.DND_MODE_RULE;
+import static com.android.os.AtomsProto.DNDModeProto.CHANNELS_BYPASSING_FIELD_NUMBER;
+import static com.android.os.AtomsProto.DNDModeProto.ENABLED_FIELD_NUMBER;
+import static com.android.os.AtomsProto.DNDModeProto.ID_FIELD_NUMBER;
+import static com.android.os.AtomsProto.DNDModeProto.UID_FIELD_NUMBER;
+import static com.android.os.AtomsProto.DNDModeProto.ZEN_MODE_FIELD_NUMBER;
 
 import static junit.framework.Assert.assertEquals;
 import static junit.framework.Assert.assertFalse;
 import static junit.framework.TestCase.assertTrue;
+import static junit.framework.TestCase.fail;
 
 import static org.junit.Assert.assertNotEquals;
 import static org.mockito.ArgumentMatchers.any;
@@ -70,10 +79,12 @@
 import android.media.AudioSystem;
 import android.media.VolumePolicy;
 import android.net.Uri;
+import android.os.Process;
 import android.os.UserHandle;
 import android.provider.Settings;
 import android.provider.Settings.Global;
 import android.service.notification.Condition;
+import android.service.notification.DNDModeProto;
 import android.service.notification.ZenModeConfig;
 import android.service.notification.ZenModeConfig.ScheduleInfo;
 import android.service.notification.ZenPolicy;
@@ -82,6 +93,7 @@
 import android.testing.TestableLooper;
 import android.util.ArrayMap;
 import android.util.Log;
+import android.util.StatsEvent;
 import android.util.Xml;
 
 import com.android.internal.R;
@@ -106,6 +118,9 @@
 import java.io.IOException;
 import java.io.InputStream;
 import java.io.Reader;
+import java.util.ArrayList;
+import java.util.LinkedList;
+import java.util.List;
 import java.util.Objects;
 
 @SmallTest
@@ -115,6 +130,7 @@
 
     private static final String EVENTS_DEFAULT_RULE_ID = "EVENTS_DEFAULT_RULE";
     private static final String SCHEDULE_DEFAULT_RULE_ID = "EVERY_NIGHT_DEFAULT_RULE";
+    private static final int ZEN_MODE_FOR_TESTING = 99;
 
     ConditionProviders mConditionProviders;
     @Mock NotificationManager mNotificationManager;
@@ -124,6 +140,7 @@
     private Context mContext;
     private ContentResolver mContentResolver;
     @Mock AppOpsManager mAppOps;
+    private WrappedSysUiStatsEvent.WrappedBuilderFactory mStatsEventBuilderFactory;
 
     @Before
     public void setUp() {
@@ -140,6 +157,7 @@
             Log.d("ZenModeHelperTest", "Couldn't mock default zen mode config xml file err=" +
                     e.toString());
         }
+        mStatsEventBuilderFactory = new WrappedSysUiStatsEvent.WrappedBuilderFactory();
 
         when(mContext.getSystemService(AppOpsManager.class)).thenReturn(mAppOps);
         when(mContext.getSystemService(NotificationManager.class)).thenReturn(mNotificationManager);
@@ -147,7 +165,7 @@
                 AppGlobals.getPackageManager());
         mConditionProviders.addSystemProvider(new CountdownConditionProvider());
         mZenModeHelperSpy = spy(new ZenModeHelper(mContext, mTestableLooper.getLooper(),
-                mConditionProviders));
+                mConditionProviders, mStatsEventBuilderFactory));
     }
 
     private XmlResourceParser getDefaultConfigParser() throws IOException, XmlPullParserException {
@@ -212,6 +230,10 @@
     }
 
     private ArrayMap<String, ZenModeConfig.ZenRule> getCustomAutomaticRules() {
+        return getCustomAutomaticRules(ZEN_MODE_IMPORTANT_INTERRUPTIONS);
+    }
+
+    private ArrayMap<String, ZenModeConfig.ZenRule> getCustomAutomaticRules(int zenMode) {
         ArrayMap<String, ZenModeConfig.ZenRule> automaticRules = new ArrayMap<>();
         ZenModeConfig.ZenRule customRule = new ZenModeConfig.ZenRule();
         final ScheduleInfo customRuleInfo = new ScheduleInfo();
@@ -219,10 +241,10 @@
         customRule.creationTime = 0;
         customRule.id = "customRule";
         customRule.name = "Custom Rule";
-        customRule.zenMode = Settings.Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS;
+        customRule.zenMode = zenMode;
         customRule.conditionId = ZenModeConfig.toScheduleConditionId(customRuleInfo);
         customRule.configurationActivity =
-                new ComponentName("android", "ScheduleConditionProvider");
+                new ComponentName("not.android", "ScheduleConditionProvider");
         customRule.pkg = customRule.configurationActivity.getPackageName();
         automaticRules.put("customRule", customRule);
         return automaticRules;
@@ -244,7 +266,7 @@
 
     @Test
     public void testZenOn_NotificationApplied() {
-        mZenModeHelperSpy.mZenMode = Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS;
+        mZenModeHelperSpy.mZenMode = ZEN_MODE_IMPORTANT_INTERRUPTIONS;
         // The most permissive policy
         mZenModeHelperSpy.mConsolidatedPolicy = new Policy(Policy.PRIORITY_CATEGORY_ALARMS |
                 PRIORITY_CATEGORY_MEDIA | PRIORITY_CATEGORY_MESSAGES
@@ -267,7 +289,7 @@
 
     @Test
     public void testZenOn_StarredCallers_CallTypesBlocked() {
-        mZenModeHelperSpy.mZenMode = Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS;
+        mZenModeHelperSpy.mZenMode = ZEN_MODE_IMPORTANT_INTERRUPTIONS;
         // The most permissive policy
         mZenModeHelperSpy.mConsolidatedPolicy = new Policy(Policy.PRIORITY_CATEGORY_ALARMS |
                 PRIORITY_CATEGORY_MEDIA | PRIORITY_CATEGORY_MESSAGES
@@ -287,7 +309,7 @@
 
     @Test
     public void testZenOn_AllCallers_CallTypesAllowed() {
-        mZenModeHelperSpy.mZenMode = Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS;
+        mZenModeHelperSpy.mZenMode = ZEN_MODE_IMPORTANT_INTERRUPTIONS;
         // The most permissive policy
         mZenModeHelperSpy.mConsolidatedPolicy = new Policy(Policy.PRIORITY_CATEGORY_ALARMS |
                 PRIORITY_CATEGORY_MEDIA | PRIORITY_CATEGORY_MESSAGES
@@ -307,7 +329,7 @@
 
     @Test
     public void testZenOn_AllowAlarmsMedia_NoAlarmMediaMuteApplied() {
-        mZenModeHelperSpy.mZenMode = Settings.Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS;
+        mZenModeHelperSpy.mZenMode = ZEN_MODE_IMPORTANT_INTERRUPTIONS;
         mZenModeHelperSpy.mConsolidatedPolicy = new Policy(Policy.PRIORITY_CATEGORY_ALARMS |
                 PRIORITY_CATEGORY_MEDIA, 0, 0, 0, 0, 0);
 
@@ -320,7 +342,7 @@
 
     @Test
     public void testZenOn_DisallowAlarmsMedia_AlarmMediaMuteApplied() {
-        mZenModeHelperSpy.mZenMode = Settings.Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS;
+        mZenModeHelperSpy.mZenMode = ZEN_MODE_IMPORTANT_INTERRUPTIONS;
         mZenModeHelperSpy.mConsolidatedPolicy = new Policy(0, 0, 0, 0, 0, 0);
         mZenModeHelperSpy.applyRestrictions();
         verify(mZenModeHelperSpy, atLeastOnce()).applyRestrictions(true, true,
@@ -406,7 +428,7 @@
     public void testZenAllCannotBypass() {
         // Only audio attributes with SUPPRESIBLE_NEVER can bypass
         // with special case USAGE_ASSISTANCE_SONIFICATION
-        mZenModeHelperSpy.mZenMode = Settings.Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS;
+        mZenModeHelperSpy.mZenMode = ZEN_MODE_IMPORTANT_INTERRUPTIONS;
         mZenModeHelperSpy.mConsolidatedPolicy = new Policy(0, 0, 0, 0, 0, 0);
         mZenModeHelperSpy.applyRestrictions();
 
@@ -428,7 +450,7 @@
     @Test
     public void testApplyRestrictions_whitelist_priorityOnlyMode() {
         mZenModeHelperSpy.setPriorityOnlyDndExemptPackages(new String[] {PKG_O});
-        mZenModeHelperSpy.mZenMode = Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS;
+        mZenModeHelperSpy.mZenMode = ZEN_MODE_IMPORTANT_INTERRUPTIONS;
         mZenModeHelperSpy.mConsolidatedPolicy = new Policy(0, 0, 0, 0, 0, 0);
         mZenModeHelperSpy.applyRestrictions();
 
@@ -479,7 +501,7 @@
         Settings.Secure.putInt(mContentResolver, Settings.Secure.ZEN_SETTINGS_UPDATED, 0);
         mZenModeHelperSpy.mIsBootComplete = true;
         mZenModeHelperSpy.mConsolidatedPolicy = new Policy(0, 0, 0, 0, 0, 0);
-        mZenModeHelperSpy.setZenModeSetting(Settings.Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS);
+        mZenModeHelperSpy.setZenModeSetting(ZEN_MODE_IMPORTANT_INTERRUPTIONS);
 
         verify(mZenModeHelperSpy, times(1)).createZenUpgradeNotification();
         verify(mNotificationManager, times(1)).notify(eq(ZenModeHelper.TAG),
@@ -494,7 +516,7 @@
         Settings.Secure.putInt(mContentResolver, Settings.Secure.SHOW_ZEN_UPGRADE_NOTIFICATION, 0);
         Settings.Secure.putInt(mContentResolver, Settings.Secure.ZEN_SETTINGS_UPDATED, 0);
         mZenModeHelperSpy.mIsBootComplete = true;
-        mZenModeHelperSpy.setZenModeSetting(Settings.Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS);
+        mZenModeHelperSpy.setZenModeSetting(ZEN_MODE_IMPORTANT_INTERRUPTIONS);
 
         verify(mZenModeHelperSpy, never()).createZenUpgradeNotification();
         verify(mNotificationManager, never()).notify(eq(ZenModeHelper.TAG),
@@ -507,7 +529,7 @@
         Settings.Secure.putInt(mContentResolver, Settings.Secure.SHOW_ZEN_UPGRADE_NOTIFICATION, 0);
         Settings.Secure.putInt(mContentResolver, Settings.Secure.ZEN_SETTINGS_UPDATED, 1);
         mZenModeHelperSpy.mIsBootComplete = true;
-        mZenModeHelperSpy.setZenModeSetting(Settings.Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS);
+        mZenModeHelperSpy.setZenModeSetting(ZEN_MODE_IMPORTANT_INTERRUPTIONS);
 
         verify(mZenModeHelperSpy, never()).createZenUpgradeNotification();
         verify(mNotificationManager, never()).notify(eq(ZenModeHelper.TAG),
@@ -524,7 +546,7 @@
         // 1. Current ringer is normal
         when(mAudioManager.getRingerModeInternal()).thenReturn(AudioManager.RINGER_MODE_NORMAL);
         // Set zen to priority-only with all notification sounds muted (so ringer will be muted)
-        mZenModeHelperSpy.mZenMode = Settings.Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS;
+        mZenModeHelperSpy.mZenMode = ZEN_MODE_IMPORTANT_INTERRUPTIONS;
         mZenModeHelperSpy.mConfig.allowReminders = false;
         mZenModeHelperSpy.mConfig.allowCalls = false;
         mZenModeHelperSpy.mConfig.allowMessages = false;
@@ -568,7 +590,7 @@
         // ringtone, notification and system streams are affected by ringer mode
         mZenModeHelperSpy.mConfig.allowAlarms = true;
         mZenModeHelperSpy.mConfig.allowReminders = true;
-        mZenModeHelperSpy.mZenMode = Settings.Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS;
+        mZenModeHelperSpy.mZenMode = ZEN_MODE_IMPORTANT_INTERRUPTIONS;
         ZenModeHelper.RingerModeDelegate ringerModeDelegateRingerMuted =
                 mZenModeHelperSpy.new RingerModeDelegate();
 
@@ -615,7 +637,7 @@
 
         // 1. Current ringer is normal
         when(mAudioManager.getRingerModeInternal()).thenReturn(AudioManager.RINGER_MODE_NORMAL);
-        mZenModeHelperSpy.mZenMode = Settings.Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS;
+        mZenModeHelperSpy.mZenMode = ZEN_MODE_IMPORTANT_INTERRUPTIONS;
         mZenModeHelperSpy.mConfig.allowReminders = true;
 
         // 2. apply priority only zen - verify ringer is normal
@@ -640,7 +662,7 @@
 
         // 1. Current ringer is silent
         when(mAudioManager.getRingerModeInternal()).thenReturn(AudioManager.RINGER_MODE_SILENT);
-        mZenModeHelperSpy.mZenMode = Settings.Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS;
+        mZenModeHelperSpy.mZenMode = ZEN_MODE_IMPORTANT_INTERRUPTIONS;
         mZenModeHelperSpy.mConfig.allowReminders = true;
 
         // 2. apply priority only zen - verify ringer is silent
@@ -666,7 +688,7 @@
         // 1. Current ringer is normal
         when(mAudioManager.getRingerModeInternal()).thenReturn(AudioManager.RINGER_MODE_NORMAL);
         // Set zen to priority-only with all notification sounds muted (so ringer will be muted)
-        mZenModeHelperSpy.mZenMode = Settings.Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS;
+        mZenModeHelperSpy.mZenMode = ZEN_MODE_IMPORTANT_INTERRUPTIONS;
         mZenModeHelperSpy.mConfig.allowReminders = true;
 
         // 2. apply priority only zen - verify zen will still be normal
@@ -728,7 +750,7 @@
 
         // apply zen off multiple times - verify ringer is not set to normal
         when(mAudioManager.getRingerModeInternal()).thenReturn(AudioManager.RINGER_MODE_SILENT);
-        mZenModeHelperSpy.mZenMode = Settings.Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS;
+        mZenModeHelperSpy.mZenMode = ZEN_MODE_IMPORTANT_INTERRUPTIONS;
         for (int i = 0; i < 3; i++) {
             // if zen doesn't change, zen should not reapply itself to the ringer
             mZenModeHelperSpy.evaluateZenMode("test", true);
@@ -756,7 +778,7 @@
 
         // apply zen off multiple times - verify ringer is not set to normal
         when(mAudioManager.getRingerModeInternal()).thenReturn(AudioManager.RINGER_MODE_VIBRATE);
-        mZenModeHelperSpy.mZenMode = Settings.Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS;
+        mZenModeHelperSpy.mZenMode = ZEN_MODE_IMPORTANT_INTERRUPTIONS;
         for (int i = 0; i < 3; i++) {
             // if zen doesn't change, zen should not reapply itself to the ringer
             mZenModeHelperSpy.evaluateZenMode("test", true);
@@ -768,7 +790,7 @@
 
     @Test
     public void testParcelConfig() {
-        mZenModeHelperSpy.mZenMode = Settings.Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS;
+        mZenModeHelperSpy.mZenMode = ZEN_MODE_IMPORTANT_INTERRUPTIONS;
         mZenModeHelperSpy.mConfig.allowAlarms = false;
         mZenModeHelperSpy.mConfig.allowMedia = false;
         mZenModeHelperSpy.mConfig.allowSystem = false;
@@ -792,7 +814,7 @@
 
     @Test
     public void testWriteXml() throws Exception {
-        mZenModeHelperSpy.mZenMode = Settings.Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS;
+        mZenModeHelperSpy.mZenMode = ZEN_MODE_IMPORTANT_INTERRUPTIONS;
         mZenModeHelperSpy.mConfig.allowAlarms = false;
         mZenModeHelperSpy.mConfig.allowMedia = false;
         mZenModeHelperSpy.mConfig.allowSystem = false;
@@ -806,7 +828,7 @@
         mZenModeHelperSpy.mConfig.suppressedVisualEffects = SUPPRESSED_EFFECT_BADGE;
         mZenModeHelperSpy.mConfig.manualRule = new ZenModeConfig.ZenRule();
         mZenModeHelperSpy.mConfig.manualRule.zenMode =
-                Settings.Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS;
+                ZEN_MODE_IMPORTANT_INTERRUPTIONS;
         mZenModeHelperSpy.mConfig.manualRule.component = new ComponentName("a", "a");
         mZenModeHelperSpy.mConfig.manualRule.pkg = "a";
         mZenModeHelperSpy.mConfig.manualRule.enabled = true;
@@ -822,6 +844,102 @@
     }
 
     @Test
+    public void testProto() {
+        mZenModeHelperSpy.mZenMode = ZEN_MODE_IMPORTANT_INTERRUPTIONS;
+        mZenModeHelperSpy.mConfig.manualRule = new ZenModeConfig.ZenRule();
+
+        int n = mZenModeHelperSpy.mConfig.automaticRules.size();
+        List<String> ids = new ArrayList<>(n);
+        for (ZenModeConfig.ZenRule rule : mZenModeHelperSpy.mConfig.automaticRules.values()) {
+            ids.add(rule.id);
+        }
+        ids.add("");
+
+        List<StatsEvent> events = new LinkedList<>();
+        mZenModeHelperSpy.pullRules(events);
+        assertEquals(n + 1, events.size());
+        for (WrappedSysUiStatsEvent.WrappedBuilder builder : mStatsEventBuilderFactory.builders) {
+            if (builder.getAtomId() == DND_MODE_RULE) {
+                if (builder.getInt(ZEN_MODE_FIELD_NUMBER) == DNDModeProto.ROOT_CONFIG) {
+                    assertTrue(builder.getBoolean(ENABLED_FIELD_NUMBER));
+                    assertFalse(builder.getBoolean(CHANNELS_BYPASSING_FIELD_NUMBER));
+                }
+                assertEquals(Process.SYSTEM_UID, builder.getInt(UID_FIELD_NUMBER));
+                assertTrue(builder.getBooleanAnnotation(UID_FIELD_NUMBER, ANNOTATION_ID_IS_UID));
+                String name = (String) builder.getValue(ID_FIELD_NUMBER);
+                assertTrue("unexpected rule id", ids.contains(name));
+                ids.remove(name);
+            } else {
+                fail("unexpected atom id: " + builder.getAtomId());
+            }
+        }
+        assertEquals("extra rule in output", 0, ids.size());
+    }
+
+    @Test
+    public void testProtoWithAutoRule() throws Exception {
+        setupZenConfig();
+        // one enabled automatic rule
+        mZenModeHelperSpy.mConfig.automaticRules = getCustomAutomaticRules(ZEN_MODE_FOR_TESTING);
+
+        List<StatsEvent> events = new LinkedList<>();
+        mZenModeHelperSpy.pullRules(events);
+
+        boolean foundCustomEvent = false;
+        for (WrappedSysUiStatsEvent.WrappedBuilder builder : mStatsEventBuilderFactory.builders) {
+            if (builder.getAtomId() == DND_MODE_RULE) {
+                if (ZEN_MODE_FOR_TESTING == builder.getInt(ZEN_MODE_FIELD_NUMBER)) {
+                    foundCustomEvent = true;
+                    assertEquals(0, builder.getInt(UID_FIELD_NUMBER));
+                    assertTrue(builder.getBoolean(ENABLED_FIELD_NUMBER));
+                }
+            } else {
+                fail("unexpected atom id: " + builder.getAtomId());
+            }
+        }
+        assertTrue("couldn't find custom rule", foundCustomEvent);
+    }
+
+    @Test
+    public void testProtoRedactsIds() throws Exception {
+        setupZenConfig();
+        // one enabled automatic rule
+        mZenModeHelperSpy.mConfig.automaticRules = getCustomAutomaticRules();
+
+        List<StatsEvent> events = new LinkedList<>();
+        mZenModeHelperSpy.pullRules(events);
+
+        boolean foundCustomEvent = false;
+        for (WrappedSysUiStatsEvent.WrappedBuilder builder : mStatsEventBuilderFactory.builders) {
+            if (builder.getAtomId() == DND_MODE_RULE
+                    && "customRule".equals(builder.getString(ID_FIELD_NUMBER))) {
+                fail("non-default IDs should be redacted");
+            }
+        }
+    }
+
+    @Test
+    public void testProtoWithManualRule() throws Exception {
+        setupZenConfig();
+        mZenModeHelperSpy.mConfig.automaticRules = getCustomAutomaticRules();
+        mZenModeHelperSpy.mConfig.manualRule = new ZenModeConfig.ZenRule();
+        mZenModeHelperSpy.mConfig.manualRule.enabled = true;
+        mZenModeHelperSpy.mConfig.manualRule.enabler = "com.enabler";
+
+        List<StatsEvent> events = new LinkedList<>();
+        mZenModeHelperSpy.pullRules(events);
+
+        boolean foundManualRule = false;
+        for (WrappedSysUiStatsEvent.WrappedBuilder builder : mStatsEventBuilderFactory.builders) {
+            if (builder.getAtomId() == DND_MODE_RULE
+                    && ZenModeConfig.MANUAL_RULE_ID.equals(builder.getString(ID_FIELD_NUMBER))) {
+                assertEquals(0, builder.getInt(UID_FIELD_NUMBER));
+                foundManualRule = true;
+            }
+        }
+        assertTrue("couldn't find manual rule", foundManualRule);    }
+
+    @Test
     public void testWriteXml_onlyBackupsTargetUser() throws Exception {
         // Setup configs for user 10 and 11.
         setupZenConfig();
@@ -906,7 +1024,7 @@
         customRule.creationTime = 0;
         customRule.id = "customRule";
         customRule.name = "Custom Rule";
-        customRule.zenMode = Settings.Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS;
+        customRule.zenMode = ZEN_MODE_IMPORTANT_INTERRUPTIONS;
         customRule.conditionId = ZenModeConfig.toScheduleConditionId(customRuleInfo);
         customRule.configurationActivity =
                 new ComponentName("android", "ScheduleConditionProvider");
@@ -951,7 +1069,7 @@
         customRule.creationTime = 0;
         customRule.id = ruleId;
         customRule.name = "Custom Rule";
-        customRule.zenMode = Settings.Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS;
+        customRule.zenMode = ZEN_MODE_IMPORTANT_INTERRUPTIONS;
         customRule.conditionId = ZenModeConfig.toScheduleConditionId(customRuleInfo);
         customRule.configurationActivity =
                 new ComponentName("android", "ScheduleConditionProvider");
@@ -986,7 +1104,7 @@
         final ScheduleInfo weeknights = new ScheduleInfo();
         customRule.enabled = true;
         customRule.name = "Custom Rule";
-        customRule.zenMode = Settings.Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS;
+        customRule.zenMode = ZEN_MODE_IMPORTANT_INTERRUPTIONS;
         customRule.conditionId = ZenModeConfig.toScheduleConditionId(weeknights);
         customRule.component = new ComponentName("android", "ScheduleConditionProvider");
         enabledAutoRule.put("customRule", customRule);
@@ -1151,7 +1269,7 @@
         final ScheduleInfo weeknights = new ScheduleInfo();
         customRule.enabled = false;
         customRule.name = "Custom Rule";
-        customRule.zenMode = Settings.Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS;
+        customRule.zenMode = ZEN_MODE_IMPORTANT_INTERRUPTIONS;
         customRule.conditionId = ZenModeConfig.toScheduleConditionId(weeknights);
         customRule.component = new ComponentName("android", "ScheduleConditionProvider");
         disabledAutoRule.put("customRule", customRule);
@@ -1187,7 +1305,7 @@
         final ScheduleInfo customRuleInfo = new ScheduleInfo();
         customRule.enabled = false;
         customRule.name = "Custom Rule";
-        customRule.zenMode = Settings.Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS;
+        customRule.zenMode = ZEN_MODE_IMPORTANT_INTERRUPTIONS;
         customRule.conditionId = ZenModeConfig.toScheduleConditionId(customRuleInfo);
         customRule.component = new ComponentName("android", "ScheduleConditionProvider");
         customRule.zenPolicy = new ZenPolicy.Builder()
@@ -1200,7 +1318,7 @@
         final ScheduleInfo defaultScheduleRuleInfo = new ScheduleInfo();
         defaultScheduleRule.enabled = false;
         defaultScheduleRule.name = "Default Schedule Rule";
-        defaultScheduleRule.zenMode = Settings.Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS;
+        defaultScheduleRule.zenMode = ZEN_MODE_IMPORTANT_INTERRUPTIONS;
         defaultScheduleRule.conditionId = ZenModeConfig.toScheduleConditionId(
                 defaultScheduleRuleInfo);
         customRule.component = new ComponentName("android", "ScheduleConditionProvider");
@@ -1238,7 +1356,7 @@
         final ScheduleInfo customRuleInfo = new ScheduleInfo();
         customRule.enabled = false;
         customRule.name = "Custom Rule";
-        customRule.zenMode = Settings.Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS;
+        customRule.zenMode = ZEN_MODE_IMPORTANT_INTERRUPTIONS;
         customRule.conditionId = ZenModeConfig.toScheduleConditionId(customRuleInfo);
         customRule.component = new ComponentName("android", "ScheduleConditionProvider");
         customRule.zenPolicy = new ZenPolicy.Builder()
@@ -1251,7 +1369,7 @@
         final ScheduleInfo defaultScheduleRuleInfo = new ScheduleInfo();
         defaultScheduleRule.enabled = false;
         defaultScheduleRule.name = "Default Schedule Rule";
-        defaultScheduleRule.zenMode = Settings.Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS;
+        defaultScheduleRule.zenMode = ZEN_MODE_IMPORTANT_INTERRUPTIONS;
         defaultScheduleRule.conditionId = ZenModeConfig.toScheduleConditionId(
                 defaultScheduleRuleInfo);
         defaultScheduleRule.id = ZenModeConfig.EVERY_NIGHT_DEFAULT_RULE_ID;
@@ -1265,7 +1383,7 @@
         final ScheduleInfo defaultEventRuleInfo = new ScheduleInfo();
         defaultEventRule.enabled = false;
         defaultEventRule.name = "Default Event Rule";
-        defaultEventRule.zenMode = Settings.Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS;
+        defaultEventRule.zenMode = ZEN_MODE_IMPORTANT_INTERRUPTIONS;
         defaultEventRule.conditionId = ZenModeConfig.toScheduleConditionId(
                 defaultEventRuleInfo);
         defaultEventRule.id = ZenModeConfig.EVENTS_DEFAULT_RULE_ID;
@@ -1295,6 +1413,10 @@
         assertTrue(rules.containsKey("customRule"));
 
         setupZenConfigMaintained();
+
+        List<StatsEvent> events = new LinkedList<>();
+        mZenModeHelperSpy.pullRules(events);
+        assertEquals(4, events.size());
     }
 
     @Test
@@ -1323,10 +1445,12 @@
 
     @Test
     public void testEmptyDefaultRulesMap() {
+        List<StatsEvent> events = new LinkedList<>();
         ZenModeConfig config = new ZenModeConfig();
         config.automaticRules = new ArrayMap<>();
         mZenModeHelperSpy.mConfig = config;
         mZenModeHelperSpy.updateDefaultZenRules(); // shouldn't throw null pointer
+        mZenModeHelperSpy.pullRules(events); // shouldn't throw null pointer
     }
 
     @Test
@@ -1342,7 +1466,7 @@
         updatedDefaultRule.creationTime = 0;
         updatedDefaultRule.id = SCHEDULE_DEFAULT_RULE_ID;
         updatedDefaultRule.name = "Schedule Default Rule";
-        updatedDefaultRule.zenMode = Settings.Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS;
+        updatedDefaultRule.zenMode = ZEN_MODE_IMPORTANT_INTERRUPTIONS;
         updatedDefaultRule.conditionId = ZenModeConfig.toScheduleConditionId(new ScheduleInfo());
         updatedDefaultRule.component = new ComponentName("android", "ScheduleConditionProvider");
 
@@ -1368,7 +1492,7 @@
         updatedDefaultRule.creationTime = 0;
         updatedDefaultRule.id = SCHEDULE_DEFAULT_RULE_ID;
         updatedDefaultRule.name = "Schedule Default Rule";
-        updatedDefaultRule.zenMode = Settings.Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS;
+        updatedDefaultRule.zenMode = ZEN_MODE_IMPORTANT_INTERRUPTIONS;
         updatedDefaultRule.conditionId = ZenModeConfig.toScheduleConditionId(new ScheduleInfo());
         updatedDefaultRule.component = new ComponentName("android", "ScheduleConditionProvider");
 
@@ -1395,7 +1519,7 @@
         customDefaultRule.creationTime = 0;
         customDefaultRule.id = SCHEDULE_DEFAULT_RULE_ID;
         customDefaultRule.name = "Schedule Default Rule";
-        customDefaultRule.zenMode = Settings.Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS;
+        customDefaultRule.zenMode = ZEN_MODE_IMPORTANT_INTERRUPTIONS;
         customDefaultRule.conditionId = ZenModeConfig.toScheduleConditionId(new ScheduleInfo());
         customDefaultRule.component = new ComponentName("android", "ScheduleConditionProvider");
 
@@ -1433,7 +1557,7 @@
     }
 
     private void setupZenConfig() {
-        mZenModeHelperSpy.mZenMode = Settings.Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS;
+        mZenModeHelperSpy.mZenMode = ZEN_MODE_IMPORTANT_INTERRUPTIONS;
         mZenModeHelperSpy.mConfig.allowAlarms = false;
         mZenModeHelperSpy.mConfig.allowMedia = false;
         mZenModeHelperSpy.mConfig.allowSystem = false;
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/ZenPolicyTest.java b/services/tests/uiservicestests/src/com/android/server/notification/ZenPolicyTest.java
index a0ee417..b16ca8b 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/ZenPolicyTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/ZenPolicyTest.java
@@ -17,14 +17,18 @@
 package com.android.server.notification;
 
 import static junit.framework.Assert.assertEquals;
+import static junit.framework.Assert.fail;
 
 import android.service.notification.ZenPolicy;
+import android.service.notification.nano.DNDPolicyProto;
 import android.test.suitebuilder.annotation.SmallTest;
 
 import androidx.test.runner.AndroidJUnit4;
 
 import com.android.server.UiServiceTestCase;
 
+import com.google.protobuf.nano.InvalidProtocolBufferNanoException;
+
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
@@ -190,6 +194,7 @@
         ZenPolicy policy = builder.build();
         assertEquals(ZenPolicy.STATE_UNSET, policy.getPriorityCategoryMessages());
         assertEquals(ZenPolicy.PEOPLE_TYPE_UNSET, policy.getPriorityMessageSenders());
+        assertProtoMatches(policy, policy.toProto());
     }
 
     @Test
@@ -201,6 +206,7 @@
         ZenPolicy policy = builder.build();
         assertEquals(ZenPolicy.STATE_ALLOW, policy.getPriorityCategoryCalls());
         assertEquals(ZenPolicy.PEOPLE_TYPE_ANYONE, policy.getPriorityCallSenders());
+        assertProtoMatches(policy, policy.toProto());
     }
 
     @Test
@@ -210,6 +216,7 @@
         ZenPolicy policy = builder.build();
         assertAllPriorityCategoriesUnsetExcept(policy, -1);
         assertAllVisualEffectsUnsetExcept(policy, -1);
+        assertProtoMatches(policy, policy.toProto());
     }
 
     @Test
@@ -221,12 +228,14 @@
         assertAllPriorityCategoriesUnsetExcept(policy, ZenPolicy.PRIORITY_CATEGORY_REMINDERS);
         assertEquals(ZenPolicy.STATE_ALLOW, policy.getPriorityCategoryReminders());
         assertAllVisualEffectsUnsetExcept(policy, -1);
+        assertProtoMatches(policy, policy.toProto());
 
         builder.allowReminders(false);
         policy = builder.build();
         assertAllPriorityCategoriesUnsetExcept(policy, ZenPolicy.PRIORITY_CATEGORY_REMINDERS);
         assertEquals(ZenPolicy.STATE_DISALLOW, policy.getPriorityCategoryReminders());
         assertAllVisualEffectsUnsetExcept(policy, -1);
+        assertProtoMatches(policy, policy.toProto());
     }
 
     @Test
@@ -238,12 +247,14 @@
         assertAllPriorityCategoriesUnsetExcept(policy, ZenPolicy.PRIORITY_CATEGORY_EVENTS);
         assertEquals(ZenPolicy.STATE_ALLOW, policy.getPriorityCategoryEvents());
         assertAllVisualEffectsUnsetExcept(policy, -1);
+        assertProtoMatches(policy, policy.toProto());
 
         builder.allowEvents(false);
         policy = builder.build();
         assertAllPriorityCategoriesUnsetExcept(policy, ZenPolicy.PRIORITY_CATEGORY_EVENTS);
         assertEquals(ZenPolicy.STATE_DISALLOW, policy.getPriorityCategoryEvents());
         assertAllVisualEffectsUnsetExcept(policy, -1);
+        assertProtoMatches(policy, policy.toProto());
     }
 
     @Test
@@ -256,6 +267,7 @@
         assertEquals(ZenPolicy.STATE_ALLOW, policy.getPriorityCategoryMessages());
         assertEquals(ZenPolicy.PEOPLE_TYPE_ANYONE, policy.getPriorityMessageSenders());
         assertAllVisualEffectsUnsetExcept(policy, -1);
+        assertProtoMatches(policy, policy.toProto());
 
         builder.allowMessages(ZenPolicy.PEOPLE_TYPE_CONTACTS);
         policy = builder.build();
@@ -263,6 +275,7 @@
         assertEquals(ZenPolicy.STATE_ALLOW, policy.getPriorityCategoryMessages());
         assertEquals(ZenPolicy.PEOPLE_TYPE_CONTACTS, policy.getPriorityMessageSenders());
         assertAllVisualEffectsUnsetExcept(policy, -1);
+        assertProtoMatches(policy, policy.toProto());
 
         builder.allowMessages(ZenPolicy.PEOPLE_TYPE_STARRED);
         policy = builder.build();
@@ -270,6 +283,7 @@
         assertEquals(ZenPolicy.STATE_ALLOW, policy.getPriorityCategoryMessages());
         assertEquals(ZenPolicy.PEOPLE_TYPE_STARRED, policy.getPriorityMessageSenders());
         assertAllVisualEffectsUnsetExcept(policy, -1);
+        assertProtoMatches(policy, policy.toProto());
 
         builder.allowMessages(ZenPolicy.PEOPLE_TYPE_NONE);
         policy = builder.build();
@@ -277,11 +291,13 @@
         assertEquals(ZenPolicy.STATE_DISALLOW, policy.getPriorityCategoryMessages());
         assertEquals(ZenPolicy.PEOPLE_TYPE_NONE, policy.getPriorityMessageSenders());
         assertAllVisualEffectsUnsetExcept(policy, -1);
+        assertProtoMatches(policy, policy.toProto());
 
         builder.allowMessages(ZenPolicy.PEOPLE_TYPE_UNSET);
         policy = builder.build();
         assertAllPriorityCategoriesUnsetExcept(policy, -1);
         assertAllVisualEffectsUnsetExcept(policy, -1);
+        assertProtoMatches(policy, policy.toProto());
     }
 
     @Test
@@ -294,6 +310,7 @@
         assertEquals(ZenPolicy.STATE_ALLOW, policy.getPriorityCategoryCalls());
         assertEquals(ZenPolicy.PEOPLE_TYPE_ANYONE, policy.getPriorityCallSenders());
         assertAllVisualEffectsUnsetExcept(policy, -1);
+        assertProtoMatches(policy, policy.toProto());
 
         builder.allowCalls(ZenPolicy.PEOPLE_TYPE_CONTACTS);
         policy = builder.build();
@@ -301,6 +318,7 @@
         assertEquals(ZenPolicy.STATE_ALLOW, policy.getPriorityCategoryCalls());
         assertEquals(ZenPolicy.PEOPLE_TYPE_CONTACTS, policy.getPriorityCallSenders());
         assertAllVisualEffectsUnsetExcept(policy, -1);
+        assertProtoMatches(policy, policy.toProto());
 
         builder.allowCalls(ZenPolicy.PEOPLE_TYPE_STARRED);
         policy = builder.build();
@@ -308,6 +326,7 @@
         assertEquals(ZenPolicy.STATE_ALLOW, policy.getPriorityCategoryCalls());
         assertEquals(ZenPolicy.PEOPLE_TYPE_STARRED, policy.getPriorityCallSenders());
         assertAllVisualEffectsUnsetExcept(policy, -1);
+        assertProtoMatches(policy, policy.toProto());
 
         builder.allowCalls(ZenPolicy.PEOPLE_TYPE_NONE);
         policy = builder.build();
@@ -315,11 +334,13 @@
         assertEquals(ZenPolicy.STATE_DISALLOW, policy.getPriorityCategoryCalls());
         assertEquals(ZenPolicy.PEOPLE_TYPE_NONE, policy.getPriorityCallSenders());
         assertAllVisualEffectsUnsetExcept(policy, -1);
+        assertProtoMatches(policy, policy.toProto());
 
         builder.allowCalls(ZenPolicy.PEOPLE_TYPE_UNSET);
         policy = builder.build();
         assertAllPriorityCategoriesUnsetExcept(policy, -1);
         assertAllVisualEffectsUnsetExcept(policy, -1);
+        assertProtoMatches(policy, policy.toProto());
     }
 
     @Test
@@ -331,12 +352,14 @@
         assertAllPriorityCategoriesUnsetExcept(policy, ZenPolicy.PRIORITY_CATEGORY_REPEAT_CALLERS);
         assertEquals(ZenPolicy.STATE_ALLOW, policy.getPriorityCategoryRepeatCallers());
         assertAllVisualEffectsUnsetExcept(policy, -1);
+        assertProtoMatches(policy, policy.toProto());
 
         builder.allowRepeatCallers(false);
         policy = builder.build();
         assertAllPriorityCategoriesUnsetExcept(policy, ZenPolicy.PRIORITY_CATEGORY_REPEAT_CALLERS);
         assertEquals(ZenPolicy.STATE_DISALLOW, policy.getPriorityCategoryRepeatCallers());
         assertAllVisualEffectsUnsetExcept(policy, -1);
+        assertProtoMatches(policy, policy.toProto());
     }
 
     @Test
@@ -348,12 +371,14 @@
         assertAllPriorityCategoriesUnsetExcept(policy, ZenPolicy.PRIORITY_CATEGORY_ALARMS);
         assertEquals(ZenPolicy.STATE_ALLOW, policy.getPriorityCategoryAlarms());
         assertAllVisualEffectsUnsetExcept(policy, -1);
+        assertProtoMatches(policy, policy.toProto());
 
         builder.allowAlarms(false);
         policy = builder.build();
         assertAllPriorityCategoriesUnsetExcept(policy, ZenPolicy.PRIORITY_CATEGORY_ALARMS);
         assertEquals(ZenPolicy.STATE_DISALLOW, policy.getPriorityCategoryAlarms());
         assertAllVisualEffectsUnsetExcept(policy, -1);
+        assertProtoMatches(policy, policy.toProto());
     }
 
     @Test
@@ -365,12 +390,14 @@
         assertAllPriorityCategoriesUnsetExcept(policy, ZenPolicy.PRIORITY_CATEGORY_MEDIA);
         assertEquals(ZenPolicy.STATE_ALLOW, policy.getPriorityCategoryMedia());
         assertAllVisualEffectsUnsetExcept(policy, -1);
+        assertProtoMatches(policy, policy.toProto());
 
         builder.allowMedia(false);
         policy = builder.build();
         assertAllPriorityCategoriesUnsetExcept(policy, ZenPolicy.PRIORITY_CATEGORY_MEDIA);
         assertEquals(ZenPolicy.STATE_DISALLOW, policy.getPriorityCategoryMedia());
         assertAllVisualEffectsUnsetExcept(policy, -1);
+        assertProtoMatches(policy, policy.toProto());
     }
 
     @Test
@@ -382,12 +409,119 @@
         assertAllPriorityCategoriesUnsetExcept(policy, ZenPolicy.PRIORITY_CATEGORY_SYSTEM);
         assertEquals(ZenPolicy.STATE_ALLOW, policy.getPriorityCategorySystem());
         assertAllVisualEffectsUnsetExcept(policy, -1);
+        assertProtoMatches(policy, policy.toProto());
 
         builder.allowSystem(false);
         policy = builder.build();
         assertAllPriorityCategoriesUnsetExcept(policy, ZenPolicy.PRIORITY_CATEGORY_SYSTEM);
         assertEquals(ZenPolicy.STATE_DISALLOW, policy.getPriorityCategorySystem());
         assertAllVisualEffectsUnsetExcept(policy, -1);
+        assertProtoMatches(policy, policy.toProto());
+    }
+
+    @Test
+    public void tesShowFullScreenIntent() {
+        ZenPolicy.Builder builder = new ZenPolicy.Builder();
+
+        builder.showFullScreenIntent(true);
+        ZenPolicy policy = builder.build();
+        assertAllVisualEffectsUnsetExcept(policy, ZenPolicy.VISUAL_EFFECT_FULL_SCREEN_INTENT);
+        assertProtoMatches(policy, policy.toProto());
+
+        builder.showFullScreenIntent(false);
+        policy = builder.build();
+        assertAllVisualEffectsUnsetExcept(policy, ZenPolicy.VISUAL_EFFECT_FULL_SCREEN_INTENT);
+        assertProtoMatches(policy, policy.toProto());
+    }
+
+    @Test
+    public void tesShowLights() {
+        ZenPolicy.Builder builder = new ZenPolicy.Builder();
+
+        builder.showLights(true);
+        ZenPolicy policy = builder.build();
+        assertAllVisualEffectsUnsetExcept(policy, ZenPolicy.VISUAL_EFFECT_LIGHTS);
+        assertProtoMatches(policy, policy.toProto());
+
+        builder.showLights(false);
+        policy = builder.build();
+        assertAllVisualEffectsUnsetExcept(policy, ZenPolicy.VISUAL_EFFECT_LIGHTS);
+        assertProtoMatches(policy, policy.toProto());
+    }
+
+    @Test
+    public void tesShowPeeking() {
+        ZenPolicy.Builder builder = new ZenPolicy.Builder();
+
+        builder.showPeeking(true);
+        ZenPolicy policy = builder.build();
+        assertAllVisualEffectsUnsetExcept(policy, ZenPolicy.VISUAL_EFFECT_PEEK);
+        assertProtoMatches(policy, policy.toProto());
+
+        builder.showPeeking(false);
+        policy = builder.build();
+        assertAllVisualEffectsUnsetExcept(policy, ZenPolicy.VISUAL_EFFECT_PEEK);
+        assertProtoMatches(policy, policy.toProto());
+    }
+
+    @Test
+    public void tesShowStatusBarIcons() {
+        ZenPolicy.Builder builder = new ZenPolicy.Builder();
+
+        builder.showStatusBarIcons(true);
+        ZenPolicy policy = builder.build();
+        assertAllVisualEffectsUnsetExcept(policy, ZenPolicy.VISUAL_EFFECT_STATUS_BAR);
+        assertProtoMatches(policy, policy.toProto());
+
+        builder.showStatusBarIcons(false);
+        policy = builder.build();
+        assertAllVisualEffectsUnsetExcept(policy, ZenPolicy.VISUAL_EFFECT_STATUS_BAR);
+        assertProtoMatches(policy, policy.toProto());
+    }
+
+    @Test
+    public void tesShowBadges() {
+        ZenPolicy.Builder builder = new ZenPolicy.Builder();
+
+        builder.showBadges(true);
+        ZenPolicy policy = builder.build();
+        assertAllVisualEffectsUnsetExcept(policy, ZenPolicy.VISUAL_EFFECT_BADGE);
+        assertProtoMatches(policy, policy.toProto());
+
+        builder.showBadges(false);
+        policy = builder.build();
+        assertAllVisualEffectsUnsetExcept(policy, ZenPolicy.VISUAL_EFFECT_BADGE);
+        assertProtoMatches(policy, policy.toProto());
+    }
+
+    @Test
+    public void tesShowInAmbientDisplay() {
+        ZenPolicy.Builder builder = new ZenPolicy.Builder();
+
+        builder.showInAmbientDisplay(true);
+        ZenPolicy policy = builder.build();
+        assertAllVisualEffectsUnsetExcept(policy, ZenPolicy.VISUAL_EFFECT_AMBIENT);
+        assertProtoMatches(policy, policy.toProto());
+
+        builder.showInAmbientDisplay(false);
+        policy = builder.build();
+        assertAllVisualEffectsUnsetExcept(policy, ZenPolicy.VISUAL_EFFECT_AMBIENT);
+        assertProtoMatches(policy, policy.toProto());
+    }
+
+    @Test
+    public void tesShowInNotificationList() {
+        ZenPolicy.Builder builder = new ZenPolicy.Builder();
+
+        builder.showInNotificationList(true);
+        ZenPolicy policy = builder.build();
+        assertAllVisualEffectsUnsetExcept(policy, ZenPolicy.VISUAL_EFFECT_NOTIFICATION_LIST);
+        assertProtoMatches(policy, policy.toProto());
+
+        builder.showInNotificationList(false);
+        policy = builder.build();
+        assertAllVisualEffectsUnsetExcept(policy, ZenPolicy.VISUAL_EFFECT_NOTIFICATION_LIST);
+        assertProtoMatches(policy, policy.toProto());
     }
 
     private void assertAllPriorityCategoriesUnsetExcept(ZenPolicy policy, int except) {
@@ -453,4 +587,35 @@
             assertEquals(ZenPolicy.STATE_UNSET, policy.getVisualEffectNotificationList());
         }
     }
+
+    private void assertProtoMatches(ZenPolicy policy, byte[] bytes) {
+        try {
+            DNDPolicyProto proto = DNDPolicyProto.parseFrom(bytes);
+
+            assertEquals(policy.getPriorityCategoryCalls(), proto.calls);
+            assertEquals(policy.getPriorityCategoryRepeatCallers(), proto.repeatCallers);
+            assertEquals(policy.getPriorityCategoryMessages(), proto.messages);
+            assertEquals(policy.getPriorityCategoryConversations(), proto.conversations);
+            assertEquals(policy.getPriorityCategoryReminders(), proto.reminders);
+            assertEquals(policy.getPriorityCategoryEvents(), proto.events);
+            assertEquals(policy.getPriorityCategoryAlarms(), proto.alarms);
+            assertEquals(policy.getPriorityCategoryMedia(), proto.media);
+            assertEquals(policy.getPriorityCategorySystem(), proto.system);
+
+            assertEquals(policy.getVisualEffectFullScreenIntent(), proto.fullscreen);
+            assertEquals(policy.getVisualEffectLights(), proto.lights);
+            assertEquals(policy.getVisualEffectPeek(), proto.peek);
+            assertEquals(policy.getVisualEffectStatusBar(), proto.statusBar);
+            assertEquals(policy.getVisualEffectBadge(), proto.badge);
+            assertEquals(policy.getVisualEffectAmbient(), proto.ambient);
+            assertEquals(policy.getVisualEffectNotificationList(), proto.notificationList);
+
+            assertEquals(policy.getPriorityCallSenders(), proto.allowCallsFrom);
+            assertEquals(policy.getPriorityMessageSenders(), proto.allowMessagesFrom);
+            assertEquals(policy.getPriorityConversationSenders(), proto.allowConversationsFrom);
+        } catch (InvalidProtocolBufferNanoException e) {
+            fail("could not parse proto bytes");
+        }
+
+    }
 }
diff --git a/services/tests/wmtests/AndroidManifest.xml b/services/tests/wmtests/AndroidManifest.xml
index 30df0d4..4040fa6 100644
--- a/services/tests/wmtests/AndroidManifest.xml
+++ b/services/tests/wmtests/AndroidManifest.xml
@@ -54,6 +54,8 @@
         <activity android:name="com.android.server.wm.TaskStackChangedListenerTest$ActivityViewTestActivity" />
         <activity android:name="com.android.server.wm.TaskStackChangedListenerTest$ActivityInActivityView"
                   android:resizeableActivity="true" />
+        <activity android:name="com.android.server.wm.TaskStackChangedListenerTest$ActivityLaunchesNewActivityInActivityView"
+            android:resizeableActivity="true" />
         <activity android:name="com.android.server.wm.TaskStackChangedListenerTest$LandscapeActivity"
                   android:screenOrientation="sensorLandscape"
                   android:showWhenLocked="true"
diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java b/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java
index 4ee933a..29b96eb 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java
@@ -794,6 +794,39 @@
     }
 
     /**
+     * Verify that when top focused activity is on secondary display, when finishing the top focused
+     * activity on default display, the preferred top stack on default display should be changed by
+     * adjusting focus.
+     */
+    @Test
+    public void testFinishActivityIfPossible_PreferredTopStackChanged() {
+        final ActivityRecord topActivityOnNonTopDisplay =
+                createActivityOnDisplay(true /* defaultDisplay */, null /* process */);
+        ActivityStack topRootableTask = topActivityOnNonTopDisplay.getRootTask();
+        topRootableTask.moveToFront("test");
+        assertTrue(topRootableTask.isTopStackInDisplayArea());
+        assertEquals(topRootableTask, topActivityOnNonTopDisplay.getDisplayArea()
+                .mPreferredTopFocusableStack);
+
+        final ActivityRecord secondaryDisplayActivity =
+                createActivityOnDisplay(false /* defaultDisplay */, null /* process */);
+        topRootableTask = secondaryDisplayActivity.getRootTask();
+        topRootableTask.moveToFront("test");
+        assertTrue(topRootableTask.isTopStackInDisplayArea());
+        assertEquals(topRootableTask,
+                secondaryDisplayActivity.getDisplayArea().mPreferredTopFocusableStack);
+
+        // The global top focus activity is on secondary display now.
+        // Finish top activity on default display and verify the next preferred top focusable stack
+        // on default display has changed.
+        topActivityOnNonTopDisplay.setState(RESUMED, "test");
+        topActivityOnNonTopDisplay.finishIfPossible(0 /* resultCode */, null /* resultData */,
+                null /* resultGrants */, "test", false /* oomAdj */);
+        assertEquals(mTask, mStack.getTopMostTask());
+        assertEquals(mStack, mActivity.getDisplayArea().mPreferredTopFocusableStack);
+    }
+
+    /**
      * Verify that resumed activity is paused due to finish request.
      */
     @Test
diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityTaskManagerServiceTests.java b/services/tests/wmtests/src/com/android/server/wm/ActivityTaskManagerServiceTests.java
index bd616a3..64b5eca 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ActivityTaskManagerServiceTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ActivityTaskManagerServiceTests.java
@@ -17,7 +17,6 @@
 package com.android.server.wm;
 
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.any;
-import static com.android.dx.mockito.inline.extended.ExtendedMockito.doNothing;
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn;
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.mock;
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.mockitoSession;
@@ -111,7 +110,7 @@
         final ActivityStack stack = new StackBuilder(mRootWindowContainer).build();
         final ActivityRecord activity = stack.getBottomMostTask().getTopNonFinishingActivity();
         ClientLifecycleManager lifecycleManager = mService.getLifecycleManager();
-        doNothing().when(lifecycleManager).scheduleTransaction(any());
+        doReturn(false).when(activity).inPinnedWindowingMode();
         doReturn(false).when(activity).checkEnterPictureInPictureState(anyString(), anyBoolean());
 
         mService.requestPictureInPictureMode(activity.token);
@@ -120,6 +119,19 @@
         verify(lifecycleManager, times(0)).scheduleTransaction(any());
     }
 
+    @Test(expected = IllegalStateException.class)
+    public void testOnPictureInPictureRequested_alreadyInPIPMode() throws RemoteException {
+        final ActivityStack stack = new StackBuilder(mRootWindowContainer).build();
+        final ActivityRecord activity = stack.getBottomMostTask().getTopNonFinishingActivity();
+        ClientLifecycleManager lifecycleManager = mService.getLifecycleManager();
+        doReturn(true).when(activity).inPinnedWindowingMode();
+
+        mService.requestPictureInPictureMode(activity.token);
+
+        // Check that no transactions with enter pip requests are made.
+        verify(lifecycleManager, times(0)).scheduleTransaction(any());
+    }
+
     @Test
     public void testDisplayWindowListener() {
         final ArrayList<Integer> added = new ArrayList<>();
diff --git a/services/tests/wmtests/src/com/android/server/wm/AppWindowTokenTests.java b/services/tests/wmtests/src/com/android/server/wm/AppWindowTokenTests.java
index 02de408..a16bd2a 100644
--- a/services/tests/wmtests/src/com/android/server/wm/AppWindowTokenTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/AppWindowTokenTests.java
@@ -38,7 +38,7 @@
 
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.doCallRealMethod;
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn;
-import static com.android.dx.mockito.inline.extended.ExtendedMockito.mock;
+import static com.android.server.wm.WindowContainer.POSITION_TOP;
 import static com.android.server.wm.WindowStateAnimator.STACK_CLIP_AFTER_ANIM;
 import static com.android.server.wm.WindowStateAnimator.STACK_CLIP_BEFORE_ANIM;
 import static com.android.server.wm.WindowStateAnimator.STACK_CLIP_NONE;
@@ -65,12 +65,12 @@
 import androidx.test.filters.FlakyTest;
 import androidx.test.filters.SmallTest;
 
-import com.android.server.wm.SurfaceAnimator.OnAnimationFinishedCallback;
-
 import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
+import java.util.ArrayList;
+
 /**
  * Tests for the {@link ActivityRecord} class.
  *
@@ -406,12 +406,11 @@
         assertHasStartingWindow(activity2);
 
         // Assert that bottom activity is allowed to do animation.
+        ArrayList<WindowContainer> sources = new ArrayList<>();
+        sources.add(activity2);
         doReturn(true).when(activity2).okToAnimate();
         doReturn(true).when(activity2).isAnimating();
-        final OnAnimationFinishedCallback onAnimationFinishedCallback =
-                mock(OnAnimationFinishedCallback.class);
-        assertTrue(activity2.applyAnimation(null, TRANSIT_ACTIVITY_OPEN, true, false,
-                onAnimationFinishedCallback));
+        assertTrue(activity2.applyAnimation(null, TRANSIT_ACTIVITY_OPEN, true, false, sources));
     }
 
     @Test
@@ -454,6 +453,32 @@
         assertFalse(middle.isVisible());
     }
 
+    @Test
+    public void testTransferStartingWindowSetFixedRotation() {
+        mWm.mIsFixedRotationTransformEnabled = true;
+        final ActivityRecord topActivity = createTestActivityRecordForGivenTask(mTask);
+        mTask.positionChildAt(topActivity, POSITION_TOP);
+        mActivity.addStartingWindow(mPackageName,
+                android.R.style.Theme, null, "Test", 0, 0, 0, 0, null, true, true, false, true,
+                false);
+        waitUntilHandlersIdle();
+
+        // Make activities to have different rotation from it display and set fixed rotation
+        // transform to activity1.
+        int rotation = (mDisplayContent.getRotation() + 1) % 4;
+        mDisplayContent.setFixedRotationLaunchingApp(mActivity, rotation);
+        doReturn(rotation).when(mDisplayContent)
+                .rotationForActivityInDifferentOrientation(topActivity);
+
+        // Make sure the fixed rotation transform linked to activity2 when adding starting window
+        // on activity2.
+        topActivity.addStartingWindow(mPackageName,
+                android.R.style.Theme, null, "Test", 0, 0, 0, 0, mActivity.appToken.asBinder(),
+                false, false, false, true, false);
+        waitUntilHandlersIdle();
+        assertTrue(topActivity.hasFixedRotationTransform());
+    }
+
     private ActivityRecord createIsolatedTestActivityRecord() {
         final ActivityStack taskStack = createTaskStackOnDisplay(mDisplayContent);
         final Task task = createTaskInStack(taskStack, 0 /* userId */);
diff --git a/services/tests/wmtests/src/com/android/server/wm/DimmerTests.java b/services/tests/wmtests/src/com/android/server/wm/DimmerTests.java
index 77ceeed..f7beb74 100644
--- a/services/tests/wmtests/src/com/android/server/wm/DimmerTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/DimmerTests.java
@@ -29,18 +29,14 @@
 import static org.mockito.ArgumentMatchers.any;
 import static org.mockito.ArgumentMatchers.anyBoolean;
 import static org.mockito.ArgumentMatchers.eq;
-import static org.mockito.ArgumentMatchers.isNull;
-import static org.mockito.Mockito.never;
 import static org.mockito.Mockito.when;
 
-import android.annotation.Nullable;
 import android.graphics.Rect;
 import android.platform.test.annotations.Presubmit;
 import android.view.SurfaceControl;
 import android.view.SurfaceSession;
 
 import com.android.server.wm.SurfaceAnimator.AnimationType;
-import com.android.server.wm.SurfaceAnimator.OnAnimationFinishedCallback;
 
 import org.junit.Before;
 import org.junit.Test;
@@ -119,12 +115,8 @@
     private static class SurfaceAnimatorStarterImpl implements Dimmer.SurfaceAnimatorStarter {
         @Override
         public void startAnimation(SurfaceAnimator surfaceAnimator, SurfaceControl.Transaction t,
-                AnimationAdapter anim, boolean hidden, @AnimationType int type,
-                @Nullable OnAnimationFinishedCallback animationFinishedCallback) {
+                AnimationAdapter anim, boolean hidden, @AnimationType int type) {
             surfaceAnimator.mStaticAnimationFinishedCallback.onAnimationFinished(type, anim);
-            if (animationFinishedCallback != null) {
-                animationFinishedCallback.onAnimationFinished(type, anim);
-            }
         }
     }
 
@@ -229,7 +221,7 @@
         mDimmer.updateDims(mTransaction, new Rect());
         verify(mSurfaceAnimatorStarter).startAnimation(any(SurfaceAnimator.class), any(
                 SurfaceControl.Transaction.class), any(AnimationAdapter.class), anyBoolean(),
-                eq(ANIMATION_TYPE_DIMMER), isNull());
+                eq(ANIMATION_TYPE_DIMMER));
         verify(mHost.getPendingTransaction()).remove(dimLayer);
     }
 
@@ -287,7 +279,7 @@
         mDimmer.updateDims(mTransaction, new Rect());
         verify(mSurfaceAnimatorStarter, never()).startAnimation(any(SurfaceAnimator.class), any(
                 SurfaceControl.Transaction.class), any(AnimationAdapter.class), anyBoolean(),
-                eq(ANIMATION_TYPE_DIMMER), isNull());
+                eq(ANIMATION_TYPE_DIMMER));
         verify(mTransaction).remove(dimLayer);
     }
 
diff --git a/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java b/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java
index 4ad7dff..d3f677c 100644
--- a/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java
@@ -1144,7 +1144,14 @@
         assertTrue(app.hasFixedRotationTransform(app2));
         assertTrue(mDisplayContent.isFixedRotationLaunchingApp(app2));
 
+        // The fixed rotation transform can only be finished when all animation finished.
+        doReturn(false).when(app2).isAnimating(anyInt(), anyInt());
+        mDisplayContent.mAppTransition.notifyAppTransitionFinishedLocked(app2.token);
+        assertTrue(app.hasFixedRotationTransform());
+        assertTrue(app2.hasFixedRotationTransform());
+
         // The display should be rotated after the launch is finished.
+        doReturn(false).when(app).isAnimating(anyInt(), anyInt());
         mDisplayContent.mAppTransition.notifyAppTransitionFinishedLocked(app.token);
 
         // The fixed rotation should be cleared and the new rotation is applied to display.
diff --git a/services/tests/wmtests/src/com/android/server/wm/DisplayPolicyLayoutTests.java b/services/tests/wmtests/src/com/android/server/wm/DisplayPolicyLayoutTests.java
index 27c4e9b..1922351 100644
--- a/services/tests/wmtests/src/com/android/server/wm/DisplayPolicyLayoutTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/DisplayPolicyLayoutTests.java
@@ -57,6 +57,7 @@
 import android.graphics.Rect;
 import android.platform.test.annotations.Presubmit;
 import android.util.Pair;
+import android.util.SparseArray;
 import android.view.DisplayCutout;
 import android.view.DisplayInfo;
 import android.view.InsetsState;
@@ -776,15 +777,15 @@
     }
 
     private void assertSimulateLayoutSameDisplayFrames() {
-        final int uiMode = 0;
         final String prefix = "";
         final InsetsState simulatedInsetsState = new InsetsState();
         final DisplayFrames simulatedDisplayFrames = createDisplayFrames();
-        mDisplayPolicy.beginLayoutLw(mFrames, uiMode);
+        mDisplayPolicy.beginLayoutLw(mFrames, mDisplayContent.getConfiguration().uiMode);
         // Force the display bounds because it is not synced with display frames in policy test.
         mDisplayContent.getWindowConfiguration().setBounds(mFrames.mUnrestricted);
         mDisplayContent.getInsetsStateController().onPostLayout();
-        mDisplayPolicy.simulateLayoutDisplay(simulatedDisplayFrames, simulatedInsetsState, uiMode);
+        mDisplayPolicy.simulateLayoutDisplay(simulatedDisplayFrames, simulatedInsetsState,
+                new SparseArray<>() /* barContentFrames */);
 
         final StringWriter realFramesDump = new StringWriter();
         mFrames.dump(prefix, new PrintWriter(realFramesDump));
diff --git a/services/tests/wmtests/src/com/android/server/wm/RecentsAnimationControllerTest.java b/services/tests/wmtests/src/com/android/server/wm/RecentsAnimationControllerTest.java
index ca6679d..243468a 100644
--- a/services/tests/wmtests/src/com/android/server/wm/RecentsAnimationControllerTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/RecentsAnimationControllerTest.java
@@ -349,11 +349,19 @@
         assertEquals(Configuration.ORIENTATION_PORTRAIT,
                 homeActivity.getConfiguration().orientation);
 
-        // Home activity won't become top (return to landActivity), so its fixed rotation and the
-        // top rotated record should be cleared.
+        // Home activity won't become top (return to landActivity), so the top rotated record should
+        // be cleared.
         mController.cleanupAnimation(REORDER_MOVE_TO_ORIGINAL_POSITION);
-        assertFalse(homeActivity.hasFixedRotationTransform());
+        assertFalse(mDefaultDisplay.isFixedRotationLaunchingApp(homeActivity));
         assertFalse(mDefaultDisplay.hasTopFixedRotationLaunchingApp());
+        // The transform should keep until the transition is done, so the restored configuration
+        // won't be sent to activity and cause unnecessary configuration change.
+        assertTrue(homeActivity.hasFixedRotationTransform());
+
+        // In real case the transition will be executed from RecentsAnimation#finishAnimation.
+        mDefaultDisplay.mFixedRotationTransitionListener.onAppTransitionFinishedLocked(
+                homeActivity.token);
+        assertFalse(homeActivity.hasFixedRotationTransform());
     }
 
     @Test
diff --git a/services/tests/wmtests/src/com/android/server/wm/SizeCompatTests.java b/services/tests/wmtests/src/com/android/server/wm/SizeCompatTests.java
index 665cf83..15b395c 100644
--- a/services/tests/wmtests/src/com/android/server/wm/SizeCompatTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/SizeCompatTests.java
@@ -24,6 +24,7 @@
 import static android.view.Surface.ROTATION_90;
 
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.doNothing;
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn;
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.eq;
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.mock;
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.never;
@@ -288,14 +289,29 @@
 
         // Move the non-resizable activity to the new display.
         mStack.reparent(newDisplay.getDefaultTaskDisplayArea(), true /* onTop */);
-        // The configuration bounds should keep the same.
+        // The configuration bounds [820, 0 - 1820, 2500] should keep the same.
         assertEquals(origWidth, configBounds.width());
         assertEquals(origHeight, configBounds.height());
         assertScaled();
 
+        final Rect newDisplayBounds = newDisplay.getWindowConfiguration().getBounds();
         // The scaled bounds should exclude notch area (1000 - 100 == 360 * 2500 / 1000 = 900).
-        assertEquals(newDisplay.getBounds().height() - notchHeight,
+        assertEquals(newDisplayBounds.height() - notchHeight,
                 (int) ((float) mActivity.getBounds().width() * origHeight / origWidth));
+
+        // Recompute the natural configuration in the new display.
+        mActivity.clearSizeCompatMode();
+        mActivity.ensureActivityConfiguration(0 /* globalChanges */, false /* preserveWindow */);
+        // Because the display cannot rotate, the portrait activity will fit the short side of
+        // display with keeping portrait bounds [200, 0 - 700, 1000] in center.
+        assertEquals(newDisplayBounds.height(), configBounds.height());
+        assertEquals(configBounds.height() * newDisplayBounds.height() / newDisplayBounds.width(),
+                configBounds.width());
+        assertFitted();
+        // The appBounds should be [200, 100 - 700, 1000].
+        final Rect appBounds = mActivity.getWindowConfiguration().getAppBounds();
+        assertEquals(configBounds.width(), appBounds.width());
+        assertEquals(configBounds.height() - notchHeight, appBounds.height());
     }
 
     @Test
@@ -491,7 +507,10 @@
         mService.mWindowManager.mIsFixedRotationTransformEnabled = true;
         final int dw = 1000;
         final int dh = 2500;
-        setUpDisplaySizeWithApp(dw, dh);
+        final int notchHeight = 200;
+        setUpApp(new TestDisplayContent.Builder(mService, dw, dh).setNotch(notchHeight).build());
+        addStatusBar(mActivity.mDisplayContent);
+
         mActivity.mDisplayContent.prepareAppTransition(WindowManager.TRANSIT_ACTIVITY_OPEN,
                 false /* alwaysKeepCurrent */);
         mActivity.mDisplayContent.mOpeningApps.add(mActivity);
@@ -503,31 +522,76 @@
         // Display keeps in original orientation.
         assertEquals(Configuration.ORIENTATION_PORTRAIT,
                 mActivity.mDisplayContent.getConfiguration().orientation);
-        // Activity bounds should be [350, 0 - 2150, 1000] in landscape. Its width=1000*1.8=1800.
+        // The width should be restricted by the max aspect ratio = 1000 * 1.8 = 1800.
         assertEquals((int) (dw * maxAspect), mActivity.getBounds().width());
-        // The bounds should be horizontal centered: (2500-1900)/2=350.
-        assertEquals((dh - mActivity.getBounds().width()) / 2, mActivity.getBounds().left);
+        // The notch is at the left side of the landscape activity. The bounds should be horizontal
+        // centered in the remaining area [200, 0 - 2500, 1000], so its left should be
+        // 200 + (2300 - 1800) / 2 = 450. The bounds should be [450, 0 - 2250, 1000].
+        assertEquals(notchHeight + (dh - notchHeight - mActivity.getBounds().width()) / 2,
+                mActivity.getBounds().left);
 
         // The letterbox needs a main window to layout.
-        addWindowToActivity(mActivity);
+        final WindowState w = addWindowToActivity(mActivity);
         // Compute the frames of the window and invoke {@link ActivityRecord#layoutLetterbox}.
         mActivity.mRootWindowContainer.performSurfacePlacement();
-        // The letterbox insets should be [350, 0 - 350, 0].
+        // The letterbox insets should be [450, 0 - 250, 0].
         assertEquals(new Rect(mActivity.getBounds().left, 0, dh - mActivity.getBounds().right, 0),
                 mActivity.getLetterboxInsets());
+
+        final StatusBarController statusBarController =
+                mActivity.mDisplayContent.getDisplayPolicy().getStatusBarController();
+        // The activity doesn't fill the display, so the letterbox of the rotated activity is
+        // overlapped with the rotated content frame of status bar. Hence the status bar shouldn't
+        // be transparent.
+        assertFalse(statusBarController.isTransparentAllowed(w));
+
+        // Make the activity fill the display.
+        prepareUnresizable(10 /* maxAspect */, SCREEN_ORIENTATION_LANDSCAPE);
+        w.mWinAnimator.mDrawState = WindowStateAnimator.HAS_DRAWN;
+        // Refresh the letterbox.
+        mActivity.mRootWindowContainer.performSurfacePlacement();
+
+        // The letterbox should only cover the notch area, so status bar can be transparent.
+        assertEquals(new Rect(notchHeight, 0, 0, 0), mActivity.getLetterboxInsets());
+        assertTrue(statusBarController.isTransparentAllowed(w));
     }
 
-    private WindowState addWindowToActivity(ActivityRecord activity) {
+    private static WindowState addWindowToActivity(ActivityRecord activity) {
         final WindowManager.LayoutParams params = new WindowManager.LayoutParams();
         params.type = WindowManager.LayoutParams.TYPE_BASE_APPLICATION;
         final WindowTestUtils.TestWindowState w = new WindowTestUtils.TestWindowState(
-                mService.mWindowManager, mock(Session.class), new TestIWindow(), params, mActivity);
+                activity.mWmService, mock(Session.class), new TestIWindow(), params, activity);
         WindowTestsBase.makeWindowVisible(w);
         w.mWinAnimator.mDrawState = WindowStateAnimator.HAS_DRAWN;
-        mActivity.addWindow(w);
+        activity.addWindow(w);
         return w;
     }
 
+    private static void addStatusBar(DisplayContent displayContent) {
+        final DisplayPolicy displayPolicy = displayContent.getDisplayPolicy();
+        doReturn(true).when(displayPolicy).hasStatusBar();
+        displayPolicy.onConfigurationChanged();
+
+        final WindowTestUtils.TestWindowToken token = WindowTestUtils.createTestWindowToken(
+                WindowManager.LayoutParams.TYPE_STATUS_BAR, displayContent);
+        final WindowManager.LayoutParams attrs =
+                new WindowManager.LayoutParams(WindowManager.LayoutParams.TYPE_STATUS_BAR);
+        attrs.gravity = android.view.Gravity.TOP;
+        attrs.layoutInDisplayCutoutMode =
+                WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS;
+        attrs.setFitInsetsTypes(0 /* types */);
+        final WindowTestUtils.TestWindowState statusBar = new WindowTestUtils.TestWindowState(
+                displayContent.mWmService, mock(Session.class), new TestIWindow(), attrs, token);
+        token.addWindow(statusBar);
+        statusBar.setRequestedSize(displayContent.mBaseDisplayWidth,
+                displayContent.getDisplayUiContext().getResources().getDimensionPixelSize(
+                        com.android.internal.R.dimen.status_bar_height));
+
+        displayPolicy.addWindowLw(statusBar, attrs);
+        displayPolicy.beginLayoutLw(displayContent.mDisplayFrames,
+                displayContent.getConfiguration().uiMode);
+    }
+
     /**
      * Setup {@link #mActivity} as a size-compat-mode-able activity with fixed aspect and/or
      * orientation.
diff --git a/services/tests/wmtests/src/com/android/server/wm/TaskStackChangedListenerTest.java b/services/tests/wmtests/src/com/android/server/wm/TaskStackChangedListenerTest.java
index 2c17bbe..2bd3424 100644
--- a/services/tests/wmtests/src/com/android/server/wm/TaskStackChangedListenerTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/TaskStackChangedListenerTest.java
@@ -299,6 +299,20 @@
         waitForCallback(singleTaskDisplayDrawnLatch);
     }
 
+    public static class ActivityLaunchesNewActivityInActivityView extends TestActivity {
+        private boolean mActivityBLaunched = false;
+
+        @Override
+        protected void onPostResume() {
+            super.onPostResume();
+            if (mActivityBLaunched) {
+                return;
+            }
+            mActivityBLaunched = true;
+            startActivity(new Intent(this, ActivityB.class));
+        }
+    }
+
     @Test
     public void testSingleTaskDisplayEmpty() throws Exception {
         final Instrumentation instrumentation = getInstrumentation();
@@ -335,13 +349,20 @@
         });
         waitForCallback(activityViewReadyLatch);
 
+        // 1. start ActivityLaunchesNewActivityInActivityView in an ActivityView
+        // 2. ActivityLaunchesNewActivityInActivityView launches ActivityB
+        // 3. ActivityB finishes self.
+        // 4. Verify ITaskStackListener#onSingleTaskDisplayEmpty is not called yet.
         final Context context = instrumentation.getContext();
-        Intent intent = new Intent(context, ActivityInActivityView.class);
+        Intent intent = new Intent(context, ActivityLaunchesNewActivityInActivityView.class);
         intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_MULTIPLE_TASK);
         activityView.startActivity(intent);
         waitForCallback(singleTaskDisplayDrawnLatch);
+        UiDevice.getInstance(getInstrumentation()).waitForIdle();
         assertEquals(1, singleTaskDisplayEmptyLatch.getCount());
 
+        // 5. Release the container, and ActivityLaunchesNewActivityInActivityView finishes.
+        // 6. Verify ITaskStackListener#onSingleTaskDisplayEmpty is called.
         activityView.release();
         waitForCallback(activityViewDestroyedLatch);
         waitForCallback(singleTaskDisplayEmptyLatch);
diff --git a/services/tests/wmtests/src/com/android/server/wm/TaskStackTests.java b/services/tests/wmtests/src/com/android/server/wm/TaskStackTests.java
index d65b084..f1dbde0 100644
--- a/services/tests/wmtests/src/com/android/server/wm/TaskStackTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/TaskStackTests.java
@@ -153,7 +153,8 @@
 
         // Stack removal is deferred if one of its child is animating.
         doReturn(true).when(stack).hasWindowsAlive();
-        doReturn(true).when(task).isAnimating(eq(TRANSITION | CHILDREN), anyInt());
+        doReturn(stack).when(task).getAnimatingContainer(
+                eq(TRANSITION | CHILDREN), anyInt());
 
         stack.removeIfPossible();
         // For the case of deferred removal the task controller will still be connected to the its
diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowContainerTests.java b/services/tests/wmtests/src/com/android/server/wm/WindowContainerTests.java
index 00439f8..87485ea 100644
--- a/services/tests/wmtests/src/com/android/server/wm/WindowContainerTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/WindowContainerTests.java
@@ -66,14 +66,14 @@
 
 import androidx.test.filters.SmallTest;
 
-import com.android.server.wm.SurfaceAnimator.OnAnimationFinishedCallback;
-
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.mockito.Mockito;
 
+import java.util.ArrayList;
 import java.util.Comparator;
 
+
 /**
  * Test class for {@link WindowContainer}.
  *
@@ -828,17 +828,21 @@
     public void testTaskCanApplyAnimation() {
         final ActivityStack stack = createTaskStackOnDisplay(mDisplayContent);
         final Task task = createTaskInStack(stack, 0 /* userId */);
-        final ActivityRecord activity =
+        final ActivityRecord activity2 =
                 WindowTestUtils.createActivityRecordInTask(mDisplayContent, task);
-        verifyWindowContainerApplyAnimation(task, activity);
+        final ActivityRecord activity1 =
+                WindowTestUtils.createActivityRecordInTask(mDisplayContent, task);
+        verifyWindowContainerApplyAnimation(task, activity1, activity2);
     }
 
     @Test
     public void testStackCanApplyAnimation() {
         final ActivityStack stack = createTaskStackOnDisplay(mDisplayContent);
-        final ActivityRecord activity = WindowTestUtils.createActivityRecordInTask(mDisplayContent,
+        final ActivityRecord activity2 = WindowTestUtils.createActivityRecordInTask(mDisplayContent,
                 createTaskInStack(stack, 0 /* userId */));
-        verifyWindowContainerApplyAnimation(stack, activity);
+        final ActivityRecord activity1 = WindowTestUtils.createActivityRecordInTask(mDisplayContent,
+                createTaskInStack(stack, 0 /* userId */));
+        verifyWindowContainerApplyAnimation(stack, activity1, activity2);
     }
 
     @Test
@@ -871,7 +875,8 @@
         assertEquals(displayArea, displayArea.getDisplayArea());
     }
 
-    private void verifyWindowContainerApplyAnimation(WindowContainer wc, ActivityRecord act) {
+    private void verifyWindowContainerApplyAnimation(WindowContainer wc, ActivityRecord act,
+            ActivityRecord act2) {
         // Initial remote animation for app transition.
         final RemoteAnimationAdapter adapter = new RemoteAnimationAdapter(
                 new IRemoteAnimationRunner.Stub() {
@@ -895,17 +900,23 @@
         wc.getDisplayContent().mAppTransition.overridePendingAppTransitionRemote(adapter);
         spyOn(wc);
         doReturn(true).when(wc).okToAnimate();
-        final OnAnimationFinishedCallback onAnimationFinishedCallback =
-                mock(OnAnimationFinishedCallback.class);
 
         // Make sure animating state is as expected after applied animation.
-        assertTrue(wc.applyAnimation(null, TRANSIT_TASK_OPEN, true, false,
-                onAnimationFinishedCallback));
-        assertEquals(wc.getTopMostActivity(), act);
+
+        // Animation target is promoted from act to wc. act2 is a descendant of wc, but not a source
+        // of the animation.
+        ArrayList<WindowContainer<WindowState>> sources = new ArrayList<>();
+        sources.add(act);
+        assertTrue(wc.applyAnimation(null, TRANSIT_TASK_OPEN, true, false, sources));
+
+        assertEquals(act, wc.getTopMostActivity());
         assertTrue(wc.isAnimating());
+        assertTrue(wc.isAnimating(0, ANIMATION_TYPE_APP_TRANSITION));
+        assertTrue(wc.getAnimationSources().contains(act));
+        assertFalse(wc.getAnimationSources().contains(act2));
         assertTrue(act.isAnimating(PARENTS));
-        verify(onAnimationFinishedCallback, times(0)).onAnimationFinished(
-                eq(ANIMATION_TYPE_APP_TRANSITION), any());
+        assertTrue(act.isAnimating(PARENTS, ANIMATION_TYPE_APP_TRANSITION));
+        assertEquals(wc, act.getAnimatingContainer(PARENTS, ANIMATION_TYPE_APP_TRANSITION));
 
         // Make sure animation finish callback will be received and reset animating state after
         // animation finish.
@@ -914,8 +925,6 @@
         verify(wc).onAnimationFinished(eq(ANIMATION_TYPE_APP_TRANSITION), any());
         assertFalse(wc.isAnimating());
         assertFalse(act.isAnimating(PARENTS));
-        verify(onAnimationFinishedCallback, times(1)).onAnimationFinished(
-                eq(ANIMATION_TYPE_APP_TRANSITION), any());
     }
 
     /* Used so we can gain access to some protected members of the {@link WindowContainer} class */
diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowStateTests.java b/services/tests/wmtests/src/com/android/server/wm/WindowStateTests.java
index e9ed20b..b51784d 100644
--- a/services/tests/wmtests/src/com/android/server/wm/WindowStateTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/WindowStateTests.java
@@ -692,4 +692,14 @@
         sameTokenWindow.removeImmediately();
         assertFalse(sameTokenWindow.needsRelativeLayeringToIme());
     }
+
+    @Test
+    public void testNeedsRelativeLayeringToIme_startingWindow() {
+        WindowState sameTokenWindow = createWindow(null, TYPE_APPLICATION_STARTING,
+                mAppWindow.mToken, "SameTokenWindow");
+        mDisplayContent.mInputMethodTarget = mAppWindow;
+        sameTokenWindow.mActivityRecord.getStack().setWindowingMode(
+                WINDOWING_MODE_SPLIT_SCREEN_PRIMARY);
+        assertFalse(sameTokenWindow.needsRelativeLayeringToIme());
+    }
 }
diff --git a/telephony/common/com/android/internal/telephony/CarrierAppUtils.java b/telephony/common/com/android/internal/telephony/CarrierAppUtils.java
index b3d7c0d..4606fb4 100644
--- a/telephony/common/com/android/internal/telephony/CarrierAppUtils.java
+++ b/telephony/common/com/android/internal/telephony/CarrierAppUtils.java
@@ -21,7 +21,6 @@
 import android.content.Context;
 import android.content.pm.ApplicationInfo;
 import android.content.pm.PackageManager;
-import android.content.res.Resources;
 import android.os.SystemConfigManager;
 import android.os.UserHandle;
 import android.permission.PermissionManager;
@@ -30,9 +29,7 @@
 import android.util.ArrayMap;
 import android.util.Log;
 
-import com.android.internal.R;
 import com.android.internal.annotations.VisibleForTesting;
-import com.android.internal.telephony.util.ArrayUtils;
 
 import java.util.ArrayList;
 import java.util.List;
@@ -162,12 +159,9 @@
         try {
             for (ApplicationInfo ai : candidates) {
                 String packageName = ai.packageName;
-                String[] restrictedCarrierApps = Resources.getSystem().getStringArray(
-                        R.array.config_restrictedPreinstalledCarrierApps);
                 boolean hasPrivileges = telephonyManager != null
                         && telephonyManager.checkCarrierPrivilegesForPackageAnyPhone(packageName)
-                                == TelephonyManager.CARRIER_PRIVILEGE_STATUS_HAS_ACCESS
-                        && !ArrayUtils.contains(restrictedCarrierApps, packageName);
+                                == TelephonyManager.CARRIER_PRIVILEGE_STATUS_HAS_ACCESS;
 
                 // add hiddenUntilInstalled flag for carrier apps and associated apps
                 packageManager.setSystemAppState(
diff --git a/telephony/java/android/telephony/CarrierConfigManager.java b/telephony/java/android/telephony/CarrierConfigManager.java
index a85bd06..53aad23 100755
--- a/telephony/java/android/telephony/CarrierConfigManager.java
+++ b/telephony/java/android/telephony/CarrierConfigManager.java
@@ -2829,14 +2829,12 @@
     /**
      * A list of 4 customized LTE Reference Signal Signal to Noise Ratio (RSSNR) thresholds.
      *
-     * 4 threshold integers must be within the boundaries [-200, 300], and the levels are:
-     *     "NONE: [-200, threshold1)"
+     * 4 threshold integers must be within the boundaries [-20 dB, 30 dB], and the levels are:
+     *     "NONE: [-20, threshold1)"
      *     "POOR: [threshold1, threshold2)"
      *     "MODERATE: [threshold2, threshold3)"
      *     "GOOD:  [threshold3, threshold4)"
-     *     "EXCELLENT:  [threshold4, 300]"
-     * Note: the unit of the values is 10*db; it is derived by multiplying 10 on the original dB
-     * value reported by modem.
+     *     "EXCELLENT:  [threshold4, 30]"
      *
      * This key is considered invalid if the format is violated. If the key is invalid or
      * not configured, a default value set will apply.
@@ -4198,10 +4196,10 @@
                 });
         sDefaults.putIntArray(KEY_LTE_RSSNR_THRESHOLDS_INT_ARRAY,
                 new int[] {
-                        -30, /* SIGNAL_STRENGTH_POOR */
-                        10,  /* SIGNAL_STRENGTH_MODERATE */
-                        45,  /* SIGNAL_STRENGTH_GOOD */
-                        130  /* SIGNAL_STRENGTH_GREAT */
+                        -3, /* SIGNAL_STRENGTH_POOR */
+                        1,  /* SIGNAL_STRENGTH_MODERATE */
+                        5,  /* SIGNAL_STRENGTH_GOOD */
+                        13  /* SIGNAL_STRENGTH_GREAT */
                 });
         sDefaults.putIntArray(KEY_WCDMA_RSCP_THRESHOLDS_INT_ARRAY,
                 new int[] {
diff --git a/telephony/java/android/telephony/CellIdentityLte.java b/telephony/java/android/telephony/CellIdentityLte.java
index 1993550..e6279dc 100644
--- a/telephony/java/android/telephony/CellIdentityLte.java
+++ b/telephony/java/android/telephony/CellIdentityLte.java
@@ -366,7 +366,7 @@
         .append(" mPci=").append(mPci)
         .append(" mTac=").append(mTac)
         .append(" mEarfcn=").append(mEarfcn)
-        .append(" mBands=").append(mBands)
+        .append(" mBands=").append(Arrays.toString(mBands))
         .append(" mBandwidth=").append(mBandwidth)
         .append(" mMcc=").append(mMccStr)
         .append(" mMnc=").append(mMncStr)
diff --git a/telephony/java/android/telephony/CellIdentityNr.java b/telephony/java/android/telephony/CellIdentityNr.java
index 8dd7bdd..e34bbfc 100644
--- a/telephony/java/android/telephony/CellIdentityNr.java
+++ b/telephony/java/android/telephony/CellIdentityNr.java
@@ -242,7 +242,7 @@
                 .append(" mPci = ").append(mPci)
                 .append(" mTac = ").append(mTac)
                 .append(" mNrArfcn = ").append(mNrArfcn)
-                .append(" mBands = ").append(mBands)
+                .append(" mBands = ").append(Arrays.toString(mBands))
                 .append(" mMcc = ").append(mMccStr)
                 .append(" mMnc = ").append(mMncStr)
                 .append(" mNci = ").append(mNci)
diff --git a/telephony/java/android/telephony/CellSignalStrengthLte.java b/telephony/java/android/telephony/CellSignalStrengthLte.java
index 2529387..c26936e 100644
--- a/telephony/java/android/telephony/CellSignalStrengthLte.java
+++ b/telephony/java/android/telephony/CellSignalStrengthLte.java
@@ -118,7 +118,7 @@
      * @param rssi in dBm [-113,-51], UNKNOWN
      * @param rsrp in dBm [-140,-43], UNKNOWN
      * @param rsrq in dB [-34, 3], UNKNOWN
-     * @param rssnr in 10*dB [-200, +300], UNKNOWN
+     * @param rssnr in dB [-20, +30], UNKNOWN
      * @param cqi [0, 15], UNKNOWN
      * @param timingAdvance [0, 1282], UNKNOWN
      *
@@ -131,7 +131,7 @@
         mSignalStrength = mRssi;
         mRsrp = inRangeOrUnavailable(rsrp, -140, -43);
         mRsrq = inRangeOrUnavailable(rsrq, -34, 3);
-        mRssnr = inRangeOrUnavailable(rssnr, -200, 300);
+        mRssnr = inRangeOrUnavailable(rssnr, -20, 30);
         mCqi = inRangeOrUnavailable(cqi, 0, 15);
         mTimingAdvance = inRangeOrUnavailable(timingAdvance, 0, 1282);
         updateLevel(null, null);
@@ -143,7 +143,7 @@
         this(convertRssiAsuToDBm(lte.signalStrength),
                 lte.rsrp != CellInfo.UNAVAILABLE ? -lte.rsrp : lte.rsrp,
                 lte.rsrq != CellInfo.UNAVAILABLE ? -lte.rsrq : lte.rsrq,
-                lte.rssnr, lte.cqi, lte.timingAdvance);
+                convertRssnrUnitFromTenDbToDB(lte.rssnr), lte.cqi, lte.timingAdvance);
     }
 
     /** @hide */
@@ -208,10 +208,10 @@
     };
     // Lifted from Default carrier configs and max range of RSSNR
     private static final int[] sRssnrThresholds = new int[] {
-            -30, /* SIGNAL_STRENGTH_POOR */
-            10,  /* SIGNAL_STRENGTH_MODERATE */
-            45,  /* SIGNAL_STRENGTH_GOOD */
-            130  /* SIGNAL_STRENGTH_GREAT */
+            -3, /* SIGNAL_STRENGTH_POOR */
+            1,  /* SIGNAL_STRENGTH_MODERATE */
+            5,  /* SIGNAL_STRENGTH_GOOD */
+            13  /* SIGNAL_STRENGTH_GREAT */
     };
     private static final int sRsrpBoost = 0;
 
@@ -556,6 +556,10 @@
         Rlog.w(LOG_TAG, s);
     }
 
+    private static int convertRssnrUnitFromTenDbToDB(int rssnr) {
+        return rssnr / 10;
+    }
+
     private static int convertRssiAsuToDBm(int rssiAsu) {
         if (rssiAsu == SIGNAL_STRENGTH_LTE_RSSI_ASU_UNKNOWN) {
             return CellInfo.UNAVAILABLE;
diff --git a/telephony/java/android/telephony/PhysicalChannelConfig.java b/telephony/java/android/telephony/PhysicalChannelConfig.java
index 4273f5a..af62ba4 100644
--- a/telephony/java/android/telephony/PhysicalChannelConfig.java
+++ b/telephony/java/android/telephony/PhysicalChannelConfig.java
@@ -19,8 +19,8 @@
 import android.annotation.IntDef;
 import android.os.Parcel;
 import android.os.Parcelable;
-
 import android.telephony.Annotation.NetworkType;
+
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
 import java.util.Arrays;
@@ -241,13 +241,13 @@
                 .append(",mCellBandwidthDownlinkKhz=")
                 .append(mCellBandwidthDownlinkKhz)
                 .append(",mRat=")
-                .append(mRat)
+                .append(TelephonyManager.getNetworkTypeName(mRat))
                 .append(",mFrequencyRange=")
-                .append(mFrequencyRange)
+                .append(ServiceState.frequencyRangeToString(mFrequencyRange))
                 .append(",mChannelNumber=")
                 .append(mChannelNumber)
                 .append(",mContextIds=")
-                .append(mContextIds.toString())
+                .append(Arrays.toString(mContextIds))
                 .append(",mPhysicalCellId=")
                 .append(mPhysicalCellId)
                 .append("}")
diff --git a/telephony/java/android/telephony/ServiceState.java b/telephony/java/android/telephony/ServiceState.java
index c6b06b4..9e2ba68 100644
--- a/telephony/java/android/telephony/ServiceState.java
+++ b/telephony/java/android/telephony/ServiceState.java
@@ -1033,6 +1033,26 @@
     }
 
     /**
+     * Convert frequency range into string
+     *
+     * @param range The cellular frequency range
+     * @return Frequency range in string format
+     *
+     * @hide
+     */
+    public static @NonNull String frequencyRangeToString(@FrequencyRange int range) {
+        switch (range) {
+            case FREQUENCY_RANGE_UNKNOWN: return "UNKNOWN";
+            case FREQUENCY_RANGE_LOW: return "LOW";
+            case FREQUENCY_RANGE_MID: return "MID";
+            case FREQUENCY_RANGE_HIGH: return "HIGH";
+            case FREQUENCY_RANGE_MMWAVE: return "MMWAVE";
+            default:
+                return Integer.toString(range);
+        }
+    }
+
+    /**
      * Convert RIL Service State to String
      *
      * @param serviceState
diff --git a/telephony/java/android/telephony/TelephonyManager.java b/telephony/java/android/telephony/TelephonyManager.java
index fadebaa..ee14608 100644
--- a/telephony/java/android/telephony/TelephonyManager.java
+++ b/telephony/java/android/telephony/TelephonyManager.java
@@ -8197,6 +8197,140 @@
         return false;
     }
 
+    /** @hide */
+    @IntDef({
+            ALLOWED_NETWORK_TYPES_REASON_POWER
+    })
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface AllowedNetworkTypesReason{}
+
+    /**
+     * To indicate allowed network type change is requested by power manager.
+     * Power Manger configuration won't affect the settings configured through
+     * {@link setAllowedNetworkTypes} and will result in allowing network types that are in both
+     * configurations (i.e intersection of both sets).
+     * @hide
+     */
+    public static final int ALLOWED_NETWORK_TYPES_REASON_POWER = 0;
+
+    /**
+     * Set the allowed network types of the device and
+     * provide the reason triggering the allowed network change.
+     * This can be called for following reasons
+     * <ol>
+     * <li>Allowed network types control by power manager
+     * {@link #ALLOWED_NETWORK_TYPES_REASON_POWER}
+     * </ol>
+     * This API will result in allowing an intersection of allowed network types for all reasons,
+     * including the configuration done through {@link setAllowedNetworkTypes}.
+     * While this API and {@link setAllowedNetworkTypes} is controlling allowed network types
+     * on device, user preference will still be set through {@link #setPreferredNetworkTypeBitmask}.
+     * Thus resultant network type configured on modem will be an intersection of the network types
+     * from setAllowedNetworkTypesForReason, {@link setAllowedNetworkTypes}
+     * and {@link #setPreferredNetworkTypeBitmask}.
+     *
+     * @param reason the reason the allowed network type change is taking place
+     * @param allowedNetworkTypes The bitmask of allowed network types.
+     * @throws IllegalStateException if the Telephony process is not currently available.
+     * @throws IllegalArgumentException if invalid AllowedNetworkTypesReason is passed.
+     * @hide
+     */
+    @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE)
+    public void setAllowedNetworkTypesForReason(@AllowedNetworkTypesReason int reason,
+            @NetworkTypeBitMask long allowedNetworkTypes) {
+        if (reason != ALLOWED_NETWORK_TYPES_REASON_POWER) {
+            throw new IllegalArgumentException("invalid AllowedNetworkTypesReason.");
+        }
+        try {
+            ITelephony telephony = getITelephony();
+            if (telephony != null) {
+                telephony.setAllowedNetworkTypesForReason(getSubId(), reason,
+                        allowedNetworkTypes);
+            } else {
+                throw new IllegalStateException("telephony service is null.");
+            }
+        } catch (RemoteException ex) {
+            Rlog.e(TAG, "setAllowedNetworkTypesForReason RemoteException", ex);
+            ex.rethrowFromSystemServer();
+        }
+    }
+
+    /**
+     * Get the allowed network types for certain reason.
+     *
+     * {@link #getAllowedNetworkTypesForReason} returns allowed network type for a
+     * specific reason. For effective allowed network types configured on device,
+     * query {@link getEffectiveAllowedNetworkTypes}
+     *
+     * <p>Requires Permission:
+     * {@link android.Manifest.permission#READ_PRIVILEGED_PHONE_STATE READ_PRIVILEGED_PHONE_STATE}
+     * or that the calling app has carrier privileges (see {@link #hasCarrierPrivileges}).
+     *s
+     * @param reason the reason the allowed network type change is taking place
+     * @return the allowed network type bitmask
+     * @throws IllegalStateException if the Telephony process is not currently available.
+     * @throws IllegalArgumentException if invalid AllowedNetworkTypesReason is passed.
+     * @hide
+     */
+    @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
+    public @NetworkTypeBitMask long getAllowedNetworkTypesForReason(
+            @AllowedNetworkTypesReason int reason) {
+        if (reason != ALLOWED_NETWORK_TYPES_REASON_POWER) {
+            throw new IllegalArgumentException("invalid AllowedNetworkTypesReason.");
+        }
+        try {
+            ITelephony telephony = getITelephony();
+            if (telephony != null) {
+                return telephony.getAllowedNetworkTypesForReason(getSubId(), reason);
+            } else {
+                throw new IllegalStateException("telephony service is null.");
+            }
+        } catch (RemoteException ex) {
+            Rlog.e(TAG, "getAllowedNetworkTypesForReason RemoteException", ex);
+            ex.rethrowFromSystemServer();
+        }
+        return -1;
+    }
+
+    /**
+     * Get bit mask of all network types.
+     *
+     * @return bit mask of all network types
+     * @hide
+     */
+    public static @NetworkTypeBitMask long getAllNetworkTypesBitmask() {
+        return NETWORK_STANDARDS_FAMILY_BITMASK_3GPP | NETWORK_STANDARDS_FAMILY_BITMASK_3GPP2;
+    }
+
+    /**
+     * Get the allowed network types configured on the device.
+     * This API will return an intersection of allowed network types for all reasons,
+     * including the configuration done through setAllowedNetworkTypes
+     *
+     * <p>Requires Permission:
+     * {@link android.Manifest.permission#READ_PRIVILEGED_PHONE_STATE READ_PRIVILEGED_PHONE_STATE}
+     * or that the calling app has carrier privileges (see {@link #hasCarrierPrivileges}).
+     *
+     * @return the allowed network type bitmask
+     * @throws IllegalStateException if the Telephony process is not currently available.
+     * @hide
+     */
+    @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
+    public @NetworkTypeBitMask long getEffectiveAllowedNetworkTypes() {
+        try {
+            ITelephony telephony = getITelephony();
+            if (telephony != null) {
+                return telephony.getEffectiveAllowedNetworkTypes(getSubId());
+            } else {
+                throw new IllegalStateException("telephony service is null.");
+            }
+        } catch (RemoteException ex) {
+            Rlog.e(TAG, "getEffectiveAllowedNetworkTypes RemoteException", ex);
+            ex.rethrowFromSystemServer();
+        }
+        return -1;
+    }
+
     /**
      * Set the preferred network type to global mode which includes LTE, CDMA, EvDo and GSM/WCDMA.
      *
diff --git a/telephony/java/com/android/internal/telephony/ITelephony.aidl b/telephony/java/com/android/internal/telephony/ITelephony.aidl
index 3690200..b70937c 100644
--- a/telephony/java/com/android/internal/telephony/ITelephony.aidl
+++ b/telephony/java/com/android/internal/telephony/ITelephony.aidl
@@ -956,6 +956,35 @@
     boolean setAllowedNetworkTypes(int subId, long allowedNetworkTypes);
 
     /**
+     * Get the allowed network types for certain reason.
+     *
+     * @param subId the id of the subscription.
+     * @param reason the reason the allowed network type change is taking place
+     * @return allowedNetworkTypes the allowed network types.
+     */
+    long getAllowedNetworkTypesForReason(int subId, int reason);
+
+    /**
+     * Get the effective allowed network types on the device. This API will
+     * return an intersection of allowed network types for all reasons,
+     * including the configuration done through setAllowedNetworkTypes
+     *
+     * @param subId the id of the subscription.
+     * @return allowedNetworkTypes the allowed network types.
+     */
+     long getEffectiveAllowedNetworkTypes(int subId);
+
+    /**
+     * Set the allowed network types and provide the reason triggering the allowed network change.
+     *
+     * @param subId the id of the subscription.
+     * @param reason the reason the allowed network type change is taking place
+     * @param allowedNetworkTypes the allowed network types.
+     * @return true on success; false on any failure.
+     */
+    boolean setAllowedNetworkTypesForReason(int subId, int reason, long allowedNetworkTypes);
+
+    /**
      * Set the preferred network type.
      * Used for device configuration by some CDMA operators.
      *
diff --git a/tests/net/common/java/android/net/NetworkAgentConfigTest.kt b/tests/net/common/java/android/net/NetworkAgentConfigTest.kt
index de65ba2..a4d8353 100644
--- a/tests/net/common/java/android/net/NetworkAgentConfigTest.kt
+++ b/tests/net/common/java/android/net/NetworkAgentConfigTest.kt
@@ -44,7 +44,7 @@
             setPartialConnectivityAcceptable(false)
             setUnvalidatedConnectivityAcceptable(true)
         }.build()
-        assertParcelSane(config, 9)
+        assertParcelSane(config, 10)
     }
 
     @Test @IgnoreUpTo(Build.VERSION_CODES.Q)
diff --git a/tests/net/java/com/android/server/ConnectivityServiceTest.java b/tests/net/java/com/android/server/ConnectivityServiceTest.java
index c86d388..385005f 100644
--- a/tests/net/java/com/android/server/ConnectivityServiceTest.java
+++ b/tests/net/java/com/android/server/ConnectivityServiceTest.java
@@ -100,6 +100,7 @@
 import static org.mockito.ArgumentMatchers.anyString;
 import static org.mockito.ArgumentMatchers.argThat;
 import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.ArgumentMatchers.isNull;
 import static org.mockito.ArgumentMatchers.startsWith;
 import static org.mockito.Matchers.anyInt;
 import static org.mockito.Mockito.any;
@@ -164,6 +165,8 @@
 import android.net.LinkProperties;
 import android.net.MatchAllNetworkSpecifier;
 import android.net.Network;
+import android.net.NetworkAgent;
+import android.net.NetworkAgentConfig;
 import android.net.NetworkCapabilities;
 import android.net.NetworkFactory;
 import android.net.NetworkInfo;
@@ -6800,6 +6803,30 @@
         assertEquals(wifiLp, mService.getActiveLinkProperties());
     }
 
+    @Test
+    public void testLegacyExtraInfoSentToNetworkMonitor() throws Exception {
+        class TestNetworkAgent extends NetworkAgent {
+            TestNetworkAgent(Context context, Looper looper, NetworkAgentConfig config) {
+                super(context, looper, "MockAgent", new NetworkCapabilities(),
+                        new LinkProperties(), 40 , config, null /* provider */);
+            }
+        }
+        final NetworkAgent naNoExtraInfo = new TestNetworkAgent(
+                mServiceContext, mCsHandlerThread.getLooper(), new NetworkAgentConfig());
+        naNoExtraInfo.register();
+        verify(mNetworkStack).makeNetworkMonitor(any(), isNull(String.class), any());
+        naNoExtraInfo.unregister();
+
+        reset(mNetworkStack);
+        final NetworkAgentConfig config =
+                new NetworkAgentConfig.Builder().setLegacyExtraInfo("legacyinfo").build();
+        final NetworkAgent naExtraInfo = new TestNetworkAgent(
+                mServiceContext, mCsHandlerThread.getLooper(), config);
+        naExtraInfo.register();
+        verify(mNetworkStack).makeNetworkMonitor(any(), eq("legacyinfo"), any());
+        naExtraInfo.unregister();
+    }
+
     private void setupLocationPermissions(
             int targetSdk, boolean locationToggle, String op, String perm) throws Exception {
         final ApplicationInfo applicationInfo = new ApplicationInfo();
diff --git a/tests/net/java/com/android/server/net/NetworkStatsSubscriptionsMonitorTest.java b/tests/net/java/com/android/server/net/NetworkStatsSubscriptionsMonitorTest.java
new file mode 100644
index 0000000..058856d
--- /dev/null
+++ b/tests/net/java/com/android/server/net/NetworkStatsSubscriptionsMonitorTest.java
@@ -0,0 +1,218 @@
+/*
+ * Copyright (C) 2020 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.net;
+
+import static org.junit.Assert.assertEquals;
+import static org.mockito.Mockito.any;
+import static org.mockito.Mockito.anyInt;
+import static org.mockito.Mockito.eq;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.reset;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import android.annotation.NonNull;
+import android.content.Context;
+import android.os.Looper;
+import android.telephony.PhoneStateListener;
+import android.telephony.ServiceState;
+import android.telephony.SubscriptionManager;
+import android.telephony.TelephonyManager;
+
+import com.android.internal.util.CollectionUtils;
+import com.android.server.net.NetworkStatsSubscriptionsMonitor.Delegate;
+import com.android.server.net.NetworkStatsSubscriptionsMonitor.RatTypeListener;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+import org.mockito.ArgumentCaptor;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.concurrent.Executor;
+import java.util.concurrent.Executors;
+
+@RunWith(JUnit4.class)
+public final class NetworkStatsSubscriptionsMonitorTest {
+    private static final int TEST_SUBID1 = 3;
+    private static final int TEST_SUBID2 = 5;
+    private static final String TEST_IMSI1 = "466921234567890";
+    private static final String TEST_IMSI2 = "466920987654321";
+    private static final String TEST_IMSI3 = "466929999999999";
+
+    @Mock private Context mContext;
+    @Mock private PhoneStateListener mPhoneStateListener;
+    @Mock private SubscriptionManager mSubscriptionManager;
+    @Mock private TelephonyManager mTelephonyManager;
+    @Mock private Delegate mDelegate;
+    private final List<Integer> mTestSubList = new ArrayList<>();
+
+    private final Executor mExecutor = Executors.newSingleThreadExecutor();
+    private NetworkStatsSubscriptionsMonitor mMonitor;
+
+    @Before
+    public void setUp() {
+        MockitoAnnotations.initMocks(this);
+
+        if (Looper.myLooper() == null) {
+            Looper.prepare();
+        }
+
+        when(mTelephonyManager.createForSubscriptionId(anyInt())).thenReturn(mTelephonyManager);
+
+        when(mContext.getSystemService(eq(Context.TELEPHONY_SUBSCRIPTION_SERVICE)))
+                .thenReturn(mSubscriptionManager);
+        when(mContext.getSystemService(eq(Context.TELEPHONY_SERVICE)))
+                .thenReturn(mTelephonyManager);
+
+        mMonitor = new NetworkStatsSubscriptionsMonitor(mContext, mExecutor, mDelegate);
+    }
+
+    @Test
+    public void testStartStop() {
+        // Verify that addOnSubscriptionsChangedListener() is never called before start().
+        verify(mSubscriptionManager, never())
+                .addOnSubscriptionsChangedListener(mExecutor, mMonitor);
+        mMonitor.start();
+        verify(mSubscriptionManager).addOnSubscriptionsChangedListener(mExecutor, mMonitor);
+
+        // Verify that removeOnSubscriptionsChangedListener() is never called before stop()
+        verify(mSubscriptionManager, never()).removeOnSubscriptionsChangedListener(mMonitor);
+        mMonitor.stop();
+        verify(mSubscriptionManager).removeOnSubscriptionsChangedListener(mMonitor);
+    }
+
+    @NonNull
+    private static int[] convertArrayListToIntArray(@NonNull List<Integer> arrayList) {
+        final int[] list = new int[arrayList.size()];
+        for (int i = 0; i < arrayList.size(); i++) {
+            list[i] = arrayList.get(i);
+        }
+        return list;
+    }
+
+    private void setRatTypeForSub(List<RatTypeListener> listeners,
+            int subId, int type) {
+        final ServiceState serviceState = mock(ServiceState.class);
+        when(serviceState.getDataNetworkType()).thenReturn(type);
+        final RatTypeListener match = CollectionUtils
+                .find(listeners, it -> it.getSubId() == subId);
+        if (match != null) {
+            match.onServiceStateChanged(serviceState);
+        }
+    }
+
+    private void addTestSub(int subId, String subscriberId) {
+        // add SubId to TestSubList.
+        if (!mTestSubList.contains(subId)) {
+            mTestSubList.add(subId);
+        }
+        final int[] subList = convertArrayListToIntArray(mTestSubList);
+        when(mSubscriptionManager.getCompleteActiveSubscriptionIdList()).thenReturn(subList);
+        when(mTelephonyManager.getSubscriberId(subId)).thenReturn(subscriberId);
+        mMonitor.onSubscriptionsChanged();
+    }
+
+    private void removeTestSub(int subId) {
+        // Remove subId from TestSubList.
+        mTestSubList.removeIf(it -> it == subId);
+        final int[] subList = convertArrayListToIntArray(mTestSubList);
+        when(mSubscriptionManager.getCompleteActiveSubscriptionIdList()).thenReturn(subList);
+        mMonitor.onSubscriptionsChanged();
+    }
+
+    private void assertRatTypeChangedForSub(String subscriberId, int ratType) {
+        assertEquals(mMonitor.getRatTypeForSubscriberId(subscriberId), ratType);
+        final ArgumentCaptor<Integer> typeCaptor = ArgumentCaptor.forClass(Integer.class);
+        // Verify callback with the subscriberId and the RAT type should be as expected.
+        // It will fail if get a callback with an unexpected RAT type.
+        verify(mDelegate).onCollapsedRatTypeChanged(eq(subscriberId), typeCaptor.capture());
+        final int type = typeCaptor.getValue();
+        assertEquals(ratType, type);
+    }
+
+    private void assertRatTypeNotChangedForSub(String subscriberId, int ratType) {
+        assertEquals(mMonitor.getRatTypeForSubscriberId(subscriberId), ratType);
+        // Should never get callback with any RAT type.
+        verify(mDelegate, never()).onCollapsedRatTypeChanged(eq(subscriberId), anyInt());
+    }
+
+    @Test
+    public void testSubChangedAndRatTypeChanged() {
+        final ArgumentCaptor<RatTypeListener> ratTypeListenerCaptor =
+                ArgumentCaptor.forClass(RatTypeListener.class);
+
+        mMonitor.start();
+        // Insert sim1, verify RAT type is NETWORK_TYPE_UNKNOWN, and never get any callback
+        // before changing RAT type.
+        addTestSub(TEST_SUBID1, TEST_IMSI1);
+        assertRatTypeNotChangedForSub(TEST_IMSI1, TelephonyManager.NETWORK_TYPE_UNKNOWN);
+
+        // Insert sim2.
+        addTestSub(TEST_SUBID2, TEST_IMSI2);
+        assertRatTypeNotChangedForSub(TEST_IMSI1, TelephonyManager.NETWORK_TYPE_UNKNOWN);
+        verify(mTelephonyManager, times(2)).listen(ratTypeListenerCaptor.capture(),
+                eq(PhoneStateListener.LISTEN_SERVICE_STATE));
+        reset(mDelegate);
+
+        // Set RAT type of sim1 to UMTS.
+        // Verify RAT type of sim1 after subscription gets onCollapsedRatTypeChanged() callback
+        // and others remain untouched.
+        setRatTypeForSub(ratTypeListenerCaptor.getAllValues(), TEST_SUBID1,
+                TelephonyManager.NETWORK_TYPE_UMTS);
+        assertRatTypeChangedForSub(TEST_IMSI1, TelephonyManager.NETWORK_TYPE_UMTS);
+        assertRatTypeNotChangedForSub(TEST_IMSI2, TelephonyManager.NETWORK_TYPE_UNKNOWN);
+        assertRatTypeNotChangedForSub(TEST_IMSI3, TelephonyManager.NETWORK_TYPE_UNKNOWN);
+        reset(mDelegate);
+
+        // Set RAT type of sim2 to LTE.
+        // Verify RAT type of sim2 after subscription gets onCollapsedRatTypeChanged() callback
+        // and others remain untouched.
+        setRatTypeForSub(ratTypeListenerCaptor.getAllValues(), TEST_SUBID2,
+                TelephonyManager.NETWORK_TYPE_LTE);
+        assertRatTypeNotChangedForSub(TEST_IMSI1, TelephonyManager.NETWORK_TYPE_UMTS);
+        assertRatTypeChangedForSub(TEST_IMSI2, TelephonyManager.NETWORK_TYPE_LTE);
+        assertRatTypeNotChangedForSub(TEST_IMSI3, TelephonyManager.NETWORK_TYPE_UNKNOWN);
+        reset(mDelegate);
+
+        // Remove sim2 and verify that callbacks are fired and RAT type is correct for sim2.
+        // while the other two remain untouched.
+        removeTestSub(TEST_SUBID2);
+        verify(mTelephonyManager).listen(any(), eq(PhoneStateListener.LISTEN_NONE));
+        assertRatTypeNotChangedForSub(TEST_IMSI1, TelephonyManager.NETWORK_TYPE_UMTS);
+        assertRatTypeChangedForSub(TEST_IMSI2, TelephonyManager.NETWORK_TYPE_UNKNOWN);
+        assertRatTypeNotChangedForSub(TEST_IMSI3, TelephonyManager.NETWORK_TYPE_UNKNOWN);
+        reset(mDelegate);
+
+        // Set RAT type of sim1 to UNKNOWN. Then stop monitoring subscription changes
+        // and verify that the listener for sim1 is removed.
+        setRatTypeForSub(ratTypeListenerCaptor.getAllValues(), TEST_SUBID1,
+                TelephonyManager.NETWORK_TYPE_UNKNOWN);
+        assertRatTypeChangedForSub(TEST_IMSI1, TelephonyManager.NETWORK_TYPE_UNKNOWN);
+        reset(mDelegate);
+
+        mMonitor.stop();
+        verify(mTelephonyManager, times(2)).listen(any(), eq(PhoneStateListener.LISTEN_NONE));
+        assertRatTypeChangedForSub(TEST_IMSI1, TelephonyManager.NETWORK_TYPE_UNKNOWN);
+    }
+}
diff --git a/tests/utils/hostutils/Android.bp b/tests/utils/hostutils/Android.bp
new file mode 100644
index 0000000..c9ad702
--- /dev/null
+++ b/tests/utils/hostutils/Android.bp
@@ -0,0 +1,28 @@
+// Copyright (C) 2020 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.
+//
+
+java_library_host {
+    name: "frameworks-base-hostutils",
+
+    srcs: [
+        "src/**/*.java",
+        "src/**/*.kt",
+    ],
+
+    libs: [
+        "tradefed",
+        "junit",
+    ],
+}
diff --git a/tests/utils/hostutils/src/com/android/internal/util/test/SystemPreparer.java b/tests/utils/hostutils/src/com/android/internal/util/test/SystemPreparer.java
new file mode 100644
index 0000000..6bd6985
--- /dev/null
+++ b/tests/utils/hostutils/src/com/android/internal/util/test/SystemPreparer.java
@@ -0,0 +1,362 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.internal.util.test;
+
+import static org.junit.Assert.assertTrue;
+
+import com.android.tradefed.device.DeviceNotAvailableException;
+import com.android.tradefed.device.ITestDevice;
+import com.android.tradefed.log.LogUtil;
+
+import org.junit.Assert;
+import org.junit.ClassRule;
+import org.junit.rules.ExternalResource;
+import org.junit.rules.TemporaryFolder;
+import org.junit.rules.TestRule;
+import org.junit.runner.Description;
+import org.junit.runners.model.Statement;
+
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.ArrayList;
+
+import javax.annotation.Nullable;
+
+/**
+ * Allows pushing files onto the device and various options for rebooting. Useful for installing
+ * APKs/files to system partitions which otherwise wouldn't be easily changed.
+ *
+ * It's strongly recommended to pass in a {@link ClassRule} annotated {@link TestRuleDelegate} to
+ * do a full reboot at the end of a test to ensure the device is in a valid state, assuming the
+ * default {@link RebootStrategy#FULL} isn't used.
+ */
+public class SystemPreparer extends ExternalResource {
+    private static final long OVERLAY_ENABLE_TIMEOUT_MS = 30000;
+
+    // The paths of the files pushed onto the device through this rule.
+    private ArrayList<String> mPushedFiles = new ArrayList<>();
+
+    // The package names of packages installed through this rule.
+    private ArrayList<String> mInstalledPackages = new ArrayList<>();
+
+    private final TemporaryFolder mHostTempFolder;
+    private final DeviceProvider mDeviceProvider;
+    private final RebootStrategy mRebootStrategy;
+    private final TearDownRule mTearDownRule;
+
+    public SystemPreparer(TemporaryFolder hostTempFolder, DeviceProvider deviceProvider) {
+        this(hostTempFolder, RebootStrategy.FULL, null, deviceProvider);
+    }
+
+    public SystemPreparer(TemporaryFolder hostTempFolder, RebootStrategy rebootStrategy,
+            @Nullable TestRuleDelegate testRuleDelegate, DeviceProvider deviceProvider) {
+        mHostTempFolder = hostTempFolder;
+        mDeviceProvider = deviceProvider;
+        mRebootStrategy = rebootStrategy;
+        mTearDownRule = new TearDownRule(mDeviceProvider);
+        if (testRuleDelegate != null) {
+            testRuleDelegate.setDelegate(mTearDownRule);
+        }
+    }
+
+    /** Copies a file within the host test jar to a path on device. */
+    public SystemPreparer pushResourceFile(String filePath, String outputPath)
+            throws DeviceNotAvailableException, IOException {
+        final ITestDevice device = mDeviceProvider.getDevice();
+        remount();
+        assertTrue(device.pushFile(copyResourceToTemp(filePath), outputPath));
+        mPushedFiles.add(outputPath);
+        return this;
+    }
+
+    /** Copies a file directly from the host file system to a path on device. */
+    public SystemPreparer pushFile(File file, String outputPath)
+            throws DeviceNotAvailableException {
+        final ITestDevice device = mDeviceProvider.getDevice();
+        remount();
+        assertTrue(device.pushFile(file, outputPath));
+        mPushedFiles.add(outputPath);
+        return this;
+    }
+
+    /** Deletes the given path from the device */
+    public SystemPreparer deleteFile(String file) throws DeviceNotAvailableException {
+        final ITestDevice device = mDeviceProvider.getDevice();
+        remount();
+        device.deleteFile(file);
+        return this;
+    }
+
+    /** Installs an APK within the host test jar onto the device. */
+    public SystemPreparer installResourceApk(String resourcePath, String packageName)
+            throws DeviceNotAvailableException, IOException {
+        final ITestDevice device = mDeviceProvider.getDevice();
+        final File tmpFile = copyResourceToTemp(resourcePath);
+        final String result = device.installPackage(tmpFile, true /* reinstall */);
+        Assert.assertNull(result);
+        mInstalledPackages.add(packageName);
+        return this;
+    }
+
+    /** Sets the enable state of an overlay package. */
+    public SystemPreparer setOverlayEnabled(String packageName, boolean enabled)
+            throws DeviceNotAvailableException {
+        final ITestDevice device = mDeviceProvider.getDevice();
+        final String enable = enabled ? "enable" : "disable";
+
+        // Wait for the overlay to change its enabled state.
+        final long endMillis = System.currentTimeMillis() + OVERLAY_ENABLE_TIMEOUT_MS;
+        String result;
+        while (System.currentTimeMillis() <= endMillis) {
+            device.executeShellCommand(String.format("cmd overlay %s %s", enable, packageName));
+            result = device.executeShellCommand("cmd overlay dump isenabled "
+                    + packageName);
+            if (((enabled) ? "true\n" : "false\n").equals(result)) {
+                return this;
+            }
+
+            try {
+                Thread.sleep(200);
+            } catch (InterruptedException ignore) {
+            }
+        }
+
+        throw new IllegalStateException(String.format("Failed to %s overlay %s:\n%s", enable,
+                packageName, device.executeShellCommand("cmd overlay list")));
+    }
+
+    /** Restarts the device and waits until after boot is completed. */
+    public SystemPreparer reboot() throws DeviceNotAvailableException {
+        ITestDevice device = mDeviceProvider.getDevice();
+        switch (mRebootStrategy) {
+            case FULL:
+                device.reboot();
+                break;
+            case UNTIL_ONLINE:
+                device.rebootUntilOnline();
+                break;
+            case USERSPACE:
+                device.rebootUserspace();
+                break;
+            case USERSPACE_UNTIL_ONLINE:
+                device.rebootUserspaceUntilOnline();
+                break;
+            case START_STOP:
+                device.executeShellCommand("stop");
+                device.executeShellCommand("start");
+                ITestDevice.RecoveryMode cachedRecoveryMode = device.getRecoveryMode();
+                device.setRecoveryMode(ITestDevice.RecoveryMode.ONLINE);
+
+                if (device.isEncryptionSupported()) {
+                    if (device.isDeviceEncrypted()) {
+                        LogUtil.CLog.e("Device is encrypted after userspace reboot!");
+                        device.unlockDevice();
+                    }
+                }
+
+                device.setRecoveryMode(cachedRecoveryMode);
+                device.waitForDeviceAvailable();
+                break;
+        }
+        return this;
+    }
+
+    public SystemPreparer remount() throws DeviceNotAvailableException {
+        mTearDownRule.remount();
+        return this;
+    }
+
+    /** Copies a file within the host test jar to a temporary file on the host machine. */
+    private File copyResourceToTemp(String resourcePath) throws IOException {
+        final File tempFile = mHostTempFolder.newFile();
+        final ClassLoader classLoader = getClass().getClassLoader();
+        try (InputStream assetIs = classLoader.getResource(resourcePath).openStream();
+             FileOutputStream assetOs = new FileOutputStream(tempFile)) {
+            if (assetIs == null) {
+                throw new IllegalStateException("Failed to find resource " + resourcePath);
+            }
+
+            int b;
+            while ((b = assetIs.read()) >= 0) {
+                assetOs.write(b);
+            }
+        }
+
+        return tempFile;
+    }
+
+    /** Removes installed packages and files that were pushed to the device. */
+    @Override
+    protected void after() {
+        final ITestDevice device = mDeviceProvider.getDevice();
+        try {
+            remount();
+            for (final String file : mPushedFiles) {
+                device.deleteFile(file);
+            }
+            for (final String packageName : mInstalledPackages) {
+                device.uninstallPackage(packageName);
+            }
+            reboot();
+        } catch (DeviceNotAvailableException e) {
+            Assert.fail(e.toString());
+        }
+    }
+
+    /**
+     * A hacky workaround since {@link org.junit.AfterClass} and {@link ClassRule} require static
+     * members. Will defer assignment of the actual {@link TestRule} to execute until after any
+     * test case has been run.
+     *
+     * In effect, this makes the {@link ITestDevice} to be accessible after all test cases have
+     * been executed, allowing {@link ITestDevice#reboot()} to be used to fully restore the device.
+     */
+    public static class TestRuleDelegate implements TestRule {
+
+        private boolean mThrowOnNull;
+
+        @Nullable
+        private TestRule mTestRule;
+
+        public TestRuleDelegate(boolean throwOnNull) {
+            mThrowOnNull = throwOnNull;
+        }
+
+        public void setDelegate(TestRule testRule) {
+            mTestRule = testRule;
+        }
+
+        @Override
+        public Statement apply(Statement base, Description description) {
+            if (mTestRule == null) {
+                if (mThrowOnNull) {
+                    throw new IllegalStateException("TestRule delegate was not set");
+                } else {
+                    return new Statement() {
+                        @Override
+                        public void evaluate() throws Throwable {
+                            base.evaluate();
+                        }
+                    };
+                }
+            }
+
+            Statement statement = mTestRule.apply(base, description);
+            mTestRule = null;
+            return statement;
+        }
+    }
+
+    /**
+     * Forces a full reboot at the end of the test class to restore any device state.
+     */
+    private static class TearDownRule extends ExternalResource {
+
+        private DeviceProvider mDeviceProvider;
+        private boolean mInitialized;
+        private boolean mWasVerityEnabled;
+        private boolean mWasAdbRoot;
+        private boolean mIsVerityEnabled;
+
+        TearDownRule(DeviceProvider deviceProvider) {
+            mDeviceProvider = deviceProvider;
+        }
+
+        @Override
+        protected void before() {
+            // This method will never be run
+        }
+
+        @Override
+        protected void after() {
+            try {
+                initialize();
+                ITestDevice device = mDeviceProvider.getDevice();
+                if (mWasVerityEnabled != mIsVerityEnabled) {
+                    device.executeShellCommand(
+                            mWasVerityEnabled ? "enable-verity" : "disable-verity");
+                }
+                device.reboot();
+                if (!mWasAdbRoot) {
+                    device.disableAdbRoot();
+                }
+            } catch (DeviceNotAvailableException e) {
+                Assert.fail(e.toString());
+            }
+        }
+
+        /**
+         * Remount is done inside this class so that the verity state can be tracked.
+         */
+        public void remount() throws DeviceNotAvailableException {
+            initialize();
+            ITestDevice device = mDeviceProvider.getDevice();
+            device.enableAdbRoot();
+            if (mIsVerityEnabled) {
+                mIsVerityEnabled = false;
+                device.executeShellCommand("disable-verity");
+                device.reboot();
+            }
+            device.executeShellCommand("remount");
+            device.waitForDeviceAvailable();
+        }
+
+        private void initialize() throws DeviceNotAvailableException {
+            if (mInitialized) {
+                return;
+            }
+            mInitialized = true;
+            ITestDevice device = mDeviceProvider.getDevice();
+            mWasAdbRoot = device.isAdbRoot();
+            device.enableAdbRoot();
+            String veritySystem = device.getProperty("partition.system.verified");
+            String verityVendor = device.getProperty("partition.vendor.verified");
+            mWasVerityEnabled = (veritySystem != null && !veritySystem.isEmpty())
+                    || (verityVendor != null && !verityVendor.isEmpty());
+            mIsVerityEnabled = mWasVerityEnabled;
+        }
+    }
+
+    public interface DeviceProvider {
+        ITestDevice getDevice();
+    }
+
+    /**
+     * How to reboot the device. Ordered from slowest to fastest.
+     */
+    public enum RebootStrategy {
+        /** @see ITestDevice#reboot() */
+        FULL,
+
+        /** @see ITestDevice#rebootUntilOnline() () */
+        UNTIL_ONLINE,
+
+        /** @see ITestDevice#rebootUserspace() */
+        USERSPACE,
+
+        /** @see ITestDevice#rebootUserspaceUntilOnline() () */
+        USERSPACE_UNTIL_ONLINE,
+
+        /**
+         * Uses shell stop && start to "reboot" the device. May leave invalid state after each test.
+         * Whether this matters or not depends on what's being tested.
+         */
+        START_STOP
+    }
+}
diff --git a/wifi/Android.bp b/wifi/Android.bp
index 9c5b7b66..941ff61 100644
--- a/wifi/Android.bp
+++ b/wifi/Android.bp
@@ -12,6 +12,12 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
+java_defaults {
+    name: "wifi-module-sdk-version-defaults",
+    min_sdk_version: "30",
+    target_sdk_version: "30",
+}
+
 filegroup {
     name: "framework-wifi-updatable-exported-aidl-sources",
     srcs: ["aidl-export/**/*.aidl"],
@@ -73,6 +79,7 @@
 // classes before they are renamed.
 java_library {
     name: "framework-wifi-pre-jarjar",
+    defaults: ["wifi-module-sdk-version-defaults"],
     sdk_version: "module_current",
     static_libs: [
         "framework-wifi-util-lib",
@@ -98,7 +105,10 @@
 // post-jarjar version of framework-wifi
 java_sdk_library {
     name: "framework-wifi",
-    defaults: ["framework-module-defaults"],
+    defaults: [
+        "framework-module-defaults",
+        "wifi-module-sdk-version-defaults",
+    ],
     static_libs: [
         "framework-wifi-util-lib",
         "android.hardware.wifi-V1.0-java-constants",
diff --git a/wifi/java/android/net/wifi/SoftApCapability.java b/wifi/java/android/net/wifi/SoftApCapability.java
index 18b26db..dcb57ec 100644
--- a/wifi/java/android/net/wifi/SoftApCapability.java
+++ b/wifi/java/android/net/wifi/SoftApCapability.java
@@ -102,7 +102,9 @@
     /**
      * Returns true when all of the queried features are supported, otherwise false.
      *
-     * @param features One or combination of the features from {@link @HotspotFeatures}
+     * @param features One or combination of the following features:
+     * {@link #SOFTAP_FEATURE_ACS_OFFLOAD}, {@link #SOFTAP_FEATURE_CLIENT_FORCE_DISCONNECT} or
+     * {@link #SOFTAP_FEATURE_WPA3_SAE}.
      */
     public boolean areFeaturesSupported(@HotspotFeatures long features) {
         return (mSupportedFeatures & features) == features;
@@ -122,7 +124,9 @@
      * Constructor with combination of the feature.
      * Zero to no supported feature.
      *
-     * @param features One or combination of the features from {@link @HotspotFeatures}.
+     * @param features One or combination of the following features:
+     * {@link #SOFTAP_FEATURE_ACS_OFFLOAD}, {@link #SOFTAP_FEATURE_CLIENT_FORCE_DISCONNECT} or
+     * {@link #SOFTAP_FEATURE_WPA3_SAE}.
      * @hide
      */
     public SoftApCapability(@HotspotFeatures long features) {
diff --git a/wifi/java/android/net/wifi/SoftApConfiguration.java b/wifi/java/android/net/wifi/SoftApConfiguration.java
index 457e0db..2bcd4f4 100644
--- a/wifi/java/android/net/wifi/SoftApConfiguration.java
+++ b/wifi/java/android/net/wifi/SoftApConfiguration.java
@@ -165,7 +165,8 @@
 
     /**
      * The operating band of the AP.
-     * One of the band types from {@link @BandType}.
+     * One or combination of the following band type:
+     * {@link #BAND_2GHZ}, {@link #BAND_5GHZ}, {@link #BAND_6GHZ}.
      */
     private final @BandType int mBand;
 
@@ -181,7 +182,11 @@
 
     /**
      * The operating security type of the AP.
-     * One of the security types from {@link @SecurityType}
+     * One of the following security types:
+     * {@link #SECURITY_TYPE_OPEN},
+     * {@link #SECURITY_TYPE_WPA2_PSK},
+     * {@link #SECURITY_TYPE_WPA3_SAE_TRANSITION},
+     * {@link #SECURITY_TYPE_WPA3_SAE}
      */
     private final @SecurityType int mSecurityType;
 
@@ -393,8 +398,12 @@
     }
 
     /**
-     * Returns {@link BandType} set to be the band for the AP.
-     * {@link Builder#setBand(@BandType int)}.
+     * Returns band type set to be the band for the AP.
+     *
+     * One or combination of the following band type:
+     * {@link #BAND_2GHZ}, {@link #BAND_5GHZ}, {@link #BAND_6GHZ}.
+     *
+     * {@link Builder#setBand(int)}.
      *
      * @hide
      */
@@ -679,15 +688,19 @@
         /**
          * Specifies that this AP should use specific security type with the given ASCII passphrase.
          *
-         * @param securityType one of the security types from {@link @SecurityType}.
-         * @param passphrase The passphrase to use for sepcific {@link @SecurityType} configuration
-         * or null with {@link @SecurityType#SECURITY_TYPE_OPEN}.
+         * @param securityType One of the following security types:
+         * {@link #SECURITY_TYPE_OPEN},
+         * {@link #SECURITY_TYPE_WPA2_PSK},
+         * {@link #SECURITY_TYPE_WPA3_SAE_TRANSITION},
+         * {@link #SECURITY_TYPE_WPA3_SAE}.
+         * @param passphrase The passphrase to use for sepcific {@code securityType} configuration
+         * or null with {@link #SECURITY_TYPE_OPEN}.
          *
          * @return Builder for chaining.
          * @throws IllegalArgumentException when the passphrase length is invalid and
-         *         {@code securityType} is not {@link @SecurityType#SECURITY_TYPE_OPEN}
+         *         {@code securityType} is not {@link #SECURITY_TYPE_OPEN}
          *         or non-null passphrase and {@code securityType} is
-         *         {@link @SecurityType#SECURITY_TYPE_OPEN}.
+         *         {@link #SECURITY_TYPE_OPEN}.
          */
         @NonNull
         public Builder setPassphrase(@Nullable String passphrase, @SecurityType int securityType) {
@@ -735,9 +748,10 @@
         /**
          * Specifies the band for the AP.
          * <p>
-         * <li>If not set, defaults to BAND_2GHZ {@link @BandType}.</li>
+         * <li>If not set, defaults to {@link #BAND_2GHZ}.</li>
          *
-         * @param band One or combination of the band types from {@link @BandType}.
+         * @param band One or combination of the following band type:
+         * {@link #BAND_2GHZ}, {@link #BAND_5GHZ}, {@link #BAND_6GHZ}.
          * @return Builder for chaining.
          */
         @NonNull
@@ -758,7 +772,7 @@
          * <p>
          * The default for the channel is a the special value 0 to have the framework
          * auto-select a valid channel from the band configured with
-         * {@link #setBand(@BandType int)}.
+         * {@link #setBand(int)}.
          *
          * The channel auto selection will offload to driver when
          * {@link SoftApCapability#areFeaturesSupported(
diff --git a/wifi/java/android/net/wifi/nl80211/WifiNl80211Manager.java b/wifi/java/android/net/wifi/nl80211/WifiNl80211Manager.java
index 3215246..4116234 100644
--- a/wifi/java/android/net/wifi/nl80211/WifiNl80211Manager.java
+++ b/wifi/java/android/net/wifi/nl80211/WifiNl80211Manager.java
@@ -1039,11 +1039,11 @@
      * The result depends on the on the country code that has been set.
      *
      * @param band as specified by one of the WifiScanner.WIFI_BAND_* constants.
-     * The following bands are supported {@link @WifiScanner.WifiBandBasic}:
-     * WifiScanner.WIFI_BAND_24_GHZ
-     * WifiScanner.WIFI_BAND_5_GHZ
-     * WifiScanner.WIFI_BAND_5_GHZ_DFS_ONLY
-     * WifiScanner.WIFI_BAND_6_GHZ
+     * The following bands are supported:
+     * {@link WifiScanner#WIFI_BAND_24_GHZ},
+     * {@link WifiScanner#WIFI_BAND_5_GHZ},
+     * {@link WifiScanner#WIFI_BAND_5_GHZ_DFS_ONLY},
+     * {@link WifiScanner#WIFI_BAND_6_GHZ}
      * @return frequencies vector of valid frequencies (MHz), or an empty array for error.
      * @throws IllegalArgumentException if band is not recognized.
      */