Merge "Remove binder threadpool init from puller tests" into rvc-dev
diff --git a/apex/jobscheduler/service/java/com/android/server/job/TEST_MAPPING b/apex/jobscheduler/service/java/com/android/server/job/TEST_MAPPING
index cdcd6598..e2e1180 100644
--- a/apex/jobscheduler/service/java/com/android/server/job/TEST_MAPPING
+++ b/apex/jobscheduler/service/java/com/android/server/job/TEST_MAPPING
@@ -1,6 +1,13 @@
 {
     "presubmit": [
         {
+            "name": "CtsJobSchedulerTestCases",
+            "options": [
+                {"exclude-annotation": "androidx.test.filters.FlakyTest"},
+                {"exclude-annotation": "androidx.test.filters.LargeTest"}
+            ]
+        },
+        {
             "name": "FrameworksMockingServicesTests",
             "options": [
                 {"include-filter": "com.android.server.job"},
diff --git a/apex/statsd/aidl/android/os/IStatsManagerService.aidl b/apex/statsd/aidl/android/os/IStatsManagerService.aidl
index 4a259f5..b59a97e 100644
--- a/apex/statsd/aidl/android/os/IStatsManagerService.aidl
+++ b/apex/statsd/aidl/android/os/IStatsManagerService.aidl
@@ -128,7 +128,7 @@
     void removeConfiguration(in long configId, in String packageName);
 
     /** Tell StatsManagerService to register a puller for the given atom tag with statsd. */
-    oneway void registerPullAtomCallback(int atomTag, long coolDownNs, long timeoutNs,
+    oneway void registerPullAtomCallback(int atomTag, long coolDownMillis, long timeoutMillis,
             in int[] additiveFields, IPullAtomCallback pullerCallback);
 
     /** Tell StatsManagerService to unregister the pulller for the given atom tag from statsd. */
diff --git a/apex/statsd/aidl/android/os/IStatsd.aidl b/apex/statsd/aidl/android/os/IStatsd.aidl
index 10b1e5b..c8aec53 100644
--- a/apex/statsd/aidl/android/os/IStatsd.aidl
+++ b/apex/statsd/aidl/android/os/IStatsd.aidl
@@ -186,8 +186,9 @@
     * Registers a puller callback function that, when invoked, pulls the data
     * for the specified atom tag.
     */
-    oneway void registerPullAtomCallback(int uid, int atomTag, long coolDownNs, long timeoutNs,
-                           in int[] additiveFields, IPullAtomCallback pullerCallback);
+    oneway void registerPullAtomCallback(int uid, int atomTag, long coolDownMillis,
+                                         long timeoutMillis,in int[] additiveFields,
+                                         IPullAtomCallback pullerCallback);
 
    /**
     * Registers a puller callback function that, when invoked, pulls the data
diff --git a/apex/statsd/framework/java/android/app/StatsManager.java b/apex/statsd/framework/java/android/app/StatsManager.java
index e637187..f021dcf 100644
--- a/apex/statsd/framework/java/android/app/StatsManager.java
+++ b/apex/statsd/framework/java/android/app/StatsManager.java
@@ -119,14 +119,12 @@
     /**
      * @hide
      **/
-    @VisibleForTesting
-    public static final long DEFAULT_COOL_DOWN_NS = 1_000_000_000L; // 1 second.
+    @VisibleForTesting public static final long DEFAULT_COOL_DOWN_MILLIS = 1_000L; // 1 second.
 
     /**
      * @hide
      **/
-    @VisibleForTesting
-    public static final long DEFAULT_TIMEOUT_NS = 10_000_000_000L; // 10 seconds.
+    @VisibleForTesting public static final long DEFAULT_TIMEOUT_MILLIS = 10_000L; // 10 seconds.
 
     /**
      * Constructor for StatsManagerClient.
@@ -489,23 +487,24 @@
     }
 
     /**
-     * Registers a callback for an atom when that atom is to be pulled. The stats service will
+     * Sets a callback for an atom when that atom is to be pulled. The stats service will
      * invoke pullData in the callback when the stats service determines that this atom needs to be
      * pulled. This method should not be called by third-party apps.
      *
      * @param atomTag           The tag of the atom for this puller callback.
      * @param metadata          Optional metadata specifying the timeout, cool down time, and
      *                          additive fields for mapping isolated to host uids.
-     * @param callback          The callback to be invoked when the stats service pulls the atom.
      * @param executor          The executor in which to run the callback.
+     * @param callback          The callback to be invoked when the stats service pulls the atom.
      *
      */
     @RequiresPermission(android.Manifest.permission.REGISTER_STATS_PULL_ATOM)
-    public void registerPullAtomCallback(int atomTag, @Nullable PullAtomMetadata metadata,
+    public void setPullAtomCallback(int atomTag, @Nullable PullAtomMetadata metadata,
             @NonNull @CallbackExecutor Executor executor,
             @NonNull StatsPullAtomCallback callback) {
-        long coolDownNs = metadata == null ? DEFAULT_COOL_DOWN_NS : metadata.mCoolDownNs;
-        long timeoutNs = metadata == null ? DEFAULT_TIMEOUT_NS : metadata.mTimeoutNs;
+        long coolDownMillis =
+                metadata == null ? DEFAULT_COOL_DOWN_MILLIS : metadata.mCoolDownMillis;
+        long timeoutMillis = metadata == null ? DEFAULT_TIMEOUT_MILLIS : metadata.mTimeoutMillis;
         int[] additiveFields = metadata == null ? new int[0] : metadata.mAdditiveFields;
         if (additiveFields == null) {
             additiveFields = new int[0];
@@ -516,8 +515,8 @@
                 IStatsManagerService service = getIStatsManagerServiceLocked();
                 PullAtomCallbackInternal rec =
                     new PullAtomCallbackInternal(atomTag, callback, executor);
-                service.registerPullAtomCallback(atomTag, coolDownNs, timeoutNs, additiveFields,
-                        rec);
+                service.registerPullAtomCallback(
+                        atomTag, coolDownMillis, timeoutMillis, additiveFields, rec);
             } catch (RemoteException e) {
                 throw new RuntimeException("Unable to register pull callback", e);
             }
@@ -525,14 +524,14 @@
     }
 
     /**
-     * Unregisters a callback for an atom when that atom is to be pulled. Note that any ongoing
+     * Clears a callback for an atom when that atom is to be pulled. Note that any ongoing
      * pulls will still occur. This method should not be called by third-party apps.
      *
      * @param atomTag           The tag of the atom of which to unregister
      *
      */
     @RequiresPermission(android.Manifest.permission.REGISTER_STATS_PULL_ATOM)
-    public void unregisterPullAtomCallback(int atomTag) {
+    public void clearPullAtomCallback(int atomTag) {
         synchronized (sLock) {
             try {
                 IStatsManagerService service = getIStatsManagerServiceLocked();
@@ -585,14 +584,14 @@
      *
      */
     public static class PullAtomMetadata {
-        private final long mCoolDownNs;
-        private final long mTimeoutNs;
+        private final long mCoolDownMillis;
+        private final long mTimeoutMillis;
         private final int[] mAdditiveFields;
 
         // Private Constructor for builder
-        private PullAtomMetadata(long coolDownNs, long timeoutNs, int[] additiveFields) {
-            mCoolDownNs = coolDownNs;
-            mTimeoutNs = timeoutNs;
+        private PullAtomMetadata(long coolDownMillis, long timeoutMillis, int[] additiveFields) {
+            mCoolDownMillis = coolDownMillis;
+            mTimeoutMillis = timeoutMillis;
             mAdditiveFields = additiveFields;
         }
 
@@ -600,8 +599,8 @@
          *  Builder for PullAtomMetadata.
          */
         public static class Builder {
-            private long mCoolDownNs;
-            private long mTimeoutNs;
+            private long mCoolDownMillis;
+            private long mTimeoutMillis;
             private int[] mAdditiveFields;
 
             /**
@@ -609,27 +608,28 @@
              * StatsManager#registerPullAtomCallback
              */
             public Builder() {
-                mCoolDownNs = DEFAULT_COOL_DOWN_NS;
-                mTimeoutNs = DEFAULT_TIMEOUT_NS;
+                mCoolDownMillis = DEFAULT_COOL_DOWN_MILLIS;
+                mTimeoutMillis = DEFAULT_TIMEOUT_MILLIS;
                 mAdditiveFields = null;
             }
 
             /**
-             * Set the cool down time of the pull in nanoseconds. If two successive pulls are issued
-             * within the cool down, a cached version of the first will be used for the second.
+             * Set the cool down time of the pull in milliseconds. If two successive pulls are
+             * issued within the cool down, a cached version of the first pull will be used for the
+             * second pull.
              */
             @NonNull
-            public Builder setCoolDownNs(long coolDownNs) {
-                mCoolDownNs = coolDownNs;
+            public Builder setCoolDownMillis(long coolDownMillis) {
+                mCoolDownMillis = coolDownMillis;
                 return this;
             }
 
             /**
-             * Set the maximum time the pull can take in nanoseconds.
+             * Set the maximum time the pull can take in milliseconds.
              */
             @NonNull
-            public Builder setTimeoutNs(long timeoutNs) {
-                mTimeoutNs = timeoutNs;
+            public Builder setTimeoutMillis(long timeoutMillis) {
+                mTimeoutMillis = timeoutMillis;
                 return this;
             }
 
@@ -652,30 +652,32 @@
              */
             @NonNull
             public PullAtomMetadata build() {
-                return new PullAtomMetadata(mCoolDownNs, mTimeoutNs, mAdditiveFields);
+                return new PullAtomMetadata(mCoolDownMillis, mTimeoutMillis, mAdditiveFields);
             }
         }
 
         /**
-         * @hide
+         * Return the cool down time of this pull in milliseconds.
          */
-        @VisibleForTesting
-        public long getCoolDownNs() {
-            return mCoolDownNs;
+        public long getCoolDownMillis() {
+            return mCoolDownMillis;
         }
 
         /**
-         * @hide
+         * Return the maximum amount of time this pull can take in milliseconds.
          */
-        @VisibleForTesting
-        public long getTimeoutNs() {
-            return mTimeoutNs;
+        public long getTimeoutMillis() {
+            return mTimeoutMillis;
         }
 
         /**
-         * @hide
+         * Return the additive fields of this pulled atom.
+         *
+         * This is only applicable for atoms that have a uid field. When tasks are run in
+         * isolated processes, the data will be attributed to the host uid. Additive fields
+         * will be combined when the non-additive fields are the same.
          */
-        @VisibleForTesting
+        @Nullable
         public int[] getAdditiveFields() {
             return mAdditiveFields;
         }
diff --git a/apex/statsd/framework/test/src/android/app/PullAtomMetadataTest.java b/apex/statsd/framework/test/src/android/app/PullAtomMetadataTest.java
index 0ae6134..fd386bd 100644
--- a/apex/statsd/framework/test/src/android/app/PullAtomMetadataTest.java
+++ b/apex/statsd/framework/test/src/android/app/PullAtomMetadataTest.java
@@ -33,28 +33,28 @@
     @Test
     public void testEmpty() {
         PullAtomMetadata metadata = new PullAtomMetadata.Builder().build();
-        assertThat(metadata.getTimeoutNs()).isEqualTo(StatsManager.DEFAULT_TIMEOUT_NS);
-        assertThat(metadata.getCoolDownNs()).isEqualTo(StatsManager.DEFAULT_COOL_DOWN_NS);
+        assertThat(metadata.getTimeoutMillis()).isEqualTo(StatsManager.DEFAULT_TIMEOUT_MILLIS);
+        assertThat(metadata.getCoolDownMillis()).isEqualTo(StatsManager.DEFAULT_COOL_DOWN_MILLIS);
         assertThat(metadata.getAdditiveFields()).isNull();
     }
 
     @Test
-    public void testSetTimeoutNs() {
-        long timeoutNs = 500_000_000L;
+    public void testSetTimeoutMillis() {
+        long timeoutMillis = 500L;
         PullAtomMetadata metadata =
-                new PullAtomMetadata.Builder().setTimeoutNs(timeoutNs).build();
-        assertThat(metadata.getTimeoutNs()).isEqualTo(timeoutNs);
-        assertThat(metadata.getCoolDownNs()).isEqualTo(StatsManager.DEFAULT_COOL_DOWN_NS);
+                new PullAtomMetadata.Builder().setTimeoutMillis(timeoutMillis).build();
+        assertThat(metadata.getTimeoutMillis()).isEqualTo(timeoutMillis);
+        assertThat(metadata.getCoolDownMillis()).isEqualTo(StatsManager.DEFAULT_COOL_DOWN_MILLIS);
         assertThat(metadata.getAdditiveFields()).isNull();
     }
 
     @Test
-    public void testSetCoolDownNs() {
-        long coolDownNs = 10_000_000_000L;
+    public void testSetCoolDownMillis() {
+        long coolDownMillis = 10_000L;
         PullAtomMetadata metadata =
-                new PullAtomMetadata.Builder().setCoolDownNs(coolDownNs).build();
-        assertThat(metadata.getTimeoutNs()).isEqualTo(StatsManager.DEFAULT_TIMEOUT_NS);
-        assertThat(metadata.getCoolDownNs()).isEqualTo(coolDownNs);
+                new PullAtomMetadata.Builder().setCoolDownMillis(coolDownMillis).build();
+        assertThat(metadata.getTimeoutMillis()).isEqualTo(StatsManager.DEFAULT_TIMEOUT_MILLIS);
+        assertThat(metadata.getCoolDownMillis()).isEqualTo(coolDownMillis);
         assertThat(metadata.getAdditiveFields()).isNull();
     }
 
@@ -63,23 +63,23 @@
         int[] fields = {2, 4, 6};
         PullAtomMetadata metadata =
                 new PullAtomMetadata.Builder().setAdditiveFields(fields).build();
-        assertThat(metadata.getTimeoutNs()).isEqualTo(StatsManager.DEFAULT_TIMEOUT_NS);
-        assertThat(metadata.getCoolDownNs()).isEqualTo(StatsManager.DEFAULT_COOL_DOWN_NS);
+        assertThat(metadata.getTimeoutMillis()).isEqualTo(StatsManager.DEFAULT_TIMEOUT_MILLIS);
+        assertThat(metadata.getCoolDownMillis()).isEqualTo(StatsManager.DEFAULT_COOL_DOWN_MILLIS);
         assertThat(metadata.getAdditiveFields()).isEqualTo(fields);
     }
 
     @Test
     public void testSetAllElements() {
-        long timeoutNs = 300L;
-        long coolDownNs = 9572L;
+        long timeoutMillis = 300L;
+        long coolDownMillis = 9572L;
         int[] fields = {3, 2};
         PullAtomMetadata metadata = new PullAtomMetadata.Builder()
-                .setTimeoutNs(timeoutNs)
-                .setCoolDownNs(coolDownNs)
+                .setTimeoutMillis(timeoutMillis)
+                .setCoolDownMillis(coolDownMillis)
                 .setAdditiveFields(fields)
                 .build();
-        assertThat(metadata.getTimeoutNs()).isEqualTo(timeoutNs);
-        assertThat(metadata.getCoolDownNs()).isEqualTo(coolDownNs);
+        assertThat(metadata.getTimeoutMillis()).isEqualTo(timeoutMillis);
+        assertThat(metadata.getCoolDownMillis()).isEqualTo(coolDownMillis);
         assertThat(metadata.getAdditiveFields()).isEqualTo(fields);
     }
 }
diff --git a/apex/statsd/service/java/com/android/server/stats/StatsManagerService.java b/apex/statsd/service/java/com/android/server/stats/StatsManagerService.java
index 4e4bc40..58c78da 100644
--- a/apex/statsd/service/java/com/android/server/stats/StatsManagerService.java
+++ b/apex/statsd/service/java/com/android/server/stats/StatsManagerService.java
@@ -136,25 +136,25 @@
     }
 
     private static class PullerValue {
-        private final long mCoolDownNs;
-        private final long mTimeoutNs;
+        private final long mCoolDownMillis;
+        private final long mTimeoutMillis;
         private final int[] mAdditiveFields;
         private final IPullAtomCallback mCallback;
 
-        PullerValue(long coolDownNs, long timeoutNs, int[] additiveFields,
+        PullerValue(long coolDownMillis, long timeoutMillis, int[] additiveFields,
                 IPullAtomCallback callback) {
-            mCoolDownNs = coolDownNs;
-            mTimeoutNs = timeoutNs;
+            mCoolDownMillis = coolDownMillis;
+            mTimeoutMillis = timeoutMillis;
             mAdditiveFields = additiveFields;
             mCallback = callback;
         }
 
-        public long getCoolDownNs() {
-            return mCoolDownNs;
+        public long getCoolDownMillis() {
+            return mCoolDownMillis;
         }
 
-        public long getTimeoutNs() {
-            return mTimeoutNs;
+        public long getTimeoutMillis() {
+            return mTimeoutMillis;
         }
 
         public int[] getAdditiveFields() {
@@ -169,12 +169,13 @@
     private final ArrayMap<PullerKey, PullerValue> mPullers = new ArrayMap<>();
 
     @Override
-    public void registerPullAtomCallback(int atomTag, long coolDownNs, long timeoutNs,
+    public void registerPullAtomCallback(int atomTag, long coolDownMillis, long timeoutMillis,
             int[] additiveFields, IPullAtomCallback pullerCallback) {
         enforceRegisterStatsPullAtomPermission();
         int callingUid = Binder.getCallingUid();
         PullerKey key = new PullerKey(callingUid, atomTag);
-        PullerValue val = new PullerValue(coolDownNs, timeoutNs, additiveFields, pullerCallback);
+        PullerValue val =
+                new PullerValue(coolDownMillis, timeoutMillis, additiveFields, pullerCallback);
 
         // Always cache the puller in StatsManagerService. If statsd is down, we will register the
         // puller when statsd comes back up.
@@ -189,8 +190,8 @@
 
         final long token = Binder.clearCallingIdentity();
         try {
-            statsd.registerPullAtomCallback(
-                    callingUid, atomTag, coolDownNs, timeoutNs, additiveFields, pullerCallback);
+            statsd.registerPullAtomCallback(callingUid, atomTag, coolDownMillis, timeoutMillis,
+                    additiveFields, pullerCallback);
         } catch (RemoteException e) {
             Log.e(TAG, "Failed to access statsd to register puller for atom " + atomTag);
         } finally {
@@ -596,8 +597,8 @@
         for (Map.Entry<PullerKey, PullerValue> entry : pullersCopy.entrySet()) {
             PullerKey key = entry.getKey();
             PullerValue value = entry.getValue();
-            statsd.registerPullAtomCallback(key.getUid(), key.getAtom(), value.getCoolDownNs(),
-                    value.getTimeoutNs(), value.getAdditiveFields(), value.getCallback());
+            statsd.registerPullAtomCallback(key.getUid(), key.getAtom(), value.getCoolDownMillis(),
+                    value.getTimeoutMillis(), value.getAdditiveFields(), value.getCallback());
         }
     }
 
diff --git a/apex/statsd/tests/libstatspull/src/com/android/internal/os/statsd/libstats/LibStatsPullTests.java b/apex/statsd/tests/libstatspull/src/com/android/internal/os/statsd/libstats/LibStatsPullTests.java
index e119b4c..d4e51e0 100644
--- a/apex/statsd/tests/libstatspull/src/com/android/internal/os/statsd/libstats/LibStatsPullTests.java
+++ b/apex/statsd/tests/libstatspull/src/com/android/internal/os/statsd/libstats/LibStatsPullTests.java
@@ -229,7 +229,7 @@
         // Let the current bucket finish.
         Thread.sleep(LONG_SLEEP_MILLIS);
         List<Atom> data = StatsConfigUtils.getGaugeMetricDataList(statsManager, sConfigId);
-        statsManager.unregisterPullAtomCallback(PULL_ATOM_TAG);
+        unregisterStatsPuller(PULL_ATOM_TAG);
         assertThat(data.size()).isEqualTo(sAtomsPerPull);
 
         for (int i = 0; i < data.size(); i++) {
diff --git a/api/current.txt b/api/current.txt
index 1cf6832..d4cbe6d 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -26909,7 +26909,6 @@
     method public final void notifyRequestFailed(long, int);
     method public final void notifyRoutes(@NonNull java.util.Collection<android.media.MediaRoute2Info>);
     method public final void notifySessionCreated(@NonNull android.media.RoutingSessionInfo, long);
-    method public final void notifySessionCreationFailed(long);
     method public final void notifySessionReleased(@NonNull String);
     method public final void notifySessionUpdated(@NonNull android.media.RoutingSessionInfo);
     method @CallSuper @Nullable public android.os.IBinder onBind(@NonNull android.content.Intent);
@@ -43514,6 +43513,7 @@
     field public static final int TYPE_RADIATOR = 16; // 0x10
     field public static final int TYPE_REFRIGERATOR = 48; // 0x30
     field public static final int TYPE_REMOTE_CONTROL = 17; // 0x11
+    field public static final int TYPE_ROUTINE = 52; // 0x34
     field public static final int TYPE_SECURITY_SYSTEM = 46; // 0x2e
     field public static final int TYPE_SET_TOP = 18; // 0x12
     field public static final int TYPE_SHOWER = 29; // 0x1d
@@ -48315,10 +48315,6 @@
     field public static final String EXTRA_SUBSCRIPTION_ID = "android.telephony.extra.SUBSCRIPTION_ID";
     field public static final String EXTRA_VOICEMAIL_NUMBER = "android.telephony.extra.VOICEMAIL_NUMBER";
     field public static final String METADATA_HIDE_VOICEMAIL_SETTINGS_MENU = "android.telephony.HIDE_VOICEMAIL_SETTINGS_MENU";
-    field public static final int MODEM_COUNT_DUAL_MODEM = 2; // 0x2
-    field public static final int MODEM_COUNT_NO_MODEM = 0; // 0x0
-    field public static final int MODEM_COUNT_SINGLE_MODEM = 1; // 0x1
-    field public static final int MODEM_COUNT_TRI_MODEM = 3; // 0x3
     field public static final int MULTISIM_ALLOWED = 0; // 0x0
     field public static final int MULTISIM_NOT_SUPPORTED_BY_CARRIER = 2; // 0x2
     field public static final int MULTISIM_NOT_SUPPORTED_BY_HARDWARE = 1; // 0x1
diff --git a/api/system-current.txt b/api/system-current.txt
index c51fab4..f062112 100755
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -702,12 +702,12 @@
   public final class StatsManager {
     method @RequiresPermission(allOf={android.Manifest.permission.DUMP, android.Manifest.permission.PACKAGE_USAGE_STATS}) public void addConfig(long, byte[]) throws android.app.StatsManager.StatsUnavailableException;
     method @Deprecated @RequiresPermission(allOf={android.Manifest.permission.DUMP, android.Manifest.permission.PACKAGE_USAGE_STATS}) public boolean addConfiguration(long, byte[]);
+    method @RequiresPermission(android.Manifest.permission.REGISTER_STATS_PULL_ATOM) public void clearPullAtomCallback(int);
     method @Deprecated @Nullable @RequiresPermission(allOf={android.Manifest.permission.DUMP, android.Manifest.permission.PACKAGE_USAGE_STATS}) public byte[] getData(long);
     method @Deprecated @Nullable @RequiresPermission(allOf={android.Manifest.permission.DUMP, android.Manifest.permission.PACKAGE_USAGE_STATS}) public byte[] getMetadata();
     method @RequiresPermission(allOf={android.Manifest.permission.DUMP, android.Manifest.permission.PACKAGE_USAGE_STATS}) public long[] getRegisteredExperimentIds() throws android.app.StatsManager.StatsUnavailableException;
     method @RequiresPermission(allOf={android.Manifest.permission.DUMP, android.Manifest.permission.PACKAGE_USAGE_STATS}) public byte[] getReports(long) throws android.app.StatsManager.StatsUnavailableException;
     method @RequiresPermission(allOf={android.Manifest.permission.DUMP, android.Manifest.permission.PACKAGE_USAGE_STATS}) public byte[] getStatsMetadata() throws android.app.StatsManager.StatsUnavailableException;
-    method @RequiresPermission(android.Manifest.permission.REGISTER_STATS_PULL_ATOM) public void registerPullAtomCallback(int, @Nullable android.app.StatsManager.PullAtomMetadata, @NonNull java.util.concurrent.Executor, @NonNull android.app.StatsManager.StatsPullAtomCallback);
     method @RequiresPermission(allOf={android.Manifest.permission.DUMP, android.Manifest.permission.PACKAGE_USAGE_STATS}) public void removeConfig(long) throws android.app.StatsManager.StatsUnavailableException;
     method @Deprecated @RequiresPermission(allOf={android.Manifest.permission.DUMP, android.Manifest.permission.PACKAGE_USAGE_STATS}) public boolean removeConfiguration(long);
     method @NonNull @RequiresPermission(allOf={android.Manifest.permission.DUMP, android.Manifest.permission.PACKAGE_USAGE_STATS}) public long[] setActiveConfigsChangedOperation(@Nullable android.app.PendingIntent) throws android.app.StatsManager.StatsUnavailableException;
@@ -715,7 +715,7 @@
     method @Deprecated @RequiresPermission(allOf={android.Manifest.permission.DUMP, android.Manifest.permission.PACKAGE_USAGE_STATS}) public boolean setBroadcastSubscriber(long, long, android.app.PendingIntent);
     method @Deprecated @RequiresPermission(allOf={android.Manifest.permission.DUMP, android.Manifest.permission.PACKAGE_USAGE_STATS}) public boolean setDataFetchOperation(long, android.app.PendingIntent);
     method @RequiresPermission(allOf={android.Manifest.permission.DUMP, android.Manifest.permission.PACKAGE_USAGE_STATS}) public void setFetchReportsOperation(android.app.PendingIntent, long) throws android.app.StatsManager.StatsUnavailableException;
-    method @RequiresPermission(android.Manifest.permission.REGISTER_STATS_PULL_ATOM) public void unregisterPullAtomCallback(int);
+    method @RequiresPermission(android.Manifest.permission.REGISTER_STATS_PULL_ATOM) public void setPullAtomCallback(int, @Nullable android.app.StatsManager.PullAtomMetadata, @NonNull java.util.concurrent.Executor, @NonNull android.app.StatsManager.StatsPullAtomCallback);
     field public static final String ACTION_STATSD_STARTED = "android.app.action.STATSD_STARTED";
     field public static final String EXTRA_STATS_ACTIVE_CONFIG_KEYS = "android.app.extra.STATS_ACTIVE_CONFIG_KEYS";
     field public static final String EXTRA_STATS_BROADCAST_SUBSCRIBER_COOKIES = "android.app.extra.STATS_BROADCAST_SUBSCRIBER_COOKIES";
@@ -729,14 +729,17 @@
   }
 
   public static class StatsManager.PullAtomMetadata {
+    method @Nullable public int[] getAdditiveFields();
+    method public long getCoolDownMillis();
+    method public long getTimeoutMillis();
   }
 
   public static class StatsManager.PullAtomMetadata.Builder {
     ctor public StatsManager.PullAtomMetadata.Builder();
     method @NonNull public android.app.StatsManager.PullAtomMetadata build();
     method @NonNull public android.app.StatsManager.PullAtomMetadata.Builder setAdditiveFields(@NonNull int[]);
-    method @NonNull public android.app.StatsManager.PullAtomMetadata.Builder setCoolDownNs(long);
-    method @NonNull public android.app.StatsManager.PullAtomMetadata.Builder setTimeoutNs(long);
+    method @NonNull public android.app.StatsManager.PullAtomMetadata.Builder setCoolDownMillis(long);
+    method @NonNull public android.app.StatsManager.PullAtomMetadata.Builder setTimeoutMillis(long);
   }
 
   public static interface StatsManager.StatsPullAtomCallback {
@@ -4992,6 +4995,11 @@
     field public static final int LENGTH_TYPE_UNDEFINED = 0; // 0x0
     field public static final int LENGTH_TYPE_WITHOUT_ADDITIONAL_HEADER = 1; // 0x1
     field public static final int LENGTH_TYPE_WITH_ADDITIONAL_HEADER = 2; // 0x2
+    field public static final int PACKET_TYPE_COMPRESSED = 2; // 0x2
+    field public static final int PACKET_TYPE_EXTENSION = 6; // 0x6
+    field public static final int PACKET_TYPE_IPV4 = 0; // 0x0
+    field public static final int PACKET_TYPE_MPEG2_TS = 7; // 0x7
+    field public static final int PACKET_TYPE_SIGNALING = 4; // 0x4
   }
 
   public static class AlpFilterConfiguration.Builder extends android.media.tv.tuner.filter.FilterConfiguration.Builder<android.media.tv.tuner.filter.AlpFilterConfiguration.Builder> {
@@ -5072,6 +5080,7 @@
     field public static final int TYPE_MMTP = 2; // 0x2
     field public static final int TYPE_TLV = 8; // 0x8
     field public static final int TYPE_TS = 1; // 0x1
+    field public static final int TYPE_UNDEFINED = 0; // 0x0
   }
 
   public interface FilterCallback {
@@ -5082,9 +5091,6 @@
   public abstract class FilterConfiguration {
     method @Nullable public android.media.tv.tuner.filter.Settings getSettings();
     method public abstract int getType();
-    field public static final int PACKET_TYPE_COMPRESSED = 2; // 0x2
-    field public static final int PACKET_TYPE_IPV4 = 0; // 0x0
-    field public static final int PACKET_TYPE_SIGNALING = 4; // 0x4
   }
 
   public abstract static class FilterConfiguration.Builder<T extends android.media.tv.tuner.filter.FilterConfiguration.Builder<T>> {
@@ -5282,6 +5288,11 @@
     method public int getType();
     method public boolean isCompressedIpPacket();
     method public boolean isPassthrough();
+    field public static final int PACKET_TYPE_COMPRESSED = 3; // 0x3
+    field public static final int PACKET_TYPE_IPV4 = 1; // 0x1
+    field public static final int PACKET_TYPE_IPV6 = 2; // 0x2
+    field public static final int PACKET_TYPE_NULL = 255; // 0xff
+    field public static final int PACKET_TYPE_SIGNALING = 254; // 0xfe
   }
 
   public static class TlvFilterConfiguration.Builder extends android.media.tv.tuner.filter.FilterConfiguration.Builder<android.media.tv.tuner.filter.TlvFilterConfiguration.Builder> {
@@ -11658,7 +11669,6 @@
     method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public boolean isAnyRadioPoweredOn();
     method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public boolean isApnMetered(int);
     method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public boolean isApplicationOnUicc(int);
-    method public boolean isCurrentSimOperator(@NonNull String, int, @Nullable String);
     method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public boolean isDataAllowedInVoiceCall();
     method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public boolean isDataConnectionEnabled();
     method public boolean isDataConnectivityPossible();
@@ -11677,6 +11687,7 @@
     method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public boolean isTetheringApnRequired();
     method @Deprecated @RequiresPermission(anyOf={android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE, android.Manifest.permission.READ_PHONE_STATE}) public boolean isVideoCallingEnabled();
     method @Deprecated @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE) public boolean isVisualVoicemailEnabled(android.telecom.PhoneAccountHandle);
+    method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public boolean matchesCurrentSimOperator(@NonNull String, int, @Nullable String);
     method public boolean modifyDevicePolicyOverrideApn(@NonNull android.content.Context, int, @NonNull android.telephony.data.ApnSetting);
     method public boolean needsOtaServiceProvisioning();
     method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void notifyOtaEmergencyNumberDbInstalled();
diff --git a/cmds/statsd/Android.bp b/cmds/statsd/Android.bp
index a2fee8b..bd6ca47 100644
--- a/cmds/statsd/Android.bp
+++ b/cmds/statsd/Android.bp
@@ -164,10 +164,6 @@
     export_generated_headers: [
         "atoms_info.h",
     ],
-    shared_libs: [
-        "libcutils",
-        "libstatslog",
-    ],
     apex_available: [
         //TODO(b/149782403): Remove this once statsd no longer links against libstatsmetadata
         "com.android.os.statsd",
diff --git a/cmds/statsd/src/StatsService.cpp b/cmds/statsd/src/StatsService.cpp
index 7ab6c71..f18aaa5 100644
--- a/cmds/statsd/src/StatsService.cpp
+++ b/cmds/statsd/src/StatsService.cpp
@@ -1196,13 +1196,14 @@
     return Status::ok();
 }
 
-Status StatsService::registerPullAtomCallback(int32_t uid, int32_t atomTag, int64_t coolDownNs,
-                                    int64_t timeoutNs, const std::vector<int32_t>& additiveFields,
-                                    const shared_ptr<IPullAtomCallback>& pullerCallback) {
+Status StatsService::registerPullAtomCallback(int32_t uid, int32_t atomTag, int64_t coolDownMillis,
+                                              int64_t timeoutMillis,
+                                              const std::vector<int32_t>& additiveFields,
+                                              const shared_ptr<IPullAtomCallback>& pullerCallback) {
     ENFORCE_UID(AID_SYSTEM);
-
     VLOG("StatsService::registerPullAtomCallback called.");
-    mPullerManager->RegisterPullAtomCallback(uid, atomTag, coolDownNs, timeoutNs, additiveFields,
+    mPullerManager->RegisterPullAtomCallback(uid, atomTag, MillisToNano(coolDownMillis),
+                                             MillisToNano(timeoutMillis), additiveFields,
                                              pullerCallback);
     return Status::ok();
 }
diff --git a/cmds/statsd/src/StatsService.h b/cmds/statsd/src/StatsService.h
index e6723c8..c256e1f 100644
--- a/cmds/statsd/src/StatsService.h
+++ b/cmds/statsd/src/StatsService.h
@@ -167,8 +167,9 @@
     /**
      * Binder call to register a callback function for a pulled atom.
      */
-    virtual Status registerPullAtomCallback(int32_t uid, int32_t atomTag, int64_t coolDownNs,
-            int64_t timeoutNs, const std::vector<int32_t>& additiveFields,
+    virtual Status registerPullAtomCallback(
+            int32_t uid, int32_t atomTag, int64_t coolDownMillis, int64_t timeoutMillis,
+            const std::vector<int32_t>& additiveFields,
             const shared_ptr<IPullAtomCallback>& pullerCallback) override;
 
     /**
diff --git a/cmds/statsd/src/atom_field_options.proto b/cmds/statsd/src/atom_field_options.proto
index 9c875ba..40a24dc 100644
--- a/cmds/statsd/src/atom_field_options.proto
+++ b/cmds/statsd/src/atom_field_options.proto
@@ -116,5 +116,5 @@
 
     optional bool allow_from_any_uid = 50003 [default = false];
 
-    optional string module = 50004;
+    repeated string module = 50004;
 }
diff --git a/cmds/statsd/src/atoms.proto b/cmds/statsd/src/atoms.proto
index e58e7bc..9645a46 100644
--- a/cmds/statsd/src/atoms.proto
+++ b/cmds/statsd/src/atoms.proto
@@ -3600,9 +3600,10 @@
     // See NotificationSectionsManager.PriorityBucket.
     enum NotificationSection {
         SECTION_UNKNOWN = 0;
-        SECTION_PEOPLE = 1;
-        SECTION_ALERTING = 2;
-        SECTION_SILENT = 3;
+        SECTION_HEADS_UP = 1;
+        SECTION_PEOPLE = 2;
+        SECTION_ALERTING = 3;
+        SECTION_SILENT = 4;
     }
     optional NotificationSection section = 6;
 }
diff --git a/core/java/android/inputmethodservice/InputMethodService.java b/core/java/android/inputmethodservice/InputMethodService.java
index 9e63934..1b6c1ee 100644
--- a/core/java/android/inputmethodservice/InputMethodService.java
+++ b/core/java/android/inputmethodservice/InputMethodService.java
@@ -611,6 +611,10 @@
         public void unbindInput() {
             if (DEBUG) Log.v(TAG, "unbindInput(): binding=" + mInputBinding
                     + " ic=" + mInputConnection);
+            // Unbind input is per process per display.
+            // TODO(b/150902448): free-up IME surface when target is changing.
+            //  e.g. DisplayContent#setInputMethodTarget()
+            removeImeSurface();
             onUnbindInput();
             mInputBinding = null;
             mInputConnection = null;
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index 4216cf3..83a304f 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -6608,6 +6608,18 @@
                 "accessibility_button_target_component";
 
         /**
+         * Setting specifying the accessibility services, accessibility shortcut targets,
+         * or features to be toggled via the long press accessibility button in the navigation bar.
+         *
+         * <p> This is a colon-separated string list which contains the flattened
+         * {@link ComponentName} and the class name of a system class implementing a supported
+         * accessibility feature.
+         * @hide
+         */
+        public static final String ACCESSIBILITY_BUTTON_LONG_PRESS_TARGETS =
+                "accessibility_button_long_press_targets";
+
+        /**
          * The system class name of magnification controller which is a target to be toggled via
          * accessibility shortcut or accessibility button.
          *
diff --git a/core/java/android/service/controls/DeviceTypes.java b/core/java/android/service/controls/DeviceTypes.java
index 6594d2c..ac3b36c 100644
--- a/core/java/android/service/controls/DeviceTypes.java
+++ b/core/java/android/service/controls/DeviceTypes.java
@@ -27,7 +27,7 @@
 public class DeviceTypes {
 
     // Update this when adding new concrete types. Does not count TYPE_UNKNOWN
-    private static final int NUM_CONCRETE_TYPES = 51;
+    private static final int NUM_CONCRETE_TYPES = 52;
 
     public static final @DeviceType int TYPE_UNKNOWN = 0;
     public static final @DeviceType int TYPE_AC_HEATER = 1;
@@ -87,6 +87,11 @@
     public static final @DeviceType int TYPE_CAMERA = 50;
     public static final @DeviceType int TYPE_DOORBELL = 51;
 
+    /*
+     * Also known as macros, routines can aggregate a series of actions across multiple devices
+     */
+    public static final @DeviceType int TYPE_ROUTINE = 52;
+
     // Update this when adding new generic types.
     private static final int NUM_GENERIC_TYPES = 7;
     public static final @DeviceType int TYPE_GENERIC_ON_OFF = -1;
@@ -165,7 +170,8 @@
             TYPE_REFRIGERATOR,
             TYPE_THERMOSTAT,
             TYPE_CAMERA,
-            TYPE_DOORBELL
+            TYPE_DOORBELL,
+            TYPE_ROUTINE
             })
     public @interface DeviceType {}
 
diff --git a/core/java/android/util/FeatureFlagUtils.java b/core/java/android/util/FeatureFlagUtils.java
index cfbe393..6b87a10 100644
--- a/core/java/android/util/FeatureFlagUtils.java
+++ b/core/java/android/util/FeatureFlagUtils.java
@@ -71,7 +71,7 @@
         // introduced in R and will be removed in the next release (b/148367230).
         DEFAULT_FLAGS.put(SETTINGS_DO_NOT_RESTORE_PRESERVED, "false");
 
-        DEFAULT_FLAGS.put("settings_tether_all_in_one", "false");
+        DEFAULT_FLAGS.put("settings_tether_all_in_one", "true");
         DEFAULT_FLAGS.put(SETTINGS_SCHEDULES_FLAG, "false");
         DEFAULT_FLAGS.put("settings_contextual_home2", "false");
     }
diff --git a/core/java/android/view/WindowContainerTransaction.java b/core/java/android/view/WindowContainerTransaction.java
index f406be9..e05c374 100644
--- a/core/java/android/view/WindowContainerTransaction.java
+++ b/core/java/android/view/WindowContainerTransaction.java
@@ -72,6 +72,33 @@
     }
 
     /**
+     * Resize a container's app bounds. This is the bounds used to report appWidth/Height to an
+     * app's DisplayInfo. It is derived by subtracting the overlapping portion of the navbar from
+     * the full bounds.
+     */
+    public WindowContainerTransaction setAppBounds(IWindowContainer container, Rect appBounds) {
+        Change chg = getOrCreateChange(container.asBinder());
+        chg.mConfiguration.windowConfiguration.setAppBounds(appBounds);
+        chg.mConfigSetMask |= ActivityInfo.CONFIG_WINDOW_CONFIGURATION;
+        chg.mWindowSetMask |= WindowConfiguration.WINDOW_CONFIG_APP_BOUNDS;
+        return this;
+    }
+
+    /**
+     * Resize a container's configuration size. The configuration size is what gets reported to the
+     * app via screenWidth/HeightDp and influences which resources get loaded. This size is
+     * derived by subtracting the overlapping portions of both the statusbar and the navbar from
+     * the full bounds.
+     */
+    public WindowContainerTransaction setScreenSizeDp(IWindowContainer container, int w, int h) {
+        Change chg = getOrCreateChange(container.asBinder());
+        chg.mConfiguration.screenWidthDp = w;
+        chg.mConfiguration.screenHeightDp = h;
+        chg.mConfigSetMask |= ActivityInfo.CONFIG_SCREEN_SIZE;
+        return this;
+    }
+
+    /**
      * Notify activies within the hiearchy of a container that they have entered picture-in-picture
      * mode with the given bounds.
      */
@@ -161,7 +188,8 @@
 
     @Override
     public String toString() {
-        return "WindowContainerTransaction { changes = " + mChanges + " }";
+        return "WindowContainerTransaction { changes = " + mChanges + " hops = " + mHierarchyOps
+                + " }";
     }
 
     @Override
@@ -269,6 +297,11 @@
                     (mConfigSetMask & ActivityInfo.CONFIG_WINDOW_CONFIGURATION) != 0
                             && ((mWindowSetMask & WindowConfiguration.WINDOW_CONFIG_BOUNDS)
                                     != 0);
+            final boolean changesAppBounds =
+                    (mConfigSetMask & ActivityInfo.CONFIG_WINDOW_CONFIGURATION) != 0
+                            && ((mWindowSetMask & WindowConfiguration.WINDOW_CONFIG_APP_BOUNDS)
+                                    != 0);
+            final boolean changesSs = (mConfigSetMask & ActivityInfo.CONFIG_SCREEN_SIZE) != 0;
             final boolean changesSss =
                     (mConfigSetMask & ActivityInfo.CONFIG_SMALLEST_SCREEN_SIZE) != 0;
             StringBuilder sb = new StringBuilder();
@@ -276,9 +309,16 @@
             if (changesBounds) {
                 sb.append("bounds:" + mConfiguration.windowConfiguration.getBounds() + ",");
             }
+            if (changesAppBounds) {
+                sb.append("appbounds:" + mConfiguration.windowConfiguration.getAppBounds() + ",");
+            }
             if (changesSss) {
                 sb.append("ssw:" + mConfiguration.smallestScreenWidthDp + ",");
             }
+            if (changesSs) {
+                sb.append("sw/h:" + mConfiguration.screenWidthDp + "x"
+                        + mConfiguration.screenHeightDp + ",");
+            }
             if ((mChangeMask & CHANGE_FOCUSABLE) != 0) {
                 sb.append("focusable:" + mFocusable + ",");
             }
diff --git a/core/java/com/android/internal/app/AbstractMultiProfilePagerAdapter.java b/core/java/com/android/internal/app/AbstractMultiProfilePagerAdapter.java
index bcf731d..d50826f 100644
--- a/core/java/com/android/internal/app/AbstractMultiProfilePagerAdapter.java
+++ b/core/java/com/android/internal/app/AbstractMultiProfilePagerAdapter.java
@@ -299,11 +299,8 @@
                     .createEvent(DevicePolicyEnums.RESOLVER_EMPTY_STATE_WORK_APPS_DISABLED)
                     .setStrings(getMetricsCategory())
                     .write();
-            showEmptyState(activeListAdapter,
-                    R.drawable.ic_work_apps_off,
-                    R.string.resolver_turn_on_work_apps,
-                    R.string.resolver_turn_on_work_apps_explanation,
-                    (View.OnClickListener) v -> {
+            showWorkProfileOffEmptyState(activeListAdapter,
+                    v -> {
                         ProfileDescriptor descriptor = getItem(
                                 userHandleToPageIndex(activeListAdapter.getUserHandle()));
                         showSpinner(descriptor.getEmptyStateView());
@@ -319,27 +316,29 @@
                                 DevicePolicyEnums.RESOLVER_EMPTY_STATE_NO_SHARING_TO_PERSONAL)
                             .setStrings(getMetricsCategory())
                             .write();
-                    showEmptyState(activeListAdapter,
-                            R.drawable.ic_sharing_disabled,
-                            R.string.resolver_cant_share_with_personal_apps,
-                            R.string.resolver_cant_share_cross_profile_explanation);
+                    showNoWorkToPersonalIntentsEmptyState(activeListAdapter);
                 } else {
                     DevicePolicyEventLogger.createEvent(
                             DevicePolicyEnums.RESOLVER_EMPTY_STATE_NO_SHARING_TO_WORK)
                             .setStrings(getMetricsCategory())
                             .write();
-                    showEmptyState(activeListAdapter,
-                            R.drawable.ic_sharing_disabled,
-                            R.string.resolver_cant_share_with_work_apps,
-                            R.string.resolver_cant_share_cross_profile_explanation);
+                    showNoPersonalToWorkIntentsEmptyState(activeListAdapter);
                 }
                 return false;
             }
         }
-        showListView(activeListAdapter);
         return activeListAdapter.rebuildList(doPostProcessing);
     }
 
+    protected abstract void showWorkProfileOffEmptyState(
+            ResolverListAdapter activeListAdapter, View.OnClickListener listener);
+
+    protected abstract void showNoPersonalToWorkIntentsEmptyState(
+            ResolverListAdapter activeListAdapter);
+
+    protected abstract void showNoWorkToPersonalIntentsEmptyState(
+            ResolverListAdapter activeListAdapter);
+
     void showEmptyState(ResolverListAdapter listAdapter) {
         UserHandle listUserHandle = listAdapter.getUserHandle();
         if (UserHandle.myUserId() == listUserHandle.getIdentifier()
@@ -353,16 +352,16 @@
             showEmptyState(listAdapter,
                     R.drawable.ic_no_apps,
                     R.string.resolver_no_apps_available,
-                    R.string.resolver_no_apps_available_explanation);
+                    /* subtitleRes */ 0);
         }
     }
 
-    private void showEmptyState(ResolverListAdapter activeListAdapter,
+    protected void showEmptyState(ResolverListAdapter activeListAdapter,
             @DrawableRes int iconRes, @StringRes int titleRes, @StringRes int subtitleRes) {
         showEmptyState(activeListAdapter, iconRes, titleRes, subtitleRes, /* buttonOnClick */ null);
     }
 
-    private void showEmptyState(ResolverListAdapter activeListAdapter,
+    protected void showEmptyState(ResolverListAdapter activeListAdapter,
             @DrawableRes int iconRes, @StringRes int titleRes, @StringRes int subtitleRes,
             View.OnClickListener buttonOnClick) {
         ProfileDescriptor descriptor = getItem(
@@ -379,11 +378,18 @@
         title.setText(titleRes);
 
         TextView subtitle = emptyStateView.findViewById(R.id.resolver_empty_state_subtitle);
-        subtitle.setText(subtitleRes);
+        if (subtitleRes != 0) {
+            subtitle.setVisibility(View.VISIBLE);
+            subtitle.setText(subtitleRes);
+        } else {
+            subtitle.setVisibility(View.GONE);
+        }
 
         Button button = emptyStateView.findViewById(R.id.resolver_empty_state_button);
         button.setVisibility(buttonOnClick != null ? View.VISIBLE : View.GONE);
         button.setOnClickListener(buttonOnClick);
+
+        activeListAdapter.markTabLoaded();
     }
 
     private void showSpinner(View emptyStateView) {
@@ -403,7 +409,7 @@
         emptyStateView.findViewById(R.id.resolver_empty_state_progress).setVisibility(View.GONE);
     }
 
-    private void showListView(ResolverListAdapter activeListAdapter) {
+    protected void showListView(ResolverListAdapter activeListAdapter) {
         ProfileDescriptor descriptor = getItem(
                 userHandleToPageIndex(activeListAdapter.getUserHandle()));
         descriptor.rootView.findViewById(R.id.resolver_list).setVisibility(View.VISIBLE);
diff --git a/core/java/com/android/internal/app/ChooserMultiProfilePagerAdapter.java b/core/java/com/android/internal/app/ChooserMultiProfilePagerAdapter.java
index b39d42ec..2167b1e 100644
--- a/core/java/com/android/internal/app/ChooserMultiProfilePagerAdapter.java
+++ b/core/java/com/android/internal/app/ChooserMultiProfilePagerAdapter.java
@@ -20,6 +20,7 @@
 import android.content.Context;
 import android.os.UserHandle;
 import android.view.LayoutInflater;
+import android.view.View;
 import android.view.ViewGroup;
 
 import com.android.internal.R;
@@ -169,6 +170,32 @@
         return ResolverActivity.METRICS_CATEGORY_CHOOSER;
     }
 
+    @Override
+    protected void showWorkProfileOffEmptyState(ResolverListAdapter activeListAdapter,
+            View.OnClickListener listener) {
+        showEmptyState(activeListAdapter,
+                R.drawable.ic_work_apps_off,
+                R.string.resolver_turn_on_work_apps_share,
+                /* subtitleRes */ 0,
+                listener);
+    }
+
+    @Override
+    protected void showNoPersonalToWorkIntentsEmptyState(ResolverListAdapter activeListAdapter) {
+        showEmptyState(activeListAdapter,
+                R.drawable.ic_sharing_disabled,
+                R.string.resolver_cant_share_with_work_apps,
+                R.string.resolver_cant_share_cross_profile_explanation);
+    }
+
+    @Override
+    protected void showNoWorkToPersonalIntentsEmptyState(ResolverListAdapter activeListAdapter) {
+        showEmptyState(activeListAdapter,
+                R.drawable.ic_sharing_disabled,
+                R.string.resolver_cant_share_with_personal_apps,
+                R.string.resolver_cant_share_cross_profile_explanation);
+    }
+
     class ChooserProfileDescriptor extends ProfileDescriptor {
         private ChooserActivity.ChooserGridAdapter chooserGridAdapter;
         private RecyclerView recyclerView;
diff --git a/core/java/com/android/internal/app/ResolverActivity.java b/core/java/com/android/internal/app/ResolverActivity.java
index 6ab6185..ec371d9 100644
--- a/core/java/com/android/internal/app/ResolverActivity.java
+++ b/core/java/com/android/internal/app/ResolverActivity.java
@@ -163,7 +163,7 @@
      * TODO(arangelov): Remove a couple of weeks after work/personal tabs are finalized.
      */
     @VisibleForTesting
-    public static boolean ENABLE_TABBED_VIEW = false;
+    public static boolean ENABLE_TABBED_VIEW = true;
     private static final String TAB_TAG_PERSONAL = "personal";
     private static final String TAB_TAG_WORK = "work";
 
@@ -989,6 +989,8 @@
         }
         if (shouldShowEmptyState(listAdapter)) {
             mMultiProfilePagerAdapter.showEmptyState(listAdapter);
+        } else {
+            mMultiProfilePagerAdapter.showListView(listAdapter);
         }
         if (doPostProcessing) {
             if (mMultiProfilePagerAdapter.getCurrentUserHandle().getIdentifier()
@@ -1337,9 +1339,12 @@
                     + "cannot be null.");
         }
         // We partially rebuild the inactive adapter to determine if we should auto launch
-        boolean rebuildCompleted = mMultiProfilePagerAdapter.rebuildActiveTab(true);
+        // isTabLoaded will be true here if the empty state screen is shown instead of the list.
+        boolean rebuildCompleted = mMultiProfilePagerAdapter.rebuildActiveTab(true)
+                || mMultiProfilePagerAdapter.getActiveListAdapter().isTabLoaded();
         if (shouldShowTabs()) {
-            boolean rebuildInactiveCompleted = mMultiProfilePagerAdapter.rebuildInactiveTab(false);
+            boolean rebuildInactiveCompleted = mMultiProfilePagerAdapter.rebuildInactiveTab(false)
+                    || mMultiProfilePagerAdapter.getInactiveListAdapter().isTabLoaded();
             rebuildCompleted = rebuildCompleted && rebuildInactiveCompleted;
         }
 
@@ -1399,8 +1404,8 @@
         if (numberOfProfiles == 1 && maybeAutolaunchIfSingleTarget()) {
             return true;
         } else if (numberOfProfiles == 2
-                && mMultiProfilePagerAdapter.getActiveListAdapter().isListLoaded()
-                && mMultiProfilePagerAdapter.getInactiveListAdapter().isListLoaded()
+                && mMultiProfilePagerAdapter.getActiveListAdapter().isTabLoaded()
+                && mMultiProfilePagerAdapter.getInactiveListAdapter().isTabLoaded()
                 && (maybeAutolaunchIfNoAppsOnInactiveTab()
                         || maybeAutolaunchIfCrossProfileSupported())) {
             return true;
@@ -1595,9 +1600,17 @@
     }
 
     private void resetTabsHeaderStyle(TabWidget tabWidget) {
+        String workContentDescription = getString(R.string.resolver_work_tab_accessibility);
+        String personalContentDescription = getString(R.string.resolver_personal_tab_accessibility);
         for (int i = 0; i < tabWidget.getChildCount(); i++) {
-            TextView title = tabWidget.getChildAt(i).findViewById(android.R.id.title);
+            View tabView = tabWidget.getChildAt(i);
+            TextView title = tabView.findViewById(android.R.id.title);
             title.setTextColor(getColor(R.color.resolver_tabs_inactive_color));
+            if (title.getText().equals(getString(R.string.resolver_personal_tab))) {
+                tabView.setContentDescription(personalContentDescription);
+            } else if (title.getText().equals(getString(R.string.resolver_work_tab))) {
+                tabView.setContentDescription(workContentDescription);
+            }
         }
     }
 
diff --git a/core/java/com/android/internal/app/ResolverListAdapter.java b/core/java/com/android/internal/app/ResolverListAdapter.java
index 54453d0..61a404e 100644
--- a/core/java/com/android/internal/app/ResolverListAdapter.java
+++ b/core/java/com/android/internal/app/ResolverListAdapter.java
@@ -87,7 +87,7 @@
     private final ResolverListCommunicator mResolverListCommunicator;
     private Runnable mPostListReadyRunnable;
     private final boolean mIsAudioCaptureDevice;
-    private boolean mIsListLoaded;
+    private boolean mIsTabLoaded;
 
     public ResolverListAdapter(Context context, List<Intent> payloadIntents,
             Intent[] initialIntents, List<ResolveInfo> rList,
@@ -192,7 +192,7 @@
         mLastChosenPosition = -1;
         mAllTargetsAreBrowsers = false;
         mDisplayList.clear();
-        mIsListLoaded = false;
+        mIsTabLoaded = false;
 
         if (mBaseResolveList != null) {
             currentResolveList = mUnfilteredResolveList = new ArrayList<>();
@@ -354,7 +354,7 @@
 
         mResolverListCommunicator.sendVoiceChoicesIfNeeded();
         postListReadyRunnable(doPostProcessing);
-        mIsListLoaded = true;
+        mIsTabLoaded = true;
     }
 
     /**
@@ -614,8 +614,12 @@
         return mIntents;
     }
 
-    protected boolean isListLoaded() {
-        return mIsListLoaded;
+    protected boolean isTabLoaded() {
+        return mIsTabLoaded;
+    }
+
+    protected void markTabLoaded() {
+        mIsTabLoaded = true;
     }
 
     /**
diff --git a/core/java/com/android/internal/app/ResolverMultiProfilePagerAdapter.java b/core/java/com/android/internal/app/ResolverMultiProfilePagerAdapter.java
index f6382d3..0440f5e 100644
--- a/core/java/com/android/internal/app/ResolverMultiProfilePagerAdapter.java
+++ b/core/java/com/android/internal/app/ResolverMultiProfilePagerAdapter.java
@@ -20,6 +20,7 @@
 import android.content.Context;
 import android.os.UserHandle;
 import android.view.LayoutInflater;
+import android.view.View;
 import android.view.ViewGroup;
 import android.widget.ListView;
 
@@ -161,6 +162,32 @@
         return ResolverActivity.METRICS_CATEGORY_RESOLVER;
     }
 
+    @Override
+    protected void showWorkProfileOffEmptyState(ResolverListAdapter activeListAdapter,
+            View.OnClickListener listener) {
+        showEmptyState(activeListAdapter,
+                R.drawable.ic_work_apps_off,
+                R.string.resolver_turn_on_work_apps_view,
+                /* subtitleRes */ 0,
+                listener);
+    }
+
+    @Override
+    protected void showNoPersonalToWorkIntentsEmptyState(ResolverListAdapter activeListAdapter) {
+        showEmptyState(activeListAdapter,
+                R.drawable.ic_sharing_disabled,
+                R.string.resolver_cant_access_work_apps,
+                R.string.resolver_cant_access_work_apps_explanation);
+    }
+
+    @Override
+    protected void showNoWorkToPersonalIntentsEmptyState(ResolverListAdapter activeListAdapter) {
+        showEmptyState(activeListAdapter,
+                R.drawable.ic_sharing_disabled,
+                R.string.resolver_cant_access_personal_apps,
+                R.string.resolver_cant_access_personal_apps_explanation);
+    }
+
     class ResolverProfileDescriptor extends ProfileDescriptor {
         private ResolverListAdapter resolverListAdapter;
         final ListView listView;
diff --git a/core/java/com/android/internal/compat/CompatibilityChangeInfo.java b/core/java/com/android/internal/compat/CompatibilityChangeInfo.java
index 16628d7..ab890d2 100644
--- a/core/java/com/android/internal/compat/CompatibilityChangeInfo.java
+++ b/core/java/com/android/internal/compat/CompatibilityChangeInfo.java
@@ -30,6 +30,7 @@
     private final @Nullable String mName;
     private final int mEnableAfterTargetSdk;
     private final boolean mDisabled;
+    private final boolean mLoggingOnly;
     private final @Nullable String mDescription;
 
     public long getId() {
@@ -49,17 +50,22 @@
         return mDisabled;
     }
 
+    public boolean getLoggingOnly() {
+        return mLoggingOnly;
+    }
+
     public String getDescription()  {
         return mDescription;
     }
 
     public CompatibilityChangeInfo(
             Long changeId, String name, int enableAfterTargetSdk, boolean disabled,
-            String description) {
+            boolean loggingOnly, String description) {
         this.mChangeId = changeId;
         this.mName = name;
         this.mEnableAfterTargetSdk = enableAfterTargetSdk;
         this.mDisabled = disabled;
+        this.mLoggingOnly = loggingOnly;
         this.mDescription = description;
     }
 
@@ -68,6 +74,7 @@
         mName = in.readString();
         mEnableAfterTargetSdk = in.readInt();
         mDisabled = in.readBoolean();
+        mLoggingOnly = in.readBoolean();
         mDescription = in.readString();
     }
 
@@ -82,6 +89,7 @@
         dest.writeString(mName);
         dest.writeInt(mEnableAfterTargetSdk);
         dest.writeBoolean(mDisabled);
+        dest.writeBoolean(mLoggingOnly);
         dest.writeString(mDescription);
     }
 
diff --git a/core/java/com/android/internal/compat/OverrideAllowedState.java b/core/java/com/android/internal/compat/OverrideAllowedState.java
index 56216c2..bed41b3 100644
--- a/core/java/com/android/internal/compat/OverrideAllowedState.java
+++ b/core/java/com/android/internal/compat/OverrideAllowedState.java
@@ -33,7 +33,8 @@
             DISABLED_NOT_DEBUGGABLE,
             DISABLED_NON_TARGET_SDK,
             DISABLED_TARGET_SDK_TOO_HIGH,
-            PACKAGE_DOES_NOT_EXIST
+            PACKAGE_DOES_NOT_EXIST,
+            LOGGING_ONLY_CHANGE
     })
     @Retention(RetentionPolicy.SOURCE)
     public @interface State {
@@ -60,6 +61,10 @@
      * Package does not exist.
      */
     public static final int PACKAGE_DOES_NOT_EXIST = 4;
+    /**
+     * Change is marked as logging only, and cannot be toggled.
+     */
+    public static final int LOGGING_ONLY_CHANGE = 5;
 
     @State
     public final int state;
@@ -118,6 +123,10 @@
                         "Cannot override %1$d for %2$s because the package does not exist, and "
                                 + "the change is targetSdk gated.",
                         changeId, packageName));
+            case LOGGING_ONLY_CHANGE:
+                throw new SecurityException(String.format(
+                        "Cannot override %1$d because it is marked as a logging-only change.",
+                        changeId));
         }
     }
 
diff --git a/core/java/com/android/internal/net/VpnConfig.java b/core/java/com/android/internal/net/VpnConfig.java
index 6d2d735..7dc3871 100644
--- a/core/java/com/android/internal/net/VpnConfig.java
+++ b/core/java/com/android/internal/net/VpnConfig.java
@@ -232,7 +232,7 @@
                 .append(", allowIPv4=").append(allowIPv4)
                 .append(", allowIPv6=").append(allowIPv6)
                 .append(", underlyingNetworks=").append(Arrays.toString(underlyingNetworks))
-                .append(", proxyInfo=").append(proxyInfo.toString())
+                .append(", proxyInfo=").append(proxyInfo)
                 .append("}")
                 .toString();
     }
diff --git a/core/java/com/android/internal/widget/ResolverDrawerLayout.java b/core/java/com/android/internal/widget/ResolverDrawerLayout.java
index b117e40..c83cab7 100644
--- a/core/java/com/android/internal/widget/ResolverDrawerLayout.java
+++ b/core/java/com/android/internal/widget/ResolverDrawerLayout.java
@@ -121,7 +121,8 @@
 
     private final Rect mTempRect = new Rect();
 
-    private AbsListView mNestedScrollingChild;
+    private AbsListView mNestedListChild;
+    private RecyclerView mNestedRecyclerChild;
 
     private final ViewTreeObserver.OnTouchModeChangeListener mTouchModeChangeListener =
             new ViewTreeObserver.OnTouchModeChangeListener() {
@@ -347,11 +348,20 @@
         return mIsDragging || mOpenOnClick;
     }
 
-    private boolean isNestedChildScrolled() {
-        return mNestedScrollingChild != null
-                && mNestedScrollingChild.getChildCount() > 0
-                && (mNestedScrollingChild.getFirstVisiblePosition() > 0
-                        || mNestedScrollingChild.getChildAt(0).getTop() < 0);
+    private boolean isNestedListChildScrolled() {
+        return  mNestedListChild != null
+                && mNestedListChild.getChildCount() > 0
+                && (mNestedListChild.getFirstVisiblePosition() > 0
+                        || mNestedListChild.getChildAt(0).getTop() < 0);
+    }
+
+    private boolean isNestedRecyclerChildScrolled() {
+        if (mNestedRecyclerChild != null && mNestedRecyclerChild.getChildCount() > 0) {
+            final RecyclerView.ViewHolder vh =
+                    mNestedRecyclerChild.findViewHolderForAdapterPosition(0);
+            return vh == null || vh.itemView.getTop() < 0;
+        }
+        return false;
     }
 
     @Override
@@ -396,8 +406,10 @@
                 }
                 if (mIsDragging) {
                     final float dy = y - mLastTouchY;
-                    if (dy > 0 && isNestedChildScrolled()) {
-                        mNestedScrollingChild.smoothScrollBy((int) -dy, 0);
+                    if (dy > 0 && isNestedListChildScrolled()) {
+                        mNestedListChild.smoothScrollBy((int) -dy, 0);
+                    } else if (dy > 0 && isNestedRecyclerChildScrolled()) {
+                        mNestedRecyclerChild.scrollBy(0, (int) -dy);
                     } else {
                         performDrag(dy);
                     }
@@ -452,8 +464,10 @@
                             smoothScrollTo(mCollapsibleHeight + mUncollapsibleHeight, yvel);
                             mDismissOnScrollerFinished = true;
                         } else {
-                            if (isNestedChildScrolled()) {
-                                mNestedScrollingChild.smoothScrollToPosition(0);
+                            if (isNestedListChildScrolled()) {
+                                mNestedListChild.smoothScrollToPosition(0);
+                            } else if (isNestedRecyclerChildScrolled()) {
+                                mNestedRecyclerChild.smoothScrollToPosition(0);
                             }
                             smoothScrollTo(yvel < 0 ? 0 : mCollapsibleHeight, yvel);
                         }
@@ -729,8 +743,11 @@
     @Override
     public boolean onStartNestedScroll(View child, View target, int nestedScrollAxes) {
         if ((nestedScrollAxes & View.SCROLL_AXIS_VERTICAL) != 0) {
-            if (child instanceof AbsListView) {
-                mNestedScrollingChild = (AbsListView) child;
+            if (target instanceof AbsListView) {
+                mNestedListChild = (AbsListView) target;
+            }
+            if (target instanceof RecyclerView) {
+                mNestedRecyclerChild = (RecyclerView) target;
             }
             return true;
         }
diff --git a/core/jni/Android.bp b/core/jni/Android.bp
index 9ddaa98..189a0a7 100644
--- a/core/jni/Android.bp
+++ b/core/jni/Android.bp
@@ -140,6 +140,7 @@
                 "android_media_AudioEffectDescriptor.cpp",
                 "android_media_AudioRecord.cpp",
                 "android_media_AudioSystem.cpp",
+                "android_media_AudioTrackCallback.cpp",
                 "android_media_AudioTrack.cpp",
                 "android_media_AudioAttributes.cpp",
                 "android_media_AudioProductStrategies.cpp",
diff --git a/core/jni/android_media_AudioTrack.cpp b/core/jni/android_media_AudioTrack.cpp
index a888b43..1351818 100644
--- a/core/jni/android_media_AudioTrack.cpp
+++ b/core/jni/android_media_AudioTrack.cpp
@@ -31,13 +31,14 @@
 #include <binder/MemoryHeapBase.h>
 #include <binder/MemoryBase.h>
 
-#include "android_media_AudioFormat.h"
+#include "android_media_AudioAttributes.h"
 #include "android_media_AudioErrors.h"
+#include "android_media_AudioFormat.h"
+#include "android_media_AudioTrackCallback.h"
+#include "android_media_DeviceCallback.h"
 #include "android_media_MediaMetricsJNI.h"
 #include "android_media_PlaybackParams.h"
-#include "android_media_DeviceCallback.h"
 #include "android_media_VolumeShaper.h"
-#include "android_media_AudioAttributes.h"
 
 #include <cinttypes>
 
@@ -75,22 +76,12 @@
 
 // ----------------------------------------------------------------------------
 class AudioTrackJniStorage {
-    public:
-        sp<MemoryHeapBase>         mMemHeap;
-        sp<MemoryBase>             mMemBase;
-        audiotrack_callback_cookie mCallbackData;
-        sp<JNIDeviceCallback>      mDeviceCallback;
-
-    AudioTrackJniStorage() {
-        mCallbackData.audioTrack_class = 0;
-        mCallbackData.audioTrack_ref = 0;
-        mCallbackData.isOffload = false;
-    }
-
-    ~AudioTrackJniStorage() {
-        mMemBase.clear();
-        mMemHeap.clear();
-    }
+public:
+    sp<MemoryHeapBase> mMemHeap;
+    sp<MemoryBase> mMemBase;
+    audiotrack_callback_cookie mCallbackData{};
+    sp<JNIDeviceCallback> mDeviceCallback;
+    sp<JNIAudioTrackCallback> mAudioTrackCallback;
 
     bool allocSharedMem(int sizeInBytes) {
         mMemHeap = new MemoryHeapBase(sizeInBytes, 0, "AudioTrack Heap Base");
@@ -459,6 +450,10 @@
         lpJniStorage->mCallbackData.audioTrack_ref = env->NewGlobalRef(weak_this);
         lpJniStorage->mCallbackData.busy = false;
     }
+    lpJniStorage->mAudioTrackCallback =
+            new JNIAudioTrackCallback(env, thiz, lpJniStorage->mCallbackData.audioTrack_ref,
+                                      javaAudioTrackFields.postNativeEventInJava);
+    lpTrack->setAudioTrackCallback(lpJniStorage->mAudioTrackCallback);
 
     nSession = (jint *) env->GetPrimitiveArrayCritical(jSession, NULL);
     if (nSession == NULL) {
diff --git a/core/jni/android_media_AudioTrackCallback.cpp b/core/jni/android_media_AudioTrackCallback.cpp
new file mode 100644
index 0000000..d97566b
--- /dev/null
+++ b/core/jni/android_media_AudioTrackCallback.cpp
@@ -0,0 +1,99 @@
+/*
+ * 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.
+ */
+
+//#define LOG_NDEBUG 0
+
+#define LOG_TAG "AudioTrackCallback-JNI"
+
+#include <algorithm>
+
+#include <nativehelper/JNIHelp.h>
+#include <utils/Errors.h>
+#include <utils/Log.h>
+
+#include "android_media_AudioTrackCallback.h"
+#include "core_jni_helpers.h"
+
+using namespace android;
+
+#define BYTE_BUFFER_NAME "java/nio/ByteBuffer"
+#define BYTE_BUFFER_ALLOCATE_DIRECT_NAME "allocateDirect"
+
+JNIAudioTrackCallback::JNIAudioTrackCallback(JNIEnv* env, jobject thiz, jobject weak_thiz,
+                                             jmethodID postEventFromNative) {
+    // Hold onto the AudioTrack class for use in calling the static method
+    // that posts events to the application thread.
+    jclass clazz = env->GetObjectClass(thiz);
+    if (clazz == nullptr) {
+        return;
+    }
+    mClass = (jclass)env->NewGlobalRef(clazz);
+
+    // We use a weak reference so the AudioTrack object can be garbage collected.
+    // The reference is only used as a proxy for callbacks.
+    mObject = env->NewGlobalRef(weak_thiz);
+
+    mPostEventFromNative = postEventFromNative;
+
+    jclass byteBufferClass = FindClassOrDie(env, BYTE_BUFFER_NAME);
+    mByteBufferClass = (jclass)env->NewGlobalRef(byteBufferClass);
+    mAllocateDirectMethod =
+            GetStaticMethodIDOrDie(env, mByteBufferClass, BYTE_BUFFER_ALLOCATE_DIRECT_NAME,
+                                   "(I)Ljava/nio/ByteBuffer;");
+}
+
+JNIAudioTrackCallback::~JNIAudioTrackCallback() {
+    // remove global references
+    JNIEnv* env = AndroidRuntime::getJNIEnv();
+    if (env == nullptr) {
+        return;
+    }
+    env->DeleteGlobalRef(mObject);
+    env->DeleteGlobalRef(mClass);
+    env->DeleteGlobalRef(mByteBufferClass);
+}
+
+binder::Status JNIAudioTrackCallback::onCodecFormatChanged(
+        const std::vector<uint8_t>& audioMetadata) {
+    JNIEnv* env = AndroidRuntime::getJNIEnv();
+    if (env == nullptr) {
+        return binder::Status::ok();
+    }
+
+    jobject byteBuffer = env->CallStaticObjectMethod(mByteBufferClass, mAllocateDirectMethod,
+                                                     (jint)audioMetadata.size());
+    if (env->ExceptionCheck()) {
+        ALOGW("An exception occurred while allocating direct buffer");
+        env->ExceptionDescribe();
+        env->ExceptionClear();
+    }
+    if (byteBuffer == nullptr) {
+        ALOGE("Failed allocating a direct ByteBuffer");
+        return binder::Status::fromStatusT(NO_MEMORY);
+    }
+
+    uint8_t* byteBufferAddr = (uint8_t*)env->GetDirectBufferAddress(byteBuffer);
+    std::copy(audioMetadata.begin(), audioMetadata.end(), byteBufferAddr);
+    env->CallStaticVoidMethod(mClass, mPostEventFromNative, mObject,
+                              AUDIO_NATIVE_EVENT_CODEC_FORMAT_CHANGE, 0, 0, byteBuffer);
+    if (env->ExceptionCheck()) {
+        ALOGW("An exception occurred while notifying codec format changed.");
+        env->ExceptionDescribe();
+        env->ExceptionClear();
+    }
+
+    return binder::Status::ok();
+}
diff --git a/core/jni/android_media_AudioTrackCallback.h b/core/jni/android_media_AudioTrackCallback.h
new file mode 100644
index 0000000..3b8a8bb
--- /dev/null
+++ b/core/jni/android_media_AudioTrackCallback.h
@@ -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.
+ */
+
+#ifndef ANDROID_MEDIA_AUDIO_TRACK_CALLBACK_H
+#define ANDROID_MEDIA_AUDIO_TRACK_CALLBACK_H
+
+#include <android/media/BnAudioTrackCallback.h>
+
+namespace android {
+
+#define AUDIO_NATIVE_EVENT_CODEC_FORMAT_CHANGE 100
+
+// TODO(b/149870866) : Extract common part for JNIAudioTrackCallback and JNIDeviceCallback
+class JNIAudioTrackCallback : public media::BnAudioTrackCallback {
+public:
+    JNIAudioTrackCallback(JNIEnv* env, jobject thiz, jobject weak_thiz,
+                          jmethodID postEventFromNative);
+    ~JNIAudioTrackCallback() override;
+
+    binder::Status onCodecFormatChanged(const std::vector<uint8_t>& audioMetadata) override;
+
+private:
+    jclass mClass;                   // Reference to AudioTrack class
+    jobject mObject;                 // Weak ref to AudioTrack Java object to call on
+    jmethodID mPostEventFromNative;  // postEventFromNative method ID
+    jclass mByteBufferClass;         // Reference to ByteBuffer class
+    jmethodID mAllocateDirectMethod; // ByteBuffer.allocateDirect method ID
+};
+
+}; // namespace android
+
+#endif // ANDROID_MEDIA_AUDIO_TRACK_CALLBACK_H
diff --git a/core/proto/android/providers/settings/secure.proto b/core/proto/android/providers/settings/secure.proto
index 6d9e8ab..a3313b2 100644
--- a/core/proto/android/providers/settings/secure.proto
+++ b/core/proto/android/providers/settings/secure.proto
@@ -77,6 +77,7 @@
         optional SettingProto interactive_ui_timeout_ms = 33 [ (android.privacy).dest = DEST_AUTOMATIC ];
         // Settings for magnification mode
         optional SettingProto accessibility_magnification_mode = 34 [ (android.privacy).dest = DEST_AUTOMATIC ];
+        optional SettingProto button_long_press_targets = 35 [ (android.privacy).dest = DEST_AUTOMATIC ];
     }
     optional Accessibility accessibility = 2;
 
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index 2356b17..addcd81 100644
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -5385,26 +5385,36 @@
         <xliff:g id="package_name" example="com.android.example">%1$s</xliff:g> has been put into the RESTRICTED bucket</string>
 
     <!-- ResolverActivity - profile tabs -->
-    <!-- Label for the perosnal tab of the share sheet and intent resolver [CHAR LIMIT=NONE] -->
+    <!-- Label of a tab on a screen. A user can tap this tap to switch to the 'Personal' view (that shows their personal content) if they have a work profile on their device. [CHAR LIMIT=NONE] -->
     <string name="resolver_personal_tab">Personal</string>
-    <!-- Label for the work tab of the share sheet and intent resolver [CHAR LIMIT=NONE] -->
+    <!-- Label of a tab on a screen. A user can tap this tab to switch to the 'Work' view (that shows their work content) if they have a work profile on their device. [CHAR LIMIT=NONE] -->
     <string name="resolver_work_tab">Work</string>
-    <!-- Label to indicate that the user cannot share with work apps [CHAR LIMIT=NONE] -->
+    <!-- Accessibility label for the personal tab button. [CHAR LIMIT=NONE] -->
+    <string name="resolver_personal_tab_accessibility">Personal view</string>
+    <!-- Accessibility label for the work tab button. [CHAR LIMIT=NONE] -->
+    <string name="resolver_work_tab_accessibility">Work view</string>
+    <!-- Title of a screen. This text lets the user know that their IT admin doesn't allow them to share personal content with work apps. [CHAR LIMIT=NONE] -->
     <string name="resolver_cant_share_with_work_apps">Can\u2019t share with work apps</string>
-    <!-- Label to indicate that the user cannot share with personal apps [CHAR LIMIT=NONE] -->
+    <!-- Title of a screen. This text lets the user know that their IT admin doesn't allow them to share work content with personal apps. [CHAR LIMIT=NONE] -->
     <string name="resolver_cant_share_with_personal_apps">Can\u2019t share with personal apps</string>
-    <!-- Label to explain to the user that sharing between personal and work apps is not enabled by the IT admin [CHAR LIMIT=NONE] -->
-    <string name="resolver_cant_share_cross_profile_explanation">Your IT admin blocked sharing between personal and work apps</string>
-    <!-- Label to indicate that the user has to turn on work apps in order to access work data [CHAR LIMIT=NONE] -->
-    <string name="resolver_turn_on_work_apps">Turn on work apps</string>
-    <!-- Label to explain that the user has to turn on work apps in order to access work data [CHAR LIMIT=NONE] -->
-    <string name="resolver_turn_on_work_apps_explanation">Turn on work apps to access work apps &amp; contacts</string>
-    <!-- Label to indicate that no apps are resolved [CHAR LIMIT=NONE] -->
+    <!-- Error message. This text is explaining that the user's IT admin doesn't allow sharing between personal and work apps. [CHAR LIMIT=NONE] -->
+    <string name="resolver_cant_share_cross_profile_explanation">Your IT admin blocked sharing between personal and work profiles</string>
+    <!-- Title of an error screen. This error message lets the user know that their IT admin blocked access to work apps, and the personal content that they're trying to view in a work app, such as Chrome, isn't allowed. [CHAR LIMIT=NONE] -->
+    <string name="resolver_cant_access_work_apps">Can\u2019t access work apps</string>
+    <!-- Error message. This message lets the user know that their IT admin blocked access to work apps, and the personal content that they're trying to view in a work app, such as Chrome, isn't allowed. [CHAR LIMIT=NONE] -->
+    <string name="resolver_cant_access_work_apps_explanation">Your IT admin doesn\u2019t let you view personal content in work apps</string>
+    <!-- Title of an error screen. This error message lets the user know that their IT admin blocked access to personal apps, and the work content that they're trying to view in a personal app, such as Chrome, isn't allowed. [CHAR LIMIT=NONE] -->
+    <string name="resolver_cant_access_personal_apps">Can\u2019t access personal apps</string>
+    <!-- Error message. This message lets the user know that their IT admin blocked access to personal apps, and the work content that they're trying to view in a personal app, such as Chrome, isn't allowed. [CHAR LIMIT=NONE] -->
+    <string name="resolver_cant_access_personal_apps_explanation">Your IT admin doesn\u2019t let you view work content in personal apps</string>
+    <!-- Error message. This text lets the user know that they need to turn on work apps in order to share content. There's also a button a user can tap to turn on the apps. [CHAR LIMIT=NONE] -->
+    <string name="resolver_turn_on_work_apps_share">Turn on work profile to share content</string>
+    <!-- Error message. This text lets the user know that they need to turn on work apps in order to view content. There's also a button a user can tap to turn on the apps. [CHAR LIMIT=NONE] -->
+    <string name="resolver_turn_on_work_apps_view">Turn on work profile to view content</string>
+    <!-- Error message. This text lets the user know that work apps aren't available on the device. [CHAR LIMIT=NONE] -->
     <string name="resolver_no_apps_available">No apps available</string>
-    <!-- Label to explain that no apps are resolved [CHAR LIMIT=NONE] -->
-    <string name="resolver_no_apps_available_explanation">We couldn\u2019t find any apps</string>
-    <!-- Button which switches on the disabled work profile [CHAR LIMIT=NONE] -->
-    <string name="resolver_switch_on_work">Switch on work</string>
+    <!-- Button text. This button turns on a user's work profile so they can access their work apps and data. [CHAR LIMIT=NONE] -->
+    <string name="resolver_switch_on_work">Turn on</string>
 
     <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. [CHAR LIMIT=NONE] -->
     <string name="permlab_accessCallAudio">Record or play audio in telephony calls</string>
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index c1d8168..0971aad 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -3874,7 +3874,9 @@
   <java-symbol type="color" name="resolver_tabs_active_color" />
   <java-symbol type="color" name="resolver_tabs_inactive_color" />
   <java-symbol type="string" name="resolver_personal_tab" />
+  <java-symbol type="string" name="resolver_personal_tab_accessibility" />
   <java-symbol type="string" name="resolver_work_tab" />
+  <java-symbol type="string" name="resolver_work_tab_accessibility" />
   <java-symbol type="id" name="stub" />
   <java-symbol type="id" name="resolver_empty_state" />
   <java-symbol type="id" name="resolver_empty_state_icon" />
@@ -3886,11 +3888,13 @@
   <java-symbol type="string" name="resolver_cant_share_with_work_apps" />
   <java-symbol type="string" name="resolver_cant_share_with_personal_apps" />
   <java-symbol type="string" name="resolver_cant_share_cross_profile_explanation" />
-  <java-symbol type="string" name="resolver_turn_on_work_apps" />
-  <java-symbol type="string" name="resolver_turn_on_work_apps_explanation" />
+  <java-symbol type="string" name="resolver_cant_access_work_apps" />
+  <java-symbol type="string" name="resolver_cant_access_work_apps_explanation" />
+  <java-symbol type="string" name="resolver_cant_access_personal_apps" />
+  <java-symbol type="string" name="resolver_cant_access_personal_apps_explanation" />
+  <java-symbol type="string" name="resolver_turn_on_work_apps_view" />
+  <java-symbol type="string" name="resolver_turn_on_work_apps_share" />
   <java-symbol type="string" name="resolver_no_apps_available" />
-  <java-symbol type="string" name="resolver_no_apps_available_explanation" />
-  <java-symbol type="string" name="resolver_no_apps_available_explanation" />
   <java-symbol type="string" name="resolver_switch_on_work" />
   <java-symbol type="drawable" name="ic_work_apps_off" />
   <java-symbol type="drawable" name="ic_sharing_disabled" />
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 6d0e58b..24e96d4 100644
--- a/core/tests/coretests/src/com/android/internal/app/ChooserActivityTest.java
+++ b/core/tests/coretests/src/com/android/internal/app/ChooserActivityTest.java
@@ -1340,7 +1340,7 @@
         onView(withText(R.string.resolver_work_tab)).perform(click());
         waitForIdle();
 
-        onView(withText(R.string.resolver_turn_on_work_apps))
+        onView(withText(R.string.resolver_turn_on_work_apps_share))
                 .check(matches(isDisplayed()));
     }
 
diff --git a/core/tests/coretests/src/com/android/internal/app/ResolverActivityTest.java b/core/tests/coretests/src/com/android/internal/app/ResolverActivityTest.java
index a7bf488..9d1ca61 100644
--- a/core/tests/coretests/src/com/android/internal/app/ResolverActivityTest.java
+++ b/core/tests/coretests/src/com/android/internal/app/ResolverActivityTest.java
@@ -624,7 +624,7 @@
         onView(withText(R.string.resolver_work_tab)).perform(click());
         waitForIdle();
 
-        onView(withText(R.string.resolver_turn_on_work_apps))
+        onView(withText(R.string.resolver_turn_on_work_apps_view))
                 .check(matches(isDisplayed()));
     }
 
diff --git a/libs/WindowManager/Jetpack/Android.bp b/libs/WindowManager/Jetpack/Android.bp
new file mode 100644
index 0000000..308c1a5
--- /dev/null
+++ b/libs/WindowManager/Jetpack/Android.bp
@@ -0,0 +1,38 @@
+// 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_library_import {
+    name: "window-extensions",
+    aars: ["window-extensions-release.aar"],
+    sdk_version: "current",
+}
+
+java_library {
+    name: "androidx.window.extensions",
+    srcs: ["src/**/*.java"],
+    static_libs: ["window-extensions"],
+    installable: true,
+    sdk_version: "core_platform",
+    vendor: true,
+    libs: ["framework", "androidx.annotation_annotation",],
+    required: ["androidx.window.extensions.xml",],
+}
+
+prebuilt_etc {
+    name: "androidx.window.extensions.xml",
+    vendor: true,
+    sub_dir: "permissions",
+    src: "androidx.window.extensions.xml",
+    filename_from_src: true,
+}
diff --git a/libs/WindowManager/Jetpack/androidx.window.extensions.xml b/libs/WindowManager/Jetpack/androidx.window.extensions.xml
new file mode 100644
index 0000000..1f0ff66
--- /dev/null
+++ b/libs/WindowManager/Jetpack/androidx.window.extensions.xml
@@ -0,0 +1,21 @@
+<?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/libs/WindowManager/Jetpack/src/androidx/window/extensions/ExtensionHelper.java b/libs/WindowManager/Jetpack/src/androidx/window/extensions/ExtensionHelper.java
new file mode 100644
index 0000000..c4f11a0
--- /dev/null
+++ b/libs/WindowManager/Jetpack/src/androidx/window/extensions/ExtensionHelper.java
@@ -0,0 +1,130 @@
+/*
+ * 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.
+ */
+
+package androidx.window.extensions;
+
+import static android.view.Display.INVALID_DISPLAY;
+import static android.view.Surface.ROTATION_0;
+import static android.view.Surface.ROTATION_180;
+import static android.view.Surface.ROTATION_270;
+import static android.view.Surface.ROTATION_90;
+
+import android.app.Activity;
+import android.app.ActivityThread;
+import android.graphics.Rect;
+import android.hardware.display.DisplayManagerGlobal;
+import android.os.IBinder;
+import android.view.DisplayInfo;
+import android.view.Surface;
+
+/**
+ * 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 {
+    /**
+     * Rotate the input rectangle specified in default display orientation to the current display
+     * rotation.
+     */
+    static void rotateRectToDisplayRotation(Rect inOutRect, int displayId) {
+        DisplayManagerGlobal dmGlobal = DisplayManagerGlobal.getInstance();
+        DisplayInfo displayInfo = dmGlobal.getDisplayInfo(displayId);
+        int rotation = displayInfo.rotation;
+
+        boolean isSideRotation = rotation == ROTATION_90 || rotation == ROTATION_270;
+        int displayWidth = isSideRotation ? displayInfo.logicalHeight : displayInfo.logicalWidth;
+        int displayHeight = isSideRotation ? displayInfo.logicalWidth : displayInfo.logicalHeight;
+
+        inOutRect.intersect(0, 0, displayWidth, displayHeight);
+
+        rotateBounds(inOutRect, displayWidth, displayHeight, rotation);
+    }
+
+    /**
+     * Rotate the input rectangle within parent bounds for a given delta.
+     */
+    private static void rotateBounds(Rect inOutRect, int parentWidth, int parentHeight,
+            @Surface.Rotation int delta) {
+        int origLeft = inOutRect.left;
+        switch (delta) {
+            case ROTATION_0:
+                return;
+            case ROTATION_90:
+                inOutRect.left = inOutRect.top;
+                inOutRect.top = parentWidth - inOutRect.right;
+                inOutRect.right = inOutRect.bottom;
+                inOutRect.bottom = parentWidth - origLeft;
+                return;
+            case ROTATION_180:
+                inOutRect.left = parentWidth - inOutRect.right;
+                inOutRect.right = parentWidth - origLeft;
+                return;
+            case ROTATION_270:
+                inOutRect.left = parentHeight - inOutRect.bottom;
+                inOutRect.bottom = inOutRect.right;
+                inOutRect.right = parentHeight - inOutRect.top;
+                inOutRect.top = origLeft;
+                return;
+        }
+    }
+
+    /** Transform rectangle from absolute coordinate space to the window coordinate space. */
+    static void transformToWindowSpaceRect(Rect inOutRect, IBinder windowToken) {
+        Rect windowRect = getWindowRect(windowToken);
+        if (windowRect == null) {
+            inOutRect.setEmpty();
+            return;
+        }
+        if (!Rect.intersects(inOutRect, windowRect)) {
+            inOutRect.setEmpty();
+            return;
+        }
+        inOutRect.intersect(windowRect);
+        inOutRect.offset(-windowRect.left, -windowRect.top);
+    }
+
+    /**
+     * Get the current window bounds in absolute coordinates.
+     * NOTE: Only works with Activity windows.
+     */
+    private static Rect getWindowRect(IBinder windowToken) {
+        Activity activity = ActivityThread.currentActivityThread().getActivity(windowToken);
+        final Rect windowRect = new Rect();
+        if (activity != null) {
+            activity.getWindow().getDecorView().getWindowDisplayFrame(windowRect);
+        }
+        return windowRect;
+    }
+
+    /**
+     * Check if this window is an Activity window that is in multi-window mode.
+     */
+    static boolean isInMultiWindow(IBinder windowToken) {
+        Activity activity = ActivityThread.currentActivityThread().getActivity(windowToken);
+        return activity != null && activity.isInMultiWindowMode();
+    }
+
+    /**
+     * Get the id of the parent display for the window.
+     * NOTE: Only works with Activity windows.
+     */
+    static int getWindowDisplay(IBinder windowToken) {
+        Activity activity = ActivityThread.currentActivityThread().getActivity(windowToken);
+        return activity != null
+                ? activity.getWindowManager().getDefaultDisplay().getDisplayId() : INVALID_DISPLAY;
+    }
+}
diff --git a/libs/WindowManager/Jetpack/src/androidx/window/extensions/ExtensionProvider.java b/libs/WindowManager/Jetpack/src/androidx/window/extensions/ExtensionProvider.java
new file mode 100644
index 0000000..47349f1
--- /dev/null
+++ b/libs/WindowManager/Jetpack/src/androidx/window/extensions/ExtensionProvider.java
@@ -0,0 +1,42 @@
+/*
+ * 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.
+ */
+
+package androidx.window.extensions;
+
+import android.content.Context;
+
+/**
+ * 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 {
+
+    /**
+     * The support library will instantiate the vendor implementation using this interface.
+     * @return An implementation of {@link ExtensionInterface}.
+     */
+    public static ExtensionInterface getExtensionImpl(Context context) {
+        return new SettingsExtensionImpl(context);
+    }
+
+    /**
+     * The support library will use this method to check API version compatibility.
+     * @return API version string in MAJOR.MINOR.PATCH-description format.
+     */
+    public static String getApiVersion() {
+        return "1.0.0-settings_sample";
+    }
+}
diff --git a/libs/WindowManager/Jetpack/src/androidx/window/extensions/SettingsExtensionImpl.java b/libs/WindowManager/Jetpack/src/androidx/window/extensions/SettingsExtensionImpl.java
new file mode 100644
index 0000000..7a3fbf3
--- /dev/null
+++ b/libs/WindowManager/Jetpack/src/androidx/window/extensions/SettingsExtensionImpl.java
@@ -0,0 +1,217 @@
+/*
+ * 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.
+ */
+
+package androidx.window.extensions;
+
+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 android.content.ContentResolver;
+import android.content.Context;
+import android.database.ContentObserver;
+import android.graphics.Rect;
+import android.net.Uri;
+import android.os.Handler;
+import android.os.IBinder;
+import android.os.Looper;
+import android.provider.Settings;
+import android.text.TextUtils;
+import android.util.Log;
+
+import androidx.annotation.NonNull;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+class SettingsExtensionImpl extends StubExtension {
+    private static final String TAG = "SettingsExtension";
+
+    private static final String DEVICE_POSTURE = "device_posture";
+    private static final String DISPLAY_FEATURES = "display_features";
+
+    private static final Pattern FEATURE_PATTERN =
+            Pattern.compile("([a-z]+)-\\[(\\d+),(\\d+),(\\d+),(\\d+)]");
+
+    private static final String FEATURE_TYPE_FOLD = "fold";
+    private static final String FEATURE_TYPE_HINGE = "hinge";
+
+    private Context mContext;
+    private SettingsObserver mSettingsObserver;
+
+    final class SettingsObserver extends ContentObserver {
+        private final Uri mDevicePostureUri =
+                Settings.Global.getUriFor(DEVICE_POSTURE);
+        private final Uri mDisplayFeaturesUri =
+                Settings.Global.getUriFor(DISPLAY_FEATURES);
+        private final ContentResolver mResolver = mContext.getContentResolver();
+        private boolean mRegisteredObservers;
+
+
+        private SettingsObserver() {
+            super(new Handler(Looper.getMainLooper()));
+        }
+
+        private void registerObserversIfNeeded() {
+            if (mRegisteredObservers) {
+                return;
+            }
+            mRegisteredObservers = true;
+            mResolver.registerContentObserver(mDevicePostureUri, false /* notifyForDescendents */,
+                    this /* ContentObserver */);
+            mResolver.registerContentObserver(mDisplayFeaturesUri, false /* notifyForDescendents */,
+                    this /* ContentObserver */);
+        }
+
+        private void unregisterObserversIfNeeded() {
+            if (!mRegisteredObservers) {
+                return;
+            }
+            mRegisteredObservers = false;
+            mResolver.unregisterContentObserver(this);
+        }
+
+        @Override
+        public void onChange(boolean selfChange, Uri uri) {
+            if (uri == null) {
+                return;
+            }
+
+            if (mDevicePostureUri.equals(uri)) {
+                updateDevicePosture();
+                return;
+            }
+            if (mDisplayFeaturesUri.equals(uri)) {
+                updateDisplayFeatures();
+                return;
+            }
+        }
+    }
+
+    SettingsExtensionImpl(Context context) {
+        mContext = context;
+        mSettingsObserver = new SettingsObserver();
+    }
+
+    private void updateDevicePosture() {
+        updateDeviceState(getDeviceState());
+    }
+
+    /** Update display features with values read from settings. */
+    private void updateDisplayFeatures() {
+        for (IBinder windowToken : getWindowsListeningForLayoutChanges()) {
+            ExtensionWindowLayoutInfo newLayout = getWindowLayoutInfo(windowToken);
+            updateWindowLayout(windowToken, newLayout);
+        }
+    }
+
+    @NonNull
+    @Override
+    public ExtensionDeviceState getDeviceState() {
+        ContentResolver resolver = mContext.getContentResolver();
+        int posture = Settings.Global.getInt(resolver, DEVICE_POSTURE,
+                ExtensionDeviceState.POSTURE_UNKNOWN);
+        return new ExtensionDeviceState(posture);
+    }
+
+    @NonNull
+    @Override
+    public ExtensionWindowLayoutInfo getWindowLayoutInfo(@NonNull IBinder windowToken) {
+        List<ExtensionDisplayFeature> displayFeatures = readDisplayFeatures(windowToken);
+        return new ExtensionWindowLayoutInfo(displayFeatures);
+    }
+
+    private List<ExtensionDisplayFeature> readDisplayFeatures(IBinder windowToken) {
+        List<ExtensionDisplayFeature> features = new ArrayList<ExtensionDisplayFeature>();
+        int displayId = getWindowDisplay(windowToken);
+        if (displayId != DEFAULT_DISPLAY) {
+            Log.w(TAG, "This sample doesn't support display features on secondary displays");
+            return features;
+        }
+
+        ContentResolver resolver = mContext.getContentResolver();
+        final String displayFeaturesString = Settings.Global.getString(resolver, DISPLAY_FEATURES);
+        if (isInMultiWindow(windowToken)) {
+            // It is recommended not to report any display features in multi-window mode, since it
+            // won't be possible to synchronize the display feature positions with window movement.
+            return features;
+        }
+        if (TextUtils.isEmpty(displayFeaturesString)) {
+            return features;
+        }
+
+        String[] featureStrings = displayFeaturesString.split(";");
+        for (String featureString : featureStrings) {
+            Matcher featureMatcher = FEATURE_PATTERN.matcher(featureString);
+            if (!featureMatcher.matches()) {
+                Log.e(TAG, "Malformed feature description format: " + featureString);
+                continue;
+            }
+            try {
+                String featureType = featureMatcher.group(1);
+                int type;
+                switch (featureType) {
+                    case FEATURE_TYPE_FOLD:
+                        type = ExtensionDisplayFeature.TYPE_FOLD;
+                        break;
+                    case FEATURE_TYPE_HINGE:
+                        type = ExtensionDisplayFeature.TYPE_HINGE;
+                        break;
+                    default: {
+                        Log.e(TAG, "Malformed feature type: " + featureType);
+                        continue;
+                    }
+                }
+
+                int left = Integer.parseInt(featureMatcher.group(2));
+                int top = Integer.parseInt(featureMatcher.group(3));
+                int right = Integer.parseInt(featureMatcher.group(4));
+                int bottom = Integer.parseInt(featureMatcher.group(5));
+                Rect featureRect = new Rect(left, top, right, bottom);
+                rotateRectToDisplayRotation(featureRect, displayId);
+                transformToWindowSpaceRect(featureRect, windowToken);
+                if (!featureRect.isEmpty()) {
+                    ExtensionDisplayFeature feature =
+                            new ExtensionDisplayFeature(featureRect, type);
+                    features.add(feature);
+                } else {
+                    Log.w(TAG, "Failed to adjust feature to window");
+                }
+            } catch (NumberFormatException e) {
+                Log.e(TAG, "Malformed feature description: " + featureString);
+            }
+        }
+        return features;
+    }
+
+    @Override
+    protected void onListenersChanged() {
+        if (mSettingsObserver == null) {
+            return;
+        }
+
+        if (hasListeners()) {
+            mSettingsObserver.registerObserversIfNeeded();
+        } else {
+            mSettingsObserver.unregisterObserversIfNeeded();
+        }
+    }
+}
diff --git a/libs/WindowManager/Jetpack/window-extensions-release.aar b/libs/WindowManager/Jetpack/window-extensions-release.aar
new file mode 100644
index 0000000..0ebbb86
--- /dev/null
+++ b/libs/WindowManager/Jetpack/window-extensions-release.aar
Binary files differ
diff --git a/location/java/com/android/internal/location/gnssmetrics/GnssMetrics.java b/location/java/com/android/internal/location/gnssmetrics/GnssMetrics.java
index 1ac4b4b..323bba3 100644
--- a/location/java/com/android/internal/location/gnssmetrics/GnssMetrics.java
+++ b/location/java/com/android/internal/location/gnssmetrics/GnssMetrics.java
@@ -624,7 +624,7 @@
 
     private void registerGnssStats() {
         mPullAtomCallback = new StatsPullAtomCallbackImpl();
-        mStatsManager.registerPullAtomCallback(
+        mStatsManager.setPullAtomCallback(
                 FrameworkStatsLog.GNSS_STATS,
                 null, // use default PullAtomMetadata values
                 BackgroundThread.getExecutor(), mPullAtomCallback);
diff --git a/media/java/android/media/AudioMetadata.java b/media/java/android/media/AudioMetadata.java
index 7245aab..e67ba59 100644
--- a/media/java/android/media/AudioMetadata.java
+++ b/media/java/android/media/AudioMetadata.java
@@ -16,10 +16,18 @@
 
 package android.media;
 
+import android.annotation.IntRange;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
+import android.util.Log;
 import android.util.Pair;
 
+import java.lang.reflect.ParameterizedType;
+import java.nio.BufferUnderflowException;
+import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
+import java.nio.charset.Charset;
+import java.nio.charset.StandardCharsets;
 import java.util.HashMap;
 import java.util.HashSet;
 import java.util.Objects;
@@ -30,6 +38,8 @@
  * configuration and capability requests within the Audio Framework.
  */
 public final class AudioMetadata {
+    private static final String TAG = "AudioMetadata";
+
     /**
      * Key interface for the map.
      *
@@ -273,7 +283,7 @@
      * @hide
      */
     @NonNull
-    public static <T> Key<T> createKey(String name, Class<T> type) {
+    public static <T> Key<T> createKey(@NonNull String name, @NonNull Class<T> type) {
         // Implementation specific.
         return new Key<T>() {
             private final String mName = name;
@@ -296,6 +306,26 @@
             public boolean isFromFramework() {
                 return true;
             }
+
+            /**
+             * Return true if the name and the type of two objects are the same.
+             */
+            @Override
+            public boolean equals(Object obj) {
+                if (obj == this) {
+                    return true;
+                }
+                if (!(obj instanceof Key)) {
+                    return false;
+                }
+                Key<?> other = (Key<?>) obj;
+                return mName.equals(other.getName()) && mType.equals(other.getValueClass());
+            }
+
+            @Override
+            public int hashCode() {
+                return Objects.hash(mName, mType);
+            }
         };
     }
 
@@ -364,6 +394,27 @@
             return mHashMap.size();
         }
 
+        /**
+         * Return true if the object is a BaseMap and the content from two BaseMap are the same.
+         * Note: Need to override the equals functions of Key<T> for HashMap comparison.
+         */
+        @Override
+        public boolean equals(Object obj) {
+            if (obj == this) {
+                return true;
+            }
+            if (!(obj instanceof BaseMap)) {
+                return false;
+            }
+            BaseMap other = (BaseMap) obj;
+            return mHashMap.equals(other.mHashMap);
+        }
+
+        @Override
+        public int hashCode() {
+            return Objects.hash(mHashMap);
+        }
+
         /*
          * Implementation specific.
          *
@@ -401,6 +452,445 @@
                 new HashMap();
     }
 
+    // The audio metadata object type index should be kept the same as
+    // the ones in audio_utils::metadata::metadata_types
+    private static final int AUDIO_METADATA_OBJ_TYPE_NONE = 0;
+    private static final int AUDIO_METADATA_OBJ_TYPE_INT = 1;
+    private static final int AUDIO_METADATA_OBJ_TYPE_LONG = 2;
+    private static final int AUDIO_METADATA_OBJ_TYPE_FLOAT = 3;
+    private static final int AUDIO_METADATA_OBJ_TYPE_DOUBLE = 4;
+    private static final int AUDIO_METADATA_OBJ_TYPE_STRING = 5;
+    // BaseMap is corresponding to audio_utils::metadata::Data
+    private static final int AUDIO_METADATA_OBJ_TYPE_BASEMAP = 6;
+
+    private static final HashMap<Class, Integer> AUDIO_METADATA_OBJ_TYPES = new HashMap<>() {{
+            put(Integer.class, AUDIO_METADATA_OBJ_TYPE_INT);
+            put(Long.class, AUDIO_METADATA_OBJ_TYPE_LONG);
+            put(Float.class, AUDIO_METADATA_OBJ_TYPE_FLOAT);
+            put(Double.class, AUDIO_METADATA_OBJ_TYPE_DOUBLE);
+            put(String.class, AUDIO_METADATA_OBJ_TYPE_STRING);
+            put(BaseMap.class, AUDIO_METADATA_OBJ_TYPE_BASEMAP);
+        }};
+
+    private static final Charset AUDIO_METADATA_CHARSET = StandardCharsets.UTF_8;
+
+    /**
+     * An auto growing byte buffer
+     */
+    private static class AutoGrowByteBuffer {
+        private static final int INTEGER_BYTE_COUNT = Integer.SIZE / Byte.SIZE;
+        private static final int LONG_BYTE_COUNT = Long.SIZE / Byte.SIZE;
+        private static final int FLOAT_BYTE_COUNT = Float.SIZE / Byte.SIZE;
+        private static final int DOUBLE_BYTE_COUNT = Double.SIZE / Byte.SIZE;
+
+        private ByteBuffer mBuffer;
+
+        AutoGrowByteBuffer() {
+            this(1024);
+        }
+
+        AutoGrowByteBuffer(@IntRange(from = 0) int initialCapacity) {
+            mBuffer = ByteBuffer.allocateDirect(initialCapacity);
+        }
+
+        public ByteBuffer getRawByteBuffer() {
+            // Slice the buffer from 0 to position.
+            int limit = mBuffer.limit();
+            int position = mBuffer.position();
+            mBuffer.limit(position);
+            mBuffer.position(0);
+            ByteBuffer buffer = mBuffer.slice();
+
+            // Restore position and limit.
+            mBuffer.limit(limit);
+            mBuffer.position(position);
+            return buffer;
+        }
+
+        public ByteOrder order() {
+            return mBuffer.order();
+        }
+
+        public int position() {
+            return mBuffer.position();
+        }
+
+        public AutoGrowByteBuffer position(int newPosition) {
+            mBuffer.position(newPosition);
+            return this;
+        }
+
+        public AutoGrowByteBuffer order(ByteOrder order) {
+            mBuffer.order(order);
+            return this;
+        }
+
+        public AutoGrowByteBuffer putInt(int value) {
+            ensureCapacity(INTEGER_BYTE_COUNT);
+            mBuffer.putInt(value);
+            return this;
+        }
+
+        public AutoGrowByteBuffer putLong(long value) {
+            ensureCapacity(LONG_BYTE_COUNT);
+            mBuffer.putLong(value);
+            return this;
+        }
+
+        public AutoGrowByteBuffer putFloat(float value) {
+            ensureCapacity(FLOAT_BYTE_COUNT);
+            mBuffer.putFloat(value);
+            return this;
+        }
+
+        public AutoGrowByteBuffer putDouble(double value) {
+            ensureCapacity(DOUBLE_BYTE_COUNT);
+            mBuffer.putDouble(value);
+            return this;
+        }
+
+        public AutoGrowByteBuffer put(byte[] src) {
+            ensureCapacity(src.length);
+            mBuffer.put(src);
+            return this;
+        }
+
+        /**
+         * Ensures capacity to append at least <code>count</code> values.
+         */
+        private void ensureCapacity(@IntRange int count) {
+            if (mBuffer.remaining() < count) {
+                int newCapacity = mBuffer.position() + count;
+                if (newCapacity > Integer.MAX_VALUE >> 1) {
+                    throw new IllegalStateException(
+                            "Item memory requirements too large: " + newCapacity);
+                }
+                newCapacity <<= 1;
+                ByteBuffer buffer = ByteBuffer.allocateDirect(newCapacity);
+                buffer.order(mBuffer.order());
+
+                // Copy data from old buffer to new buffer
+                mBuffer.flip();
+                buffer.put(mBuffer);
+
+                // Set buffer to new buffer
+                mBuffer = buffer;
+            }
+        }
+    }
+
+    /**
+     * @hide
+     * Describes a unpacking/packing contract of type {@code T} out of a {@link ByteBuffer}
+     *
+     * @param <T> the type being unpack
+     */
+    private interface DataPackage<T> {
+        /**
+         * Read an item from a {@link ByteBuffer}.
+         *
+         * The parceling format is assumed the same as the one described in
+         * audio_utils::Metadata.h. Copied here as a reference.
+         * All values are native endian order.
+         *
+         * Datum = { (type_size_t)  Type (the type index from type_as_value<T>.)
+         *           (datum_size_t) Size (size of datum, including the size field)
+         *           (byte string)  Payload<Type>
+         *         }
+         *
+         * Primitive types:
+         * Payload<Type> = { bytes in native endian order }
+         *
+         * Vector, Map, Container types:
+         * Payload<Type> = { (index_size_t) number of elements
+         *                   (byte string)  Payload<Element_Type> * number
+         *                 }
+         *
+         * Pair container types:
+         * Payload<Type> = { (byte string) Payload<first>,
+         *                   (byte string) Payload<second>
+         *                 }
+         *
+         * @param buffer the byte buffer to read from
+         * @return an object, which types is given type for {@link DataPackage}
+         * @throws BufferUnderflowException when there is no enough data remaining
+         *      in the buffer for unpacking.
+         */
+        @Nullable
+        T unpack(ByteBuffer buffer);
+
+        /**
+         * Pack the item into a byte array. This is the reversed way of unpacking.
+         *
+         * @param output is the stream to which to write the data
+         * @param obj the item to pack
+         * @return true if packing successfully. Otherwise, return false.
+         */
+        boolean pack(AutoGrowByteBuffer output, T obj);
+
+        /**
+         * Return what kind of data is contained in the package.
+         */
+        default Class getMyType() {
+            return (Class) ((ParameterizedType) getClass().getGenericInterfaces()[0])
+                    .getActualTypeArguments()[0];
+        }
+    }
+
+    /*****************************************************************************************
+     * Following class are common {@link DataPackage} implementations, which include types
+     * that are defined in audio_utils::metadata::metadata_types
+     *
+     * For Java
+     *     int32_t corresponds to Integer
+     *     int64_t corresponds to Long
+     *     float corresponds to Float
+     *     double corresponds to Double
+     *     std::string corresponds to String
+     *     Data corresponds to BaseMap
+     *     Datum corresponds to Object
+     ****************************************************************************************/
+
+    private static final HashMap<Integer, DataPackage<?>> DATA_PACKAGES = new HashMap<>() {{
+            put(AUDIO_METADATA_OBJ_TYPE_INT, new DataPackage<Integer>() {
+                @Override
+                @Nullable
+                public Integer unpack(ByteBuffer buffer) {
+                    return buffer.getInt();
+                }
+
+                @Override
+                public boolean pack(AutoGrowByteBuffer output, Integer obj) {
+                    output.putInt(obj);
+                    return true;
+                }
+            });
+            put(AUDIO_METADATA_OBJ_TYPE_LONG, new DataPackage<Long>() {
+                @Override
+                @Nullable
+                public Long unpack(ByteBuffer buffer) {
+                    return buffer.getLong();
+                }
+
+                @Override
+                public boolean pack(AutoGrowByteBuffer output, Long obj) {
+                    output.putLong(obj);
+                    return true;
+                }
+            });
+            put(AUDIO_METADATA_OBJ_TYPE_FLOAT, new DataPackage<Float>() {
+                @Override
+                @Nullable
+                public Float unpack(ByteBuffer buffer) {
+                    return buffer.getFloat();
+                }
+
+                @Override
+                public boolean pack(AutoGrowByteBuffer output, Float obj) {
+                    output.putFloat(obj);
+                    return true;
+                }
+            });
+            put(AUDIO_METADATA_OBJ_TYPE_DOUBLE, new DataPackage<Double>() {
+                @Override
+                @Nullable
+                public Double unpack(ByteBuffer buffer) {
+                    return buffer.getDouble();
+                }
+
+                @Override
+                public boolean pack(AutoGrowByteBuffer output, Double obj) {
+                    output.putDouble(obj);
+                    return true;
+                }
+            });
+            put(AUDIO_METADATA_OBJ_TYPE_STRING, new DataPackage<String>() {
+                @Override
+                @Nullable
+                public String unpack(ByteBuffer buffer) {
+                    int dataSize = buffer.getInt();
+                    if (buffer.position() + dataSize > buffer.limit()) {
+                        return null;
+                    }
+                    byte[] valueArr = new byte[dataSize];
+                    buffer.get(valueArr);
+                    String value = new String(valueArr, AUDIO_METADATA_CHARSET);
+                    return value;
+                }
+
+                /**
+                 * This is a reversed operation of unpack. It is needed to write the String
+                 * at bytes encoded with AUDIO_METADATA_CHARSET. There should be an integer
+                 * value representing the length of the bytes written before the bytes.
+                 */
+                @Override
+                public boolean pack(AutoGrowByteBuffer output, String obj) {
+                    byte[] valueArr = obj.getBytes(AUDIO_METADATA_CHARSET);
+                    output.putInt(valueArr.length);
+                    output.put(valueArr);
+                    return true;
+                }
+            });
+            put(AUDIO_METADATA_OBJ_TYPE_BASEMAP, new BaseMapPackage());
+        }};
+    // ObjectPackage is a special case that it is expected to unpack audio_utils::metadata::Datum,
+    // which contains data type and data size besides the payload for the data.
+    private static final ObjectPackage OBJECT_PACKAGE = new ObjectPackage();
+
+    private static class ObjectPackage implements DataPackage<Pair<Class, Object>> {
+        /**
+         * The {@link ObjectPackage} will unpack byte string for audio_utils::metadata::Datum.
+         * Since the Datum is a std::any, {@link Object} is used to carrying the data. The
+         * data type is stored in the data package header. In that case, a {@link Class}
+         * will also be returned to indicate the actual type for the object.
+         */
+        @Override
+        @Nullable
+        public Pair<Class, Object> unpack(ByteBuffer buffer) {
+            int dataType = buffer.getInt();
+            DataPackage dataPackage = DATA_PACKAGES.get(dataType);
+            if (dataPackage == null) {
+                Log.e(TAG, "Cannot find DataPackage for type:" + dataType);
+                return null;
+            }
+            int dataSize = buffer.getInt();
+            int position = buffer.position();
+            Object obj = dataPackage.unpack(buffer);
+            if (buffer.position() - position != dataSize) {
+                Log.e(TAG, "Broken data package");
+                return null;
+            }
+            return new Pair<Class, Object>(dataPackage.getMyType(), obj);
+        }
+
+        @Override
+        public boolean pack(AutoGrowByteBuffer output, Pair<Class, Object> obj) {
+            final Integer dataType = AUDIO_METADATA_OBJ_TYPES.get(obj.first);
+            if (dataType == null) {
+                Log.e(TAG, "Cannot find data type for " + obj.first);
+                return false;
+            }
+            DataPackage dataPackage = DATA_PACKAGES.get(dataType);
+            if (dataPackage == null) {
+                Log.e(TAG, "Cannot find DataPackage for type:" + dataType);
+                return false;
+            }
+            output.putInt(dataType);
+            int position = output.position(); // Keep current position.
+            output.putInt(0); // Keep a place for the size of payload.
+            int payloadIdx = output.position();
+            if (!dataPackage.pack(output, obj.second)) {
+                Log.i(TAG, "Failed to pack object: " + obj.second);
+                return false;
+            }
+            // Put the actual payload size.
+            int currentPosition = output.position();
+            output.position(position);
+            output.putInt(currentPosition - payloadIdx);
+            output.position(currentPosition);
+            return true;
+        }
+    }
+
+    /**
+     * BaseMap will be corresponding to audio_utils::metadata::Data.
+     */
+    private static class BaseMapPackage implements DataPackage<BaseMap> {
+        @Override
+        @Nullable
+        public BaseMap unpack(ByteBuffer buffer) {
+            BaseMap ret = new BaseMap();
+            int mapSize = buffer.getInt();
+            DataPackage<String> strDataPackage =
+                    (DataPackage<String>) DATA_PACKAGES.get(AUDIO_METADATA_OBJ_TYPE_STRING);
+            if (strDataPackage == null) {
+                Log.e(TAG, "Cannot find DataPackage for String");
+                return null;
+            }
+            for (int i = 0; i < mapSize; i++) {
+                String key = strDataPackage.unpack(buffer);
+                if (key == null) {
+                    Log.e(TAG, "Failed to unpack key for map");
+                    return null;
+                }
+                Pair<Class, Object> value = OBJECT_PACKAGE.unpack(buffer);
+                if (value == null) {
+                    Log.e(TAG, "Failed to unpack value for map");
+                    return null;
+                }
+                ret.set(createKey(key, value.first), value.first.cast(value.second));
+            }
+            return ret;
+        }
+
+        @Override
+        public boolean pack(AutoGrowByteBuffer output, BaseMap obj) {
+            output.putInt(obj.size());
+            DataPackage<String> strDataPackage =
+                    (DataPackage<String>) DATA_PACKAGES.get(AUDIO_METADATA_OBJ_TYPE_STRING);
+            if (strDataPackage == null) {
+                Log.e(TAG, "Cannot find DataPackage for String");
+                return false;
+            }
+            for (Key<?> key : obj.keySet()) {
+                if (!strDataPackage.pack(output, key.getName())) {
+                    Log.i(TAG, "Failed to pack key: " + key.getName());
+                    return false;
+                }
+                if (!OBJECT_PACKAGE.pack(output, new Pair<>(key.getValueClass(), obj.get(key)))) {
+                    Log.i(TAG, "Failed to pack value: " + obj.get(key));
+                    return false;
+                }
+            }
+            return true;
+        }
+    }
+
+    /**
+     * @hide
+     * Extract a {@link BaseMap} from a given {@link ByteBuffer}
+     * @param buffer is a byte string that contains information to unpack.
+     * @return a {@link BaseMap} object if extracting successfully from given byte buffer.
+     *     Otherwise, returns {@code null}.
+     */
+    @Nullable
+    public static BaseMap fromByteBuffer(ByteBuffer buffer) {
+        DataPackage dataPackage = DATA_PACKAGES.get(AUDIO_METADATA_OBJ_TYPE_BASEMAP);
+        if (dataPackage == null) {
+            Log.e(TAG, "Cannot find DataPackage for BaseMap");
+            return null;
+        }
+        try {
+            return (BaseMap) dataPackage.unpack(buffer);
+        } catch (BufferUnderflowException e) {
+            Log.e(TAG, "No enough data to unpack");
+        }
+        return null;
+    }
+
+    /**
+     * @hide
+     * Pack a {link BaseMap} to a {@link ByteBuffer}
+     * @param data is the object for packing
+     * @param order is the byte order
+     * @return a {@link ByteBuffer} if successfully packing the data.
+     *     Otherwise, returns {@code null};
+     */
+    @Nullable
+    public static ByteBuffer toByteBuffer(BaseMap data, ByteOrder order) {
+        DataPackage dataPackage = DATA_PACKAGES.get(AUDIO_METADATA_OBJ_TYPE_BASEMAP);
+        if (dataPackage == null) {
+            Log.e(TAG, "Cannot find DataPackage for BaseMap");
+            return null;
+        }
+        AutoGrowByteBuffer output = new AutoGrowByteBuffer();
+        output.order(order);
+        if (dataPackage.pack(output, data)) {
+            return output.getRawByteBuffer();
+        }
+        return null;
+    }
+
     // Delete the constructor as there is nothing to implement here.
     private AudioMetadata() {}
 }
diff --git a/media/java/android/media/AudioTrack.java b/media/java/android/media/AudioTrack.java
index 81275f6..94d4fcc 100644
--- a/media/java/android/media/AudioTrack.java
+++ b/media/java/android/media/AudioTrack.java
@@ -4050,8 +4050,15 @@
         }
 
         if (what == NATIVE_EVENT_CODEC_FORMAT_CHANGE) {
-            track.mCodecFormatChangedListeners.notify(
-                    0 /* eventCode, unused */, (AudioMetadata.ReadMap) obj);
+            ByteBuffer buffer = (ByteBuffer) obj;
+            buffer.order(ByteOrder.nativeOrder());
+            buffer.rewind();
+            AudioMetadata.ReadMap audioMetaData = AudioMetadata.fromByteBuffer(buffer);
+            if (audioMetaData == null) {
+                Log.e(TAG, "Unable to get audio metadata from byte buffer");
+                return;
+            }
+            track.mCodecFormatChangedListeners.notify(0 /* eventCode, unused */, audioMetaData);
             return;
         }
 
diff --git a/media/java/android/media/IMediaRoute2ProviderServiceCallback.aidl b/media/java/android/media/IMediaRoute2ProviderServiceCallback.aidl
index ab42d75..882caad 100644
--- a/media/java/android/media/IMediaRoute2ProviderServiceCallback.aidl
+++ b/media/java/android/media/IMediaRoute2ProviderServiceCallback.aidl
@@ -28,7 +28,6 @@
     // TODO: Change it to updateRoutes?
     void updateState(in MediaRoute2ProviderInfo providerInfo);
     void notifySessionCreated(in RoutingSessionInfo sessionInfo, long requestId);
-    void notifySessionCreationFailed(long requestId);
     void notifySessionUpdated(in RoutingSessionInfo sessionInfo);
     void notifySessionReleased(in RoutingSessionInfo sessionInfo);
     void notifyRequestFailed(long requestId, int reason);
diff --git a/media/java/android/media/MediaRoute2ProviderService.java b/media/java/android/media/MediaRoute2ProviderService.java
index aa0eda1..51696a4 100644
--- a/media/java/android/media/MediaRoute2ProviderService.java
+++ b/media/java/android/media/MediaRoute2ProviderService.java
@@ -233,6 +233,7 @@
         String sessionId = sessionInfo.getId();
         synchronized (mSessionLock) {
             if (mSessionInfo.containsKey(sessionId)) {
+                // TODO: Notify failure to the requester, and throw exception if needed.
                 Log.w(TAG, "Ignoring duplicate session id.");
                 return;
             }
@@ -253,24 +254,6 @@
     }
 
     /**
-     * Notifies clients of that the session could not be created.
-     *
-     * @param requestId id of the previous request to create the session provided in
-     *                  {@link #onCreateSession(long, String, String, Bundle)}.
-     * @see #onCreateSession(long, String, String, Bundle)
-     */
-    public final void notifySessionCreationFailed(long requestId) {
-        if (mRemoteCallback == null) {
-            return;
-        }
-        try {
-            mRemoteCallback.notifySessionCreationFailed(requestId);
-        } catch (RemoteException ex) {
-            Log.w(TAG, "Failed to notify session creation failed.");
-        }
-    }
-
-    /**
      * Notifies the existing session is updated. For example, when
      * {@link RoutingSessionInfo#getSelectedRoutes() selected routes} are changed.
      */
@@ -364,7 +347,7 @@
      * {@link Bundle} which contains how to control the session.
      * <p>
      * If you can't create the session or want to reject the request, call
-     * {@link #notifySessionCreationFailed(long)} with the given {@code requestId}.
+     * {@link #notifyRequestFailed(long, int)} with the given {@code requestId}.
      *
      * @param requestId the id of this request
      * @param packageName the package name of the application that selected the route
diff --git a/media/java/android/media/MediaRouter2Manager.java b/media/java/android/media/MediaRouter2Manager.java
index 734d78e..cf45328 100644
--- a/media/java/android/media/MediaRouter2Manager.java
+++ b/media/java/android/media/MediaRouter2Manager.java
@@ -304,13 +304,9 @@
      * @see Callback#onTransferFailed(RoutingSessionInfo, MediaRoute2Info)
      */
     public void transfer(@NonNull RoutingSessionInfo sessionInfo,
-            @Nullable MediaRoute2Info route) {
+            @NonNull MediaRoute2Info route) {
         Objects.requireNonNull(sessionInfo, "sessionInfo must not be null");
-
-        if (route == null) {
-            releaseSession(sessionInfo);
-            return;
-        }
+        Objects.requireNonNull(route, "route must not be null");
 
         //TODO: Ignore unknown route.
         if (sessionInfo.getTransferableRoutes().contains(route.getId())) {
@@ -334,10 +330,10 @@
                 int requestId = mNextRequestId.getAndIncrement();
                 mMediaRouterService.requestCreateSessionWithManager(
                         client, sessionInfo.getClientPackageName(), route, requestId);
-                releaseSession(sessionInfo);
             } catch (RemoteException ex) {
                 Log.e(TAG, "Unable to select media route", ex);
             }
+            releaseSession(sessionInfo);
         }
     }
 
diff --git a/media/java/android/media/RoutingSessionInfo.java b/media/java/android/media/RoutingSessionInfo.java
index ffb26fe..629cf154 100644
--- a/media/java/android/media/RoutingSessionInfo.java
+++ b/media/java/android/media/RoutingSessionInfo.java
@@ -22,6 +22,7 @@
 import android.os.Parcel;
 import android.os.Parcelable;
 import android.text.TextUtils;
+import android.util.Log;
 
 import java.util.ArrayList;
 import java.util.Collections;
@@ -73,10 +74,14 @@
         mClientPackageName = builder.mClientPackageName;
         mProviderId = builder.mProviderId;
 
-        mSelectedRoutes = Collections.unmodifiableList(builder.mSelectedRoutes);
-        mSelectableRoutes = Collections.unmodifiableList(builder.mSelectableRoutes);
-        mDeselectableRoutes = Collections.unmodifiableList(builder.mDeselectableRoutes);
-        mTransferableRoutes = Collections.unmodifiableList(builder.mTransferableRoutes);
+        mSelectedRoutes = Collections.unmodifiableList(
+                convertToUniqueRouteIds(builder.mSelectedRoutes));
+        mSelectableRoutes = Collections.unmodifiableList(
+                convertToUniqueRouteIds(builder.mSelectableRoutes));
+        mDeselectableRoutes = Collections.unmodifiableList(
+                convertToUniqueRouteIds(builder.mDeselectableRoutes));
+        mTransferableRoutes = Collections.unmodifiableList(
+                convertToUniqueRouteIds(builder.mTransferableRoutes));
 
         mVolumeHandling = builder.mVolumeHandling;
         mVolumeMax = builder.mVolumeMax;
@@ -326,6 +331,24 @@
         return result.toString();
     }
 
+    private List<String> convertToUniqueRouteIds(@NonNull List<String> routeIds) {
+        if (routeIds == null) {
+            Log.w(TAG, "routeIds is null. Returning an empty list");
+            return Collections.emptyList();
+        }
+
+        // mProviderId can be null if not set. Return the original list for this case.
+        if (mProviderId == null) {
+            return routeIds;
+        }
+
+        List<String> result = new ArrayList<>();
+        for (String routeId : routeIds) {
+            result.add(MediaRouter2Utils.toUniqueId(mProviderId, routeId));
+        }
+        return result;
+    }
+
     /**
      * Builder class for {@link RoutingSessionInfo}.
      */
@@ -345,7 +368,6 @@
         Bundle mControlHints;
         boolean mIsSystemSession;
 
-        //TODO: Remove this.
         /**
          * Constructor for builder to create {@link RoutingSessionInfo}.
          * <p>
@@ -392,6 +414,14 @@
             mDeselectableRoutes = new ArrayList<>(sessionInfo.mDeselectableRoutes);
             mTransferableRoutes = new ArrayList<>(sessionInfo.mTransferableRoutes);
 
+            if (mProviderId != null) {
+                // They must have unique IDs.
+                mSelectedRoutes.replaceAll(MediaRouter2Utils::getOriginalId);
+                mSelectableRoutes.replaceAll(MediaRouter2Utils::getOriginalId);
+                mDeselectableRoutes.replaceAll(MediaRouter2Utils::getOriginalId);
+                mTransferableRoutes.replaceAll(MediaRouter2Utils::getOriginalId);
+            }
+
             mVolumeHandling = sessionInfo.mVolumeHandling;
             mVolumeMax = sessionInfo.mVolumeMax;
             mVolume = sessionInfo.mVolume;
@@ -431,12 +461,6 @@
                 throw new IllegalArgumentException("providerId must not be empty");
             }
             mProviderId = providerId;
-
-            mSelectedRoutes.replaceAll(routeId -> getUniqueId(mProviderId, routeId));
-            mSelectableRoutes.replaceAll(routeId -> getUniqueId(mProviderId, routeId));
-            mDeselectableRoutes.replaceAll(routeId -> getUniqueId(mProviderId, routeId));
-            mTransferableRoutes.replaceAll(routeId -> getUniqueId(mProviderId, routeId));
-
             return this;
         }
 
@@ -457,7 +481,7 @@
             if (TextUtils.isEmpty(routeId)) {
                 throw new IllegalArgumentException("routeId must not be empty");
             }
-            mSelectedRoutes.add(getUniqueId(mProviderId, routeId));
+            mSelectedRoutes.add(routeId);
             return this;
         }
 
@@ -469,7 +493,7 @@
             if (TextUtils.isEmpty(routeId)) {
                 throw new IllegalArgumentException("routeId must not be empty");
             }
-            mSelectedRoutes.remove(getUniqueId(mProviderId, routeId));
+            mSelectedRoutes.remove(routeId);
             return this;
         }
 
@@ -490,7 +514,7 @@
             if (TextUtils.isEmpty(routeId)) {
                 throw new IllegalArgumentException("routeId must not be empty");
             }
-            mSelectableRoutes.add(getUniqueId(mProviderId, routeId));
+            mSelectableRoutes.add(routeId);
             return this;
         }
 
@@ -502,7 +526,7 @@
             if (TextUtils.isEmpty(routeId)) {
                 throw new IllegalArgumentException("routeId must not be empty");
             }
-            mSelectableRoutes.remove(getUniqueId(mProviderId, routeId));
+            mSelectableRoutes.remove(routeId);
             return this;
         }
 
@@ -523,7 +547,7 @@
             if (TextUtils.isEmpty(routeId)) {
                 throw new IllegalArgumentException("routeId must not be empty");
             }
-            mDeselectableRoutes.add(getUniqueId(mProviderId, routeId));
+            mDeselectableRoutes.add(routeId);
             return this;
         }
 
@@ -535,7 +559,7 @@
             if (TextUtils.isEmpty(routeId)) {
                 throw new IllegalArgumentException("routeId must not be empty");
             }
-            mDeselectableRoutes.remove(getUniqueId(mProviderId, routeId));
+            mDeselectableRoutes.remove(routeId);
             return this;
         }
 
@@ -556,7 +580,7 @@
             if (TextUtils.isEmpty(routeId)) {
                 throw new IllegalArgumentException("routeId must not be empty");
             }
-            mTransferableRoutes.add(getUniqueId(mProviderId, routeId));
+            mTransferableRoutes.add(routeId);
             return this;
         }
 
@@ -568,7 +592,7 @@
             if (TextUtils.isEmpty(routeId)) {
                 throw new IllegalArgumentException("routeId must not be empty");
             }
-            mTransferableRoutes.remove(getUniqueId(mProviderId, routeId));
+            mTransferableRoutes.remove(routeId);
             return this;
         }
 
@@ -634,15 +658,4 @@
             return new RoutingSessionInfo(this);
         }
     }
-
-    private static String getUniqueId(String providerId, String routeId) {
-        if (TextUtils.isEmpty(providerId)) {
-            return routeId;
-        }
-        String originalId = MediaRouter2Utils.getOriginalId(routeId);
-        if (originalId == null) {
-            originalId = routeId;
-        }
-        return MediaRouter2Utils.toUniqueId(providerId, originalId);
-    }
 }
diff --git a/media/java/android/media/tv/tuner/filter/AlpFilterConfiguration.java b/media/java/android/media/tv/tuner/filter/AlpFilterConfiguration.java
index 064ab80..7b29494 100644
--- a/media/java/android/media/tv/tuner/filter/AlpFilterConfiguration.java
+++ b/media/java/android/media/tv/tuner/filter/AlpFilterConfiguration.java
@@ -34,6 +34,27 @@
  */
 @SystemApi
 public class AlpFilterConfiguration extends FilterConfiguration {
+    /**
+     * IPv4 packet type.
+     */
+    public static final int PACKET_TYPE_IPV4 = 0;
+    /**
+     * Compressed packet type.
+     */
+    public static final int PACKET_TYPE_COMPRESSED = 2;
+    /**
+     * Signaling packet type.
+     */
+    public static final int PACKET_TYPE_SIGNALING = 4;
+    /**
+     * Extension packet type.
+     */
+    public static final int PACKET_TYPE_EXTENSION = 6;
+    /**
+     * MPEG-2 TS packet type.
+     */
+    public static final int PACKET_TYPE_MPEG2_TS = 7;
+
     /** @hide */
     @Retention(RetentionPolicy.SOURCE)
     @IntDef(prefix = "LENGTH_TYPE_", value =
@@ -73,8 +94,9 @@
 
     /**
      * Gets packet type.
+     *
+     * <p>The meaning of each packet type value is shown in ATSC A/330:2019 table 5.2.
      */
-    @FilterConfiguration.PacketType
     public int getPacketType() {
         return mPacketType;
     }
@@ -110,9 +132,11 @@
 
         /**
          * Sets packet type.
+         *
+         * <p>The meaning of each packet type value is shown in ATSC A/330:2019 table 5.2.
          */
         @NonNull
-        public Builder setPacketType(@FilterConfiguration.PacketType int packetType) {
+        public Builder setPacketType(int packetType) {
             mPacketType = packetType;
             return this;
         }
diff --git a/media/java/android/media/tv/tuner/filter/Filter.java b/media/java/android/media/tv/tuner/filter/Filter.java
index cfb943b..52bdb59 100644
--- a/media/java/android/media/tv/tuner/filter/Filter.java
+++ b/media/java/android/media/tv/tuner/filter/Filter.java
@@ -45,6 +45,10 @@
     public @interface Type {}
 
     /**
+     * Undefined filter type.
+     */
+    public static final int TYPE_UNDEFINED = 0;
+    /**
      * TS filter type.
      */
     public static final int TYPE_TS = Constants.DemuxFilterMainType.TS;
@@ -248,7 +252,6 @@
     /**
      * Gets the filter Id.
      */
-    @Result
     public int getId() {
         return nativeGetId();
     }
@@ -273,6 +276,8 @@
     /**
      * Starts filtering data.
      *
+     * <p>Does nothing if the filter is already started.
+     *
      * @return result status of the operation.
      */
     @Result
@@ -284,6 +289,8 @@
     /**
      * Stops filtering data.
      *
+     * <p>Does nothing if the filter is stopped or not started.
+     *
      * @return result status of the operation.
      */
     @Result
@@ -312,14 +319,13 @@
      * @param size the maximum number of bytes to read.
      * @return the number of bytes read.
      */
-    @Result
     public int read(@NonNull byte[] buffer, @BytesLong long offset, @BytesLong long size) {
         size = Math.min(size, buffer.length - offset);
         return nativeRead(buffer, offset, size);
     }
 
     /**
-     * Releases the Filter instance.
+     * Stops filtering data and releases the Filter instance.
      */
     @Override
     public void close() {
diff --git a/media/java/android/media/tv/tuner/filter/FilterConfiguration.java b/media/java/android/media/tv/tuner/filter/FilterConfiguration.java
index c1d2275..a8c9356 100644
--- a/media/java/android/media/tv/tuner/filter/FilterConfiguration.java
+++ b/media/java/android/media/tv/tuner/filter/FilterConfiguration.java
@@ -16,14 +16,10 @@
 
 package android.media.tv.tuner.filter;
 
-import android.annotation.IntDef;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.annotation.SystemApi;
 
-import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
-
 /**
  * Filter configuration used to configure filters.
  *
@@ -32,26 +28,6 @@
 @SystemApi
 public abstract class FilterConfiguration {
 
-    /** @hide */
-    @IntDef(prefix = "PACKET_TYPE_", value =
-            {PACKET_TYPE_IPV4, PACKET_TYPE_COMPRESSED, PACKET_TYPE_SIGNALING})
-    @Retention(RetentionPolicy.SOURCE)
-    public @interface PacketType {}
-
-    /**
-     * IP v4 packet type.
-     */
-    public static final int PACKET_TYPE_IPV4 = 0;
-    /**
-     * Compressed packet type.
-     */
-    public static final int PACKET_TYPE_COMPRESSED = 2;
-    /**
-     * Signaling packet type.
-     */
-    public static final int PACKET_TYPE_SIGNALING = 4;
-
-
     @Nullable
     /* package */ final Settings mSettings;
 
diff --git a/media/java/android/media/tv/tuner/filter/TlvFilterConfiguration.java b/media/java/android/media/tv/tuner/filter/TlvFilterConfiguration.java
index 3d83a74..ac4fc83 100644
--- a/media/java/android/media/tv/tuner/filter/TlvFilterConfiguration.java
+++ b/media/java/android/media/tv/tuner/filter/TlvFilterConfiguration.java
@@ -29,6 +29,27 @@
  */
 @SystemApi
 public class TlvFilterConfiguration extends FilterConfiguration {
+    /**
+     * IPv4 packet type.
+     */
+    public static final int PACKET_TYPE_IPV4 = 0x01;
+    /**
+     * IPv6 packet type.
+     */
+    public static final int PACKET_TYPE_IPV6 = 0x02;
+    /**
+     * Compressed packet type.
+     */
+    public static final int PACKET_TYPE_COMPRESSED = 0x03;
+    /**
+     * Signaling packet type.
+     */
+    public static final int PACKET_TYPE_SIGNALING = 0xFE;
+    /**
+     * NULL packet type.
+     */
+    public static final int PACKET_TYPE_NULL = 0xFF;
+
     private final int mPacketType;
     private final boolean mIsCompressedIpPacket;
     private final boolean mPassthrough;
@@ -48,8 +69,9 @@
 
     /**
      * Gets packet type.
+     *
+     * <p>The description of each packet type value is shown in ITU-R BT.1869 table 2.
      */
-    @FilterConfiguration.PacketType
     public int getPacketType() {
         return mPacketType;
     }
@@ -96,9 +118,11 @@
 
         /**
          * Sets packet type.
+         *
+         * <p>The description of each packet type value is shown in ITU-R BT.1869 table 2.
          */
         @NonNull
-        public Builder setPacketType(@FilterConfiguration.PacketType int packetType) {
+        public Builder setPacketType(int packetType) {
             mPacketType = packetType;
             return this;
         }
diff --git a/media/tests/MediaRouter/src/com/android/mediaroutertest/RoutingSessionInfoTest.java b/media/tests/MediaRouter/src/com/android/mediaroutertest/RoutingSessionInfoTest.java
index 2230e25..31f240d 100644
--- a/media/tests/MediaRouter/src/com/android/mediaroutertest/RoutingSessionInfoTest.java
+++ b/media/tests/MediaRouter/src/com/android/mediaroutertest/RoutingSessionInfoTest.java
@@ -70,7 +70,7 @@
 
         RoutingSessionInfo sessionInfoWithOtherProviderId =
                 new RoutingSessionInfo.Builder(sessionInfoWithProviderId)
-                .setProviderId(TEST_OTHER_PROVIDER_ID).build();
+                        .setProviderId(TEST_OTHER_PROVIDER_ID).build();
 
         assertNotEquals(sessionInfoWithOtherProviderId.getSelectedRoutes(),
                 sessionInfoWithProviderId.getSelectedRoutes());
diff --git a/media/tests/MediaRouter/src/com/android/mediaroutertest/SampleMediaRoute2ProviderService.java b/media/tests/MediaRouter/src/com/android/mediaroutertest/SampleMediaRoute2ProviderService.java
index 0e7c7fc..22c5bce 100644
--- a/media/tests/MediaRouter/src/com/android/mediaroutertest/SampleMediaRoute2ProviderService.java
+++ b/media/tests/MediaRouter/src/com/android/mediaroutertest/SampleMediaRoute2ProviderService.java
@@ -216,8 +216,7 @@
             @Nullable Bundle sessionHints) {
         MediaRoute2Info route = mRoutes.get(routeId);
         if (route == null || TextUtils.equals(ROUTE_ID3_SESSION_CREATION_FAILED, routeId)) {
-            // Tell the router that session cannot be created by passing null as sessionInfo.
-            notifySessionCreationFailed(requestId);
+            notifyRequestFailed(requestId, REASON_UNKNOWN_ERROR);
             return;
         }
         maybeDeselectRoute(routeId);
diff --git a/packages/SettingsLib/SchedulesProvider/src/com/android/settingslib/schedulesprovider/ScheduleInfo.java b/packages/SettingsLib/SchedulesProvider/src/com/android/settingslib/schedulesprovider/ScheduleInfo.java
index 26bcd54..bd9dc4ff 100644
--- a/packages/SettingsLib/SchedulesProvider/src/com/android/settingslib/schedulesprovider/ScheduleInfo.java
+++ b/packages/SettingsLib/SchedulesProvider/src/com/android/settingslib/schedulesprovider/ScheduleInfo.java
@@ -16,6 +16,8 @@
 
 package com.android.settingslib.schedulesprovider;
 
+import android.app.PendingIntent;
+import android.content.Context;
 import android.content.Intent;
 import android.os.Parcel;
 import android.os.Parcelable;
@@ -25,25 +27,25 @@
 
 /**
  * Schedule data item containing the schedule title text, the summary text which is displayed on the
- * summary of the Settings preference and an {@link Intent} which Settings will launch when the
- * user clicks on the preference.
+ * summary of the Settings preference and a {@link PendingIntent} which Settings will launch
+ * when the user clicks on the preference.
  */
 public class ScheduleInfo implements Parcelable {
     private static final String TAG = "ScheduleInfo";
     private final String mTitle;
     private final String mSummary;
-    private final Intent mIntent;
+    private final PendingIntent mPendingIntent;
 
     public ScheduleInfo(Builder builder) {
         mTitle = builder.mTitle;
         mSummary = builder.mSummary;
-        mIntent = builder.mIntent;
+        mPendingIntent = builder.mPendingIntent;
     }
 
     private ScheduleInfo(Parcel in) {
         mTitle = in.readString();
         mSummary = in.readString();
-        mIntent = in.readParcelable(Intent.class.getClassLoader());
+        mPendingIntent = in.readParcelable(PendingIntent.class.getClassLoader());
     }
 
     /**
@@ -61,11 +63,11 @@
     }
 
     /**
-     * Returns an {@link Intent} which Settings will launch when the user clicks on a schedule
-     * preference.
+     * Returns a {@link PendingIntent} which Settings will launch when the user clicks on a
+     * schedule preference.
      */
-    public Intent getIntent() {
-        return mIntent;
+    public PendingIntent getPendingIntent() {
+        return mPendingIntent;
     }
 
     /**
@@ -74,14 +76,15 @@
      * @return {@code true} if all member variables are valid.
      */
     public boolean isValid() {
-        return !TextUtils.isEmpty(mTitle) && !TextUtils.isEmpty(mSummary) && (mIntent != null);
+        return !TextUtils.isEmpty(mTitle) && !TextUtils.isEmpty(mSummary)
+                && (mPendingIntent != null);
     }
 
     @Override
     public void writeToParcel(Parcel dest, int flags) {
         dest.writeString(mTitle);
         dest.writeString(mSummary);
-        dest.writeParcelable(mIntent, flags);
+        dest.writeParcelable(mPendingIntent, flags);
     }
 
     @Override
@@ -104,7 +107,7 @@
     @NonNull
     @Override
     public String toString() {
-        return "title: " + mTitle + ", summary: " + mSummary + ", intent: " + mIntent;
+        return "title: " + mTitle + ", summary: " + mSummary + ", pendingIntent: " + mPendingIntent;
     }
 
     /**
@@ -113,7 +116,7 @@
     public static class Builder {
         private String mTitle;
         private String mSummary;
-        private Intent mIntent;
+        private PendingIntent mPendingIntent;
 
         /**
          * Sets the title.
@@ -138,13 +141,15 @@
         }
 
         /**
-         * Sets the {@link Intent}.
+         * Sets the {@link PendingIntent}.
+         * <p>The {@link PendingIntent} should be created with
+         * {@link PendingIntent#getActivity(Context, int, Intent, int)}.
          *
-         * @param intent The action when user clicks the preference.
+         * @param pendingIntent The pending intent to send when the user clicks the preference.
          * @return This instance.
          */
-        public Builder setIntent(@NonNull Intent intent) {
-            mIntent = intent;
+        public Builder setPendingIntent(@NonNull PendingIntent pendingIntent) {
+            mPendingIntent = pendingIntent;
             return this;
         }
 
diff --git a/packages/SettingsLib/src/com/android/settingslib/media/InfoMediaManager.java b/packages/SettingsLib/src/com/android/settingslib/media/InfoMediaManager.java
index 3ae9e1e..7e78a78 100644
--- a/packages/SettingsLib/src/com/android/settingslib/media/InfoMediaManager.java
+++ b/packages/SettingsLib/src/com/android/settingslib/media/InfoMediaManager.java
@@ -311,6 +311,21 @@
         return -1;
     }
 
+    CharSequence getSessionName() {
+        if (TextUtils.isEmpty(mPackageName)) {
+            Log.w(TAG, "Unable to get session name. The package name is null or empty!");
+            return null;
+        }
+
+        final RoutingSessionInfo info = getRoutingSessionInfo();
+        if (info != null) {
+            return info.getName();
+        }
+
+        Log.w(TAG, "Unable to get session name for package: " + mPackageName);
+        return null;
+    }
+
     private void refreshDevices() {
         mMediaDevices.clear();
         mCurrentConnectedDevice = null;
diff --git a/packages/SettingsLib/src/com/android/settingslib/media/LocalMediaManager.java b/packages/SettingsLib/src/com/android/settingslib/media/LocalMediaManager.java
index c70811f..adb3c11 100644
--- a/packages/SettingsLib/src/com/android/settingslib/media/LocalMediaManager.java
+++ b/packages/SettingsLib/src/com/android/settingslib/media/LocalMediaManager.java
@@ -324,6 +324,15 @@
         return mInfoMediaManager.getSessionVolume();
     }
 
+    /**
+     * Gets the user-visible name of the {@link android.media.RoutingSessionInfo}.
+     *
+     * @return current name of the session, and return {@code null} if not found.
+     */
+    public CharSequence getSessionName() {
+        return mInfoMediaManager.getSessionName();
+    }
+
     private MediaDevice updateCurrentConnectedDevice() {
         MediaDevice phoneMediaDevice = null;
         for (MediaDevice device : mMediaDevices) {
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 edb121b..7cd0a7c 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
@@ -460,4 +460,37 @@
 
         assertThat(mInfoMediaManager.releaseSession()).isTrue();
     }
+
+    @Test
+    public void getSessionName_packageNameIsNull_returnNull() {
+        mInfoMediaManager.mPackageName = null;
+
+        assertThat(mInfoMediaManager.getSessionName()).isNull();
+    }
+
+    @Test
+    public void getSessionName_notContainPackageName_returnNull() {
+        final List<RoutingSessionInfo> routingSessionInfos = new ArrayList<>();
+        final RoutingSessionInfo info = mock(RoutingSessionInfo.class);
+        routingSessionInfos.add(info);
+
+        mShadowRouter2Manager.setRoutingSessions(routingSessionInfos);
+        when(info.getClientPackageName()).thenReturn("com.fake.packagename");
+        when(info.getName()).thenReturn(TEST_NAME);
+
+        assertThat(mInfoMediaManager.getSessionName()).isNull();
+    }
+
+    @Test
+    public void getSessionName_containPackageName_returnName() {
+        final List<RoutingSessionInfo> routingSessionInfos = new ArrayList<>();
+        final RoutingSessionInfo info = mock(RoutingSessionInfo.class);
+        routingSessionInfos.add(info);
+
+        mShadowRouter2Manager.setRoutingSessions(routingSessionInfos);
+        when(info.getClientPackageName()).thenReturn(TEST_PACKAGE_NAME);
+        when(info.getName()).thenReturn(TEST_NAME);
+
+        assertThat(mInfoMediaManager.getSessionName()).isEqualTo(TEST_NAME);
+    }
 }
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/schedulesprovider/ScheduleInfoTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/schedulesprovider/ScheduleInfoTest.java
index 5ec89ed..b4b910d 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/schedulesprovider/ScheduleInfoTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/schedulesprovider/ScheduleInfoTest.java
@@ -17,11 +17,14 @@
 
 import static com.google.common.truth.Truth.assertThat;
 
+import android.app.PendingIntent;
+import android.content.Context;
 import android.content.Intent;
 
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.robolectric.RobolectricTestRunner;
+import org.robolectric.RuntimeEnvironment;
 
 @RunWith(RobolectricTestRunner.class)
 public class ScheduleInfoTest {
@@ -29,10 +32,12 @@
     private static final String TEST_SUMMARY = "Night Light summary";
     private static final String TEST_EMPTY_SUMMARY = "";
 
+    private final Context mContext = RuntimeEnvironment.application;
+
     @Test
     public void builder_usedValidArguments_isValid() {
-        final Intent intent = createTestIntent();
-        final ScheduleInfo info = createTestScheduleInfo(TEST_TITLE, TEST_SUMMARY, intent);
+        final PendingIntent pendingIntent = createTestPendingIntent(mContext);
+        final ScheduleInfo info = createTestScheduleInfo(TEST_TITLE, TEST_SUMMARY, pendingIntent);
 
         assertThat(info).isNotNull();
         assertThat(info.isValid()).isTrue();
@@ -40,15 +45,16 @@
 
     @Test
     public void builder_useEmptySummary_isInvalid() {
-        final Intent intent = createTestIntent();
-        final ScheduleInfo info = createTestScheduleInfo(TEST_TITLE, TEST_EMPTY_SUMMARY, intent);
+        final PendingIntent pendingIntent = createTestPendingIntent(mContext);
+        final ScheduleInfo info = createTestScheduleInfo(TEST_TITLE, TEST_EMPTY_SUMMARY,
+                pendingIntent);
 
         assertThat(info).isNotNull();
         assertThat(info.isValid()).isFalse();
     }
 
     @Test
-    public void builder_intentIsNull_isInvalid() {
+    public void builder_pendingIntentIsNull_isInvalid() {
         final ScheduleInfo info = new ScheduleInfo.Builder()
                 .setTitle(TEST_TITLE)
                 .setSummary(TEST_SUMMARY)
@@ -60,39 +66,40 @@
 
     @Test
     public void getTitle_setValidTitle_shouldReturnSameCorrectTitle() {
-        final Intent intent = createTestIntent();
-        final ScheduleInfo info = createTestScheduleInfo(TEST_TITLE, TEST_SUMMARY, intent);
+        final PendingIntent pendingIntent = createTestPendingIntent(mContext);
+        final ScheduleInfo info = createTestScheduleInfo(TEST_TITLE, TEST_SUMMARY, pendingIntent);
 
         assertThat(info.getTitle()).isEqualTo(TEST_TITLE);
     }
 
     @Test
     public void getSummary_setValidSummary_shouldReturnSameCorrectSummary() {
-        final Intent intent = createTestIntent();
-        final ScheduleInfo info = createTestScheduleInfo(TEST_TITLE, TEST_SUMMARY, intent);
+        final PendingIntent pendingIntent = createTestPendingIntent(mContext);
+        final ScheduleInfo info = createTestScheduleInfo(TEST_TITLE, TEST_SUMMARY, pendingIntent);
 
         assertThat(info.getSummary()).isEqualTo(TEST_SUMMARY);
     }
 
     @Test
-    public void getIntent_setValidIntent_shouldReturnSameCorrectIntent() {
-        final Intent intent = createTestIntent();
-        final ScheduleInfo info = createTestScheduleInfo(TEST_TITLE, TEST_SUMMARY, intent);
+    public void getPendingIntent_setValidPendingIntent_shouldReturnSameCorrectIntent() {
+        final PendingIntent pendingIntent = createTestPendingIntent(mContext);
+        final ScheduleInfo info = createTestScheduleInfo(TEST_TITLE, TEST_SUMMARY, pendingIntent);
 
-        assertThat(info.getIntent()).isEqualTo(intent);
+        assertThat(info.getPendingIntent()).isEqualTo(pendingIntent);
     }
 
-    private static Intent createTestIntent() {
-        return new Intent("android.settings.NIGHT_DISPLAY_SETTINGS").addCategory(
+    private static PendingIntent createTestPendingIntent(Context context) {
+        final Intent intent = new Intent("android.settings.NIGHT_DISPLAY_SETTINGS").addCategory(
                 Intent.CATEGORY_DEFAULT);
+        return PendingIntent.getActivity(context, 0 /* requestCode */, intent, 0 /* flags */);
     }
 
     private static ScheduleInfo createTestScheduleInfo(String title, String summary,
-            Intent intent) {
+            PendingIntent pendingIntent) {
         return new ScheduleInfo.Builder()
                 .setTitle(title)
                 .setSummary(summary)
-                .setIntent(intent)
+                .setPendingIntent(pendingIntent)
                 .build();
     }
 }
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/schedulesprovider/SchedulesProviderTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/schedulesprovider/SchedulesProviderTest.java
index eb2e8e0..6b92082 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/schedulesprovider/SchedulesProviderTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/schedulesprovider/SchedulesProviderTest.java
@@ -19,6 +19,8 @@
 
 import static org.robolectric.Shadows.shadowOf;
 
+import android.app.PendingIntent;
+import android.content.Context;
 import android.content.Intent;
 import android.os.Bundle;
 
@@ -27,6 +29,7 @@
 import org.junit.runner.RunWith;
 import org.robolectric.Robolectric;
 import org.robolectric.RobolectricTestRunner;
+import org.robolectric.RuntimeEnvironment;
 
 import java.util.ArrayList;
 
@@ -35,13 +38,16 @@
     private static final String INVALID_PACKAGE = "com.android.sunny";
     private static final String VALID_PACKAGE = "com.android.settings";
     private static final String INVALID_METHOD = "queryTestData";
+
+    private final Context mContext = RuntimeEnvironment.application;
+
     private TestSchedulesProvider mProvider;
 
     @Before
     public void setUp() {
         mProvider = Robolectric.setupContentProvider(TestSchedulesProvider.class);
         shadowOf(mProvider).setCallingPackage(VALID_PACKAGE);
-        mProvider.setScheduleInfos(TestSchedulesProvider.createOneValidScheduleInfo());
+        mProvider.setScheduleInfos(TestSchedulesProvider.createOneValidScheduleInfo(mContext));
     }
 
     @Test
@@ -76,7 +82,7 @@
 
     @Test
     public void call_addTwoValidData_returnScheduleInfoData() {
-        mProvider.setScheduleInfos(TestSchedulesProvider.createTwoValidScheduleInfos());
+        mProvider.setScheduleInfos(TestSchedulesProvider.createTwoValidScheduleInfos(mContext));
         final Bundle bundle = mProvider.call(SchedulesProvider.METHOD_GENERATE_SCHEDULE_INFO_LIST,
                 null /* arg */, null /* extras */);
 
@@ -89,7 +95,8 @@
 
     @Test
     public void call_addTwoValidDataAndOneInvalidData_returnTwoScheduleInfoData() {
-        mProvider.setScheduleInfos(TestSchedulesProvider.createTwoValidAndOneInvalidScheduleInfo());
+        mProvider.setScheduleInfos(
+                TestSchedulesProvider.createTwoValidAndOneInvalidScheduleInfo(mContext));
         final Bundle bundle = mProvider.call(SchedulesProvider.METHOD_GENERATE_SCHEDULE_INFO_LIST,
                 null /* arg */, null /* extras */);
 
@@ -112,55 +119,56 @@
             mScheduleInfos = scheduleInfos;
         }
 
-        private static ArrayList<ScheduleInfo> createOneValidScheduleInfo() {
+        private static ArrayList<ScheduleInfo> createOneValidScheduleInfo(Context context) {
             final ArrayList<ScheduleInfo> scheduleInfos = new ArrayList<>();
-            final Intent intent = new Intent("android.settings.NIGHT_DISPLAY_SETTINGS").addCategory(
-                    Intent.CATEGORY_DEFAULT);
-            final ScheduleInfo info = new ScheduleInfo.Builder().setTitle(
-                    "Night Light").setSummary("This a sunny test").setIntent(intent).build();
+
+            final ScheduleInfo info = new ScheduleInfo.Builder().setTitle("Night Light").setSummary(
+                    "This a sunny test").setPendingIntent(createTestPendingIntent(context,
+                    "android.settings.NIGHT_DISPLAY_SETTINGS")).build();
             scheduleInfos.add(info);
 
             return scheduleInfos;
         }
 
-        private static ArrayList<ScheduleInfo> createTwoValidScheduleInfos() {
+        private static ArrayList<ScheduleInfo> createTwoValidScheduleInfos(Context context) {
             final ArrayList<ScheduleInfo> scheduleInfos = new ArrayList<>();
-            Intent intent = new Intent("android.settings.NIGHT_DISPLAY_SETTINGS").addCategory(
-                    Intent.CATEGORY_DEFAULT);
-            ScheduleInfo info = new ScheduleInfo.Builder().setTitle(
-                    "Night Light").setSummary("This a sunny test").setIntent(intent).build();
+            ScheduleInfo info = new ScheduleInfo.Builder().setTitle("Night Light").setSummary(
+                    "This a sunny test").setPendingIntent(createTestPendingIntent(context,
+                    "android.settings.NIGHT_DISPLAY_SETTINGS")).build();
             scheduleInfos.add(info);
 
-            intent = new Intent("android.settings.DISPLAY_SETTINGS").addCategory(
-                    Intent.CATEGORY_DEFAULT);
             info = new ScheduleInfo.Builder().setTitle("Display").setSummary(
-                    "Display summary").setIntent(intent).build();
+                    "Display summary").setPendingIntent(
+                    createTestPendingIntent(context, "android.settings.DISPLAY_SETTINGS")).build();
             scheduleInfos.add(info);
 
             return scheduleInfos;
         }
 
-        private static ArrayList<ScheduleInfo> createTwoValidAndOneInvalidScheduleInfo() {
+        private static ArrayList<ScheduleInfo> createTwoValidAndOneInvalidScheduleInfo(
+                Context context) {
             final ArrayList<ScheduleInfo> scheduleInfos = new ArrayList<>();
-            Intent intent = new Intent("android.settings.NIGHT_DISPLAY_SETTINGS").addCategory(
-                    Intent.CATEGORY_DEFAULT);
-            ScheduleInfo info = new ScheduleInfo.Builder().setTitle(
-                    "Night Light").setSummary("This a sunny test").setIntent(intent).build();
+            ScheduleInfo info = new ScheduleInfo.Builder().setTitle("Night Light").setSummary(
+                    "This a sunny test").setPendingIntent(createTestPendingIntent(context,
+                    "android.settings.NIGHT_DISPLAY_SETTINGS")).build();
             scheduleInfos.add(info);
 
-            intent = new Intent("android.settings.DISPLAY_SETTINGS").addCategory(
-                    Intent.CATEGORY_DEFAULT);
             info = new ScheduleInfo.Builder().setTitle("Display").setSummary(
-                    "Display summary").setIntent(intent).build();
+                    "Display summary").setPendingIntent(
+                    createTestPendingIntent(context, "android.settings.DISPLAY_SETTINGS")).build();
             scheduleInfos.add(info);
 
-            intent = new Intent("android.settings.DISPLAY_SETTINGS").addCategory(
-                    Intent.CATEGORY_DEFAULT);
-            info = new ScheduleInfo.Builder().setTitle("").setSummary("Display summary").setIntent(
-                    intent).build();
+            info = new ScheduleInfo.Builder().setTitle("").setSummary(
+                    "Display summary").setPendingIntent(
+                    createTestPendingIntent(context, "android.settings.DISPLAY_SETTINGS")).build();
             scheduleInfos.add(info);
 
             return scheduleInfos;
         }
+
+        private static PendingIntent createTestPendingIntent(Context context, String action) {
+            final Intent intent = new Intent(action).addCategory(Intent.CATEGORY_DEFAULT);
+            return PendingIntent.getActivity(context, 0 /* requestCode */, intent, 0 /* flags */);
+        }
     }
 }
diff --git a/packages/SettingsProvider/src/android/provider/settings/backup/SecureSettings.java b/packages/SettingsProvider/src/android/provider/settings/backup/SecureSettings.java
index 2431381..8fa98c8 100644
--- a/packages/SettingsProvider/src/android/provider/settings/backup/SecureSettings.java
+++ b/packages/SettingsProvider/src/android/provider/settings/backup/SecureSettings.java
@@ -162,5 +162,6 @@
         Settings.Secure.AWARE_TAP_PAUSE_TOUCH_COUNT,
         Settings.Secure.PEOPLE_STRIP,
         Settings.Secure.ACCESSIBILITY_MAGNIFICATION_MODE,
+        Settings.Secure.ACCESSIBILITY_BUTTON_LONG_PRESS_TARGETS,
     };
 }
diff --git a/packages/SettingsProvider/src/android/provider/settings/validators/SecureSettingsValidators.java b/packages/SettingsProvider/src/android/provider/settings/validators/SecureSettingsValidators.java
index 5553469..75c5f95 100644
--- a/packages/SettingsProvider/src/android/provider/settings/validators/SecureSettingsValidators.java
+++ b/packages/SettingsProvider/src/android/provider/settings/validators/SecureSettingsValidators.java
@@ -245,5 +245,8 @@
                 new InclusiveIntegerRangeValidator(
                         Secure.ACCESSIBILITY_MAGNIFICATION_MODE_FULLSCREEN,
                         Secure.ACCESSIBILITY_MAGNIFICATION_MODE_WINDOW));
+        VALIDATORS.put(
+                Secure.ACCESSIBILITY_BUTTON_LONG_PRESS_TARGETS,
+                ACCESSIBILITY_SHORTCUT_TARGET_LIST_VALIDATOR);
     }
 }
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java
index d677687..8789a5c 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java
@@ -1811,6 +1811,9 @@
         dumpSetting(s, p,
                 Settings.Secure.ACCESSIBILITY_MAGNIFICATION_MODE,
                 SecureSettingsProto.Accessibility.ACCESSIBILITY_MAGNIFICATION_MODE);
+        dumpSetting(s, p,
+                Settings.Secure.ACCESSIBILITY_BUTTON_LONG_PRESS_TARGETS,
+                SecureSettingsProto.Accessibility.BUTTON_LONG_PRESS_TARGETS);
         p.end(accessibilityToken);
 
         final long adaptiveSleepToken = p.start(SecureSettingsProto.ADAPTIVE_SLEEP);
diff --git a/packages/SystemUI/res/layout/notification_conversation_info.xml b/packages/SystemUI/res/layout/notification_conversation_info.xml
index 8460612..6a7f9e2 100644
--- a/packages/SystemUI/res/layout/notification_conversation_info.xml
+++ b/packages/SystemUI/res/layout/notification_conversation_info.xml
@@ -121,7 +121,6 @@
                 android:layout_marginEnd="2dp"
                 android:ellipsize="end"
                 android:text="@string/notification_delegate_header"
-                android:layout_toEndOf="@id/pkg_divider"
                 android:maxLines="1" />
 
         </LinearLayout>
diff --git a/packages/SystemUI/res/layout/notification_info.xml b/packages/SystemUI/res/layout/notification_info.xml
index 5d03eee..6ab573b 100644
--- a/packages/SystemUI/res/layout/notification_info.xml
+++ b/packages/SystemUI/res/layout/notification_info.xml
@@ -27,51 +27,81 @@
     android:paddingStart="@*android:dimen/notification_content_margin_start">
 
     <!-- Package Info -->
-    <RelativeLayout
+    <LinearLayout
         android:id="@+id/header"
         android:layout_width="match_parent"
-        android:layout_height="wrap_content"
+        android:layout_height="@dimen/notification_guts_conversation_header_height"
+        android:gravity="center_vertical"
         android:clipChildren="false"
         android:clipToPadding="false">
         <ImageView
-            android:id="@+id/pkgicon"
-            android:layout_width="@dimen/notification_guts_header_height"
-            android:layout_height="@dimen/notification_guts_header_height"
+            android:id="@+id/pkg_icon"
+            android:layout_width="@dimen/notification_guts_conversation_icon_size"
+            android:layout_height="@dimen/notification_guts_conversation_icon_size"
             android:layout_centerVertical="true"
             android:layout_alignParentStart="true"
-            android:layout_marginEnd="3dp" />
-        <TextView
-            android:id="@+id/pkgname"
-            android:layout_width="wrap_content"
+            android:layout_marginEnd="15dp" />
+        <LinearLayout
+            android:id="@+id/names"
+            android:layout_weight="1"
+            android:layout_width="0dp"
+            android:orientation="vertical"
+
             android:layout_height="wrap_content"
+            android:minHeight="@dimen/notification_guts_conversation_icon_size"
             android:layout_centerVertical="true"
-            style="@style/TextAppearance.NotificationImportanceHeader"
-            android:layout_marginStart="3dp"
-            android:layout_marginEnd="2dp"
-            android:layout_toEndOf="@id/pkgicon"
-            android:singleLine="true" />
-        <TextView
-            android:id="@+id/pkg_divider"
-            android:layout_width="wrap_content"
-            android:layout_height="wrap_content"
-            android:layout_centerVertical="true"
-            style="@style/TextAppearance.NotificationImportanceHeader"
-            android:layout_marginStart="2dp"
-            android:layout_marginEnd="2dp"
-            android:layout_toEndOf="@id/pkgname"
-            android:text="@*android:string/notification_header_divider_symbol" />
-        <TextView
-            android:id="@+id/delegate_name"
-            android:layout_width="wrap_content"
-            android:layout_height="wrap_content"
-            android:layout_centerVertical="true"
-            style="@style/TextAppearance.NotificationImportanceHeader"
-            android:layout_marginStart="2dp"
-            android:layout_marginEnd="2dp"
-            android:ellipsize="end"
-            android:text="@string/notification_delegate_header"
-            android:layout_toEndOf="@id/pkg_divider"
-            android:maxLines="1" />
+            android:gravity="center_vertical"
+            android:layout_alignEnd="@id/pkg_icon"
+            android:layout_toEndOf="@id/pkg_icon"
+            android:layout_alignStart="@id/mute">
+            <TextView
+                android:id="@+id/channel_name"
+                android:layout_width="match_parent"
+                android:layout_height="wrap_content"
+                style="@style/TextAppearance.NotificationImportanceChannel"/>
+            <LinearLayout
+                android:layout_width="match_parent"
+                android:layout_height="wrap_content"
+                android:gravity="start"
+                android:orientation="horizontal">
+                <TextView
+                    android:id="@+id/pkg_name"
+                    android:layout_width="wrap_content"
+                    android:layout_height="wrap_content"
+                    style="@style/TextAppearance.NotificationImportanceChannelGroup"
+                    android:ellipsize="end"
+                    android:maxLines="1"/>
+                <TextView
+                    android:id="@+id/group_divider"
+                    android:layout_width="wrap_content"
+                    android:layout_height="wrap_content"
+                    android:layout_centerVertical="true"
+                    style="@style/TextAppearance.NotificationImportanceHeader"
+                    android:layout_marginStart="2dp"
+                    android:layout_marginEnd="2dp"
+                    android:text="@*android:string/notification_header_divider_symbol" />
+                <TextView
+                    android:id="@+id/group_name"
+                    android:layout_width="wrap_content"
+                    android:layout_height="wrap_content"
+                    android:layout_weight="1"
+                    style="@style/TextAppearance.NotificationImportanceChannel"/>
+            </LinearLayout>
+            <TextView
+                android:id="@+id/delegate_name"
+                android:layout_width="match_parent"
+                android:layout_height="wrap_content"
+                android:layout_centerVertical="true"
+                style="@style/TextAppearance.NotificationImportanceHeader"
+                android:layout_marginStart="2dp"
+                android:layout_marginEnd="2dp"
+                android:ellipsize="end"
+                android:text="@string/notification_delegate_header"
+                android:maxLines="1" />
+
+        </LinearLayout>
+
+        <!-- end aligned fields -->
         <!-- Optional link to app. Only appears if the channel is not disabled and the app
 asked for it -->
         <ImageButton
@@ -95,91 +125,6 @@
             android:src="@drawable/ic_settings"
             android:layout_alignParentEnd="true"
             android:tint="@color/notification_guts_link_icon_tint"/>
-    </RelativeLayout>
-
-    <!-- Channel Info Block -->
-    <LinearLayout
-        android:id="@+id/channel_info"
-        android:layout_width="match_parent"
-        android:layout_height="wrap_content"
-        android:paddingEnd="@*android:dimen/notification_content_margin_end"
-        android:gravity="center"
-        android:orientation="vertical">
-        <!-- Channel Name -->
-        <TextView
-            android:id="@+id/channel_name"
-            android:layout_width="wrap_content"
-            android:layout_height="wrap_content"
-            android:layout_weight="1"
-            style="@style/TextAppearance.NotificationImportanceChannel"/>
-        <TextView
-            android:id="@+id/group_name"
-            android:layout_width="wrap_content"
-            android:layout_height="wrap_content"
-            style="@style/TextAppearance.NotificationImportanceChannelGroup"
-            android:ellipsize="end"
-            android:maxLines="1"/>
-    </LinearLayout>
-
-    <LinearLayout
-        android:id="@+id/blocking_helper"
-        android:layout_width="match_parent"
-        android:layout_height="wrap_content"
-        android:layout_marginTop="@dimen/notification_guts_button_spacing"
-        android:layout_marginBottom="@dimen/notification_guts_button_spacing"
-        android:paddingEnd="@*android:dimen/notification_content_margin_end"
-        android:clipChildren="false"
-        android:clipToPadding="false"
-        android:orientation="vertical">
-        <!-- blocking helper text. no need for non-configurable check b/c controls won't be
-        activated in that case -->
-        <TextView
-            android:id="@+id/blocking_helper_text"
-            android:layout_width="wrap_content"
-            android:layout_height="wrap_content"
-            android:layout_marginTop="2dp"
-            android:text="@string/inline_blocking_helper"
-            style="@*android:style/TextAppearance.DeviceDefault.Notification" />
-        <RelativeLayout
-            android:id="@+id/block_buttons"
-            android:layout_width="match_parent"
-            android:layout_height="wrap_content"
-            android:layout_marginTop="@dimen/notification_guts_button_spacing">
-            <TextView
-                android:id="@+id/blocking_helper_turn_off_notifications"
-                android:text="@string/inline_turn_off_notifications"
-                android:layout_width="wrap_content"
-                android:layout_height="wrap_content"
-                android:layout_centerVertical="true"
-                android:layout_alignParentStart="true"
-                android:width="110dp"
-                android:paddingEnd="15dp"
-                android:breakStrategy="simple"
-                style="@style/TextAppearance.NotificationInfo.Button"/>
-            <TextView
-                android:id="@+id/deliver_silently"
-                android:text="@string/inline_deliver_silently_button"
-                android:layout_width="wrap_content"
-                android:layout_height="wrap_content"
-                android:layout_centerVertical="true"
-                android:layout_marginStart="@dimen/notification_guts_button_horizontal_spacing"
-                android:paddingEnd="15dp"
-                android:width="110dp"
-                android:breakStrategy="simple"
-                android:layout_toStartOf="@+id/keep_showing"
-                style="@style/TextAppearance.NotificationInfo.Button"/>
-            <TextView
-                android:id="@+id/keep_showing"
-                android:text="@string/inline_keep_button"
-                android:layout_width="wrap_content"
-                android:layout_height="wrap_content"
-                android:layout_centerVertical="true"
-                android:layout_marginStart="@dimen/notification_guts_button_horizontal_spacing"
-                android:width="110dp"
-                android:breakStrategy="simple"
-                android:layout_alignParentEnd="true"
-                style="@style/TextAppearance.NotificationInfo.Button"/>
-        </RelativeLayout>
 
     </LinearLayout>
 
@@ -357,34 +302,4 @@
         </RelativeLayout>
 
     </LinearLayout>
-
-    <com.android.systemui.statusbar.notification.row.NotificationUndoLayout
-        android:id="@+id/confirmation"
-        android:layout_width="match_parent"
-        android:layout_height="wrap_content"
-        android:visibility="gone"
-        android:orientation="horizontal" >
-        <TextView
-            android:id="@+id/confirmation_text"
-            android:layout_width="wrap_content"
-            android:layout_height="wrap_content"
-            android:layout_gravity="start|center_vertical"
-            android:layout_marginStart="@*android:dimen/notification_content_margin_start"
-            android:layout_marginEnd="@*android:dimen/notification_content_margin_start"
-            android:text="@string/notification_channel_disabled"
-            style="@style/TextAppearance.NotificationInfo.Confirmation"/>
-        <TextView
-            android:id="@+id/undo"
-            android:layout_width="wrap_content"
-            android:layout_height="wrap_content"
-            android:minWidth="@dimen/notification_importance_toggle_size"
-            android:minHeight="@dimen/notification_importance_toggle_size"
-            android:layout_marginTop="@dimen/notification_guts_button_spacing"
-            android:layout_marginBottom="@dimen/notification_guts_button_spacing"
-            android:layout_marginStart="@dimen/notification_guts_button_side_margin"
-            android:layout_marginEnd="@dimen/notification_guts_button_side_margin"
-            android:layout_gravity="end|center_vertical"
-            android:text="@string/inline_undo"
-            style="@style/TextAppearance.NotificationInfo.Button"/>
-    </com.android.systemui.statusbar.notification.row.NotificationUndoLayout>
 </com.android.systemui.statusbar.notification.row.NotificationInfo>
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 e554dcd..ebed1fc 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
@@ -64,7 +64,7 @@
     private final class InputEventReceiver extends BatchedInputEventReceiver {
 
         public InputEventReceiver(InputChannel inputChannel, Looper looper) {
-            super(inputChannel, looper, Choreographer.getSfInstance());
+            super(inputChannel, looper, Choreographer.getInstance());
         }
 
         @Override
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
index 6a6255f..4508fc7 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
@@ -23,7 +23,6 @@
 import static android.content.Intent.ACTION_USER_UNLOCKED;
 import static android.os.BatteryManager.BATTERY_STATUS_UNKNOWN;
 import static android.telephony.PhoneStateListener.LISTEN_ACTIVE_DATA_SUBSCRIPTION_ID_CHANGE;
-import static android.telephony.TelephonyManager.MODEM_COUNT_DUAL_MODEM;
 
 import static com.android.internal.widget.LockPatternUtils.StrongAuthTracker.STRONG_AUTH_REQUIRED_AFTER_BOOT;
 import static com.android.internal.widget.LockPatternUtils.StrongAuthTracker.STRONG_AUTH_REQUIRED_AFTER_DPM_LOCK_NOW;
@@ -455,7 +454,7 @@
      */
     public List<SubscriptionInfo> getFilteredSubscriptionInfo(boolean forceReload) {
         List<SubscriptionInfo> subscriptions = getSubscriptionInfo(false);
-        if (subscriptions.size() == MODEM_COUNT_DUAL_MODEM) {
+        if (subscriptions.size() == 2) {
             SubscriptionInfo info1 = subscriptions.get(0);
             SubscriptionInfo info2 = subscriptions.get(1);
             if (info1.getGroupUuid() != null && info1.getGroupUuid().equals(info2.getGroupUuid())) {
diff --git a/packages/SystemUI/src/com/android/systemui/ScreenDecorations.java b/packages/SystemUI/src/com/android/systemui/ScreenDecorations.java
index 1324524..86aa640 100644
--- a/packages/SystemUI/src/com/android/systemui/ScreenDecorations.java
+++ b/packages/SystemUI/src/com/android/systemui/ScreenDecorations.java
@@ -28,6 +28,9 @@
 import static android.view.ViewGroup.LayoutParams.WRAP_CONTENT;
 import static android.view.WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS;
 
+import android.animation.Animator;
+import android.animation.AnimatorListenerAdapter;
+import android.animation.ValueAnimator;
 import android.annotation.Dimension;
 import android.annotation.NonNull;
 import android.app.ActivityManager;
@@ -714,6 +717,8 @@
     public static class DisplayCutoutView extends View implements DisplayManager.DisplayListener,
             RegionInterceptableView {
 
+        private static final float HIDDEN_CAMERA_PROTECTION_SCALE = 0.5f;
+
         private final DisplayInfo mInfo = new DisplayInfo();
         private final Paint mPaint = new Paint();
         private final List<Rect> mBounds = new ArrayList();
@@ -732,6 +737,8 @@
         private int mRotation;
         private int mInitialPosition;
         private int mPosition;
+        private float mCameraProtectionProgress = HIDDEN_CAMERA_PROTECTION_SCALE;
+        private ValueAnimator mCameraProtectionAnimator;
 
         public DisplayCutoutView(Context context, @BoundsPosition int pos,
                 ScreenDecorations decorations) {
@@ -770,17 +777,18 @@
             getLocationOnScreen(mLocation);
             canvas.translate(-mLocation[0], -mLocation[1]);
 
-            if (mShowProtection && !mProtectionRect.isEmpty()) {
-                mPaint.setColor(mColor);
-                mPaint.setStyle(Paint.Style.FILL);
-                mPaint.setAntiAlias(true);
-                canvas.drawPath(mProtectionPath, mPaint);
-            } else if (!mBoundingPath.isEmpty()) {
+            if (!mBoundingPath.isEmpty()) {
                 mPaint.setColor(mColor);
                 mPaint.setStyle(Paint.Style.FILL);
                 mPaint.setAntiAlias(true);
                 canvas.drawPath(mBoundingPath, mPaint);
             }
+            if (mCameraProtectionProgress > HIDDEN_CAMERA_PROTECTION_SCALE
+                    && !mProtectionRect.isEmpty()) {
+                canvas.scale(mCameraProtectionProgress, mCameraProtectionProgress,
+                        mProtectionRect.centerX(), mProtectionRect.centerY());
+                canvas.drawPath(mProtectionPath, mPaint);
+            }
         }
 
         @Override
@@ -815,8 +823,31 @@
 
             mShowProtection = shouldShow;
             updateBoundingPath();
-            requestLayout();
-            invalidate();
+            // Delay the relayout until the end of the animation when hiding the cutout,
+            // otherwise we'd clip it.
+            if (mShowProtection) {
+                requestLayout();
+            }
+            if (mCameraProtectionAnimator != null) {
+                mCameraProtectionAnimator.cancel();
+            }
+            mCameraProtectionAnimator = ValueAnimator.ofFloat(mCameraProtectionProgress,
+                    mShowProtection ? 1.0f : HIDDEN_CAMERA_PROTECTION_SCALE).setDuration(750);
+            mCameraProtectionAnimator.setInterpolator(Interpolators.DECELERATE_QUINT);
+            mCameraProtectionAnimator.addUpdateListener(animation -> {
+                mCameraProtectionProgress = (float) animation.getAnimatedValue();
+                invalidate();
+            });
+            mCameraProtectionAnimator.addListener(new AnimatorListenerAdapter() {
+                @Override
+                public void onAnimationEnd(Animator animation) {
+                    mCameraProtectionAnimator = null;
+                    if (!mShowProtection) {
+                        requestLayout();
+                    }
+                }
+            });
+            mCameraProtectionAnimator.start();
         }
 
         private void update() {
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleExperimentConfig.java b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleExperimentConfig.java
index 2873811..b33eeba 100644
--- a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleExperimentConfig.java
+++ b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleExperimentConfig.java
@@ -73,6 +73,9 @@
 
     private static final String WHITELISTED_AUTO_BUBBLE_APPS = "whitelisted_auto_bubble_apps";
 
+    private static final String ALLOW_BUBBLE_OVERFLOW = "allow_bubble_overflow";
+    private static final boolean ALLOW_BUBBLE_OVERFLOW_DEFAULT = false;
+
     /**
      * When true, if a notification has the information necessary to bubble (i.e. valid
      * contentIntent and an icon or image), then a {@link android.app.Notification.BubbleMetadata}
@@ -87,6 +90,15 @@
     }
 
     /**
+     * When true, show a menu with dismissed and aged-out bubbles.
+     */
+    static boolean allowBubbleOverflow(Context context) {
+        return Settings.Secure.getInt(context.getContentResolver(),
+                ALLOW_BUBBLE_OVERFLOW,
+                ALLOW_BUBBLE_OVERFLOW_DEFAULT ? 1 : 0) != 0;
+    }
+
+    /**
      * Same as {@link #allowAnyNotifToBubble(Context)} except it filters for notifications that
      * are using {@link Notification.MessagingStyle} and have remote input.
      */
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleStackView.java b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleStackView.java
index 6647069..0cf6d89 100644
--- a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleStackView.java
+++ b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleStackView.java
@@ -589,6 +589,9 @@
     }
 
     private void setUpOverflow() {
+        if (!BubbleExperimentConfig.allowBubbleOverflow(mContext)) {
+            return;
+        }
         int overflowBtnIndex = 0;
         if (mBubbleOverflow == null) {
             mBubbleOverflow = new BubbleOverflow(getContext());
@@ -800,7 +803,8 @@
     @Nullable
     Bubble getExpandedBubble() {
         if (mExpandedBubble == null
-                || (mExpandedBubble.getIconView() == mBubbleOverflow.getBtn()
+                || (BubbleExperimentConfig.allowBubbleOverflow(mContext)
+                    && mExpandedBubble.getIconView() == mBubbleOverflow.getBtn()
                     && BubbleOverflow.KEY.equals(mExpandedBubble.getKey()))) {
             return null;
         }
@@ -857,6 +861,9 @@
     }
 
     private void updateOverflowBtnVisibility(boolean apply) {
+        if (!BubbleExperimentConfig.allowBubbleOverflow(mContext)) {
+            return;
+        }
         if (mIsExpanded) {
             if (DEBUG_BUBBLE_STACK_VIEW) {
                 Log.d(TAG, "Show overflow button.");
@@ -1083,7 +1090,8 @@
         float y = event.getRawY();
         if (mIsExpanded) {
             if (isIntersecting(mBubbleContainer, x, y)) {
-                if (isIntersecting(mBubbleOverflow.getBtn(), x, y)) {
+                if (BubbleExperimentConfig.allowBubbleOverflow(mContext)
+                        && isIntersecting(mBubbleOverflow.getBtn(), x, y)) {
                     return mBubbleOverflow.getBtn();
                 }
                 // Could be tapping or dragging a bubble while expanded
@@ -1820,8 +1828,11 @@
      * @return the number of bubbles in the stack view.
      */
     public int getBubbleCount() {
-        // Subtract 1 for the overflow button that is always in the bubble container.
-        return mBubbleContainer.getChildCount() - 1;
+        if (BubbleExperimentConfig.allowBubbleOverflow(mContext)) {
+            // Subtract 1 for the overflow button that is always in the bubble container.
+            return mBubbleContainer.getChildCount() - 1;
+        }
+        return mBubbleContainer.getChildCount();
     }
 
     /**
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 f2c8490..6eed6b8 100644
--- a/packages/SystemUI/src/com/android/systemui/controls/ui/ControlViewHolder.kt
+++ b/packages/SystemUI/src/com/android/systemui/controls/ui/ControlViewHolder.kt
@@ -28,6 +28,7 @@
 import android.service.controls.templates.ThumbnailTemplate
 import android.service.controls.templates.ToggleRangeTemplate
 import android.service.controls.templates.ToggleTemplate
+import android.util.Log
 import android.view.View
 import android.view.ViewGroup
 import android.widget.ImageView
@@ -97,15 +98,8 @@
     }
 
     fun actionResponse(@ControlAction.ResponseResult response: Int) {
-        val text = when (response) {
-            ControlAction.RESPONSE_OK -> "Success"
-            ControlAction.RESPONSE_FAIL -> "Error"
-            else -> ""
-        }
-
-        if (!text.isEmpty()) {
-            setTransientStatus(text)
-        }
+        // TODO: b/150931809 - handle response codes
+        Log.d(ControlsUiController.TAG, "Received response code: $response")
     }
 
     fun setTransientStatus(tempStatus: String) {
diff --git a/packages/SystemUI/src/com/android/systemui/pip/PipAnimationController.java b/packages/SystemUI/src/com/android/systemui/pip/PipAnimationController.java
index 1fc1fe4..36b5fad 100644
--- a/packages/SystemUI/src/com/android/systemui/pip/PipAnimationController.java
+++ b/packages/SystemUI/src/com/android/systemui/pip/PipAnimationController.java
@@ -19,11 +19,8 @@
 import android.animation.Animator;
 import android.animation.ValueAnimator;
 import android.annotation.IntDef;
-import android.annotation.MainThread;
 import android.content.Context;
 import android.graphics.Rect;
-import android.os.RemoteException;
-import android.view.IWindowContainer;
 import android.view.SurfaceControl;
 import android.view.animation.AnimationUtils;
 import android.view.animation.Interpolator;
@@ -61,31 +58,30 @@
                 com.android.internal.R.interpolator.fast_out_slow_in);
     }
 
-    @MainThread
-    PipTransitionAnimator getAnimator(IWindowContainer wc, boolean scheduleFinishPip,
+    PipTransitionAnimator getAnimator(SurfaceControl leash, boolean scheduleFinishPip,
             Rect destinationBounds, float alphaStart, float alphaEnd) {
         if (mCurrentAnimator == null) {
             mCurrentAnimator = setupPipTransitionAnimator(
-                    PipTransitionAnimator.ofAlpha(wc, scheduleFinishPip,
-                            destinationBounds, alphaStart, alphaEnd));
+                    PipTransitionAnimator.ofAlpha(leash, scheduleFinishPip, destinationBounds,
+                            alphaStart, alphaEnd));
         } else if (mCurrentAnimator.getAnimationType() == ANIM_TYPE_ALPHA
                 && mCurrentAnimator.isRunning()) {
             mCurrentAnimator.updateEndValue(alphaEnd);
         } else {
             mCurrentAnimator.cancel();
             mCurrentAnimator = setupPipTransitionAnimator(
-                    PipTransitionAnimator.ofAlpha(wc, scheduleFinishPip,
-                            destinationBounds, alphaStart, alphaEnd));
+                    PipTransitionAnimator.ofAlpha(leash, scheduleFinishPip, destinationBounds,
+                            alphaStart, alphaEnd));
         }
         return mCurrentAnimator;
     }
 
-    @MainThread
-    PipTransitionAnimator getAnimator(IWindowContainer wc, boolean scheduleFinishPip,
+    PipTransitionAnimator getAnimator(SurfaceControl leash, boolean scheduleFinishPip,
             Rect startBounds, Rect endBounds) {
         if (mCurrentAnimator == null) {
             mCurrentAnimator = setupPipTransitionAnimator(
-                    PipTransitionAnimator.ofBounds(wc, scheduleFinishPip, startBounds, endBounds));
+                    PipTransitionAnimator.ofBounds(leash, scheduleFinishPip,
+                            startBounds, endBounds));
         } else if (mCurrentAnimator.getAnimationType() == ANIM_TYPE_BOUNDS
                 && mCurrentAnimator.isRunning()) {
             mCurrentAnimator.setDestinationBounds(endBounds);
@@ -94,7 +90,8 @@
         } else {
             mCurrentAnimator.cancel();
             mCurrentAnimator = setupPipTransitionAnimator(
-                    PipTransitionAnimator.ofBounds(wc, scheduleFinishPip, startBounds, endBounds));
+                    PipTransitionAnimator.ofBounds(leash, scheduleFinishPip,
+                            startBounds, endBounds));
         }
         return mCurrentAnimator;
     }
@@ -116,18 +113,18 @@
         /**
          * Called when PiP animation is started.
          */
-        public void onPipAnimationStart(IWindowContainer wc, PipTransitionAnimator animator) {}
+        public void onPipAnimationStart(PipTransitionAnimator animator) {}
 
         /**
          * Called when PiP animation is ended.
          */
-        public void onPipAnimationEnd(IWindowContainer wc, SurfaceControl.Transaction tx,
+        public void onPipAnimationEnd(SurfaceControl.Transaction tx,
                 PipTransitionAnimator animator) {}
 
         /**
          * Called when PiP animation is cancelled.
          */
-        public void onPipAnimationCancel(IWindowContainer wc, PipTransitionAnimator animator) {}
+        public void onPipAnimationCancel(PipTransitionAnimator animator) {}
     }
 
     /**
@@ -137,7 +134,6 @@
     public abstract static class PipTransitionAnimator<T> extends ValueAnimator implements
             ValueAnimator.AnimatorUpdateListener,
             ValueAnimator.AnimatorListener {
-        private final IWindowContainer mWindowContainer;
         private final boolean mScheduleFinishPip;
         private final SurfaceControl mLeash;
         private final @AnimationType int mAnimationType;
@@ -149,23 +145,18 @@
         private PipAnimationCallback mPipAnimationCallback;
         private SurfaceControlTransactionFactory mSurfaceControlTransactionFactory;
 
-        private PipTransitionAnimator(IWindowContainer wc, boolean scheduleFinishPip,
+        private PipTransitionAnimator(SurfaceControl leash, boolean scheduleFinishPip,
                 @AnimationType int animationType, Rect destinationBounds,
                 T startValue, T endValue) {
-            mWindowContainer = wc;
             mScheduleFinishPip = scheduleFinishPip;
-            try {
-                mLeash = wc.getLeash();
-                mAnimationType = animationType;
-                mDestinationBounds.set(destinationBounds);
-                mStartValue = startValue;
-                mEndValue = endValue;
-                addListener(this);
-                addUpdateListener(this);
-                mSurfaceControlTransactionFactory = SurfaceControl.Transaction::new;
-            } catch (RemoteException e) {
-                throw new RuntimeException(e);
-            }
+            mLeash = leash;
+            mAnimationType = animationType;
+            mDestinationBounds.set(destinationBounds);
+            mStartValue = startValue;
+            mEndValue = endValue;
+            addListener(this);
+            addUpdateListener(this);
+            mSurfaceControlTransactionFactory = SurfaceControl.Transaction::new;
         }
 
         @Override
@@ -173,7 +164,7 @@
             mCurrentValue = mStartValue;
             applySurfaceControlTransaction(mLeash, newSurfaceControlTransaction(), FRACTION_START);
             if (mPipAnimationCallback != null) {
-                mPipAnimationCallback.onPipAnimationStart(mWindowContainer, this);
+                mPipAnimationCallback.onPipAnimationStart(this);
             }
         }
 
@@ -189,14 +180,14 @@
             final SurfaceControl.Transaction tx = newSurfaceControlTransaction();
             applySurfaceControlTransaction(mLeash, tx, FRACTION_END);
             if (mPipAnimationCallback != null) {
-                mPipAnimationCallback.onPipAnimationEnd(mWindowContainer, tx, this);
+                mPipAnimationCallback.onPipAnimationEnd(tx, this);
             }
         }
 
         @Override
         public void onAnimationCancel(Animator animation) {
             if (mPipAnimationCallback != null) {
-                mPipAnimationCallback.onPipAnimationCancel(mWindowContainer, this);
+                mPipAnimationCallback.onPipAnimationCancel(this);
             }
         }
 
@@ -260,9 +251,9 @@
         abstract void applySurfaceControlTransaction(SurfaceControl leash,
                 SurfaceControl.Transaction tx, float fraction);
 
-        static PipTransitionAnimator<Float> ofAlpha(IWindowContainer wc, boolean scheduleFinishPip,
+        static PipTransitionAnimator<Float> ofAlpha(SurfaceControl leash, boolean scheduleFinishPip,
                 Rect destinationBounds, float startValue, float endValue) {
-            return new PipTransitionAnimator<Float>(wc, scheduleFinishPip, ANIM_TYPE_ALPHA,
+            return new PipTransitionAnimator<Float>(leash, scheduleFinishPip, ANIM_TYPE_ALPHA,
                     destinationBounds, startValue, endValue) {
                 @Override
                 void applySurfaceControlTransaction(SurfaceControl leash,
@@ -281,10 +272,10 @@
             };
         }
 
-        static PipTransitionAnimator<Rect> ofBounds(IWindowContainer wc, boolean scheduleFinishPip,
+        static PipTransitionAnimator<Rect> ofBounds(SurfaceControl leash, boolean scheduleFinishPip,
                 Rect startValue, Rect endValue) {
             // construct new Rect instances in case they are recycled
-            return new PipTransitionAnimator<Rect>(wc, scheduleFinishPip, ANIM_TYPE_BOUNDS,
+            return new PipTransitionAnimator<Rect>(leash, scheduleFinishPip, ANIM_TYPE_BOUNDS,
                     endValue, new Rect(startValue), new Rect(endValue)) {
                 private final Rect mTmpRect = new Rect();
 
diff --git a/packages/SystemUI/src/com/android/systemui/pip/PipTaskOrganizer.java b/packages/SystemUI/src/com/android/systemui/pip/PipTaskOrganizer.java
index 836485a..4766ebc 100644
--- a/packages/SystemUI/src/com/android/systemui/pip/PipTaskOrganizer.java
+++ b/packages/SystemUI/src/com/android/systemui/pip/PipTaskOrganizer.java
@@ -30,6 +30,7 @@
 import android.graphics.Rect;
 import android.os.Handler;
 import android.os.Looper;
+import android.os.Message;
 import android.os.RemoteException;
 import android.util.Log;
 import android.view.DisplayInfo;
@@ -38,9 +39,13 @@
 import android.view.SurfaceControl;
 import android.view.WindowContainerTransaction;
 
+import com.android.internal.os.SomeArgs;
+import com.android.systemui.pip.phone.PipUpdateThread;
+
 import java.util.ArrayList;
 import java.util.List;
 import java.util.Objects;
+import java.util.function.Consumer;
 
 /**
  * Manages PiP tasks such as resize and offset.
@@ -56,7 +61,13 @@
 public class PipTaskOrganizer extends ITaskOrganizer.Stub {
     private static final String TAG = PipTaskOrganizer.class.getSimpleName();
 
+    private static final int MSG_RESIZE_IMMEDIATE = 1;
+    private static final int MSG_RESIZE_ANIMATE = 2;
+    private static final int MSG_OFFSET_ANIMATE = 3;
+    private static final int MSG_FINISH_RESIZE = 4;
+
     private final Handler mMainHandler;
+    private final Handler mUpdateHandler;
     private final ITaskOrganizerController mTaskOrganizerController;
     private final PipBoundsHandler mPipBoundsHandler;
     private final PipAnimationController mPipAnimationController;
@@ -64,11 +75,11 @@
     private final Rect mDisplayBounds = new Rect();
     private final Rect mLastReportedBounds = new Rect();
 
+    // These callbacks are called on the update thread
     private final PipAnimationController.PipAnimationCallback mPipAnimationCallback =
             new PipAnimationController.PipAnimationCallback() {
         @Override
-        public void onPipAnimationStart(IWindowContainer wc,
-                PipAnimationController.PipTransitionAnimator animator) {
+        public void onPipAnimationStart(PipAnimationController.PipTransitionAnimator animator) {
             mMainHandler.post(() -> {
                 for (int i = mPipTransitionCallbacks.size() - 1; i >= 0; i--) {
                     final PipTransitionCallback callback = mPipTransitionCallbacks.get(i);
@@ -78,7 +89,7 @@
         }
 
         @Override
-        public void onPipAnimationEnd(IWindowContainer wc, SurfaceControl.Transaction tx,
+        public void onPipAnimationEnd(SurfaceControl.Transaction tx,
                 PipAnimationController.PipTransitionAnimator animator) {
             mMainHandler.post(() -> {
                 for (int i = mPipTransitionCallbacks.size() - 1; i >= 0; i--) {
@@ -86,13 +97,11 @@
                     callback.onPipTransitionFinished();
                 }
             });
-            final Rect destinationBounds = animator.getDestinationBounds();
-            finishResizeInternal(destinationBounds, wc, tx, animator.shouldScheduleFinishPip());
+            finishResize(animator.getDestinationBounds(), tx, animator.shouldScheduleFinishPip());
         }
 
         @Override
-        public void onPipAnimationCancel(IWindowContainer wc,
-                PipAnimationController.PipTransitionAnimator animator) {
+        public void onPipAnimationCancel(PipAnimationController.PipTransitionAnimator animator) {
             mMainHandler.post(() -> {
                 for (int i = mPipTransitionCallbacks.size() - 1; i >= 0; i--) {
                     final PipTransitionCallback callback = mPipTransitionCallbacks.get(i);
@@ -102,28 +111,75 @@
         }
     };
 
+    private Handler.Callback mUpdateCallbacks = new Handler.Callback() {
+        @Override
+        public boolean handleMessage(Message msg) {
+            SomeArgs args = (SomeArgs) msg.obj;
+            Consumer<Rect> updateBoundsCallback = (Consumer<Rect>) args.arg1;
+            switch (msg.what) {
+                case MSG_RESIZE_IMMEDIATE: {
+                    Rect toBounds = (Rect) args.arg2;
+                    resizePip(toBounds);
+                    if (updateBoundsCallback != null) {
+                        updateBoundsCallback.accept(toBounds);
+                    }
+                    break;
+                }
+                case MSG_RESIZE_ANIMATE: {
+                    Rect currentBounds = (Rect) args.arg2;
+                    Rect toBounds = (Rect) args.arg3;
+                    boolean scheduleFinishPip = args.argi1 != 0;
+                    int duration = args.argi2;
+                    animateResizePip(scheduleFinishPip, currentBounds, toBounds, duration);
+                    if (updateBoundsCallback != null) {
+                        updateBoundsCallback.accept(toBounds);
+                    }
+                    break;
+                }
+                case MSG_OFFSET_ANIMATE: {
+                    Rect originalBounds = (Rect) args.arg2;
+                    final int offset = args.argi1;
+                    final int duration = args.argi2;
+                    offsetPip(originalBounds, 0 /* xOffset */, offset, duration);
+                    Rect toBounds = new Rect(originalBounds);
+                    toBounds.offset(0, offset);
+                    if (updateBoundsCallback != null) {
+                        updateBoundsCallback.accept(toBounds);
+                    }
+                    break;
+                }
+                case MSG_FINISH_RESIZE: {
+                    SurfaceControl.Transaction tx = (SurfaceControl.Transaction) args.arg2;
+                    Rect toBounds = (Rect) args.arg3;
+                    boolean scheduleFinishPip = args.argi1 != 0;
+                    finishResize(toBounds, tx, scheduleFinishPip);
+                    if (updateBoundsCallback != null) {
+                        updateBoundsCallback.accept(toBounds);
+                    }
+                    break;
+                }
+            }
+            args.recycle();
+            return true;
+        }
+    };
+
     private ActivityManager.RunningTaskInfo mTaskInfo;
+    private IWindowContainer mToken;
+    private SurfaceControl mLeash;
+    private boolean mInPip;
     private @PipAnimationController.AnimationType int mOneShotAnimationType = ANIM_TYPE_BOUNDS;
 
     public PipTaskOrganizer(Context context, @NonNull PipBoundsHandler boundsHandler) {
         mMainHandler = new Handler(Looper.getMainLooper());
+        mUpdateHandler = new Handler(PipUpdateThread.get().getLooper(), mUpdateCallbacks);
         mTaskOrganizerController = ActivityTaskManager.getTaskOrganizerController();
         mPipBoundsHandler = boundsHandler;
         mPipAnimationController = new PipAnimationController(context);
     }
 
-    /**
-     * Offset the PiP window, animate if the given duration is not {@link #DURATION_NONE}
-     */
-    public void offsetPinnedStack(Rect originalBounds, int xOffset, int yOffset, int durationMs) {
-        if (mTaskInfo == null) {
-            Log.w(TAG, "mTaskInfo is not set");
-            return;
-        }
-        final Rect destinationBounds = new Rect(originalBounds);
-        destinationBounds.offset(xOffset, yOffset);
-        animateResizePipInternal(mTaskInfo.token, false /* scheduleFinishPip*/,
-                originalBounds, destinationBounds, durationMs);
+    public Handler getUpdateHandler() {
+        return mUpdateHandler;
     }
 
     /**
@@ -171,7 +227,7 @@
         try {
             mLastReportedBounds.set(destinationBounds);
             final WindowContainerTransaction wct = new WindowContainerTransaction();
-            wct.setBounds(mTaskInfo.token, destinationBounds);
+            wct.setBounds(mToken, destinationBounds);
             mTaskOrganizerController.applyContainerTransaction(wct, null /* ITaskOrganizer */);
         } catch (RemoteException e) {
             Log.w(TAG, "Failed to apply window container transaction", e);
@@ -185,13 +241,20 @@
                 getAspectRatioOrDefault(info.pictureInPictureParams), null /* bounds */);
         Objects.requireNonNull(destinationBounds, "Missing destination bounds");
         mTaskInfo = info;
+        mToken = mTaskInfo.token;
+        mInPip = true;
+        try {
+            mLeash = mToken.getLeash();
+        } catch (RemoteException e) {
+            throw new RuntimeException("Unable to get leash", e);
+        }
         if (mOneShotAnimationType == ANIM_TYPE_BOUNDS) {
             final Rect currentBounds = mTaskInfo.configuration.windowConfiguration.getBounds();
-            animateResizePipInternal(mTaskInfo.token, true /* scheduleFinishPip */,
-                    currentBounds, destinationBounds, DURATION_DEFAULT_MS);
+            scheduleAnimateResizePip(true /* scheduleFinishPip */,
+                    currentBounds, destinationBounds, DURATION_DEFAULT_MS, null);
         } else if (mOneShotAnimationType == ANIM_TYPE_ALPHA) {
-            mMainHandler.post(() -> mPipAnimationController
-                    .getAnimator(mTaskInfo.token, true /* scheduleFinishPip */,
+            mUpdateHandler.post(() -> mPipAnimationController
+                    .getAnimator(mLeash, true /* scheduleFinishPip */,
                             destinationBounds, 0f, 1f)
                     .setPipAnimationCallback(mPipAnimationCallback)
                     .setDuration(DURATION_DEFAULT_MS)
@@ -205,12 +268,12 @@
     @Override
     public void taskVanished(IWindowContainer token) {
         Objects.requireNonNull(token, "Requires valid IWindowContainer");
-        if (token.asBinder() != mTaskInfo.token.asBinder()) {
+        if (token.asBinder() != mToken.asBinder()) {
             Log.wtf(TAG, "Unrecognized token: " + token);
             return;
         }
-        animateResizePipInternal(token, false /* scheduleFinishPip */,
-                mLastReportedBounds, mDisplayBounds, DURATION_DEFAULT_MS);
+        scheduleAnimateResizePip(mDisplayBounds, DURATION_DEFAULT_MS, null);
+        mInPip = false;
     }
 
     @Override
@@ -227,7 +290,7 @@
         final Rect destinationBounds = mPipBoundsHandler.getDestinationBounds(
                 getAspectRatioOrDefault(newParams), null /* bounds */);
         Objects.requireNonNull(destinationBounds, "Missing destination bounds");
-        animateResizePip(destinationBounds, DURATION_DEFAULT_MS);
+        scheduleAnimateResizePip(destinationBounds, DURATION_DEFAULT_MS, null);
     }
 
     /**
@@ -243,102 +306,158 @@
     }
 
     /**
-     * Directly perform manipulation/resize on the leash. This will not perform any
-     * {@link WindowContainerTransaction} until {@link #finishResize} is called.
+     * Animates resizing of the pinned stack given the duration.
      */
-    public void resizePip(Rect destinationBounds) {
-        Objects.requireNonNull(mTaskInfo, "Requires valid IWindowContainer");
-        resizePipInternal(mTaskInfo.token, destinationBounds);
+    public void scheduleAnimateResizePip(Rect toBounds, int duration,
+            Consumer<Rect> updateBoundsCallback) {
+        scheduleAnimateResizePip(false /* scheduleFinishPip */,
+                mLastReportedBounds, toBounds, duration, updateBoundsCallback);
     }
 
-    private void resizePipInternal(IWindowContainer wc,
-            Rect destinationBounds) {
-        Objects.requireNonNull(mTaskInfo, "Requires valid IWindowContainer");
-        try {
-            // Could happen when dismissPip
-            if (wc == null || wc.getLeash() == null) {
-                Log.w(TAG, "Abort animation, invalid leash");
-                return;
-            }
-            final SurfaceControl leash = wc.getLeash();
-            new SurfaceControl.Transaction()
-                    .setPosition(leash, destinationBounds.left, destinationBounds.top)
-                    .setWindowCrop(leash, destinationBounds.width(), destinationBounds.height())
-                    .apply();
-        } catch (RemoteException e) {
-            Log.w(TAG, "Abort animation, invalid window container", e);
-        } catch (Exception e) {
-            Log.e(TAG, "Should not reach here, terrible thing happened", e);
+    private void scheduleAnimateResizePip(boolean scheduleFinishPip,
+            Rect currentBounds, Rect destinationBounds, int durationMs,
+            Consumer<Rect> updateBoundsCallback) {
+        Objects.requireNonNull(mToken, "Requires valid IWindowContainer");
+        if (!mInPip) {
+            // Ignore animation when we are no longer in PIP
+            return;
         }
+        SomeArgs args = SomeArgs.obtain();
+        args.arg1 = updateBoundsCallback;
+        args.arg2 = currentBounds;
+        args.arg3 = destinationBounds;
+        args.argi1 = scheduleFinishPip ? 1 : 0;
+        args.argi2 = durationMs;
+        mUpdateHandler.sendMessage(mUpdateHandler.obtainMessage(MSG_RESIZE_ANIMATE, args));
+    }
+
+    /**
+     * Directly perform manipulation/resize on the leash. This will not perform any
+     * {@link WindowContainerTransaction} until {@link #scheduleFinishResizePip} is called.
+     */
+    public void scheduleResizePip(Rect toBounds, Consumer<Rect> updateBoundsCallback) {
+        Objects.requireNonNull(mToken, "Requires valid IWindowContainer");
+        SomeArgs args = SomeArgs.obtain();
+        args.arg1 = updateBoundsCallback;
+        args.arg2 = toBounds;
+        mUpdateHandler.sendMessage(mUpdateHandler.obtainMessage(MSG_RESIZE_IMMEDIATE, args));
     }
 
     /**
      * Finish a intermediate resize operation. This is expected to be called after
-     * {@link #resizePip}.
+     * {@link #scheduleResizePip}.
      */
-    public void finishResize(Rect destinationBounds) {
-        try {
-            final IWindowContainer wc = mTaskInfo.token;
-            SurfaceControl.Transaction tx = new SurfaceControl.Transaction()
-                    .setPosition(wc.getLeash(), destinationBounds.left,
-                            destinationBounds.top)
-                    .setWindowCrop(wc.getLeash(), destinationBounds.width(),
-                            destinationBounds.height());
-            finishResizeInternal(destinationBounds, wc, tx, false);
-        } catch (RemoteException e) {
-            Log.e(TAG, "Failed to obtain leash");
-        }
+    public void scheduleFinishResizePip(Rect destinationBounds) {
+        Objects.requireNonNull(mToken, "Requires valid IWindowContainer");
+        SurfaceControl.Transaction tx = new SurfaceControl.Transaction()
+                .setPosition(mLeash, destinationBounds.left, destinationBounds.top)
+                .setWindowCrop(mLeash, destinationBounds.width(), destinationBounds.height());
+        scheduleFinishResizePip(tx, destinationBounds, false /* scheduleFinishPip */,
+                null);
     }
 
-    private void finishResizeInternal(Rect destinationBounds, IWindowContainer wc,
-            SurfaceControl.Transaction tx, boolean shouldScheduleFinishPip) {
+    private void scheduleFinishResizePip(SurfaceControl.Transaction tx,
+            Rect destinationBounds, boolean scheduleFinishPip,
+            Consumer<Rect> updateBoundsCallback) {
+        Objects.requireNonNull(mToken, "Requires valid IWindowContainer");
+        SomeArgs args = SomeArgs.obtain();
+        args.arg1 = updateBoundsCallback;
+        args.arg2 = tx;
+        args.arg3 = destinationBounds;
+        args.argi1 = scheduleFinishPip ? 1 : 0;
+        mUpdateHandler.sendMessage(mUpdateHandler.obtainMessage(MSG_FINISH_RESIZE, args));
+    }
+
+    /**
+     * Offset the PiP window, animate if the given duration is not {@link #DURATION_NONE}
+     */
+    public void scheduleOffsetPip(Rect originalBounds, int offset, int duration,
+            Consumer<Rect> updateBoundsCallback) {
+        if (!mInPip) {
+            // Ignore offsets when we are no longer in PIP
+            return;
+        }
+        Objects.requireNonNull(mToken, "Requires valid IWindowContainer");
+        SomeArgs args = SomeArgs.obtain();
+        args.arg1 = updateBoundsCallback;
+        args.arg2 = originalBounds;
+        // offset would be zero if triggered from screen rotation.
+        args.argi1 = offset;
+        args.argi2 = duration;
+        mUpdateHandler.sendMessage(mUpdateHandler.obtainMessage(MSG_OFFSET_ANIMATE, args));
+    }
+
+    private void offsetPip(Rect originalBounds, int xOffset, int yOffset, int durationMs) {
+        if (Looper.myLooper() != mUpdateHandler.getLooper()) {
+            throw new RuntimeException("Callers should call scheduleOffsetPip() instead of this "
+                    + "directly");
+        }
+        if (mTaskInfo == null) {
+            Log.w(TAG, "mTaskInfo is not set");
+            return;
+        }
+        final Rect destinationBounds = new Rect(originalBounds);
+        destinationBounds.offset(xOffset, yOffset);
+        animateResizePip(false /* scheduleFinishPip*/, originalBounds, destinationBounds,
+                durationMs);
+    }
+
+    private void resizePip(Rect destinationBounds) {
+        if (Looper.myLooper() != mUpdateHandler.getLooper()) {
+            throw new RuntimeException("Callers should call scheduleResizePip() instead of this "
+                    + "directly");
+        }
+        Objects.requireNonNull(mToken, "Requires valid IWindowContainer");
+        // Could happen when dismissPip
+        if (mToken == null || mLeash == null) {
+            Log.w(TAG, "Abort animation, invalid leash");
+            return;
+        }
+        new SurfaceControl.Transaction()
+                .setPosition(mLeash, destinationBounds.left, destinationBounds.top)
+                .setWindowCrop(mLeash, destinationBounds.width(), destinationBounds.height())
+                .apply();
+    }
+
+    private void finishResize(Rect destinationBounds, SurfaceControl.Transaction tx,
+            boolean shouldScheduleFinishPip) {
+        if (Looper.myLooper() != mUpdateHandler.getLooper()) {
+            throw new RuntimeException("Callers should call scheduleResizePip() instead of this "
+                    + "directly");
+        }
         mLastReportedBounds.set(destinationBounds);
         try {
             final WindowContainerTransaction wct = new WindowContainerTransaction();
             if (shouldScheduleFinishPip) {
-                wct.scheduleFinishEnterPip(wc, destinationBounds);
+                wct.scheduleFinishEnterPip(mToken, destinationBounds);
             } else {
-                wct.setBounds(wc, destinationBounds);
+                wct.setBounds(mToken, destinationBounds);
             }
-            wct.setBoundsChangeTransaction(mTaskInfo.token, tx);
+            wct.setBoundsChangeTransaction(mToken, tx);
             mTaskOrganizerController.applyContainerTransaction(wct, null /* ITaskOrganizer */);
         } catch (RemoteException e) {
             Log.e(TAG, "Failed to apply container transaction", e);
         }
     }
 
-    /**
-     * Animates resizing of the pinned stack given the duration.
-     */
-    public void animateResizePip(Rect destinationBounds, int durationMs) {
-        Objects.requireNonNull(mTaskInfo, "Requires valid IWindowContainer");
-        animateResizePipInternal(mTaskInfo.token, false, mLastReportedBounds,
-                destinationBounds, durationMs);
-    }
-
-    private void animateResizePipInternal(IWindowContainer wc, boolean scheduleFinishPip,
-            Rect currentBounds, Rect destinationBounds, int durationMs) {
-        try {
-            // Could happen when dismissPip
-            if (wc == null || wc.getLeash() == null) {
-                Log.w(TAG, "Abort animation, invalid leash");
-                return;
-            }
-            final SurfaceControl leash = wc.getLeash();
-
-            mMainHandler.post(() -> mPipAnimationController
-                    .getAnimator(wc, scheduleFinishPip, currentBounds, destinationBounds)
-                    .setPipAnimationCallback(mPipAnimationCallback)
-                    .setDuration(durationMs)
-                    .start());
-        } catch (RemoteException e) {
-            Log.w(TAG, "Abort animation, invalid window container", e);
-        } catch (Exception e) {
-            Log.e(TAG, "Should not reach here, terrible thing happened", e);
+    private void animateResizePip(boolean scheduleFinishPip, Rect currentBounds,
+            Rect destinationBounds, int durationMs) {
+        if (Looper.myLooper() != mUpdateHandler.getLooper()) {
+            throw new RuntimeException("Callers should call scheduleAnimateResizePip() instead of "
+                    + "this directly");
         }
+        // Could happen when dismissPip
+        if (mToken == null || mLeash == null) {
+            Log.w(TAG, "Abort animation, invalid leash");
+            return;
+        }
+        mUpdateHandler.post(() -> mPipAnimationController
+                .getAnimator(mLeash, scheduleFinishPip, currentBounds, destinationBounds)
+                .setPipAnimationCallback(mPipAnimationCallback)
+                .setDuration(durationMs)
+                .start());
     }
 
-
     private float getAspectRatioOrDefault(@Nullable PictureInPictureParams params) {
         return params == null
                 ? mPipBoundsHandler.getDefaultAspectRatio()
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 81e8a0b..fc04f79 100644
--- a/packages/SystemUI/src/com/android/systemui/pip/phone/PipMenuActivity.java
+++ b/packages/SystemUI/src/com/android/systemui/pip/phone/PipMenuActivity.java
@@ -60,6 +60,7 @@
 import android.os.UserHandle;
 import android.util.Log;
 import android.util.Pair;
+import android.view.KeyEvent;
 import android.view.LayoutInflater;
 import android.view.MotionEvent;
 import android.view.View;
@@ -226,6 +227,15 @@
     }
 
     @Override
+    public boolean onKeyUp(int keyCode, KeyEvent event) {
+        if (keyCode == KeyEvent.KEYCODE_ESCAPE) {
+            hideMenu();
+            return true;
+        }
+        return super.onKeyUp(keyCode, event);
+    }
+
+    @Override
     protected void onNewIntent(Intent intent) {
         super.onNewIntent(intent);
         updateFromIntent(intent);
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 fdaf66a..33760be 100644
--- a/packages/SystemUI/src/com/android/systemui/pip/phone/PipMotionHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/pip/phone/PipMotionHelper.java
@@ -28,16 +28,11 @@
 import android.graphics.PointF;
 import android.graphics.Rect;
 import android.os.Debug;
-import android.os.Handler;
-import android.os.Message;
 import android.os.RemoteException;
 import android.util.Log;
-import android.view.Choreographer;
 
 import androidx.dynamicanimation.animation.SpringForce;
 
-import com.android.internal.graphics.SfVsyncFrameCallbackProvider;
-import com.android.internal.os.SomeArgs;
 import com.android.systemui.pip.PipSnapAlgorithm;
 import com.android.systemui.pip.PipTaskOrganizer;
 import com.android.systemui.shared.system.WindowManagerWrapper;
@@ -47,11 +42,12 @@
 import com.android.systemui.util.animation.PhysicsAnimator;
 
 import java.io.PrintWriter;
+import java.util.function.Consumer;
 
 /**
  * A helper to animate and manipulate the PiP.
  */
-public class PipMotionHelper implements Handler.Callback, PipAppOpsListener.Callback,
+public class PipMotionHelper implements PipAppOpsListener.Callback,
         FloatingContentCoordinator.FloatingContent {
 
     private static final String TAG = "PipMotionHelper";
@@ -68,14 +64,9 @@
     // The fraction of the stack height that the user has to drag offscreen to dismiss the PiP
     private static final float DISMISS_OFFSCREEN_FRACTION = 0.3f;
 
-    private static final int MSG_RESIZE_IMMEDIATE = 1;
-    private static final int MSG_RESIZE_ANIMATE = 2;
-    private static final int MSG_OFFSET_ANIMATE = 3;
-
     private final Context mContext;
     private final IActivityTaskManager mActivityTaskManager;
     private final PipTaskOrganizer mPipTaskOrganizer;
-    private final Handler mHandler;
 
     private PipMenuActivityController mMenuController;
     private PipSnapAlgorithm mSnapAlgorithm;
@@ -92,9 +83,6 @@
     /** The region that all of PIP must stay within. */
     private Rect mFloatingAllowedArea = new Rect();
 
-    private final SfVsyncFrameCallbackProvider mSfVsyncFrameProvider =
-            new SfVsyncFrameCallbackProvider();
-
     /**
      * Bounds that are animated using the physics animator.
      */
@@ -112,16 +100,11 @@
     private PhysicsAnimator<Rect> mAnimatedBoundsPhysicsAnimator = PhysicsAnimator.getInstance(
             mAnimatedBounds);
 
-    /** Callback that re-sizes PIP to the animated bounds. */
-    private final Choreographer.FrameCallback mResizePipVsyncCallback =
-            l -> resizePipUnchecked(mAnimatedBounds);
-
     /**
-     * Update listener that posts a vsync frame callback to resize PIP to {@link #mAnimatedBounds}.
+     * Update listener that resizes the PIP to {@link #mAnimatedBounds}.
      */
-    private final PhysicsAnimator.UpdateListener<Rect> mResizePipVsyncUpdateListener =
-            (target, values) ->
-                    mSfVsyncFrameProvider.postFrameCallback(mResizePipVsyncCallback);
+    private final PhysicsAnimator.UpdateListener<Rect> mResizePipUpdateListener =
+            (target, values) -> resizePipUnchecked(mAnimatedBounds);
 
     /** FlingConfig instances provided to PhysicsAnimator for fling gestures. */
     private PhysicsAnimator.FlingConfig mFlingConfigX;
@@ -137,12 +120,13 @@
                 new PhysicsAnimator.SpringConfig(
                         SpringForce.STIFFNESS_LOW, SpringForce.DAMPING_RATIO_LOW_BOUNCY);
 
+    private final Consumer<Rect> mUpdateBoundsCallback = (toBounds) -> mBounds.set(toBounds);
+
     public PipMotionHelper(Context context, IActivityTaskManager activityTaskManager,
             PipTaskOrganizer pipTaskOrganizer, PipMenuActivityController menuController,
             PipSnapAlgorithm snapAlgorithm, FlingAnimationUtils flingAnimationUtils,
             FloatingContentCoordinator floatingContentCoordinator) {
         mContext = context;
-        mHandler = new Handler(ForegroundThread.get().getLooper(), this);
         mActivityTaskManager = activityTaskManager;
         mPipTaskOrganizer = pipTaskOrganizer;
         mMenuController = menuController;
@@ -234,7 +218,7 @@
         }
         cancelAnimations();
         mMenuController.hideMenuWithoutResize();
-        mHandler.post(() -> {
+        mPipTaskOrganizer.getUpdateHandler().post(() -> {
             try {
                 mActivityTaskManager.dismissPip(!skipAnimation, EXPAND_STACK_TO_FULLSCREEN_DURATION);
             } catch (RemoteException e) {
@@ -253,7 +237,7 @@
         }
         cancelAnimations();
         mMenuController.hideMenuWithoutResize();
-        mHandler.post(() -> {
+        mPipTaskOrganizer.getUpdateHandler().post(() -> {
             try {
                 mActivityTaskManager.removeStacksInWindowingModes(
                         new int[]{ WINDOWING_MODE_PINNED });
@@ -406,17 +390,13 @@
      * Animates the PiP to offset it from the IME or shelf.
      */
     void animateToOffset(Rect originalBounds, int offset) {
+        if (DEBUG) {
+            Log.d(TAG, "animateToOffset: originalBounds=" + originalBounds + " offset=" + offset
+                    + " callers=\n" + Debug.getCallers(5, "    "));
+        }
         cancelAnimations();
-        adjustAndAnimatePipOffset(originalBounds, offset, SHIFT_DURATION);
-    }
-
-    private void adjustAndAnimatePipOffset(Rect originalBounds, int offset, int duration) {
-        SomeArgs args = SomeArgs.obtain();
-        args.arg1 = originalBounds;
-        // offset would be zero if triggered from screen rotation.
-        args.argi1 = offset;
-        args.argi2 = duration;
-        mHandler.sendMessage(mHandler.obtainMessage(MSG_OFFSET_ANIMATE, args));
+        mPipTaskOrganizer.scheduleOffsetPip(originalBounds, offset, SHIFT_DURATION,
+                mUpdateBoundsCallback);
     }
 
     /**
@@ -437,8 +417,7 @@
 
     /**
      * Starts the physics animator which will update the animated PIP bounds using physics
-     * animations, as well as the TimeAnimator which will apply those bounds to PIP at intervals
-     * synchronized with the SurfaceFlinger vsync frame provider.
+     * animations, as well as the TimeAnimator which will apply those bounds to PIP.
      *
      * This will also add end actions to the bounds animator that cancel the TimeAnimator and update
      * the 'real' bounds to equal the final animated bounds.
@@ -448,7 +427,7 @@
 
         mAnimatedBoundsPhysicsAnimator
                 .withEndActions(() ->  mPipTaskOrganizer.onMotionMovementEnd(mAnimatedBounds))
-                .addUpdateListener(mResizePipVsyncUpdateListener)
+                .addUpdateListener(mResizePipUpdateListener)
                 .start();
     }
 
@@ -471,9 +450,7 @@
                     + " callers=\n" + Debug.getCallers(5, "    "));
         }
         if (!toBounds.equals(mBounds)) {
-            SomeArgs args = SomeArgs.obtain();
-            args.arg1 = toBounds;
-            mHandler.sendMessage(mHandler.obtainMessage(MSG_RESIZE_IMMEDIATE, args));
+            mPipTaskOrganizer.scheduleResizePip(toBounds, mUpdateBoundsCallback);
         }
     }
 
@@ -486,10 +463,7 @@
                     + " duration=" + duration + " callers=\n" + Debug.getCallers(5, "    "));
         }
         if (!toBounds.equals(mBounds)) {
-            SomeArgs args = SomeArgs.obtain();
-            args.arg1 = toBounds;
-            args.argi1 = duration;
-            mHandler.sendMessage(mHandler.obtainMessage(MSG_RESIZE_ANIMATE, args));
+            mPipTaskOrganizer.scheduleAnimateResizePip(toBounds, duration, mUpdateBoundsCallback);
             setAnimatingToBounds(toBounds);
         }
     }
@@ -538,70 +512,6 @@
         return dismissArea.contains(endpoint.x, endpoint.y);
     }
 
-    /**
-     * Handles messages to be processed on the background thread.
-     */
-    public boolean handleMessage(Message msg) {
-        switch (msg.what) {
-            case MSG_RESIZE_IMMEDIATE: {
-                SomeArgs args = (SomeArgs) msg.obj;
-                Rect toBounds = (Rect) args.arg1;
-                mPipTaskOrganizer.resizePip(toBounds);
-                mBounds.set(toBounds);
-                return true;
-            }
-
-            case MSG_RESIZE_ANIMATE: {
-                SomeArgs args = (SomeArgs) msg.obj;
-                Rect toBounds = (Rect) args.arg1;
-                int duration = args.argi1;
-                try {
-                    StackInfo stackInfo = mActivityTaskManager.getStackInfo(
-                            WINDOWING_MODE_PINNED, ACTIVITY_TYPE_UNDEFINED);
-                    if (stackInfo == null) {
-                        // In the case where we've already re-expanded or dismissed the PiP, then
-                        // just skip the resize
-                        return true;
-                    }
-
-                    mPipTaskOrganizer.animateResizePip(toBounds, duration);
-                    mBounds.set(toBounds);
-                } catch (RemoteException e) {
-                    Log.e(TAG, "Could not animate resize pinned stack to bounds: " + toBounds, e);
-                }
-                return true;
-            }
-
-            case MSG_OFFSET_ANIMATE: {
-                SomeArgs args = (SomeArgs) msg.obj;
-                Rect originalBounds = (Rect) args.arg1;
-                final int offset = args.argi1;
-                final int duration = args.argi2;
-                try {
-                    StackInfo stackInfo = mActivityTaskManager.getStackInfo(
-                            WINDOWING_MODE_PINNED, ACTIVITY_TYPE_UNDEFINED);
-                    if (stackInfo == null) {
-                        // In the case where we've already re-expanded or dismissed the PiP, then
-                        // just skip the resize
-                        return true;
-                    }
-
-                    mPipTaskOrganizer.offsetPinnedStack(originalBounds,
-                            0 /* xOffset */, offset, duration);
-                    Rect toBounds = new Rect(originalBounds);
-                    toBounds.offset(0, offset);
-                    mBounds.set(toBounds);
-                } catch (RemoteException e) {
-                    Log.e(TAG, "Could not animate offset pinned stack with offset: " + offset, e);
-                }
-                return true;
-            }
-
-            default:
-                return false;
-        }
-    }
-
     public void dump(PrintWriter pw, String prefix) {
         final String innerPrefix = prefix + "  ";
         pw.println(prefix + TAG);
diff --git a/packages/SystemUI/src/com/android/systemui/pip/phone/ForegroundThread.java b/packages/SystemUI/src/com/android/systemui/pip/phone/PipUpdateThread.java
similarity index 70%
rename from packages/SystemUI/src/com/android/systemui/pip/phone/ForegroundThread.java
rename to packages/SystemUI/src/com/android/systemui/pip/phone/PipUpdateThread.java
index 9bf46bb..6c5d846 100644
--- a/packages/SystemUI/src/com/android/systemui/pip/phone/ForegroundThread.java
+++ b/packages/SystemUI/src/com/android/systemui/pip/phone/PipUpdateThread.java
@@ -21,33 +21,38 @@
 
 /**
  * Similar to {@link com.android.internal.os.BackgroundThread}, this is a shared singleton
- * foreground thread for each process.
+ * foreground thread for each process for updating PIP.
  */
-public final class ForegroundThread extends HandlerThread {
-    private static ForegroundThread sInstance;
+public final class PipUpdateThread extends HandlerThread {
+    private static PipUpdateThread sInstance;
     private static Handler sHandler;
 
-    private ForegroundThread() {
-        super("recents.fg");
+    private PipUpdateThread() {
+        super("pip");
     }
 
     private static void ensureThreadLocked() {
         if (sInstance == null) {
-            sInstance = new ForegroundThread();
+            sInstance = new PipUpdateThread();
             sInstance.start();
             sHandler = new Handler(sInstance.getLooper());
         }
     }
 
-    public static ForegroundThread get() {
-        synchronized (ForegroundThread.class) {
+    /**
+     * @return the static update thread instance
+     */
+    public static PipUpdateThread get() {
+        synchronized (PipUpdateThread.class) {
             ensureThreadLocked();
             return sInstance;
         }
     }
-
+    /**
+     * @return the static update thread handler instance
+     */
     public static Handler getHandler() {
-        synchronized (ForegroundThread.class) {
+        synchronized (PipUpdateThread.class) {
             ensureThreadLocked();
             return sHandler;
         }
diff --git a/packages/SystemUI/src/com/android/systemui/pip/tv/PipManager.java b/packages/SystemUI/src/com/android/systemui/pip/tv/PipManager.java
index ca44f6b..a5e9dbc 100644
--- a/packages/SystemUI/src/com/android/systemui/pip/tv/PipManager.java
+++ b/packages/SystemUI/src/com/android/systemui/pip/tv/PipManager.java
@@ -20,6 +20,8 @@
 import static android.app.WindowConfiguration.ACTIVITY_TYPE_UNDEFINED;
 import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED;
 
+import static com.android.systemui.pip.PipAnimationController.DURATION_DEFAULT_MS;
+
 import android.app.ActivityManager.RunningTaskInfo;
 import android.app.ActivityManager.StackInfo;
 import android.app.ActivityTaskManager;
@@ -50,7 +52,6 @@
 import com.android.systemui.UiOffloadThread;
 import com.android.systemui.broadcast.BroadcastDispatcher;
 import com.android.systemui.pip.BasePipManager;
-import com.android.systemui.pip.PipAnimationController;
 import com.android.systemui.pip.PipBoundsHandler;
 import com.android.systemui.pip.PipTaskOrganizer;
 import com.android.systemui.shared.system.ActivityManagerWrapper;
@@ -233,6 +234,7 @@
         if (mInitialized) {
             return;
         }
+
         mInitialized = true;
         mContext = context;
         mPipBoundsHandler = pipBoundsHandler;
@@ -434,8 +436,7 @@
                 mCurrentPipBounds = mPipBounds;
                 break;
         }
-        mPipTaskOrganizer.animateResizePip(mCurrentPipBounds,
-                PipAnimationController.DURATION_DEFAULT_MS);
+        mPipTaskOrganizer.scheduleAnimateResizePip(mCurrentPipBounds, DURATION_DEFAULT_MS, null);
     }
 
     /**
diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/TakeScreenshotService.java b/packages/SystemUI/src/com/android/systemui/screenshot/TakeScreenshotService.java
index 37a8ca5..8b8b6f8 100644
--- a/packages/SystemUI/src/com/android/systemui/screenshot/TakeScreenshotService.java
+++ b/packages/SystemUI/src/com/android/systemui/screenshot/TakeScreenshotService.java
@@ -16,10 +16,6 @@
 
 package com.android.systemui.screenshot;
 
-import static android.provider.DeviceConfig.NAMESPACE_SYSTEMUI;
-
-import static com.android.internal.config.sysui.SystemUiDeviceConfigFlags.SCREENSHOT_CORNER_FLOW;
-
 import android.app.Service;
 import android.content.Intent;
 import android.graphics.Bitmap;
@@ -33,7 +29,6 @@
 import android.os.Messenger;
 import android.os.RemoteException;
 import android.os.UserManager;
-import android.provider.DeviceConfig;
 import android.util.Log;
 import android.view.WindowManager;
 
@@ -70,8 +65,7 @@
             }
 
             // TODO (mkephart): clean up once notifications flow is fully deprecated
-            boolean useCornerFlow = DeviceConfig.getBoolean(
-                    NAMESPACE_SYSTEMUI, SCREENSHOT_CORNER_FLOW, true);
+            boolean useCornerFlow = true;
             switch (msg.what) {
                 case WindowManager.TAKE_SCREENSHOT_FULLSCREEN:
                     if (useCornerFlow) {
diff --git a/packages/SystemUI/src/com/android/systemui/stackdivider/Divider.java b/packages/SystemUI/src/com/android/systemui/stackdivider/Divider.java
index 333fa3c..c6eecf26 100644
--- a/packages/SystemUI/src/com/android/systemui/stackdivider/Divider.java
+++ b/packages/SystemUI/src/com/android/systemui/stackdivider/Divider.java
@@ -17,6 +17,8 @@
 package com.android.systemui.stackdivider;
 
 import static android.content.res.Configuration.ORIENTATION_LANDSCAPE;
+import static android.content.res.Configuration.SCREEN_HEIGHT_DP_UNDEFINED;
+import static android.content.res.Configuration.SCREEN_WIDTH_DP_UNDEFINED;
 import static android.view.Display.DEFAULT_DISPLAY;
 
 import android.animation.Animator;
@@ -214,8 +216,22 @@
                     if (mTargetAdjusted) {
                         mSplitLayout.updateAdjustedBounds(mShownTop, mHiddenTop, mShownTop);
                         wct.setBounds(mSplits.mSecondary.token, mSplitLayout.mAdjustedSecondary);
+                        // "Freeze" the configuration size so that the app doesn't get a config
+                        // or relaunch. This is required because normally nav-bar contributes
+                        // to configuration bounds (via nondecorframe).
+                        Rect adjustAppBounds = new Rect(mSplits.mSecondary.configuration
+                                .windowConfiguration.getAppBounds());
+                        adjustAppBounds.offset(0, mSplitLayout.mAdjustedSecondary.top
+                                - mSplitLayout.mSecondary.top);
+                        wct.setAppBounds(mSplits.mSecondary.token, adjustAppBounds);
+                        wct.setScreenSizeDp(mSplits.mSecondary.token,
+                                mSplits.mSecondary.configuration.screenWidthDp,
+                                mSplits.mSecondary.configuration.screenHeightDp);
                     } else {
                         wct.setBounds(mSplits.mSecondary.token, mSplitLayout.mSecondary);
+                        wct.setAppBounds(mSplits.mSecondary.token, null);
+                        wct.setScreenSizeDp(mSplits.mSecondary.token,
+                                SCREEN_WIDTH_DP_UNDEFINED, SCREEN_HEIGHT_DP_UNDEFINED);
                     }
                     try {
                         ActivityTaskManager.getTaskOrganizerController()
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationGutsManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationGutsManager.java
index d746822..bd4984e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationGutsManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationGutsManager.java
@@ -315,7 +315,6 @@
                     mNotificationActivityStarter.startNotificationGutsIntent(intent, sbn.getUid(),
                             row);
                 };
-        boolean isForBlockingHelper = row.isBlockingHelperShowing();
 
         if (!userHandle.equals(UserHandle.ALL)
                 || mLockscreenUserManager.getCurrentUserId() == UserHandle.USER_SYSTEM) {
@@ -335,13 +334,10 @@
                 row.getEntry().getChannel(),
                 row.getUniqueChannels(),
                 row.getEntry(),
-                mCheckSaveListener,
                 onSettingsClick,
                 onAppSettingsClick,
                 mDeviceProvisionedController.isDeviceProvisioned(),
                 row.getIsNonblockable(),
-                isForBlockingHelper,
-                row.getEntry().getImportance(),
                 mHighPriorityProvider.isHighPriority(row.getEntry()));
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationInfo.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationInfo.java
index 6b4511d..12aa4df 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationInfo.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationInfo.java
@@ -24,10 +24,6 @@
 
 import static java.lang.annotation.RetentionPolicy.SOURCE;
 
-import android.animation.Animator;
-import android.animation.AnimatorListenerAdapter;
-import android.animation.AnimatorSet;
-import android.animation.ObjectAnimator;
 import android.annotation.IntDef;
 import android.annotation.Nullable;
 import android.app.INotificationManager;
@@ -53,7 +49,6 @@
 import android.util.AttributeSet;
 import android.util.Log;
 import android.view.View;
-import android.view.ViewGroup;
 import android.view.accessibility.AccessibilityEvent;
 import android.widget.ImageView;
 import android.widget.LinearLayout;
@@ -63,42 +58,33 @@
 import com.android.internal.logging.MetricsLogger;
 import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
 import com.android.systemui.Dependency;
-import com.android.systemui.Interpolators;
 import com.android.systemui.R;
 import com.android.systemui.statusbar.notification.VisualStabilityManager;
 import com.android.systemui.statusbar.notification.collection.NotificationEntry;
-import com.android.systemui.statusbar.notification.logging.NotificationCounters;
 
 import java.lang.annotation.Retention;
 import java.util.List;
 import java.util.Set;
 
 /**
- * The guts of a notification revealed when performing a long press. This also houses the blocking
- * helper affordance that allows a user to keep/stop notifications after swiping one away.
+ * The guts of a notification revealed when performing a long press.
  */
 public class NotificationInfo extends LinearLayout implements NotificationGuts.GutsContent {
     private static final String TAG = "InfoGuts";
 
     @IntDef(prefix = { "ACTION_" }, value = {
             ACTION_NONE,
-            ACTION_UNDO,
+            ACTION_TOGGLE_ALERT,
             ACTION_TOGGLE_SILENT,
-            ACTION_BLOCK,
     })
     public @interface NotificationInfoAction {
     }
 
     public static final int ACTION_NONE = 0;
-    static final int ACTION_UNDO = 1;
     // standard controls
     static final int ACTION_TOGGLE_SILENT = 2;
-    // unused
-    static final int ACTION_BLOCK = 3;
-    // blocking helper
-    static final int ACTION_DELIVER_SILENTLY = 4;
     // standard controls
-    private static final int ACTION_ALERT = 5;
+    private static final int ACTION_TOGGLE_ALERT = 5;
 
     private TextView mPriorityDescriptionView;
     private TextView mSilentDescriptionView;
@@ -128,101 +114,35 @@
     @Nullable private Integer mChosenImportance;
     private boolean mIsSingleDefaultChannel;
     private boolean mIsNonblockable;
-    private NotificationEntry mEntry;
     private StatusBarNotification mSbn;
-    private AnimatorSet mExpandAnimation;
     private boolean mIsDeviceProvisioned;
 
-    private CheckSaveListener mCheckSaveListener;
     private OnSettingsClickListener mOnSettingsClickListener;
     private OnAppSettingsClickListener mAppSettingsClickListener;
     private NotificationGuts mGutsContainer;
     private Drawable mPkgIcon;
 
-    /** Whether this view is being shown as part of the blocking helper. */
-    private boolean mIsForBlockingHelper;
-
     @VisibleForTesting
     boolean mSkipPost = false;
 
-    /**
-     * String that describes how the user exit or quit out of this view, also used as a counter tag.
-     */
-    private String mExitReason = NotificationCounters.BLOCKING_HELPER_DISMISSED;
-
-
     // used by standard ui
     private OnClickListener mOnAlert = v -> {
-        mExitReason = NotificationCounters.BLOCKING_HELPER_KEEP_SHOWING;
         mChosenImportance = IMPORTANCE_DEFAULT;
         applyAlertingBehavior(BEHAVIOR_ALERTING, true /* userTriggered */);
     };
 
     // used by standard ui
     private OnClickListener mOnSilent = v -> {
-        mExitReason = NotificationCounters.BLOCKING_HELPER_DELIVER_SILENTLY;
         mChosenImportance = IMPORTANCE_LOW;
         applyAlertingBehavior(BEHAVIOR_SILENT, true /* userTriggered */);
     };
 
-
     // used by standard ui
     private OnClickListener mOnDismissSettings = v -> {
         mPressedApply = true;
         closeControls(v, true);
     };
 
-    // used by blocking helper
-    private OnClickListener mOnKeepShowing = v -> {
-        mExitReason = NotificationCounters.BLOCKING_HELPER_KEEP_SHOWING;
-        closeControls(v, true);
-        mMetricsLogger.write(getLogMaker().setCategory(
-                MetricsEvent.NOTIFICATION_BLOCKING_HELPER)
-                .setType(MetricsEvent.TYPE_ACTION)
-                .setSubtype(MetricsEvent.BLOCKING_HELPER_CLICK_STAY_SILENT));
-    };
-
-    // used by blocking helper
-    private OnClickListener mOnDeliverSilently = v -> {
-        handleSaveImportance(
-                ACTION_DELIVER_SILENTLY, MetricsEvent.BLOCKING_HELPER_CLICK_STAY_SILENT);
-    };
-
-    private void handleSaveImportance(int action, int metricsSubtype) {
-        Runnable saveImportance = () -> {
-            saveImportanceAndExitReason(action);
-            if (mIsForBlockingHelper) {
-                swapContent(action, true /* animate */);
-                mMetricsLogger.write(getLogMaker()
-                        .setCategory(MetricsEvent.NOTIFICATION_BLOCKING_HELPER)
-                        .setType(MetricsEvent.TYPE_ACTION)
-                        .setSubtype(metricsSubtype));
-            }
-        };
-        if (mCheckSaveListener != null) {
-            mCheckSaveListener.checkSave(saveImportance, mSbn);
-        } else {
-            saveImportance.run();
-        }
-    }
-
-    private OnClickListener mOnUndo = v -> {
-        // Reset exit counter that we'll log and record an undo event separately (not an exit event)
-        mExitReason = NotificationCounters.BLOCKING_HELPER_DISMISSED;
-        if (mIsForBlockingHelper) {
-            logBlockingHelperCounter(NotificationCounters.BLOCKING_HELPER_UNDO);
-            mMetricsLogger.write(getLogMaker().setCategory(
-                    MetricsEvent.NOTIFICATION_BLOCKING_HELPER)
-                    .setType(MetricsEvent.TYPE_DISMISS)
-                    .setSubtype(MetricsEvent.BLOCKING_HELPER_CLICK_UNDO));
-        } else {
-            // TODO: this can't happen?
-            mMetricsLogger.write(importanceChangeLogMaker().setType(MetricsEvent.TYPE_DISMISS));
-        }
-        saveImportanceAndExitReason(ACTION_UNDO);
-        swapContent(ACTION_UNDO, true /* animate */);
-    };
-
     public NotificationInfo(Context context, AttributeSet attrs) {
         super(context, attrs);
     }
@@ -250,30 +170,6 @@
         void onClick(View v, Intent intent);
     }
 
-    @VisibleForTesting
-    void bindNotification(
-            final PackageManager pm,
-            final INotificationManager iNotificationManager,
-            final VisualStabilityManager visualStabilityManager,
-            final String pkg,
-            final NotificationChannel notificationChannel,
-            final Set<NotificationChannel> uniqueChannelsInRow,
-            final NotificationEntry entry,
-            final CheckSaveListener checkSaveListener,
-            final OnSettingsClickListener onSettingsClick,
-            final OnAppSettingsClickListener onAppSettingsClick,
-            boolean isDeviceProvisioned,
-            boolean isNonblockable,
-            int importance,
-            boolean wasShownHighPriority)
-            throws RemoteException {
-        bindNotification(pm, iNotificationManager, visualStabilityManager, pkg, notificationChannel,
-                uniqueChannelsInRow, entry, checkSaveListener, onSettingsClick,
-                onAppSettingsClick, isDeviceProvisioned, isNonblockable,
-                false /* isBlockingHelper */,
-                importance, wasShownHighPriority);
-    }
-
     public void bindNotification(
             PackageManager pm,
             INotificationManager iNotificationManager,
@@ -282,13 +178,10 @@
             NotificationChannel notificationChannel,
             Set<NotificationChannel> uniqueChannelsInRow,
             NotificationEntry entry,
-            CheckSaveListener checkSaveListener,
             OnSettingsClickListener onSettingsClick,
             OnAppSettingsClickListener onAppSettingsClick,
             boolean isDeviceProvisioned,
             boolean isNonblockable,
-            boolean isForBlockingHelper,
-            int importance,
             boolean wasShownHighPriority)
             throws RemoteException {
         mINotificationManager = iNotificationManager;
@@ -298,18 +191,15 @@
         mPackageName = pkg;
         mUniqueChannelsInRow = uniqueChannelsInRow;
         mNumUniqueChannelsInRow = uniqueChannelsInRow.size();
-        mEntry = entry;
         mSbn = entry.getSbn();
         mPm = pm;
         mAppSettingsClickListener = onAppSettingsClick;
         mAppName = mPackageName;
-        mCheckSaveListener = checkSaveListener;
         mOnSettingsClickListener = onSettingsClick;
         mSingleNotificationChannel = notificationChannel;
         mStartingChannelImportance = mSingleNotificationChannel.getImportance();
         mWasShownHighPriority = wasShownHighPriority;
         mIsNonblockable = isNonblockable;
-        mIsForBlockingHelper = isForBlockingHelper;
         mAppUid = mSbn.getUid();
         mDelegatePkg = mSbn.getOpPkg();
         mIsDeviceProvisioned = isDeviceProvisioned;
@@ -329,36 +219,12 @@
         bindHeader();
         bindChannelDetails();
 
-        if (mIsForBlockingHelper) {
-            bindBlockingHelper();
-        } else {
-            bindInlineControls();
-        }
+        bindInlineControls();
 
         mMetricsLogger.write(notificationControlsLogMaker());
     }
 
-    private void bindBlockingHelper() {
-        findViewById(R.id.inline_controls).setVisibility(GONE);
-        findViewById(R.id.blocking_helper).setVisibility(VISIBLE);
-
-        findViewById(R.id.undo).setOnClickListener(mOnUndo);
-
-        View turnOffButton = findViewById(R.id.blocking_helper_turn_off_notifications);
-        turnOffButton.setOnClickListener(getSettingsOnClickListener());
-        turnOffButton.setVisibility(turnOffButton.hasOnClickListeners() ? VISIBLE : GONE);
-
-        TextView keepShowing = findViewById(R.id.keep_showing);
-        keepShowing.setOnClickListener(mOnKeepShowing);
-
-        View deliverSilently = findViewById(R.id.deliver_silently);
-        deliverSilently.setOnClickListener(mOnDeliverSilently);
-    }
-
     private void bindInlineControls() {
-        findViewById(R.id.inline_controls).setVisibility(VISIBLE);
-        findViewById(R.id.blocking_helper).setVisibility(GONE);
-
         if (mIsNonblockable) {
             findViewById(R.id.non_configurable_text).setVisibility(VISIBLE);
             findViewById(R.id.non_configurable_multichannel_text).setVisibility(GONE);
@@ -414,8 +280,8 @@
             // app is gone, just show package name and generic icon
             mPkgIcon = mPm.getDefaultActivityIcon();
         }
-        ((ImageView) findViewById(R.id.pkgicon)).setImageDrawable(mPkgIcon);
-        ((TextView) findViewById(R.id.pkgname)).setText(mAppName);
+        ((ImageView) findViewById(R.id.pkg_icon)).setImageDrawable(mPkgIcon);
+        ((TextView) findViewById(R.id.pkg_name)).setText(mAppName);
 
         // Delegate
         bindDelegate();
@@ -445,8 +311,6 @@
         if (mAppUid >= 0 && mOnSettingsClickListener != null && mIsDeviceProvisioned) {
             final int appUidF = mAppUid;
             return ((View view) -> {
-                logBlockingHelperCounter(
-                        NotificationCounters.BLOCKING_HELPER_NOTIF_SETTINGS);
                 mOnSettingsClickListener.onClick(view,
                         mNumUniqueChannelsInRow > 1 ? null : mSingleNotificationChannel,
                         appUidF);
@@ -487,16 +351,13 @@
 
     private void bindDelegate() {
         TextView delegateView = findViewById(R.id.delegate_name);
-        TextView dividerView = findViewById(R.id.pkg_divider);
 
         CharSequence delegatePkg = null;
         if (!TextUtils.equals(mPackageName, mDelegatePkg)) {
             // this notification was posted by a delegate!
             delegateView.setVisibility(View.VISIBLE);
-            dividerView.setVisibility(View.VISIBLE);
         } else {
             delegateView.setVisibility(View.GONE);
-            dividerView.setVisibility(View.GONE);
         }
     }
 
@@ -512,25 +373,19 @@
             }
         }
         TextView groupNameView = findViewById(R.id.group_name);
+        View divider = findViewById(R.id.group_divider);
         if (groupName != null) {
             groupNameView.setText(groupName);
-            groupNameView.setVisibility(View.VISIBLE);
+            groupNameView.setVisibility(VISIBLE);
+            divider.setVisibility(VISIBLE);
         } else {
-            groupNameView.setVisibility(View.GONE);
-        }
-    }
-
-
-    @VisibleForTesting
-    void logBlockingHelperCounter(String counterTag) {
-        if (mIsForBlockingHelper) {
-            mMetricsLogger.count(counterTag, 1);
+            groupNameView.setVisibility(GONE);
+            divider.setVisibility(GONE);
         }
     }
 
     private void saveImportance() {
-        if (!mIsNonblockable
-                || mExitReason != NotificationCounters.BLOCKING_HELPER_STOP_NOTIFICATIONS) {
+        if (!mIsNonblockable) {
             if (mChosenImportance == null) {
                 mChosenImportance = mStartingChannelImportance;
             }
@@ -621,99 +476,13 @@
                 : R.string.inline_done_button);
     }
 
-    private void saveImportanceAndExitReason(@NotificationInfoAction int action) {
-        switch (action) {
-            case ACTION_UNDO:
-                mChosenImportance = mStartingChannelImportance;
-                break;
-            case ACTION_DELIVER_SILENTLY:
-                mExitReason = NotificationCounters.BLOCKING_HELPER_DELIVER_SILENTLY;
-                mChosenImportance = mWasShownHighPriority
-                        ? IMPORTANCE_LOW : mStartingChannelImportance;
-                break;
-            default:
-                throw new IllegalArgumentException();
-        }
-    }
-
-    // only used for blocking helper
-    private void swapContent(@NotificationInfoAction int action, boolean animate) {
-        if (mExpandAnimation != null) {
-            mExpandAnimation.cancel();
-        }
-
-        View blockingHelper = findViewById(R.id.blocking_helper);
-        ViewGroup confirmation = findViewById(R.id.confirmation);
-        TextView confirmationText = findViewById(R.id.confirmation_text);
-
-        saveImportanceAndExitReason(action);
-
-        switch (action) {
-            case ACTION_UNDO:
-                break;
-            case ACTION_DELIVER_SILENTLY:
-                confirmationText.setText(R.string.notification_channel_silenced);
-                break;
-            default:
-                throw new IllegalArgumentException();
-        }
-
-        boolean isUndo = action == ACTION_UNDO;
-
-        blockingHelper.setVisibility(isUndo ? VISIBLE : GONE);
-        findViewById(R.id.channel_info).setVisibility(isUndo ? VISIBLE : GONE);
-        findViewById(R.id.header).setVisibility(isUndo ? VISIBLE : GONE);
-        confirmation.setVisibility(isUndo ? GONE : VISIBLE);
-
-        if (animate) {
-            ObjectAnimator promptAnim = ObjectAnimator.ofFloat(blockingHelper, View.ALPHA,
-                    blockingHelper.getAlpha(), isUndo ? 1f : 0f);
-            promptAnim.setInterpolator(isUndo ? Interpolators.ALPHA_IN : Interpolators.ALPHA_OUT);
-            ObjectAnimator confirmAnim = ObjectAnimator.ofFloat(confirmation, View.ALPHA,
-                    confirmation.getAlpha(), isUndo ? 0f : 1f);
-            confirmAnim.setInterpolator(isUndo ? Interpolators.ALPHA_OUT : Interpolators.ALPHA_IN);
-
-            mExpandAnimation = new AnimatorSet();
-            mExpandAnimation.playTogether(promptAnim, confirmAnim);
-            mExpandAnimation.setDuration(150);
-            mExpandAnimation.addListener(new AnimatorListenerAdapter() {
-                boolean mCancelled = false;
-
-                @Override
-                public void onAnimationCancel(Animator animation) {
-                    mCancelled = true;
-                }
-
-                @Override
-                public void onAnimationEnd(Animator animation) {
-                    if (!mCancelled) {
-                        blockingHelper.setVisibility(isUndo ? VISIBLE : GONE);
-                        confirmation.setVisibility(isUndo ? GONE : VISIBLE);
-                    }
-                }
-            });
-            mExpandAnimation.start();
-        }
-
-        // Since we're swapping/update the content, reset the timeout so the UI can't close
-        // immediately after the update.
-        if (mGutsContainer != null) {
-            mGutsContainer.resetFalsingCheck();
-        }
-    }
-
     @Override
     public void onFinishedClosing() {
         if (mChosenImportance != null) {
             mStartingChannelImportance = mChosenImportance;
         }
-        mExitReason = NotificationCounters.BLOCKING_HELPER_DISMISSED;
 
-        if (mIsForBlockingHelper) {
-            bindBlockingHelper();
-        } else {
-            bindInlineControls();
-        }
+        bindInlineControls();
 
         mMetricsLogger.write(notificationControlsLogMaker().setType(MetricsEvent.TYPE_CLOSE));
     }
@@ -756,13 +525,10 @@
     }
 
     /**
-     * Closes the controls and commits the updated importance values (indirectly). If this view is
-     * being used to show the blocking helper, this will immediately dismiss the blocking helper and
-     * commit the updated importance.
+     * Closes the controls and commits the updated importance values (indirectly).
      *
      * <p><b>Note,</b> this will only get called once the view is dismissing. This means that the
-     * user does not have the ability to undo the action anymore. See
-     * {@link #swapContent(boolean, boolean)} for where undo is handled.
+     * user does not have the ability to undo the action anymore.
      */
     @VisibleForTesting
     void closeControls(View v, boolean save) {
@@ -811,7 +577,6 @@
         if (save) {
             saveImportance();
         }
-        logBlockingHelperCounter(mExitReason);
         return false;
     }
 
@@ -822,7 +587,7 @@
 
     @VisibleForTesting
     public boolean isAnimating() {
-        return mExpandAnimation != null && mExpandAnimation.isRunning();
+        return false;
     }
 
     /**
@@ -901,8 +666,7 @@
     private LogMaker notificationControlsLogMaker() {
         return getLogMaker().setCategory(MetricsEvent.ACTION_NOTE_CONTROLS)
                 .setType(MetricsEvent.TYPE_OPEN)
-                .setSubtype(mIsForBlockingHelper ? MetricsEvent.BLOCKING_HELPER_DISPLAY
-                        : MetricsEvent.BLOCKING_HELPER_UNKNOWN);
+                .setSubtype(MetricsEvent.BLOCKING_HELPER_UNKNOWN);
     }
 
     @Retention(SOURCE)
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationUndoLayout.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationUndoLayout.java
deleted file mode 100644
index 3ea8195..0000000
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationUndoLayout.java
+++ /dev/null
@@ -1,139 +0,0 @@
-/*
- * Copyright (C) 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License
- */
-
-package com.android.systemui.statusbar.notification.row;
-
-import android.content.Context;
-import android.util.AttributeSet;
-import android.view.View;
-import android.widget.FrameLayout;
-
-import com.android.systemui.R;
-
-/**
- * Custom view for the NotificationInfo confirmation views so that the confirmation text can
- * occupy the full width of the notification and push the undo button down to the next line if
- * necessary.
- *
- * @see NotificationInfo
- */
-public class NotificationUndoLayout extends FrameLayout {
-    /**
-     * View for the prompt/confirmation text to tell the user the previous action was successful.
-     */
-    private View mConfirmationTextView;
-    /** Undo button (actionable text) view. */
-    private View mUndoView;
-
-    /**
-     * Whether {@link #mConfirmationTextView} is multiline and will require the full width of the
-     * parent (which causes the {@link #mUndoView} to push down).
-     */
-    private boolean mIsMultiline = false;
-    private int mMultilineTopMargin;
-
-    public NotificationUndoLayout(Context context) {
-        this(context, null);
-    }
-
-    public NotificationUndoLayout(Context context, AttributeSet attrs) {
-        this(context, attrs, 0);
-    }
-
-    public NotificationUndoLayout(Context context, AttributeSet attrs, int defStyleAttr) {
-        super(context, attrs, defStyleAttr);
-    }
-    @Override
-    protected void onFinishInflate() {
-        super.onFinishInflate();
-
-        mConfirmationTextView = findViewById(R.id.confirmation_text);
-        mUndoView = findViewById(R.id.undo);
-
-        mMultilineTopMargin = getResources().getDimensionPixelOffset(
-                com.android.internal.R.dimen.notification_content_margin_start);
-    }
-
-    @Override
-    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
-        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
-
-        LayoutParams confirmationLayoutParams =
-                (LayoutParams) mConfirmationTextView.getLayoutParams();
-        LayoutParams undoLayoutParams =(LayoutParams) mUndoView.getLayoutParams();
-
-        int measuredWidth = getMeasuredWidth();
-        // Ignore the left margin on the undo button - no need for additional extra space between
-        // the text and the button.
-        int requiredWidth = mConfirmationTextView.getMeasuredWidth()
-                + confirmationLayoutParams.rightMargin
-                + confirmationLayoutParams.leftMargin
-                + mUndoView.getMeasuredWidth()
-                + undoLayoutParams.rightMargin;
-        // If the measured width isn't enough to accommodate both the undo button and the text in
-        // the same line, we'll need to adjust the view to be multi-line. Otherwise, we're done.
-        if (requiredWidth > measuredWidth) {
-            mIsMultiline = true;
-
-            // Update height requirement to the text height and the button's height (along with
-            // additional spacing for the top of the text).
-            int updatedHeight = mMultilineTopMargin
-                    + mConfirmationTextView.getMeasuredHeight()
-                    + mUndoView.getMeasuredHeight()
-                    + undoLayoutParams.topMargin
-                    + undoLayoutParams.bottomMargin;
-
-            setMeasuredDimension(measuredWidth, updatedHeight);
-        } else {
-            mIsMultiline = false;
-        }
-    }
-
-    @Override
-    protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
-        // If the text view and undo view don't fit on the same line, we'll need to manually lay
-        // out the content.
-        if (mIsMultiline) {
-            // Re-align parent right/bottom values. Left and top are considered to be 0.
-            int parentBottom = getMeasuredHeight();
-            int parentRight = getMeasuredWidth();
-
-            LayoutParams confirmationLayoutParams =
-                    (LayoutParams) mConfirmationTextView.getLayoutParams();
-            LayoutParams undoLayoutParams = (LayoutParams) mUndoView.getLayoutParams();
-
-            // The confirmation text occupies the full width as computed earlier. Both side margins
-            // are equivalent, so we only need to grab the left one here.
-            mConfirmationTextView.layout(
-                    confirmationLayoutParams.leftMargin,
-                    mMultilineTopMargin,
-                    confirmationLayoutParams.leftMargin + mConfirmationTextView.getMeasuredWidth(),
-                    mMultilineTopMargin + mConfirmationTextView.getMeasuredHeight());
-
-            // The undo button is aligned bottom|end with the parent in the case of multiline text.
-            int undoViewLeft = getLayoutDirection() == View.LAYOUT_DIRECTION_RTL
-                    ? undoLayoutParams.rightMargin
-                    : parentRight - mUndoView.getMeasuredWidth() - undoLayoutParams.rightMargin;
-            mUndoView.layout(
-                    undoViewLeft,
-                    parentBottom - mUndoView.getMeasuredHeight() - undoLayoutParams.bottomMargin,
-                    undoViewLeft + mUndoView.getMeasuredWidth(),
-                    parentBottom - undoLayoutParams.bottomMargin);
-        } else {
-            super.onLayout(changed, left, top, right, bottom);
-        }
-    }
-}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/LockIcon.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/LockIcon.java
index c29ec9e..cf9d43e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/LockIcon.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/LockIcon.java
@@ -26,7 +26,6 @@
 import android.graphics.drawable.Animatable2;
 import android.graphics.drawable.AnimatedVectorDrawable;
 import android.graphics.drawable.Drawable;
-import android.hardware.biometrics.BiometricSourceType;
 import android.os.Trace;
 import android.provider.Settings;
 import android.text.TextUtils;
@@ -34,22 +33,17 @@
 import android.view.ViewTreeObserver;
 import android.view.accessibility.AccessibilityNodeInfo;
 
-import androidx.annotation.Nullable;
-
 import com.android.internal.graphics.ColorUtils;
 import com.android.keyguard.KeyguardUpdateMonitor;
-import com.android.keyguard.KeyguardUpdateMonitorCallback;
 import com.android.systemui.Dependency;
 import com.android.systemui.Interpolators;
 import com.android.systemui.R;
-import com.android.systemui.dock.DockManager;
 import com.android.systemui.statusbar.KeyguardAffordanceView;
 import com.android.systemui.statusbar.StatusBarState;
 import com.android.systemui.statusbar.notification.NotificationWakeUpCoordinator;
 import com.android.systemui.statusbar.phone.ScrimController.ScrimVisibility;
 import com.android.systemui.statusbar.policy.AccessibilityController;
 import com.android.systemui.statusbar.policy.KeyguardStateController;
-import com.android.systemui.statusbar.policy.OnHeadsUpChangedListener;
 
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
@@ -61,8 +55,7 @@
  * Manages the different states and animations of the unlock icon.
  */
 public class LockIcon extends KeyguardAffordanceView implements
-        KeyguardStateController.Callback, NotificationWakeUpCoordinator.WakeUpListener,
-        ViewTreeObserver.OnPreDrawListener, OnHeadsUpChangedListener {
+        ViewTreeObserver.OnPreDrawListener {
 
     private static final int STATE_LOCKED = 0;
     private static final int STATE_LOCK_OPEN = 1;
@@ -70,7 +63,6 @@
     private static final int STATE_BIOMETRICS_ERROR = 3;
     private final KeyguardUpdateMonitor mKeyguardUpdateMonitor;
     private final AccessibilityController mAccessibilityController;
-    private final DockManager mDockManager;
     private final KeyguardStateController mKeyguardStateController;
     private final KeyguardBypassController mBypassController;
     private final NotificationWakeUpCoordinator mWakeUpCoordinator;
@@ -130,43 +122,6 @@
                     update();
                 }
             };
-    private final DockManager.DockEventListener mDockEventListener =
-            new DockManager.DockEventListener() {
-                @Override
-                public void onEvent(int event) {
-                    boolean docked = event == DockManager.STATE_DOCKED
-                            || event == DockManager.STATE_DOCKED_HIDE;
-                    if (docked != mDocked) {
-                        mDocked = docked;
-                        update();
-                    }
-        }
-    };
-
-    private final KeyguardUpdateMonitorCallback mUpdateMonitorCallback =
-            new KeyguardUpdateMonitorCallback() {
-                @Override
-                public void onSimStateChanged(int subId, int slotId, int simState) {
-                    mSimLocked = mKeyguardUpdateMonitor.isSimPinSecure();
-                    update();
-                }
-
-                @Override
-                public void onKeyguardVisibilityChanged(boolean showing) {
-                    update();
-                }
-
-                @Override
-                public void onBiometricRunningStateChanged(boolean running,
-                        BiometricSourceType biometricSourceType) {
-                    update();
-                }
-
-                @Override
-                public void onStrongAuthStateChanged(int userId) {
-                    update();
-                }
-    };
 
     @Inject
     public LockIcon(@Named(VIEW_CONTEXT) Context context, AttributeSet attrs,
@@ -174,7 +129,6 @@
             KeyguardBypassController bypassController,
             NotificationWakeUpCoordinator wakeUpCoordinator,
             KeyguardStateController keyguardStateController,
-            @Nullable DockManager dockManager,
             HeadsUpManagerPhone headsUpManager) {
         super(context, attrs);
         mContext = context;
@@ -183,7 +137,6 @@
         mBypassController = bypassController;
         mWakeUpCoordinator = wakeUpCoordinator;
         mKeyguardStateController = keyguardStateController;
-        mDockManager = dockManager;
         mHeadsUpManager = headsUpManager;
     }
 
@@ -191,24 +144,14 @@
     protected void onAttachedToWindow() {
         super.onAttachedToWindow();
         mKeyguardStateController.addCallback(mKeyguardMonitorCallback);
-        mKeyguardUpdateMonitor.registerCallback(mUpdateMonitorCallback);
-        mWakeUpCoordinator.addListener(this);
         mSimLocked = mKeyguardUpdateMonitor.isSimPinSecure();
-        if (mDockManager != null) {
-            mDockManager.addListener(mDockEventListener);
-        }
         update();
     }
 
     @Override
     protected void onDetachedFromWindow() {
         super.onDetachedFromWindow();
-        mKeyguardUpdateMonitor.removeCallback(mUpdateMonitorCallback);
         mKeyguardStateController.removeCallback(mKeyguardMonitorCallback);
-        mWakeUpCoordinator.removeListener(this);
-        if (mDockManager != null) {
-            mDockManager.removeListener(mDockEventListener);
-        }
     }
 
     /**
@@ -306,7 +249,7 @@
      * Update the icon visibility
      * @return true if the visibility changed
      */
-    private boolean updateIconVisibility() {
+    boolean updateIconVisibility() {
         boolean onAodNotPulsingOrDocked = mDozing && (!mPulsing || mDocked);
         boolean invisible = onAodNotPulsingOrDocked || mWakeAndUnlockRunning
                 || mShowingLaunchAffordance;
@@ -424,16 +367,6 @@
         return -1;
     }
 
-    @Override
-    public void onFullyHiddenChanged(boolean isFullyHidden) {
-        if (mBypassController.getBypassEnabled()) {
-            boolean changed = updateIconVisibility();
-            if (changed) {
-                update();
-            }
-        }
-    }
-
     public void setBouncerShowingScrimmed(boolean bouncerShowing) {
         mBouncerShowingScrimmed = bouncerShowing;
         if (mBypassController.getBypassEnabled()) {
@@ -454,6 +387,18 @@
         updateDarkTint();
     }
 
+    void setSimLocked(boolean simLocked) {
+        mSimLocked = simLocked;
+    }
+
+    /** Set if the device is docked. */
+    public void setDocked(boolean docked) {
+        if (mDocked != docked) {
+            mDocked = docked;
+            update();
+        }
+    }
+
     @Retention(RetentionPolicy.SOURCE)
     @IntDef({ERROR, UNLOCK, LOCK, SCANNING})
     @interface LockAnimIndex {}
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 698a430..2b1a8a4 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/LockscreenLockIconController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/LockscreenLockIconController.java
@@ -18,20 +18,29 @@
 
 import android.content.res.TypedArray;
 import android.graphics.Color;
+import android.hardware.biometrics.BiometricSourceType;
 import android.view.View;
 import android.view.ViewGroup;
 
+import androidx.annotation.Nullable;
+
 import com.android.internal.logging.nano.MetricsProto;
 import com.android.internal.widget.LockPatternUtils;
 import com.android.keyguard.KeyguardUpdateMonitor;
+import com.android.keyguard.KeyguardUpdateMonitorCallback;
 import com.android.systemui.R;
+import com.android.systemui.dock.DockManager;
 import com.android.systemui.plugins.statusbar.StatusBarStateController;
 import com.android.systemui.statusbar.CommandQueue;
 import com.android.systemui.statusbar.KeyguardIndicationController;
+import com.android.systemui.statusbar.notification.NotificationWakeUpCoordinator;
+import com.android.systemui.statusbar.notification.NotificationWakeUpCoordinator.WakeUpListener;
 import com.android.systemui.statusbar.policy.AccessibilityController;
 import com.android.systemui.statusbar.policy.ConfigurationController;
 import com.android.systemui.statusbar.policy.ConfigurationController.ConfigurationListener;
 
+import java.util.Optional;
+
 import javax.inject.Inject;
 import javax.inject.Singleton;
 
@@ -47,6 +56,9 @@
     private final KeyguardIndicationController mKeyguardIndicationController;
     private final StatusBarStateController mStatusBarStateController;
     private final ConfigurationController mConfigurationController;
+    private final NotificationWakeUpCoordinator mNotificationWakeUpCoordinator;
+    private final KeyguardBypassController mKeyguardBypassController;
+    private final Optional<DockManager> mDockManager;
     private LockIcon mLockIcon;
 
     private View.OnAttachStateChangeListener mOnAttachStateChangeListener =
@@ -55,6 +67,10 @@
         public void onViewAttachedToWindow(View v) {
             mStatusBarStateController.addCallback(mSBStateListener);
             mConfigurationController.addCallback(mConfigurationListener);
+            mNotificationWakeUpCoordinator.addListener(mWakeUpListener);
+            mKeyguardUpdateMonitor.registerCallback(mUpdateMonitorCallback);
+
+            mDockManager.ifPresent(dockManager -> dockManager.addListener(mDockEventListener));
 
             mConfigurationListener.onThemeChanged();
         }
@@ -63,6 +79,11 @@
         public void onViewDetachedFromWindow(View v) {
             mStatusBarStateController.removeCallback(mSBStateListener);
             mConfigurationController.removeCallback(mConfigurationListener);
+            mNotificationWakeUpCoordinator.removeListener(mWakeUpListener);
+            mKeyguardUpdateMonitor.removeCallback(mUpdateMonitorCallback);
+
+
+            mDockManager.ifPresent(dockManager -> dockManager.removeListener(mDockEventListener));
         }
     };
 
@@ -115,6 +136,47 @@
         }
     };
 
+    private final WakeUpListener mWakeUpListener = new WakeUpListener() {
+        @Override
+        public void onFullyHiddenChanged(boolean isFullyHidden) {
+            if (mKeyguardBypassController.getBypassEnabled()) {
+                boolean changed = mLockIcon.updateIconVisibility();
+                if (changed) {
+                    mLockIcon.update();
+                }
+            }
+        }
+    };
+
+    private final KeyguardUpdateMonitorCallback mUpdateMonitorCallback =
+            new KeyguardUpdateMonitorCallback() {
+                @Override
+                public void onSimStateChanged(int subId, int slotId, int simState) {
+                    mLockIcon.setSimLocked(mKeyguardUpdateMonitor.isSimPinSecure());
+                    mLockIcon.update();
+                }
+
+                @Override
+                public void onKeyguardVisibilityChanged(boolean showing) {
+                    mLockIcon.update();
+                }
+
+                @Override
+                public void onBiometricRunningStateChanged(boolean running,
+                        BiometricSourceType biometricSourceType) {
+                    mLockIcon.update();
+                }
+
+                @Override
+                public void onStrongAuthStateChanged(int userId) {
+                    mLockIcon.update();
+                }
+            };
+
+    private final DockManager.DockEventListener mDockEventListener =
+            event -> mLockIcon.setDocked(event == DockManager.STATE_DOCKED
+                    || event == DockManager.STATE_DOCKED_HIDE);
+
     @Inject
     public LockscreenLockIconController(LockscreenGestureLogger lockscreenGestureLogger,
             KeyguardUpdateMonitor keyguardUpdateMonitor,
@@ -123,7 +185,10 @@
             AccessibilityController accessibilityController,
             KeyguardIndicationController keyguardIndicationController,
             StatusBarStateController statusBarStateController,
-            ConfigurationController configurationController) {
+            ConfigurationController configurationController,
+            NotificationWakeUpCoordinator notificationWakeUpCoordinator,
+            KeyguardBypassController keyguardBypassController,
+            @Nullable DockManager dockManager) {
         mLockscreenGestureLogger = lockscreenGestureLogger;
         mKeyguardUpdateMonitor = keyguardUpdateMonitor;
         mLockPatternUtils = lockPatternUtils;
@@ -132,6 +197,9 @@
         mKeyguardIndicationController = keyguardIndicationController;
         mStatusBarStateController = statusBarStateController;
         mConfigurationController = configurationController;
+        mNotificationWakeUpCoordinator = notificationWakeUpCoordinator;
+        mKeyguardBypassController = keyguardBypassController;
+        mDockManager = dockManager == null ? Optional.empty() : Optional.of(dockManager);
 
         mKeyguardIndicationController.setLockIconController(this);
     }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java
index d2d76c7..b84208c 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java
@@ -23,7 +23,6 @@
 import static android.net.wifi.WifiManager.TrafficStateCallback.DATA_ACTIVITY_NONE;
 import static android.net.wifi.WifiManager.TrafficStateCallback.DATA_ACTIVITY_OUT;
 import static android.telephony.PhoneStateListener.LISTEN_ACTIVE_DATA_SUBSCRIPTION_ID_CHANGE;
-import static android.telephony.TelephonyManager.MODEM_COUNT_DUAL_MODEM;
 
 import android.content.BroadcastReceiver;
 import android.content.Context;
@@ -606,7 +605,7 @@
     }
 
     private void filterMobileSubscriptionInSameGroup(List<SubscriptionInfo> subscriptions) {
-        if (subscriptions.size() == MODEM_COUNT_DUAL_MODEM) {
+        if (subscriptions.size() == 2) {
             SubscriptionInfo info1 = subscriptions.get(0);
             SubscriptionInfo info2 = subscriptions.get(1);
             if (info1.getGroupUuid() != null && info1.getGroupUuid().equals(info2.getGroupUuid())) {
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 6c09a46..cd46110 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/pip/PipAnimationControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/pip/PipAnimationControllerTest.java
@@ -26,7 +26,6 @@
 import android.graphics.Rect;
 import android.testing.AndroidTestingRunner;
 import android.testing.TestableLooper;
-import android.view.IWindowContainer;
 import android.view.SurfaceControl;
 
 import androidx.test.filters.SmallTest;
@@ -51,7 +50,7 @@
     private PipAnimationController mPipAnimationController;
 
     @Mock
-    private IWindowContainer mWindowContainer;
+    private SurfaceControl mLeash;
 
     @Mock
     private PipAnimationController.PipAnimationCallback mPipAnimationCallback;
@@ -65,8 +64,7 @@
     @Test
     public void getAnimator_withAlpha_returnFloatAnimator() {
         final PipAnimationController.PipTransitionAnimator animator = mPipAnimationController
-                .getAnimator(mWindowContainer, true /* scheduleFinishPip */,
-                        new Rect(), 0f, 1f);
+                .getAnimator(mLeash, true /* scheduleFinishPip */, new Rect(), 0f, 1f);
 
         assertEquals("Expect ANIM_TYPE_ALPHA animation",
                 animator.getAnimationType(), PipAnimationController.ANIM_TYPE_ALPHA);
@@ -75,8 +73,7 @@
     @Test
     public void getAnimator_withBounds_returnBoundsAnimator() {
         final PipAnimationController.PipTransitionAnimator animator = mPipAnimationController
-                .getAnimator(mWindowContainer, true /* scheduleFinishPip */,
-                        new Rect(), new Rect());
+                .getAnimator(mLeash, true /* scheduleFinishPip */, new Rect(), new Rect());
 
         assertEquals("Expect ANIM_TYPE_BOUNDS animation",
                 animator.getAnimationType(), PipAnimationController.ANIM_TYPE_BOUNDS);
@@ -88,14 +85,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(mWindowContainer, true /* scheduleFinishPip */,
-                        startValue, endValue1);
+                .getAnimator(mLeash, true /* scheduleFinishPip */, startValue, endValue1);
         oldAnimator.setSurfaceControlTransactionFactory(DummySurfaceControlTx::new);
         oldAnimator.start();
 
         final PipAnimationController.PipTransitionAnimator newAnimator = mPipAnimationController
-                .getAnimator(mWindowContainer, true /* scheduleFinishPip */,
-                        startValue, endValue2);
+                .getAnimator(mLeash, true /* scheduleFinishPip */, startValue, endValue2);
 
         assertEquals("getAnimator with same type returns same animator",
                 oldAnimator, newAnimator);
@@ -106,13 +101,11 @@
     @Test
     public void getAnimator_scheduleFinishPip() {
         PipAnimationController.PipTransitionAnimator animator = mPipAnimationController
-                .getAnimator(mWindowContainer, true /* scheduleFinishPip */,
-                        new Rect(), 0f, 1f);
+                .getAnimator(mLeash, true /* scheduleFinishPip */, new Rect(), 0f, 1f);
         assertTrue("scheduleFinishPip is true", animator.shouldScheduleFinishPip());
 
         animator = mPipAnimationController
-                .getAnimator(mWindowContainer, false /* scheduleFinishPip */,
-                        new Rect(), 0f, 1f);
+                .getAnimator(mLeash, false /* scheduleFinishPip */, new Rect(), 0f, 1f);
         assertFalse("scheduleFinishPip is false", animator.shouldScheduleFinishPip());
     }
 
@@ -122,8 +115,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(mWindowContainer, true /* scheduleFinishPip */,
-                        startValue, endValue1);
+                .getAnimator(mLeash, true /* scheduleFinishPip */, startValue, endValue1);
 
         animator.updateEndValue(endValue2);
 
@@ -135,24 +127,23 @@
         final Rect startValue = new Rect(0, 0, 100, 100);
         final Rect endValue = new Rect(100, 100, 200, 200);
         final PipAnimationController.PipTransitionAnimator animator = mPipAnimationController
-                .getAnimator(mWindowContainer, true /* scheduleFinishPip */,
-                        startValue, endValue);
+                .getAnimator(mLeash, true /* scheduleFinishPip */, startValue, endValue);
         animator.setSurfaceControlTransactionFactory(DummySurfaceControlTx::new);
 
         animator.setPipAnimationCallback(mPipAnimationCallback);
 
         // onAnimationStart triggers onPipAnimationStart
         animator.onAnimationStart(animator);
-        verify(mPipAnimationCallback).onPipAnimationStart(mWindowContainer, animator);
+        verify(mPipAnimationCallback).onPipAnimationStart(animator);
 
         // onAnimationCancel triggers onPipAnimationCancel
         animator.onAnimationCancel(animator);
-        verify(mPipAnimationCallback).onPipAnimationCancel(mWindowContainer, animator);
+        verify(mPipAnimationCallback).onPipAnimationCancel(animator);
 
         // onAnimationEnd triggers onPipAnimationEnd
         animator.onAnimationEnd(animator);
-        verify(mPipAnimationCallback).onPipAnimationEnd(eq(mWindowContainer),
-                any(SurfaceControl.Transaction.class), eq(animator));
+        verify(mPipAnimationCallback).onPipAnimationEnd(any(SurfaceControl.Transaction.class),
+                eq(animator));
     }
 
     /**
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationGutsManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationGutsManagerTest.java
index 54c0bde..e9dca699 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationGutsManagerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationGutsManagerTest.java
@@ -316,74 +316,9 @@
     }
 
     @Test
-    public void testInitializeNotificationInfoView_showBlockingHelper() throws Exception {
-        NotificationInfo notificationInfoView = mock(NotificationInfo.class);
-        ExpandableNotificationRow row = spy(mHelper.createRow());
-        row.setBlockingHelperShowing(true);
-        modifyRanking(row.getEntry())
-                .setUserSentiment(USER_SENTIMENT_NEGATIVE)
-                .build();
-        when(row.getIsNonblockable()).thenReturn(false);
-        StatusBarNotification statusBarNotification = row.getEntry().getSbn();
-        NotificationEntry entry = row.getEntry();
-
-        mGutsManager.initializeNotificationInfo(row, notificationInfoView);
-
-        verify(notificationInfoView).bindNotification(
-                any(PackageManager.class),
-                any(INotificationManager.class),
-                eq(mVisualStabilityManager),
-                eq(statusBarNotification.getPackageName()),
-                any(NotificationChannel.class),
-                anySet(),
-                eq(entry),
-                any(NotificationInfo.CheckSaveListener.class),
-                any(NotificationInfo.OnSettingsClickListener.class),
-                any(NotificationInfo.OnAppSettingsClickListener.class),
-                eq(false),
-                eq(false),
-                eq(true) /* isForBlockingHelper */,
-                eq(0),
-                eq(false) /* wasShownHighPriority */);
-    }
-
-    @Test
-    public void testInitializeNotificationInfoView_dontShowBlockingHelper() throws Exception {
-        NotificationInfo notificationInfoView = mock(NotificationInfo.class);
-        ExpandableNotificationRow row = spy(mHelper.createRow());
-        row.setBlockingHelperShowing(false);
-        modifyRanking(row.getEntry())
-                .setUserSentiment(USER_SENTIMENT_NEGATIVE)
-                .build();
-        when(row.getIsNonblockable()).thenReturn(false);
-        StatusBarNotification statusBarNotification = row.getEntry().getSbn();
-        NotificationEntry entry = row.getEntry();
-
-        mGutsManager.initializeNotificationInfo(row, notificationInfoView);
-
-        verify(notificationInfoView).bindNotification(
-                any(PackageManager.class),
-                any(INotificationManager.class),
-                eq(mVisualStabilityManager),
-                eq(statusBarNotification.getPackageName()),
-                any(NotificationChannel.class),
-                anySet(),
-                eq(entry),
-                any(NotificationInfo.CheckSaveListener.class),
-                any(NotificationInfo.OnSettingsClickListener.class),
-                any(NotificationInfo.OnAppSettingsClickListener.class),
-                eq(false),
-                eq(false),
-                eq(false) /* isForBlockingHelper */,
-                eq(0),
-                eq(false) /* wasShownHighPriority */);
-    }
-
-    @Test
     public void testInitializeNotificationInfoView_highPriority() throws Exception {
         NotificationInfo notificationInfoView = mock(NotificationInfo.class);
         ExpandableNotificationRow row = spy(mHelper.createRow());
-        row.setBlockingHelperShowing(true);
         final NotificationEntry entry = row.getEntry();
         modifyRanking(entry)
                 .setUserSentiment(USER_SENTIMENT_NEGATIVE)
@@ -403,13 +338,10 @@
                 any(NotificationChannel.class),
                 anySet(),
                 eq(entry),
-                any(NotificationInfo.CheckSaveListener.class),
                 any(NotificationInfo.OnSettingsClickListener.class),
                 any(NotificationInfo.OnAppSettingsClickListener.class),
                 eq(false),
                 eq(false),
-                eq(true) /* isForBlockingHelper */,
-                eq(IMPORTANCE_HIGH),
                 eq(true) /* wasShownHighPriority */);
     }
 
@@ -437,13 +369,10 @@
                 any(NotificationChannel.class),
                 anySet(),
                 eq(entry),
-                any(NotificationInfo.CheckSaveListener.class),
                 any(NotificationInfo.OnSettingsClickListener.class),
                 any(NotificationInfo.OnAppSettingsClickListener.class),
                 eq(true),
                 eq(false),
-                eq(false) /* isForBlockingHelper */,
-                eq(0),
                 eq(false) /* wasShownHighPriority */);
     }
 
@@ -469,13 +398,10 @@
                 any(NotificationChannel.class),
                 anySet(),
                 eq(entry),
-                any(NotificationInfo.CheckSaveListener.class),
                 any(NotificationInfo.OnSettingsClickListener.class),
                 any(NotificationInfo.OnAppSettingsClickListener.class),
                 eq(false),
                 eq(false),
-                eq(true) /* isForBlockingHelper */,
-                eq(0),
                 eq(false) /* wasShownHighPriority */);
     }
 
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationInfoTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationInfoTest.java
index c62487a..98ef691 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationInfoTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationInfoTest.java
@@ -119,15 +119,10 @@
     @Mock
     private PackageManager mMockPackageManager;
     @Mock
-    private NotificationBlockingHelperManager mBlockingHelperManager;
-    @Mock
     private VisualStabilityManager mVisualStabilityManager;
 
     @Before
     public void setUp() throws Exception {
-        mDependency.injectTestDependency(
-                NotificationBlockingHelperManager.class,
-                mBlockingHelperManager);
         mTestableLooper = TestableLooper.get(this);
 
         mDependency.injectTestDependency(Dependency.BG_LOOPER, mTestableLooper.getLooper());
@@ -183,13 +178,6 @@
                 NOTIFICATION_NEW_INTERRUPTION_MODEL, 0);
     }
 
-    // TODO: if tests are taking too long replace this with something that makes the animation
-    // finish instantly.
-    private void waitForUndoButton() {
-        PollingCheck.waitFor(1000,
-                () -> VISIBLE == mNotificationInfo.findViewById(R.id.confirmation).getVisibility());
-    }
-
     @Test
     public void testBindNotification_SetsTextApplicationName() throws Exception {
         when(mMockPackageManager.getApplicationLabel(any())).thenReturn("App Name");
@@ -203,12 +191,10 @@
                 mEntry,
                 null,
                 null,
-                null,
                 true,
                 false,
-                IMPORTANCE_DEFAULT,
                 true);
-        final TextView textView = mNotificationInfo.findViewById(R.id.pkgname);
+        final TextView textView = mNotificationInfo.findViewById(R.id.pkg_name);
         assertTrue(textView.getText().toString().contains("App Name"));
         assertEquals(VISIBLE, mNotificationInfo.findViewById(R.id.header).getVisibility());
     }
@@ -228,12 +214,10 @@
                 mEntry,
                 null,
                 null,
-                null,
                 true,
                 false,
-                IMPORTANCE_DEFAULT,
                 true);
-        final ImageView iconView = mNotificationInfo.findViewById(R.id.pkgicon);
+        final ImageView iconView = mNotificationInfo.findViewById(R.id.pkg_icon);
         assertEquals(iconDrawable, iconView.getDrawable());
     }
 
@@ -249,14 +233,12 @@
                 mEntry,
                 null,
                 null,
-                null,
                 true,
                 false,
-                IMPORTANCE_DEFAULT,
                 true);
         final TextView nameView = mNotificationInfo.findViewById(R.id.delegate_name);
         assertEquals(GONE, nameView.getVisibility());
-        final TextView dividerView = mNotificationInfo.findViewById(R.id.pkg_divider);
+        final TextView dividerView = mNotificationInfo.findViewById(R.id.group_divider);
         assertEquals(GONE, dividerView.getVisibility());
     }
 
@@ -281,16 +263,12 @@
                 entry,
                 null,
                 null,
-                null,
                 true,
                 false,
-                IMPORTANCE_DEFAULT,
                 true);
         final TextView nameView = mNotificationInfo.findViewById(R.id.delegate_name);
         assertEquals(VISIBLE, nameView.getVisibility());
         assertTrue(nameView.getText().toString().contains("Proxied"));
-        final TextView dividerView = mNotificationInfo.findViewById(R.id.pkg_divider);
-        assertEquals(VISIBLE, dividerView.getVisibility());
     }
 
     @Test
@@ -305,13 +283,13 @@
                 mEntry,
                 null,
                 null,
-                null,
                 true,
                 false,
-                IMPORTANCE_DEFAULT,
                 true);
         final TextView groupNameView = mNotificationInfo.findViewById(R.id.group_name);
         assertEquals(GONE, groupNameView.getVisibility());
+        final TextView dividerView = mNotificationInfo.findViewById(R.id.group_divider);
+        assertEquals(GONE, dividerView.getVisibility());
     }
 
     @Test
@@ -332,14 +310,14 @@
                 mEntry,
                 null,
                 null,
-                null,
                 true,
                 false,
-                IMPORTANCE_DEFAULT,
                 true);
         final TextView groupNameView = mNotificationInfo.findViewById(R.id.group_name);
         assertEquals(View.VISIBLE, groupNameView.getVisibility());
         assertEquals("Test Group Name", groupNameView.getText());
+        final TextView dividerView = mNotificationInfo.findViewById(R.id.group_divider);
+        assertEquals(View.VISIBLE, dividerView.getVisibility());
     }
 
     @Test
@@ -354,10 +332,8 @@
                 mEntry,
                 null,
                 null,
-                null,
                 true,
                 false,
-                IMPORTANCE_DEFAULT,
                 true);
         final TextView textView = mNotificationInfo.findViewById(R.id.channel_name);
         assertEquals(TEST_CHANNEL_NAME, textView.getText());
@@ -375,10 +351,8 @@
                 mEntry,
                 null,
                 null,
-                null,
                 true,
                 false,
-                IMPORTANCE_DEFAULT,
                 true);
         final TextView textView = mNotificationInfo.findViewById(R.id.channel_name);
         assertEquals(GONE, textView.getVisibility());
@@ -387,7 +361,7 @@
     @Test
     public void testBindNotification_DefaultChannelUsesChannelNameIfMoreChannelsExist()
             throws Exception {
-        // Package has one channel by default.
+        // Package has more than one channel by default.
         when(mMockINotificationManager.getNumNotificationChannelsForPackage(
                 eq(TEST_PACKAGE_NAME), eq(TEST_UID), anyBoolean())).thenReturn(10);
         mNotificationInfo.bindNotification(
@@ -400,10 +374,8 @@
                 mEntry,
                 null,
                 null,
-                null,
                 true,
                 false,
-                IMPORTANCE_DEFAULT,
                 true);
         final TextView textView = mNotificationInfo.findViewById(R.id.channel_name);
         assertEquals(VISIBLE, textView.getVisibility());
@@ -421,42 +393,14 @@
                 mEntry,
                 null,
                 null,
-                null,
                 true,
                 true,
-                IMPORTANCE_DEFAULT,
                 true);
         final TextView textView = mNotificationInfo.findViewById(R.id.channel_name);
         assertEquals(VISIBLE, textView.getVisibility());
     }
 
     @Test
-    public void testBindNotification_BlockLink_BlockingHelper() throws Exception {
-        mNotificationInfo.bindNotification(
-                mMockPackageManager,
-                mMockINotificationManager,
-                mVisualStabilityManager,
-                TEST_PACKAGE_NAME,
-                mNotificationChannel,
-                mNotificationChannelSet,
-                mEntry,
-                null,
-                mock(NotificationInfo.OnSettingsClickListener.class),
-                null,
-                true,
-                false,
-                true /* isBlockingHelper */,
-                IMPORTANCE_DEFAULT,
-                true);
-        final View block =
-                mNotificationInfo.findViewById(R.id.blocking_helper_turn_off_notifications);
-        final View interruptivenessSettings = mNotificationInfo.findViewById(
-                R.id.inline_controls);
-        assertEquals(VISIBLE, block.getVisibility());
-        assertEquals(GONE, interruptivenessSettings.getVisibility());
-    }
-
-    @Test
     public void testBindNotification_SetsOnClickListenerForSettings() throws Exception {
         final CountDownLatch latch = new CountDownLatch(1);
         mNotificationInfo.bindNotification(
@@ -467,7 +411,6 @@
                 mNotificationChannel,
                 mNotificationChannelSet,
                 mEntry,
-                null,
                 (View v, NotificationChannel c, int appUid) -> {
                     assertEquals(mNotificationChannel, c);
                     latch.countDown();
@@ -475,7 +418,6 @@
                 null,
                 true,
                 false,
-                IMPORTANCE_DEFAULT,
                 true);
 
         final View settingsButton = mNotificationInfo.findViewById(R.id.info);
@@ -496,10 +438,8 @@
                 mEntry,
                 null,
                 null,
-                null,
                 true,
                 false,
-                IMPORTANCE_DEFAULT,
                 true);
         final View settingsButton = mNotificationInfo.findViewById(R.id.info);
         assertTrue(settingsButton.getVisibility() != View.VISIBLE);
@@ -516,14 +456,12 @@
                 mNotificationChannel,
                 mNotificationChannelSet,
                 mEntry,
-                null,
                 (View v, NotificationChannel c, int appUid) -> {
                     assertEquals(mNotificationChannel, c);
                 },
                 null,
                 false,
                 false,
-                IMPORTANCE_DEFAULT,
                 true);
         final View settingsButton = mNotificationInfo.findViewById(R.id.info);
         assertTrue(settingsButton.getVisibility() != View.VISIBLE);
@@ -541,10 +479,8 @@
                 mEntry,
                 null,
                 null,
-                null,
                 true,
                 false,
-                IMPORTANCE_DEFAULT,
                 true);
         mNotificationInfo.bindNotification(
                 mMockPackageManager,
@@ -554,89 +490,16 @@
                 mNotificationChannel,
                 mNotificationChannelSet,
                 mEntry,
-                null,
                 (View v, NotificationChannel c, int appUid) -> { },
                 null,
                 true,
                 false,
-                IMPORTANCE_DEFAULT,
                 true);
         final View settingsButton = mNotificationInfo.findViewById(R.id.info);
         assertEquals(View.VISIBLE, settingsButton.getVisibility());
     }
 
     @Test
-    public void testBindNotificationLogging_notBlockingHelper() throws Exception {
-        mNotificationInfo.bindNotification(
-                mMockPackageManager,
-                mMockINotificationManager,
-                mVisualStabilityManager,
-                TEST_PACKAGE_NAME,
-                mNotificationChannel,
-                mNotificationChannelSet,
-                mEntry,
-                null,
-                null,
-                null,
-                true,
-                false,
-                IMPORTANCE_DEFAULT,
-                true);
-        verify(mMetricsLogger).write(argThat(logMaker ->
-                logMaker.getCategory() == MetricsEvent.ACTION_NOTE_CONTROLS
-                        && logMaker.getType() == MetricsEvent.TYPE_OPEN
-                        && logMaker.getSubtype() == MetricsEvent.BLOCKING_HELPER_UNKNOWN
-        ));
-    }
-
-    @Test
-    public void testBindNotificationLogging_BlockingHelper() throws Exception {
-        mNotificationInfo.bindNotification(
-                mMockPackageManager,
-                mMockINotificationManager,
-                mVisualStabilityManager,
-                TEST_PACKAGE_NAME,
-                mNotificationChannel,
-                mNotificationChannelSet,
-                mEntry,
-                null,
-                null,
-                null,
-                false,
-                true,
-                true,
-                IMPORTANCE_DEFAULT,
-                true);
-        verify(mMetricsLogger).write(argThat(logMaker ->
-                logMaker.getCategory() == MetricsEvent.ACTION_NOTE_CONTROLS
-                        && logMaker.getType() == MetricsEvent.TYPE_OPEN
-                        && logMaker.getSubtype() == MetricsEvent.BLOCKING_HELPER_DISPLAY
-        ));
-    }
-
-    @Test
-    public void testLogBlockingHelperCounter_logsForBlockingHelper() throws Exception {
-        mNotificationInfo.bindNotification(
-                mMockPackageManager,
-                mMockINotificationManager,
-                mVisualStabilityManager,
-                TEST_PACKAGE_NAME,
-                mNotificationChannel,
-                mNotificationChannelSet,
-                mEntry,
-                null,
-                null,
-                null,
-                false,
-                true,
-                true,
-                IMPORTANCE_DEFAULT,
-                true);
-        mNotificationInfo.logBlockingHelperCounter("HowCanNotifsBeRealIfAppsArent");
-        verify(mMetricsLogger).count(eq("HowCanNotifsBeRealIfAppsArent"), eq(1));
-    }
-
-    @Test
     public void testOnClickListenerPassesNullChannelForBundle() throws Exception {
         final CountDownLatch latch = new CountDownLatch(1);
         mNotificationInfo.bindNotification(
@@ -646,7 +509,6 @@
                 TEST_PACKAGE_NAME, mNotificationChannel,
                 createMultipleChannelSet(MULTIPLE_CHANNEL_COUNT),
                 mEntry,
-                null,
                 (View v, NotificationChannel c, int appUid) -> {
                     assertEquals(null, c);
                     latch.countDown();
@@ -654,7 +516,6 @@
                 null,
                 true,
                 true,
-                IMPORTANCE_DEFAULT,
                 true);
 
         mNotificationInfo.findViewById(R.id.info).performClick();
@@ -676,10 +537,8 @@
                 mEntry,
                 null,
                 null,
-                null,
                 true,
                 false,
-                IMPORTANCE_DEFAULT,
                 true);
         final TextView channelNameView =
                 mNotificationInfo.findViewById(R.id.channel_name);
@@ -699,10 +558,8 @@
                 mEntry,
                 null,
                 null,
-                null,
                 true,
                 false,
-                IMPORTANCE_DEFAULT,
                 true);
         assertEquals(GONE, mNotificationInfo.findViewById(
                 R.id.interruptiveness_settings).getVisibility());
@@ -722,10 +579,8 @@
                 mEntry,
                 null,
                 null,
-                null,
                 true,
                 true,
-                IMPORTANCE_DEFAULT,
                 true);
         final TextView view = mNotificationInfo.findViewById(R.id.non_configurable_text);
         assertEquals(View.VISIBLE, view.getVisibility());
@@ -747,10 +602,8 @@
                 mEntry,
                 null,
                 null,
-                null,
                 true,
                 false,
-                IMPORTANCE_DEFAULT,
                 true);
         assertTrue(mNotificationInfo.findViewById(R.id.alert).isSelected());
     }
@@ -767,10 +620,8 @@
                 mEntry,
                 null,
                 null,
-                null,
                 true,
                 false,
-                IMPORTANCE_DEFAULT,
                 false);
         assertTrue(mNotificationInfo.findViewById(R.id.silence).isSelected());
     }
@@ -787,10 +638,8 @@
                 mEntry,
                 null,
                 null,
-                null,
                 true,
                 false,
-                IMPORTANCE_DEFAULT,
                 true);
         mTestableLooper.processAllMessages();
         verify(mMockINotificationManager, never()).updateNotificationChannelForPackage(
@@ -810,10 +659,8 @@
                 mEntry,
                 null,
                 null,
-                null,
                 true,
                 false,
-                IMPORTANCE_LOW,
                 false);
 
         mNotificationInfo.findViewById(R.id.alert).performClick();
@@ -836,10 +683,8 @@
                 mEntry,
                 null,
                 null,
-                null,
                 true,
                 false,
-                IMPORTANCE_DEFAULT,
                 true);
 
         mNotificationInfo.findViewById(R.id.silence).performClick();
@@ -862,10 +707,8 @@
                 mEntry,
                 null,
                 null,
-                null,
                 true,
                 false,
-                IMPORTANCE_DEFAULT,
                 true);
 
         mNotificationInfo.handleCloseControls(true, false);
@@ -889,10 +732,8 @@
                 mEntry,
                 null,
                 null,
-                null,
                 true,
                 false,
-                IMPORTANCE_UNSPECIFIED,
                 true);
 
         mNotificationInfo.handleCloseControls(true, false);
@@ -904,225 +745,6 @@
     }
 
     @Test
-    public void testCloseControls_nonNullCheckSaveListenerDoesntDelayKeepShowing_BlockingHelper()
-            throws Exception {
-        NotificationInfo.CheckSaveListener listener =
-                mock(NotificationInfo.CheckSaveListener.class);
-        mNotificationChannel.setImportance(IMPORTANCE_DEFAULT);
-        mNotificationInfo.bindNotification(
-                mMockPackageManager,
-                mMockINotificationManager,
-                mVisualStabilityManager,
-                TEST_PACKAGE_NAME,
-                mNotificationChannel /* notificationChannel */,
-                createMultipleChannelSet(10) /* numUniqueChannelsInRow */,
-                mEntry,
-                listener /* checkSaveListener */,
-                null /* onSettingsClick */,
-                null /* onAppSettingsClick */,
-                true /* provisioned */,
-                false /* isNonblockable */,
-                true /* isForBlockingHelper */,
-                IMPORTANCE_DEFAULT,
-                true);
-
-        NotificationGuts guts = spy(new NotificationGuts(mContext, null));
-        when(guts.getWindowToken()).thenReturn(mock(IBinder.class));
-        doNothing().when(guts).animateClose(anyInt(), anyInt(), anyBoolean());
-        doNothing().when(guts).setExposed(anyBoolean(), anyBoolean());
-        guts.setGutsContent(mNotificationInfo);
-        mNotificationInfo.setGutsParent(guts);
-
-        mNotificationInfo.findViewById(R.id.keep_showing).performClick();
-
-        verify(mBlockingHelperManager).dismissCurrentBlockingHelper();
-        mTestableLooper.processAllMessages();
-        verify(mMockINotificationManager, times(1))
-                .setNotificationsEnabledWithImportanceLockForPackage(
-                        anyString(), eq(TEST_UID), eq(true));
-    }
-
-    @Test
-    public void testCloseControls_nonNullCheckSaveListenerDoesntDelayDismiss_BlockingHelper()
-            throws Exception {
-        NotificationInfo.CheckSaveListener listener =
-                mock(NotificationInfo.CheckSaveListener.class);
-        mNotificationChannel.setImportance(IMPORTANCE_DEFAULT);
-        mNotificationInfo.bindNotification(
-                mMockPackageManager,
-                mMockINotificationManager,
-                mVisualStabilityManager,
-                TEST_PACKAGE_NAME,
-                mNotificationChannel /* notificationChannel */,
-                createMultipleChannelSet(10) /* numUniqueChannelsInRow */,
-                mEntry,
-                listener /* checkSaveListener */,
-                null /* onSettingsClick */,
-                null /* onAppSettingsClick */,
-                false /* isNonblockable */,
-                true /* isForBlockingHelper */,
-                true, IMPORTANCE_DEFAULT,
-                true);
-
-        mNotificationInfo.handleCloseControls(true /* save */, false /* force */);
-
-        mTestableLooper.processAllMessages();
-        verify(listener, times(0)).checkSave(any(Runnable.class), eq(mSbn));
-    }
-
-    @Test
-    public void testCloseControls_checkSaveListenerDelaysStopNotifications_BlockingHelper()
-            throws Exception {
-        NotificationInfo.CheckSaveListener listener =
-                mock(NotificationInfo.CheckSaveListener.class);
-        mNotificationChannel.setImportance(IMPORTANCE_DEFAULT);
-        mNotificationInfo.bindNotification(
-                mMockPackageManager,
-                mMockINotificationManager,
-                mVisualStabilityManager,
-                TEST_PACKAGE_NAME,
-                mNotificationChannel /* notificationChannel */,
-                createMultipleChannelSet(10) /* numUniqueChannelsInRow */,
-                mEntry,
-                listener /* checkSaveListener */,
-                null /* onSettingsClick */,
-                null /* onAppSettingsClick */,
-                true /* provisioned */,
-                false /* isNonblockable */,
-                true /* isForBlockingHelper */,
-                IMPORTANCE_DEFAULT,
-                true);
-
-        mNotificationInfo.findViewById(R.id.deliver_silently).performClick();
-        mTestableLooper.processAllMessages();
-        verify(listener).checkSave(any(Runnable.class), eq(mSbn));
-    }
-
-    @Test
-    public void testCloseControls_blockingHelperDismissedIfShown() throws Exception {
-        mNotificationChannel.setImportance(IMPORTANCE_DEFAULT);
-        mNotificationInfo.bindNotification(
-                mMockPackageManager,
-                mMockINotificationManager,
-                mVisualStabilityManager,
-                TEST_PACKAGE_NAME,
-                mNotificationChannel,
-                mNotificationChannelSet /* numChannels */,
-                mEntry,
-                null /* checkSaveListener */,
-                null /* onSettingsClick */,
-                null /* onAppSettingsClick */,
-                false /* isNonblockable */,
-                true /* isForBlockingHelper */,
-                true,
-                IMPORTANCE_DEFAULT,
-                true);
-        NotificationGuts guts = mock(NotificationGuts.class);
-        doCallRealMethod().when(guts).closeControls(anyInt(), anyInt(), anyBoolean(), anyBoolean());
-        mNotificationInfo.setGutsParent(guts);
-
-        mNotificationInfo.closeControls(mNotificationInfo, true);
-
-        verify(mBlockingHelperManager).dismissCurrentBlockingHelper();
-    }
-
-    @Test
-    public void testSilentlyChangedCallsUpdateNotificationChannel_blockingHelper()
-            throws Exception {
-        mNotificationChannel.setImportance(IMPORTANCE_DEFAULT);
-        mNotificationInfo.bindNotification(
-                mMockPackageManager,
-                mMockINotificationManager,
-                mVisualStabilityManager,
-                TEST_PACKAGE_NAME,
-                mNotificationChannel,
-                mNotificationChannelSet /* numChannels */,
-                mEntry,
-                null /* checkSaveListener */,
-                null /* onSettingsClick */,
-                null /* onAppSettingsClick */,
-                true /*provisioned */,
-                false /* isNonblockable */,
-                true /* isForBlockingHelper */,
-                IMPORTANCE_DEFAULT,
-                true);
-
-        mNotificationInfo.findViewById(R.id.deliver_silently).performClick();
-        waitForUndoButton();
-        mNotificationInfo.handleCloseControls(true, false);
-
-        mTestableLooper.processAllMessages();
-        ArgumentCaptor<NotificationChannel> updated =
-                ArgumentCaptor.forClass(NotificationChannel.class);
-        verify(mMockINotificationManager, times(1)).updateNotificationChannelForPackage(
-                anyString(), eq(TEST_UID), updated.capture());
-        assertTrue((updated.getValue().getUserLockedFields()
-                & USER_LOCKED_IMPORTANCE) != 0);
-        assertEquals(IMPORTANCE_LOW, updated.getValue().getImportance());
-    }
-
-    @Test
-    public void testKeepUpdatesNotificationChannel_blockingHelper() throws Exception {
-        mNotificationChannel.setImportance(IMPORTANCE_LOW);
-        mNotificationInfo.bindNotification(
-                mMockPackageManager,
-                mMockINotificationManager,
-                mVisualStabilityManager,
-                TEST_PACKAGE_NAME,
-                mNotificationChannel,
-                mNotificationChannelSet,
-                mEntry,
-                null,
-                null,
-                null,
-                true,
-                true,
-                IMPORTANCE_LOW,
-                false);
-
-        mNotificationInfo.findViewById(R.id.keep_showing).performClick();
-        mNotificationInfo.handleCloseControls(true, false);
-
-        mTestableLooper.processAllMessages();
-        ArgumentCaptor<NotificationChannel> updated =
-                ArgumentCaptor.forClass(NotificationChannel.class);
-        verify(mMockINotificationManager, times(1)).updateNotificationChannelForPackage(
-                anyString(), eq(TEST_UID), updated.capture());
-        assertTrue(0 != (mNotificationChannel.getUserLockedFields() & USER_LOCKED_IMPORTANCE));
-        assertEquals(IMPORTANCE_LOW, mNotificationChannel.getImportance());
-    }
-
-    @Test
-    public void testNoActionsUpdatesNotificationChannel_blockingHelper() throws Exception {
-        mNotificationChannel.setImportance(IMPORTANCE_DEFAULT);
-        mNotificationInfo.bindNotification(
-                mMockPackageManager,
-                mMockINotificationManager,
-                mVisualStabilityManager,
-                TEST_PACKAGE_NAME,
-                mNotificationChannel,
-                mNotificationChannelSet,
-                mEntry,
-                null,
-                null,
-                null,
-                true,
-                true,
-                IMPORTANCE_DEFAULT,
-                true);
-
-        mNotificationInfo.handleCloseControls(true, false);
-
-        mTestableLooper.processAllMessages();
-        ArgumentCaptor<NotificationChannel> updated =
-                ArgumentCaptor.forClass(NotificationChannel.class);
-        verify(mMockINotificationManager, times(1)).updateNotificationChannelForPackage(
-                anyString(), eq(TEST_UID), updated.capture());
-        assertTrue(0 != (mNotificationChannel.getUserLockedFields() & USER_LOCKED_IMPORTANCE));
-        assertEquals(IMPORTANCE_DEFAULT, mNotificationChannel.getImportance());
-    }
-
-    @Test
     public void testSilenceCallsUpdateNotificationChannel() throws Exception {
         mNotificationChannel.setImportance(IMPORTANCE_DEFAULT);
         mNotificationInfo.bindNotification(
@@ -1135,10 +757,8 @@
                 mEntry,
                 null,
                 null,
-                null,
                 true,
                 false,
-                IMPORTANCE_DEFAULT,
                 true);
 
         mNotificationInfo.findViewById(R.id.silence).performClick();
@@ -1168,10 +788,8 @@
                 mEntry,
                 null,
                 null,
-                null,
                 true,
                 false,
-                IMPORTANCE_LOW,
                 false);
 
         mNotificationInfo.findViewById(R.id.alert).performClick();
@@ -1202,10 +820,8 @@
                 mEntry,
                 null,
                 null,
-                null,
                 true,
                 false,
-                IMPORTANCE_UNSPECIFIED,
                 true);
 
         mNotificationInfo.findViewById(R.id.silence).performClick();
@@ -1236,10 +852,8 @@
                 mEntry,
                 null,
                 null,
-                null,
                 true,
                 false,
-                IMPORTANCE_MIN,
                 false);
 
         assertEquals(mContext.getString(R.string.inline_done_button),
@@ -1273,10 +887,8 @@
                 mEntry,
                 null,
                 null,
-                null,
                 true,
                 false,
-                IMPORTANCE_MIN,
                 false);
 
         assertEquals(mContext.getString(R.string.inline_done_button),
@@ -1309,10 +921,8 @@
                 mEntry,
                 null,
                 null,
-                null,
                 true,
                 false,
-                IMPORTANCE_DEFAULT,
                 true);
 
         mNotificationInfo.findViewById(R.id.silence).performClick();
@@ -1336,10 +946,8 @@
                 mEntry,
                 null,
                 null,
-                null,
                 true,
                 false,
-                IMPORTANCE_LOW,
                 false);
 
         assertEquals(mContext.getString(R.string.inline_done_button),
@@ -1366,10 +974,8 @@
                 mEntry,
                 null,
                 null,
-                null,
                 true,
                 false,
-                IMPORTANCE_LOW,
                 false);
 
         mNotificationInfo.findViewById(R.id.alert).performClick();
@@ -1399,10 +1005,8 @@
                 mEntry,
                 null,
                 null,
-                null,
                 true,
                 false,
-                IMPORTANCE_LOW,
                 false);
 
         mNotificationInfo.findViewById(R.id.alert).performClick();
@@ -1425,14 +1029,10 @@
                 mNotificationChannel,
                 mNotificationChannelSet,
                 mEntry,
-                (Runnable saveImportance, StatusBarNotification sbn) -> {
-                    saveImportance.run();
-                },
                 null,
                 null,
                 true,
                 false,
-                IMPORTANCE_LOW,
                 false
         );
 
@@ -1460,14 +1060,10 @@
                 mNotificationChannel,
                 mNotificationChannelSet,
                 mEntry,
-                (Runnable saveImportance, StatusBarNotification sbn) -> {
-                    saveImportance.run();
-                },
                 null,
                 null,
                 true,
                 false,
-                IMPORTANCE_LOW,
                 false
         );
 
@@ -1488,14 +1084,10 @@
                 mNotificationChannel,
                 mNotificationChannelSet,
                 mEntry,
-                (Runnable saveImportance, StatusBarNotification sbn) -> {
-                    saveImportance.run();
-                },
                 null,
                 null,
                 true,
                 false,
-                IMPORTANCE_LOW,
                 false
         );
 
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/LockscreenIconControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/LockscreenIconControllerTest.java
index 05f10e3..487885a 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/LockscreenIconControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/LockscreenIconControllerTest.java
@@ -29,8 +29,10 @@
 import com.android.internal.widget.LockPatternUtils;
 import com.android.keyguard.KeyguardUpdateMonitor;
 import com.android.systemui.SysuiTestCase;
+import com.android.systemui.dock.DockManager;
 import com.android.systemui.plugins.statusbar.StatusBarStateController;
 import com.android.systemui.statusbar.KeyguardIndicationController;
+import com.android.systemui.statusbar.notification.NotificationWakeUpCoordinator;
 import com.android.systemui.statusbar.policy.AccessibilityController;
 import com.android.systemui.statusbar.policy.ConfigurationController;
 
@@ -63,6 +65,13 @@
     private StatusBarStateController mStatusBarStateController;
     @Mock
     private ConfigurationController mConfigurationController;
+    @Mock
+    private NotificationWakeUpCoordinator mNotificationWakeUpCoordinator;
+    @Mock
+    private KeyguardBypassController mKeyguardBypassController;
+    @Mock
+    private DockManager mDockManager;
+
 
     @Before
     public void setUp() {
@@ -71,7 +80,8 @@
         mLockIconController = new LockscreenLockIconController(
                 mLockscreenGestureLogger, mKeyguardUpdateMonitor, mLockPatternUtils,
                 mShadeController, mAccessibilityController, mKeyguardIndicationController,
-                mStatusBarStateController, mConfigurationController);
+                mStatusBarStateController, mConfigurationController, mNotificationWakeUpCoordinator,
+                mKeyguardBypassController, mDockManager);
 
         mLockIconController.attach(mLockIcon);
     }
diff --git a/services/core/java/com/android/server/DynamicSystemService.java b/services/core/java/com/android/server/DynamicSystemService.java
index 41207c9..318a030 100644
--- a/services/core/java/com/android/server/DynamicSystemService.java
+++ b/services/core/java/com/android/server/DynamicSystemService.java
@@ -21,6 +21,7 @@
 import android.gsi.AvbPublicKey;
 import android.gsi.GsiProgress;
 import android.gsi.IGsiService;
+import android.gsi.IGsiServiceCallback;
 import android.gsi.IGsid;
 import android.os.Environment;
 import android.os.IBinder;
@@ -115,6 +116,20 @@
         }
     }
 
+    class GsiServiceCallback extends IGsiServiceCallback.Stub {
+        // 0 for success
+        private int mResult = -1;
+
+        public synchronized void onResult(int result) {
+            mResult = result;
+            notify();
+        }
+
+        public int getResult() {
+            return mResult;
+        }
+    }
+
     @Override
     public boolean startInstallation(String dsuSlot) throws RemoteException {
         IGsiService service = getGsiService();
@@ -186,7 +201,9 @@
 
     @Override
     public boolean isInstalled() throws RemoteException {
-        return getGsiService().isGsiInstalled();
+        boolean installed = SystemProperties.getBoolean("gsid.image_installed", false);
+        Slog.i(TAG, "isInstalled(): " + installed);
+        return installed;
     }
 
     @Override
@@ -196,16 +213,37 @@
 
     @Override
     public boolean remove() throws RemoteException {
-        IGsiService gsiService = getGsiService();
-        String install_dir = gsiService.getInstalledGsiImageDir();
-        return getGsiService().removeGsi();
+        try {
+            GsiServiceCallback callback = new GsiServiceCallback();
+            synchronized (callback) {
+                getGsiService().removeGsiAsync(callback);
+                callback.wait(GSID_ROUGH_TIMEOUT_MS);
+            }
+            return callback.getResult() == 0;
+        } catch (InterruptedException e) {
+            Slog.e(TAG, "remove() was interrupted");
+            return false;
+        }
     }
 
     @Override
     public boolean setEnable(boolean enable, boolean oneShot) throws RemoteException {
         IGsiService gsiService = getGsiService();
         if (enable) {
-            return gsiService.enableGsi(oneShot, mDsuSlot) == 0;
+            try {
+                if (mDsuSlot == null) {
+                    mDsuSlot = gsiService.getActiveDsuSlot();
+                }
+                GsiServiceCallback callback = new GsiServiceCallback();
+                synchronized (callback) {
+                    gsiService.enableGsiAsync(oneShot, mDsuSlot, callback);
+                    callback.wait(GSID_ROUGH_TIMEOUT_MS);
+                }
+                return callback.getResult() == 0;
+            } catch (InterruptedException e) {
+                Slog.e(TAG, "setEnable() was interrupted");
+                return false;
+            }
         } else {
             return gsiService.disableGsi();
         }
diff --git a/services/core/java/com/android/server/UiModeManagerService.java b/services/core/java/com/android/server/UiModeManagerService.java
index 88b517c..7c833fa 100644
--- a/services/core/java/com/android/server/UiModeManagerService.java
+++ b/services/core/java/com/android/server/UiModeManagerService.java
@@ -467,9 +467,9 @@
             mNightMode = Secure.getIntForUser(context.getContentResolver(),
                     Secure.UI_NIGHT_MODE, defaultNightMode, userId);
             mOverrideNightModeOn = Secure.getIntForUser(context.getContentResolver(),
-                    Secure.UI_NIGHT_MODE_OVERRIDE_ON, defaultNightMode, userId) != 0;
+                    Secure.UI_NIGHT_MODE_OVERRIDE_ON, 0, userId) != 0;
             mOverrideNightModeOff = Secure.getIntForUser(context.getContentResolver(),
-                    Secure.UI_NIGHT_MODE_OVERRIDE_OFF, defaultNightMode, userId) != 0;
+                    Secure.UI_NIGHT_MODE_OVERRIDE_OFF, 0, userId) != 0;
             mCustomAutoNightModeStartMilliseconds = LocalTime.ofNanoOfDay(
                     Secure.getLongForUser(context.getContentResolver(),
                     Secure.DARK_THEME_CUSTOM_START_TIME,
@@ -1045,7 +1045,6 @@
                 final TwilightState lastState = mTwilightManager.getLastTwilightState();
                 activateNightMode = lastState == null ? mComputedNightMode : lastState.isNight();
             }
-            
             updateComputedNightModeLocked(activateNightMode);
         } else {
             if (mTwilightManager != null) {
@@ -1375,6 +1374,9 @@
 
     private void updateComputedNightModeLocked(boolean activate) {
         mComputedNightMode = activate;
+        if (mNightMode == MODE_NIGHT_YES || mNightMode == UiModeManager.MODE_NIGHT_NO) {
+            return;
+        }
         if (mOverrideNightModeOn && !mComputedNightMode) {
             mComputedNightMode = true;
             return;
diff --git a/services/core/java/com/android/server/Watchdog.java b/services/core/java/com/android/server/Watchdog.java
index 93b16f7..0561567 100644
--- a/services/core/java/com/android/server/Watchdog.java
+++ b/services/core/java/com/android/server/Watchdog.java
@@ -110,6 +110,7 @@
             "android.hardware.audio@5.0::IDevicesFactory",
             "android.hardware.audio@6.0::IDevicesFactory",
             "android.hardware.biometrics.face@1.0::IBiometricsFace",
+            "android.hardware.biometrics.fingerprint@2.1::IBiometricsFingerprint",
             "android.hardware.bluetooth@1.0::IBluetoothHci",
             "android.hardware.camera.provider@2.4::ICameraProvider",
             "android.hardware.gnss@1.0::IGnss",
diff --git a/services/core/java/com/android/server/am/ActivityManagerConstants.java b/services/core/java/com/android/server/am/ActivityManagerConstants.java
index 8fbe923..6b917bc 100644
--- a/services/core/java/com/android/server/am/ActivityManagerConstants.java
+++ b/services/core/java/com/android/server/am/ActivityManagerConstants.java
@@ -19,16 +19,12 @@
 import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_POWER_QUICK;
 
 import android.app.ActivityThread;
-import android.content.ComponentName;
 import android.content.ContentResolver;
 import android.content.Context;
-import android.content.pm.UserInfo;
 import android.database.ContentObserver;
 import android.net.Uri;
 import android.os.Build;
 import android.os.Handler;
-import android.os.UserHandle;
-import android.os.UserManager;
 import android.provider.DeviceConfig;
 import android.provider.DeviceConfig.OnPropertiesChangedListener;
 import android.provider.DeviceConfig.Properties;
@@ -37,7 +33,6 @@
 import android.util.ArraySet;
 import android.util.KeyValueListParser;
 import android.util.Slog;
-import android.util.SparseArray;
 
 import java.io.PrintWriter;
 import java.util.Arrays;
@@ -294,12 +289,6 @@
     // started, the restriction is on while-in-use permissions.)
     volatile boolean mFlagBackgroundFgsStartRestrictionEnabled = true;
 
-    /**
-     * UserId to Assistant ComponentName mapping.
-     * Per user Assistant ComponentName is from {@link android.provider.Settings.Secure#ASSISTANT}
-     */
-    SparseArray<ComponentName> mAssistants = new SparseArray<>();
-
     private final ActivityManagerService mService;
     private ContentResolver mResolver;
     private final KeyValueListParser mParser = new KeyValueListParser(',');
@@ -375,8 +364,6 @@
                 Settings.Global.getUriFor(
                         Settings.Global.FOREGROUND_SERVICE_STARTS_LOGGING_ENABLED);
 
-    private static final Uri ASSISTANT_URI = Settings.Secure.getUriFor(Settings.Secure.ASSISTANT);
-
     private static final Uri ENABLE_AUTOMATIC_SYSTEM_SERVER_HEAP_DUMPS_URI =
             Settings.Global.getUriFor(Settings.Global.ENABLE_AUTOMATIC_SYSTEM_SERVER_HEAP_DUMPS);
 
@@ -443,8 +430,6 @@
         mResolver.registerContentObserver(ACTIVITY_STARTS_LOGGING_ENABLED_URI, false, this);
         mResolver.registerContentObserver(FOREGROUND_SERVICE_STARTS_LOGGING_ENABLED_URI,
                 false, this);
-        mResolver.registerContentObserver(ASSISTANT_URI, false, this,
-                UserHandle.USER_ALL);
         if (mSystemServerAutomaticHeapDumpEnabled) {
             mResolver.registerContentObserver(ENABLE_AUTOMATIC_SYSTEM_SERVER_HEAP_DUMPS_URI,
                     false, this);
@@ -460,7 +445,6 @@
         // The following read from Settings.
         updateActivityStartsLoggingEnabled();
         updateForegroundServiceStartsLoggingEnabled();
-        updateAssistant();
     }
 
     private void loadDeviceConfigConstants() {
@@ -492,8 +476,6 @@
             updateForegroundServiceStartsLoggingEnabled();
         } else if (ENABLE_AUTOMATIC_SYSTEM_SERVER_HEAP_DUMPS_URI.equals(uri)) {
             updateEnableAutomaticSystemServerHeapDumps();
-        } else if (ASSISTANT_URI.equals(uri)) {
-            updateAssistant();
         }
     }
 
@@ -590,32 +572,6 @@
         mFlagForegroundServiceStartsLoggingEnabled = Settings.Global.getInt(mResolver,
                 Settings.Global.FOREGROUND_SERVICE_STARTS_LOGGING_ENABLED, 1) == 1;
     }
-
-    private void updateAssistant() {
-        final List<UserInfo> users =
-                mService.mContext.getSystemService(UserManager.class).getUsers();
-        SparseArray<ComponentName> componentNames = new SparseArray<>();
-        for (int i = 0; i < users.size(); i++) {
-            final int userId = users.get(i).id;
-            final String str = Settings.Secure.getStringForUser(mResolver,
-                    Settings.Secure.ASSISTANT, userId);
-            if (!TextUtils.isEmpty(str)) {
-                componentNames.put(userId, ComponentName.unflattenFromString(str));
-            }
-        }
-        synchronized (mService) {
-            for (int i = 0; i < mAssistants.size(); i++) {
-                mService.mServices.mWhiteListAllowWhileInUsePermissionInFgs.remove(
-                        mAssistants.valueAt(i).getPackageName());
-            }
-            mAssistants = componentNames;
-            for (int i = 0; i < mAssistants.size(); i++) {
-                mService.mServices.mWhiteListAllowWhileInUsePermissionInFgs.add(
-                        mAssistants.valueAt(i).getPackageName());
-            }
-        }
-    }
-
     private void updateBackgroundFgsStartsRestriction() {
         mFlagBackgroundFgsStartRestrictionEnabled = DeviceConfig.getBoolean(
                 DeviceConfig.NAMESPACE_ACTIVITY_MANAGER,
diff --git a/services/core/java/com/android/server/compat/CompatChange.java b/services/core/java/com/android/server/compat/CompatChange.java
index 8687f35..7bdeb59 100644
--- a/services/core/java/com/android/server/compat/CompatChange.java
+++ b/services/core/java/com/android/server/compat/CompatChange.java
@@ -63,7 +63,7 @@
     private Map<String, Boolean> mPackageOverrides;
 
     public CompatChange(long changeId) {
-        this(changeId, null, -1, false, null);
+        this(changeId, null, -1, false, false, null);
     }
 
     /**
@@ -74,8 +74,8 @@
      * @param disabled If {@code true}, overrides any {@code enableAfterTargetSdk} set.
      */
     public CompatChange(long changeId, @Nullable String name, int enableAfterTargetSdk,
-            boolean disabled, String description) {
-        super(changeId, name, enableAfterTargetSdk, disabled, description);
+            boolean disabled, boolean loggingOnly, String description) {
+        super(changeId, name, enableAfterTargetSdk, disabled, loggingOnly, description);
     }
 
     /**
@@ -83,7 +83,7 @@
      */
     public CompatChange(Change change) {
         super(change.getId(), change.getName(), change.getEnableAfterTargetSdk(),
-                change.getDisabled(), change.getDescription());
+                change.getDisabled(), change.getLoggingOnly(), change.getDescription());
     }
 
     void registerListener(ChangeListener listener) {
@@ -105,6 +105,10 @@
      * @param enabled Whether or not to enable the change.
      */
     void addPackageOverride(String pname, boolean enabled) {
+        if (getLoggingOnly()) {
+            throw new IllegalArgumentException(
+                    "Can't add overrides for a logging only change " + toString());
+        }
         if (mPackageOverrides == null) {
             mPackageOverrides = new HashMap<>();
         }
@@ -160,6 +164,9 @@
         if (getDisabled()) {
             sb.append("; disabled");
         }
+        if (getLoggingOnly()) {
+            sb.append("; loggingOnly");
+        }
         if (mPackageOverrides != null && mPackageOverrides.size() > 0) {
             sb.append("; packageOverrides=").append(mPackageOverrides);
         }
diff --git a/services/core/java/com/android/server/compat/CompatConfig.java b/services/core/java/com/android/server/compat/CompatConfig.java
index 441d9d9..bfc2f82 100644
--- a/services/core/java/com/android/server/compat/CompatConfig.java
+++ b/services/core/java/com/android/server/compat/CompatConfig.java
@@ -206,6 +206,19 @@
     }
 
     /**
+     * Returns whether the change is marked as logging only.
+     */
+    boolean isLoggingOnly(long changeId) {
+        synchronized (mChanges) {
+            CompatChange c = mChanges.get(changeId);
+            if (c == null) {
+                return false;
+            }
+            return c.getLoggingOnly();
+        }
+    }
+
+    /**
      * Removes an override previously added via {@link #addOverride(long, String, boolean)}. This
      * restores the default behaviour for the given change and app, once any app processes have been
      * restarted.
@@ -365,6 +378,7 @@
                         change.getName(),
                         change.getEnableAfterTargetSdk(),
                         change.getDisabled(),
+                        change.getLoggingOnly(),
                         change.getDescription());
             }
             return changeInfos;
diff --git a/services/core/java/com/android/server/compat/OverrideValidatorImpl.java b/services/core/java/com/android/server/compat/OverrideValidatorImpl.java
index 4bf606e..9e18c74 100644
--- a/services/core/java/com/android/server/compat/OverrideValidatorImpl.java
+++ b/services/core/java/com/android/server/compat/OverrideValidatorImpl.java
@@ -20,6 +20,7 @@
 import static com.android.internal.compat.OverrideAllowedState.DISABLED_NON_TARGET_SDK;
 import static com.android.internal.compat.OverrideAllowedState.DISABLED_NOT_DEBUGGABLE;
 import static com.android.internal.compat.OverrideAllowedState.DISABLED_TARGET_SDK_TOO_HIGH;
+import static com.android.internal.compat.OverrideAllowedState.LOGGING_ONLY_CHANGE;
 import static com.android.internal.compat.OverrideAllowedState.PACKAGE_DOES_NOT_EXIST;
 
 import android.content.Context;
@@ -51,12 +52,13 @@
 
     @Override
     public OverrideAllowedState getOverrideAllowedState(long changeId, String packageName) {
-        boolean debuggableBuild = false;
-        boolean finalBuild = false;
-        int minTargetSdk = mCompatConfig.minTargetSdkForChangeId(changeId);
+        if (mCompatConfig.isLoggingOnly(changeId)) {
+            return new OverrideAllowedState(LOGGING_ONLY_CHANGE, -1, -1);
+        }
 
-        debuggableBuild = mAndroidBuildClassifier.isDebuggableBuild();
-        finalBuild = mAndroidBuildClassifier.isFinalBuild();
+        boolean debuggableBuild = mAndroidBuildClassifier.isDebuggableBuild();
+        boolean finalBuild = mAndroidBuildClassifier.isFinalBuild();
+        int minTargetSdk = mCompatConfig.minTargetSdkForChangeId(changeId);
 
         // Allow any override for userdebug or eng builds.
         if (debuggableBuild) {
diff --git a/services/core/java/com/android/server/integrity/TEST_MAPPING b/services/core/java/com/android/server/integrity/TEST_MAPPING
index ca7f396..4959204 100644
--- a/services/core/java/com/android/server/integrity/TEST_MAPPING
+++ b/services/core/java/com/android/server/integrity/TEST_MAPPING
@@ -7,6 +7,14 @@
           "include-filter": "com.android.server.integrity."
         }
       ]
+    },
+    {
+      "name": "GtsSecurityHostTestCases",
+      "options": [
+        {
+          "include-filter": "com.google.android.security.gts.AppIntegrityManagerTest"
+        }
+      ]
     }
   ]
 }
diff --git a/services/core/java/com/android/server/locksettings/LockSettingsService.java b/services/core/java/com/android/server/locksettings/LockSettingsService.java
index 6faf674..c1c3760 100644
--- a/services/core/java/com/android/server/locksettings/LockSettingsService.java
+++ b/services/core/java/com/android/server/locksettings/LockSettingsService.java
@@ -1572,6 +1572,24 @@
                     "This operation requires secure lock screen feature");
         }
         checkWritePermission(userId);
+
+        // When changing credential for profiles with unified challenge, some callers
+        // will pass in empty credential while others will pass in the credential of
+        // the parent user. setLockCredentialInternal() handles the formal case (empty
+        // credential) correctly but not the latter. As a stopgap fix, convert the latter
+        // case to the formal. The long-term fix would be fixing LSS such that it should
+        // accept only the parent user credential on its public API interfaces, swap it
+        // with the profile's random credential at that API boundary (i.e. here) and make
+        // sure LSS internally does not special case profile with unififed challenge: b/80170828.
+        if (!savedCredential.isNone() && isManagedProfileWithUnifiedLock(userId)) {
+            // Verify the parent credential again, to make sure we have a fresh enough
+            // auth token such that getDecryptedPasswordForTiedProfile() inside
+            // setLockCredentialInternal() can function correctly.
+            verifyCredential(savedCredential, /* challenge */ 0,
+                    mUserManager.getProfileParent(userId).id);
+            savedCredential.zeroize();
+            savedCredential = LockscreenCredential.createNone();
+        }
         synchronized (mSeparateChallengeLock) {
             if (!setLockCredentialInternal(credential, savedCredential,
                     userId, /* isLockTiedToParent= */ false)) {
@@ -1627,6 +1645,7 @@
             // get credential from keystore when managed profile has unified lock
             if (savedCredential.isNone()) {
                 try {
+                    //TODO: remove as part of b/80170828
                     savedCredential = getDecryptedPasswordForTiedProfile(userId);
                 } catch (FileNotFoundException e) {
                     Slog.i(TAG, "Child profile key not found");
@@ -2876,6 +2895,7 @@
         if (savedCredential.isNone() && isManagedProfileWithUnifiedLock(userId)) {
             // get credential from keystore when managed profile has unified lock
             try {
+                //TODO: remove as part of b/80170828
                 savedCredential = getDecryptedPasswordForTiedProfile(userId);
             } catch (FileNotFoundException e) {
                 Slog.i(TAG, "Child profile key not found");
diff --git a/services/core/java/com/android/server/media/MediaRoute2Provider.java b/services/core/java/com/android/server/media/MediaRoute2Provider.java
index f144405..4cb1ed9 100644
--- a/services/core/java/com/android/server/media/MediaRoute2Provider.java
+++ b/services/core/java/com/android/server/media/MediaRoute2Provider.java
@@ -111,7 +111,6 @@
         void onProviderStateChanged(@Nullable MediaRoute2Provider provider);
         void onSessionCreated(@NonNull MediaRoute2Provider provider,
                 @Nullable RoutingSessionInfo sessionInfo, long requestId);
-        void onSessionCreationFailed(@NonNull MediaRoute2Provider provider, long requestId);
         void onSessionUpdated(@NonNull MediaRoute2Provider provider,
                 @NonNull RoutingSessionInfo sessionInfo);
         void onSessionReleased(@NonNull MediaRoute2Provider provider,
diff --git a/services/core/java/com/android/server/media/MediaRoute2ProviderServiceProxy.java b/services/core/java/com/android/server/media/MediaRoute2ProviderServiceProxy.java
index e64776c..36a7bd9 100644
--- a/services/core/java/com/android/server/media/MediaRoute2ProviderServiceProxy.java
+++ b/services/core/java/com/android/server/media/MediaRoute2ProviderServiceProxy.java
@@ -328,19 +328,6 @@
         mCallback.onSessionCreated(this, sessionInfo, requestId);
     }
 
-    private void onSessionCreationFailed(Connection connection, long requestId) {
-        if (mActiveConnection != connection) {
-            return;
-        }
-
-        if (requestId == MediaRoute2ProviderService.REQUEST_ID_NONE) {
-            Slog.w(TAG, "onSessionCreationFailed: Ignoring requestId REQUEST_ID_NONE");
-            return;
-        }
-
-        mCallback.onSessionCreationFailed(this, requestId);
-    }
-
     private void onSessionUpdated(Connection connection, RoutingSessionInfo sessionInfo) {
         if (mActiveConnection != connection) {
             return;
@@ -543,10 +530,6 @@
             mHandler.post(() -> onSessionCreated(Connection.this, sessionInfo, requestId));
         }
 
-        void postSessionCreationFailed(long requestId) {
-            mHandler.post(() -> onSessionCreationFailed(Connection.this, requestId));
-        }
-
         void postSessionUpdated(RoutingSessionInfo sessionInfo) {
             mHandler.post(() -> onSessionUpdated(Connection.this, sessionInfo));
         }
@@ -555,7 +538,7 @@
             mHandler.post(() -> onSessionReleased(Connection.this, sessionInfo));
         }
 
-        void postSessionReleased(long requestId, int reason) {
+        void postRequestFailed(long requestId, int reason) {
             mHandler.post(() -> onRequestFailed(Connection.this, requestId, reason));
         }
     }
@@ -589,14 +572,6 @@
         }
 
         @Override
-        public void notifySessionCreationFailed(long requestId) {
-            Connection connection = mConnectionRef.get();
-            if (connection != null) {
-                connection.postSessionCreationFailed(requestId);
-            }
-        }
-
-        @Override
         public void notifySessionUpdated(RoutingSessionInfo sessionInfo) {
             Connection connection = mConnectionRef.get();
             if (connection != null) {
@@ -616,7 +591,7 @@
         public void notifyRequestFailed(long requestId, int reason) {
             Connection connection = mConnectionRef.get();
             if (connection != null) {
-                connection.postSessionReleased(requestId, reason);
+                connection.postRequestFailed(requestId, reason);
             }
         }
     }
diff --git a/services/core/java/com/android/server/media/MediaRouter2ServiceImpl.java b/services/core/java/com/android/server/media/MediaRouter2ServiceImpl.java
index e78a35c..16f2add 100644
--- a/services/core/java/com/android/server/media/MediaRouter2ServiceImpl.java
+++ b/services/core/java/com/android/server/media/MediaRouter2ServiceImpl.java
@@ -608,7 +608,8 @@
         routerRecord.mUserRecord.mHandler.sendMessage(
                 obtainMessage(UserHandler::requestCreateSessionOnHandler,
                         routerRecord.mUserRecord.mHandler,
-                        routerRecord, route, uniqueRequestId, sessionHints));
+                        routerRecord, /* managerRecord= */ null, route, uniqueRequestId,
+                        sessionHints));
     }
 
     private void selectRouteWithRouter2Locked(@NonNull IMediaRouter2 router,
@@ -788,7 +789,8 @@
         routerRecord.mUserRecord.mHandler.sendMessage(
                 obtainMessage(UserHandler::requestCreateSessionOnHandler,
                         routerRecord.mUserRecord.mHandler,
-                        routerRecord, route, uniqueRequestId, null /* sessionHints */));
+                        routerRecord, managerRecord, route, uniqueRequestId,
+                        /* sessionHints= */ null));
     }
 
     private void selectRouteWithManagerLocked(@NonNull IMediaRouter2Manager manager,
@@ -927,7 +929,7 @@
         return ((long) routerOrManagerId << 32) | originalRequestId;
     }
 
-    static int toRouterOrManagerId(long uniqueRequestId) {
+    static int toRequesterId(long uniqueRequestId) {
         return (int) (uniqueRequestId >> 32);
     }
 
@@ -1107,11 +1109,6 @@
                     this, provider, sessionInfo, requestId));
         }
 
-        @Override
-        public void onSessionCreationFailed(@NonNull MediaRoute2Provider provider, long requestId) {
-            sendMessage(PooledLambda.obtainMessage(UserHandler::onSessionCreationFailedOnHandler,
-                    this, provider, requestId));
-        }
 
         @Override
         public void onSessionUpdated(@NonNull MediaRoute2Provider provider,
@@ -1223,7 +1220,8 @@
         }
 
         private void requestCreateSessionOnHandler(@NonNull RouterRecord routerRecord,
-                @NonNull MediaRoute2Info route, long requestId, @Nullable Bundle sessionHints) {
+                @Nullable ManagerRecord managerRecord, @NonNull MediaRoute2Info route,
+                long requestId, @Nullable Bundle sessionHints) {
 
             final MediaRoute2Provider provider = findProvider(route.getProviderId());
             if (provider == null) {
@@ -1235,7 +1233,7 @@
 
             // TODO: Apply timeout for each request (How many seconds should we wait?)
             SessionCreationRequest request =
-                    new SessionCreationRequest(routerRecord, route, requestId);
+                    new SessionCreationRequest(routerRecord, managerRecord, route, requestId);
             mSessionCreationRequests.add(request);
 
             provider.requestCreateSession(routerRecord.mPackageName, route.getOriginalId(),
@@ -1421,30 +1419,6 @@
             mSessionToRouterMap.put(sessionInfo.getId(), routerRecord);
         }
 
-        private void onSessionCreationFailedOnHandler(@NonNull MediaRoute2Provider provider,
-                long requestId) {
-            SessionCreationRequest matchingRequest = null;
-
-            for (SessionCreationRequest request : mSessionCreationRequests) {
-                if (request.mRequestId == requestId
-                        && TextUtils.equals(
-                                request.mRoute.getProviderId(), provider.getUniqueId())) {
-                    matchingRequest = request;
-                    break;
-                }
-            }
-
-            if (matchingRequest == null) {
-                Slog.w(TAG, "Ignoring session creation failed result for unknown request. "
-                        + "requestId=" + requestId);
-                return;
-            }
-
-            mSessionCreationRequests.remove(matchingRequest);
-            notifySessionCreationFailedToRouter(matchingRequest.mRouterRecord,
-                    toOriginalRequestId(requestId));
-        }
-
         private void onSessionInfoChangedOnHandler(@NonNull MediaRoute2Provider provider,
                 @NonNull RoutingSessionInfo sessionInfo) {
             List<IMediaRouter2Manager> managers = getManagers();
@@ -1483,30 +1457,56 @@
 
         private void onRequestFailedOnHandler(@NonNull MediaRoute2Provider provider,
                 long requestId, int reason) {
-            final int managerId = toRouterOrManagerId(requestId);
-
-            MediaRouter2ServiceImpl service = mServiceRef.get();
-            if (service == null) {
+            if (handleSessionCreationRequestFailed(provider, requestId, reason)) {
                 return;
             }
 
-            ManagerRecord managerToNotifyFailure = null;
-            synchronized (service.mLock) {
-                for (ManagerRecord manager : mUserRecord.mManagerRecords) {
-                    if (manager.mManagerId == managerId) {
-                        managerToNotifyFailure = manager;
-                        break;
-                    }
+            final int requesterId = toRequesterId(requestId);
+            for (ManagerRecord manager : getManagerRecords()) {
+                if (manager.mManagerId == requesterId) {
+                    notifyRequestFailedToManager(
+                            manager.mManager, toOriginalRequestId(requestId), reason);
+                    return;
                 }
             }
 
-            if (managerToNotifyFailure == null) {
-                Slog.w(TAG, "No matching managerRecord found for managerId=" + managerId);
-                return;
+            // Currently, only the manager can get notified of failures.
+            // TODO: Notify router too when the related callback is introduced.
+        }
+
+        // TODO: Find a way to prevent providers from notifying error on random requestId.
+        //       Solutions can be:
+        //       1) Record the other type of requests too (not only session creation request)
+        //       2) Throw exception on providers when they try to notify error on random requestId.
+        private boolean handleSessionCreationRequestFailed(@NonNull MediaRoute2Provider provider,
+                long requestId, int reason) {
+            // Check whether the failure is about creating a session
+            SessionCreationRequest matchingRequest = null;
+            for (SessionCreationRequest request : mSessionCreationRequests) {
+                if (request.mRequestId == requestId && TextUtils.equals(
+                        request.mRoute.getProviderId(), provider.getUniqueId())) {
+                    matchingRequest = request;
+                    break;
+                }
             }
 
-            notifyRequestFailedToManager(
-                    managerToNotifyFailure.mManager, toOriginalRequestId(requestId), reason);
+            if (matchingRequest == null) {
+                // The failure is not about creating a session.
+                return false;
+            }
+
+            mSessionCreationRequests.remove(matchingRequest);
+
+            // Notify the requester about the failure.
+            // The call should be made by either MediaRouter2 or MediaRouter2Manager.
+            if (matchingRequest.mRequestedManagerRecord == null) {
+                notifySessionCreationFailedToRouter(
+                        matchingRequest.mRouterRecord, toOriginalRequestId(requestId));
+            } else {
+                notifyRequestFailedToManager(matchingRequest.mRequestedManagerRecord.mManager,
+                        toOriginalRequestId(requestId), reason);
+            }
+            return true;
         }
 
         private void notifySessionCreatedToRouter(@NonNull RouterRecord routerRecord,
@@ -1596,6 +1596,16 @@
             return managers;
         }
 
+        private List<ManagerRecord> getManagerRecords() {
+            MediaRouter2ServiceImpl service = mServiceRef.get();
+            if (service == null) {
+                return new ArrayList<>();
+            }
+            synchronized (service.mLock) {
+                return new ArrayList<>(mUserRecord.mManagerRecords);
+            }
+        }
+
         private void notifyRoutesToRouter(@NonNull IMediaRouter2 router) {
             List<MediaRoute2Info> routes = new ArrayList<>();
             for (MediaRoute2ProviderInfo providerInfo : mLastProviderInfos) {
@@ -1789,12 +1799,16 @@
 
         final class SessionCreationRequest {
             public final RouterRecord mRouterRecord;
+            public final ManagerRecord mRequestedManagerRecord;
             public final MediaRoute2Info mRoute;
             public final long mRequestId;
 
+            // requestedManagerRecord is not null only when the request is made by manager.
             SessionCreationRequest(@NonNull RouterRecord routerRecord,
+                    @Nullable ManagerRecord requestedManagerRecord,
                     @NonNull MediaRoute2Info route, long requestId) {
                 mRouterRecord = routerRecord;
+                mRequestedManagerRecord = requestedManagerRecord;
                 mRoute = route;
                 mRequestId = requestId;
             }
diff --git a/services/core/java/com/android/server/media/SystemMediaRoute2Provider.java b/services/core/java/com/android/server/media/SystemMediaRoute2Provider.java
index da9c27e..1922c8c 100644
--- a/services/core/java/com/android/server/media/SystemMediaRoute2Provider.java
+++ b/services/core/java/com/android/server/media/SystemMediaRoute2Provider.java
@@ -127,7 +127,8 @@
     @Override
     public void requestCreateSession(String packageName, String routeId, long requestId,
             Bundle sessionHints) {
-        // Do nothing
+        // Handle it as an internal transfer.
+        transferToRoute(SYSTEM_SESSION_ID, routeId, requestId);
     }
 
     @Override
diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java
index b5e7ea0..e7553b6 100755
--- a/services/core/java/com/android/server/notification/NotificationManagerService.java
+++ b/services/core/java/com/android/server/notification/NotificationManagerService.java
@@ -2189,19 +2189,19 @@
 
     private void registerNotificationPreferencesPullers() {
         mPullAtomCallback = new StatsPullAtomCallbackImpl();
-        mStatsManager.registerPullAtomCallback(
+        mStatsManager.setPullAtomCallback(
                 PACKAGE_NOTIFICATION_PREFERENCES,
                 null, // use default PullAtomMetadata values
                 BackgroundThread.getExecutor(),
                 mPullAtomCallback
         );
-        mStatsManager.registerPullAtomCallback(
+        mStatsManager.setPullAtomCallback(
                 PACKAGE_NOTIFICATION_CHANNEL_PREFERENCES,
                 null, // use default PullAtomMetadata values
                 BackgroundThread.getExecutor(),
                 mPullAtomCallback
         );
-        mStatsManager.registerPullAtomCallback(
+        mStatsManager.setPullAtomCallback(
                 PACKAGE_NOTIFICATION_CHANNEL_GROUP_PREFERENCES,
                 null, // use default PullAtomMetadata values
                 BackgroundThread.getExecutor(),
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index b547105..799ce65 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -18562,9 +18562,10 @@
                 Slog.d(TAG, "Updating package:" + ps.name + " install state for user:"
                         + nextUserId);
             }
-
-            destroyAppDataLIF(pkg, nextUserId,
-                    FLAG_STORAGE_DE | FLAG_STORAGE_CE | FLAG_STORAGE_EXTERNAL);
+            if ((flags & PackageManager.DELETE_KEEP_DATA) == 0) {
+                destroyAppDataLIF(pkg, nextUserId,
+                        FLAG_STORAGE_DE | FLAG_STORAGE_CE | FLAG_STORAGE_EXTERNAL);
+            }
             clearDefaultBrowserIfNeededForUser(ps.name, nextUserId);
             removeKeystoreDataIfNeeded(mInjector.getUserManagerInternal(), nextUserId, ps.appId);
             clearPackagePreferredActivities(ps.name, nextUserId);
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 612989f..32cff3b 100644
--- a/services/core/java/com/android/server/stats/pull/StatsPullAtomService.java
+++ b/services/core/java/com/android/server/stats/pull/StatsPullAtomService.java
@@ -182,7 +182,7 @@
      * How long to wait on an individual subsystem to return its stats.
      */
     private static final long EXTERNAL_STATS_SYNC_TIMEOUT_MILLIS = 2000;
-    private static final long NS_PER_SEC = 1000000000;
+    private static final long MILLIS_PER_SEC = 1000;
     private static final long MILLI_AMP_HR_TO_NANO_AMP_SECS = 1_000_000L * 3600L;
 
     private static final int MAX_BATTERY_STATS_HELPER_FREQUENCY_MS = 1000;
@@ -680,7 +680,7 @@
         PullAtomMetadata metadata = new PullAtomMetadata.Builder()
                 .setAdditiveFields(new int[] {2, 3, 4, 5})
                 .build();
-        mStatsManager.registerPullAtomCallback(
+        mStatsManager.setPullAtomCallback(
                 tagId,
                 metadata,
                 BackgroundThread.getExecutor(),
@@ -772,7 +772,7 @@
         PullAtomMetadata metadata = new PullAtomMetadata.Builder()
                 .setAdditiveFields(new int[] {3, 4, 5, 6})
                 .build();
-        mStatsManager.registerPullAtomCallback(
+        mStatsManager.setPullAtomCallback(
                 tagId,
                 metadata,
                 BackgroundThread.getExecutor(),
@@ -810,7 +810,7 @@
         PullAtomMetadata metadata = new PullAtomMetadata.Builder()
                 .setAdditiveFields(new int[] {2, 3, 4, 5})
                 .build();
-        mStatsManager.registerPullAtomCallback(
+        mStatsManager.setPullAtomCallback(
                 tagId,
                 metadata,
                 BackgroundThread.getExecutor(),
@@ -848,7 +848,7 @@
         PullAtomMetadata metadata = new PullAtomMetadata.Builder()
                 .setAdditiveFields(new int[] {3, 4, 5, 6})
                 .build();
-        mStatsManager.registerPullAtomCallback(
+        mStatsManager.setPullAtomCallback(
                 tagId,
                 metadata,
                 BackgroundThread.getExecutor(),
@@ -886,7 +886,7 @@
         PullAtomMetadata metadata = new PullAtomMetadata.Builder()
                 .setAdditiveFields(new int[] {2, 3})
                 .build();
-        mStatsManager.registerPullAtomCallback(
+        mStatsManager.setPullAtomCallback(
                 tagId,
                 metadata,
                 BackgroundThread.getExecutor(),
@@ -955,7 +955,7 @@
 
     private void registerKernelWakelock() {
         int tagId = FrameworkStatsLog.KERNEL_WAKELOCK;
-        mStatsManager.registerPullAtomCallback(
+        mStatsManager.setPullAtomCallback(
                 tagId,
                 /* PullAtomMetadata */ null,
                 BackgroundThread.getExecutor(),
@@ -986,7 +986,7 @@
         PullAtomMetadata metadata = new PullAtomMetadata.Builder()
                 .setAdditiveFields(new int[] {3})
                 .build();
-        mStatsManager.registerPullAtomCallback(
+        mStatsManager.setPullAtomCallback(
                 tagId,
                 metadata,
                 BackgroundThread.getExecutor(),
@@ -1017,7 +1017,7 @@
         PullAtomMetadata metadata = new PullAtomMetadata.Builder()
                 .setAdditiveFields(new int[] {2, 3})
                 .build();
-        mStatsManager.registerPullAtomCallback(
+        mStatsManager.setPullAtomCallback(
                 tagId,
                 metadata,
                 BackgroundThread.getExecutor(),
@@ -1046,7 +1046,7 @@
         PullAtomMetadata metadata = new PullAtomMetadata.Builder()
                 .setAdditiveFields(new int[] {4})
                 .build();
-        mStatsManager.registerPullAtomCallback(
+        mStatsManager.setPullAtomCallback(
                 tagId,
                 metadata,
                 BackgroundThread.getExecutor(),
@@ -1078,7 +1078,7 @@
         PullAtomMetadata metadata = new PullAtomMetadata.Builder()
                 .setAdditiveFields(new int[] {2})
                 .build();
-        mStatsManager.registerPullAtomCallback(
+        mStatsManager.setPullAtomCallback(
                 tagId,
                 metadata,
                 BackgroundThread.getExecutor(),
@@ -1105,7 +1105,7 @@
         PullAtomMetadata metadata = new PullAtomMetadata.Builder()
                 .setAdditiveFields(new int[] {3})
                 .build();
-        mStatsManager.registerPullAtomCallback(
+        mStatsManager.setPullAtomCallback(
                 tagId,
                 metadata,
                 BackgroundThread.getExecutor(),
@@ -1130,7 +1130,7 @@
 
     private void registerWifiActivityInfo() {
         int tagId = FrameworkStatsLog.WIFI_ACTIVITY_INFO;
-        mStatsManager.registerPullAtomCallback(
+        mStatsManager.setPullAtomCallback(
                 tagId,
                 null, // use default PullAtomMetadata values
                 BackgroundThread.getExecutor(),
@@ -1182,7 +1182,7 @@
 
     private void registerModemActivityInfo() {
         int tagId = FrameworkStatsLog.MODEM_ACTIVITY_INFO;
-        mStatsManager.registerPullAtomCallback(
+        mStatsManager.setPullAtomCallback(
                 tagId,
                 null, // use default PullAtomMetadata values
                 BackgroundThread.getExecutor(),
@@ -1220,7 +1220,7 @@
 
     private void registerBluetoothActivityInfo() {
         int tagId = FrameworkStatsLog.BLUETOOTH_ACTIVITY_INFO;
-        mStatsManager.registerPullAtomCallback(
+        mStatsManager.setPullAtomCallback(
                 tagId,
                 /* metadata */ null,
                 BackgroundThread.getExecutor(),
@@ -1249,10 +1249,10 @@
     private void registerSystemElapsedRealtime() {
         int tagId = FrameworkStatsLog.SYSTEM_ELAPSED_REALTIME;
         PullAtomMetadata metadata = new PullAtomMetadata.Builder()
-                .setCoolDownNs(NS_PER_SEC)
-                .setTimeoutNs(NS_PER_SEC / 2)
+                .setCoolDownMillis(MILLIS_PER_SEC)
+                .setTimeoutMillis(MILLIS_PER_SEC / 2)
                 .build();
-        mStatsManager.registerPullAtomCallback(
+        mStatsManager.setPullAtomCallback(
                 tagId,
                 metadata,
                 BackgroundThread.getExecutor(),
@@ -1271,7 +1271,7 @@
 
     private void registerSystemUptime() {
         int tagId = FrameworkStatsLog.SYSTEM_UPTIME;
-        mStatsManager.registerPullAtomCallback(
+        mStatsManager.setPullAtomCallback(
                 tagId,
                 null, // use default PullAtomMetadata values
                 BackgroundThread.getExecutor(),
@@ -1293,7 +1293,7 @@
         PullAtomMetadata metadata = new PullAtomMetadata.Builder()
                 .setAdditiveFields(new int[] {4, 5, 6, 7, 8})
                 .build();
-        mStatsManager.registerPullAtomCallback(
+        mStatsManager.setPullAtomCallback(
                 tagId,
                 metadata,
                 BackgroundThread.getExecutor(),
@@ -1336,7 +1336,7 @@
 
     private void registerProcessMemoryHighWaterMark() {
         int tagId = FrameworkStatsLog.PROCESS_MEMORY_HIGH_WATER_MARK;
-        mStatsManager.registerPullAtomCallback(
+        mStatsManager.setPullAtomCallback(
                 tagId,
                 null, // use default PullAtomMetadata values
                 BackgroundThread.getExecutor(),
@@ -1389,7 +1389,7 @@
 
     private void registerProcessMemorySnapshot() {
         int tagId = FrameworkStatsLog.PROCESS_MEMORY_SNAPSHOT;
-        mStatsManager.registerPullAtomCallback(
+        mStatsManager.setPullAtomCallback(
                 tagId,
                 null, // use default PullAtomMetadata values
                 BackgroundThread.getExecutor(),
@@ -1449,7 +1449,7 @@
 
     private void registerSystemIonHeapSize() {
         int tagId = FrameworkStatsLog.SYSTEM_ION_HEAP_SIZE;
-        mStatsManager.registerPullAtomCallback(
+        mStatsManager.setPullAtomCallback(
                 tagId,
                 null, // use default PullAtomMetadata values
                 BackgroundThread.getExecutor(),
@@ -1472,7 +1472,7 @@
             return;
         }
         int tagId = FrameworkStatsLog.ION_HEAP_SIZE;
-        mStatsManager.registerPullAtomCallback(
+        mStatsManager.setPullAtomCallback(
                 tagId,
                 /* PullAtomMetadata */ null,
                 BackgroundThread.getExecutor(),
@@ -1492,7 +1492,7 @@
 
     private void registerProcessSystemIonHeapSize() {
         int tagId = FrameworkStatsLog.PROCESS_SYSTEM_ION_HEAP_SIZE;
-        mStatsManager.registerPullAtomCallback(
+        mStatsManager.setPullAtomCallback(
                 tagId,
                 null, // use default PullAtomMetadata values
                 BackgroundThread.getExecutor(),
@@ -1518,7 +1518,7 @@
 
     private void registerTemperature() {
         int tagId = FrameworkStatsLog.TEMPERATURE;
-        mStatsManager.registerPullAtomCallback(
+        mStatsManager.setPullAtomCallback(
                 tagId,
                 null, // use default PullAtomMetadata values
                 BackgroundThread.getExecutor(),
@@ -1556,7 +1556,7 @@
 
     private void registerCoolingDevice() {
         int tagId = FrameworkStatsLog.COOLING_DEVICE;
-        mStatsManager.registerPullAtomCallback(
+        mStatsManager.setPullAtomCallback(
                 tagId,
                 null, // use default PullAtomMetadata values
                 BackgroundThread.getExecutor(),
@@ -1596,7 +1596,7 @@
         PullAtomMetadata metadata = new PullAtomMetadata.Builder()
                 .setAdditiveFields(new int[] {4, 5, 6, 8, 12})
                 .build();
-        mStatsManager.registerPullAtomCallback(
+        mStatsManager.setPullAtomCallback(
                 tagId,
                 metadata,
                 BackgroundThread.getExecutor(),
@@ -1639,7 +1639,7 @@
 
     private void registerBinderCallsStatsExceptions() {
         int tagId = FrameworkStatsLog.BINDER_CALLS_EXCEPTIONS;
-        mStatsManager.registerPullAtomCallback(
+        mStatsManager.setPullAtomCallback(
                 tagId,
                 null, // use default PullAtomMetadata values
                 BackgroundThread.getExecutor(),
@@ -1674,7 +1674,7 @@
         PullAtomMetadata metadata = new PullAtomMetadata.Builder()
                 .setAdditiveFields(new int[] {5, 6, 7, 8, 9})
                 .build();
-        mStatsManager.registerPullAtomCallback(
+        mStatsManager.setPullAtomCallback(
                 tagId,
                 metadata,
                 BackgroundThread.getExecutor(),
@@ -1716,7 +1716,7 @@
 
     private void registerDiskStats() {
         int tagId = FrameworkStatsLog.DISK_STATS;
-        mStatsManager.registerPullAtomCallback(
+        mStatsManager.setPullAtomCallback(
                 tagId,
                 null, // use default PullAtomMetadata values
                 BackgroundThread.getExecutor(),
@@ -1782,7 +1782,7 @@
 
     private void registerDirectoryUsage() {
         int tagId = FrameworkStatsLog.DIRECTORY_USAGE;
-        mStatsManager.registerPullAtomCallback(
+        mStatsManager.setPullAtomCallback(
                 tagId,
                 null, // use default PullAtomMetadata values
                 BackgroundThread.getExecutor(),
@@ -1823,7 +1823,7 @@
 
     private void registerAppSize() {
         int tagId = FrameworkStatsLog.APP_SIZE;
-        mStatsManager.registerPullAtomCallback(
+        mStatsManager.setPullAtomCallback(
                 tagId,
                 null, // use default PullAtomMetadata values
                 BackgroundThread.getExecutor(),
@@ -1867,7 +1867,7 @@
 
     private void registerCategorySize() {
         int tagId = FrameworkStatsLog.CATEGORY_SIZE;
-        mStatsManager.registerPullAtomCallback(
+        mStatsManager.setPullAtomCallback(
                 tagId,
                 null, // use default PullAtomMetadata values
                 BackgroundThread.getExecutor(),
@@ -1971,7 +1971,7 @@
 
     private void registerNumFingerprintsEnrolled() {
         int tagId = FrameworkStatsLog.NUM_FINGERPRINTS_ENROLLED;
-        mStatsManager.registerPullAtomCallback(
+        mStatsManager.setPullAtomCallback(
                 tagId,
                 null, // use default PullAtomMetadata values
                 BackgroundThread.getExecutor(),
@@ -1981,7 +1981,7 @@
 
     private void registerNumFacesEnrolled() {
         int tagId = FrameworkStatsLog.NUM_FACES_ENROLLED;
-        mStatsManager.registerPullAtomCallback(
+        mStatsManager.setPullAtomCallback(
                 tagId,
                 null, // use default PullAtomMetadata values
                 BackgroundThread.getExecutor(),
@@ -2039,7 +2039,7 @@
 
     private void registerProcStats() {
         int tagId = FrameworkStatsLog.PROC_STATS;
-        mStatsManager.registerPullAtomCallback(
+        mStatsManager.setPullAtomCallback(
                 tagId,
                 null, // use default PullAtomMetadata values
                 BackgroundThread.getExecutor(),
@@ -2049,7 +2049,7 @@
 
     private void registerProcStatsPkgProc() {
         int tagId = FrameworkStatsLog.PROC_STATS_PKG_PROC;
-        mStatsManager.registerPullAtomCallback(
+        mStatsManager.setPullAtomCallback(
                 tagId,
                 null, // use default PullAtomMetadata values
                 BackgroundThread.getExecutor(),
@@ -2120,9 +2120,9 @@
         int tagId = FrameworkStatsLog.DISK_IO;
         PullAtomMetadata metadata = new PullAtomMetadata.Builder()
                 .setAdditiveFields(new int[] {2, 3, 4, 5, 6, 7, 8, 9, 10, 11})
-                .setCoolDownNs(3 * NS_PER_SEC)
+                .setCoolDownMillis(3 * MILLIS_PER_SEC)
                 .build();
-        mStatsManager.registerPullAtomCallback(
+        mStatsManager.setPullAtomCallback(
                 tagId,
                 metadata,
                 BackgroundThread.getExecutor(),
@@ -2155,7 +2155,7 @@
 
     private void registerPowerProfile() {
         int tagId = FrameworkStatsLog.POWER_PROFILE;
-        mStatsManager.registerPullAtomCallback(
+        mStatsManager.setPullAtomCallback(
                 tagId,
                 /* PullAtomMetadata */ null,
                 BackgroundThread.getExecutor(),
@@ -2180,9 +2180,9 @@
         int tagId = FrameworkStatsLog.PROCESS_CPU_TIME;
         // Min cool-down is 5 sec, in line with what ActivityManagerService uses.
         PullAtomMetadata metadata = new PullAtomMetadata.Builder()
-                .setCoolDownNs(5 * NS_PER_SEC)
+                .setCoolDownMillis(5 * MILLIS_PER_SEC)
                 .build();
-        mStatsManager.registerPullAtomCallback(
+        mStatsManager.setPullAtomCallback(
                 tagId,
                 metadata,
                 BackgroundThread.getExecutor(),
@@ -2217,7 +2217,7 @@
         PullAtomMetadata metadata = new PullAtomMetadata.Builder()
                 .setAdditiveFields(new int[] {7, 9, 11, 13, 15, 17, 19, 21})
                 .build();
-        mStatsManager.registerPullAtomCallback(
+        mStatsManager.setPullAtomCallback(
                 tagId,
                 metadata,
                 BackgroundThread.getExecutor(),
@@ -2310,7 +2310,7 @@
 
     private void registerDeviceCalculatedPowerUse() {
         int tagId = FrameworkStatsLog.DEVICE_CALCULATED_POWER_USE;
-        mStatsManager.registerPullAtomCallback(
+        mStatsManager.setPullAtomCallback(
                 tagId,
                 null, // use default PullAtomMetadata values
                 BackgroundThread.getExecutor(),
@@ -2330,7 +2330,7 @@
 
     private void registerDeviceCalculatedPowerBlameUid() {
         int tagId = FrameworkStatsLog.DEVICE_CALCULATED_POWER_BLAME_UID;
-        mStatsManager.registerPullAtomCallback(
+        mStatsManager.setPullAtomCallback(
                 tagId,
                 null, // use default PullAtomMetadata values
                 BackgroundThread.getExecutor(),
@@ -2360,7 +2360,7 @@
 
     private void registerDeviceCalculatedPowerBlameOther() {
         int tagId = FrameworkStatsLog.DEVICE_CALCULATED_POWER_BLAME_OTHER;
-        mStatsManager.registerPullAtomCallback(
+        mStatsManager.setPullAtomCallback(
                 tagId,
                 null, // use default PullAtomMetadata values
                 BackgroundThread.getExecutor(),
@@ -2396,7 +2396,7 @@
         PullAtomMetadata metadata = new PullAtomMetadata.Builder()
                 .setAdditiveFields(new int[] {1, 2, 3, 4})
                 .build();
-        mStatsManager.registerPullAtomCallback(
+        mStatsManager.setPullAtomCallback(
                 tagId,
                 metadata,
                 BackgroundThread.getExecutor(),
@@ -2447,7 +2447,7 @@
         PullAtomMetadata metadata = new PullAtomMetadata.Builder()
                 .setAdditiveFields(new int[] {1, 2, 3, 4})
                 .build();
-        mStatsManager.registerPullAtomCallback(
+        mStatsManager.setPullAtomCallback(
                 tagId,
                 metadata,
                 BackgroundThread.getExecutor(),
@@ -2485,7 +2485,7 @@
 
     private void registerBuildInformation() {
         int tagId = FrameworkStatsLog.BUILD_INFORMATION;
-        mStatsManager.registerPullAtomCallback(
+        mStatsManager.setPullAtomCallback(
                 tagId,
                 null, // use default PullAtomMetadata values
                 BackgroundThread.getExecutor(),
@@ -2512,7 +2512,7 @@
 
     private void registerRoleHolder() {
         int tagId = FrameworkStatsLog.ROLE_HOLDER;
-        mStatsManager.registerPullAtomCallback(
+        mStatsManager.setPullAtomCallback(
                 tagId,
                 null, // use default PullAtomMetadata values
                 BackgroundThread.getExecutor(),
@@ -2570,7 +2570,7 @@
 
     private void registerDangerousPermissionState() {
         int tagId = FrameworkStatsLog.DANGEROUS_PERMISSION_STATE;
-        mStatsManager.registerPullAtomCallback(
+        mStatsManager.setPullAtomCallback(
                 tagId,
                 null, // use default PullAtomMetadata values
                 BackgroundThread.getExecutor(),
@@ -2660,7 +2660,7 @@
 
     private void registerTimeZoneDataInfo() {
         int tagId = FrameworkStatsLog.TIME_ZONE_DATA_INFO;
-        mStatsManager.registerPullAtomCallback(
+        mStatsManager.setPullAtomCallback(
                 tagId,
                 null, // use default PullAtomMetadata values
                 BackgroundThread.getExecutor(),
@@ -2687,7 +2687,7 @@
 
     private void registerExternalStorageInfo() {
         int tagId = FrameworkStatsLog.EXTERNAL_STORAGE_INFO;
-        mStatsManager.registerPullAtomCallback(
+        mStatsManager.setPullAtomCallback(
                 tagId,
                 null, // use default PullAtomMetadata values
                 BackgroundThread.getExecutor(),
@@ -2737,7 +2737,7 @@
 
     private void registerAppsOnExternalStorageInfo() {
         int tagId = FrameworkStatsLog.APPS_ON_EXTERNAL_STORAGE_INFO;
-        mStatsManager.registerPullAtomCallback(
+        mStatsManager.setPullAtomCallback(
                 tagId,
                 null, // use default PullAtomMetadata values
                 BackgroundThread.getExecutor(),
@@ -2793,7 +2793,7 @@
 
     private void registerFaceSettings() {
         int tagId = FrameworkStatsLog.FACE_SETTINGS;
-        mStatsManager.registerPullAtomCallback(
+        mStatsManager.setPullAtomCallback(
                 tagId,
                 null, // use default PullAtomMetadata values
                 BackgroundThread.getExecutor(),
@@ -2847,7 +2847,7 @@
 
     private void registerAppOps() {
         int tagId = FrameworkStatsLog.APP_OPS;
-        mStatsManager.registerPullAtomCallback(
+        mStatsManager.setPullAtomCallback(
                 tagId,
                 null, // use default PullAtomMetadata values
                 BackgroundThread.getExecutor(),
@@ -2857,7 +2857,7 @@
 
     private void registerRuntimeAppOpAccessMessage() {
         int tagId = FrameworkStatsLog.RUNTIME_APP_OP_ACCESS;
-        mStatsManager.registerPullAtomCallback(
+        mStatsManager.setPullAtomCallback(
                 tagId,
                 null, // use default PullAtomMetadata values
                 BackgroundThread.getExecutor(),
@@ -2927,7 +2927,7 @@
 
     private void registerAppFeaturesOps() {
         int tagId = FrameworkStatsLog.APP_FEATURES_OPS;
-        mStatsManager.registerPullAtomCallback(
+        mStatsManager.setPullAtomCallback(
                 tagId,
                 null, // use default PullAtomMetadata values
                 BackgroundThread.getExecutor(),
@@ -3080,7 +3080,7 @@
 
     private void registerNotificationRemoteViews() {
         int tagId = FrameworkStatsLog.NOTIFICATION_REMOTE_VIEWS;
-        mStatsManager.registerPullAtomCallback(
+        mStatsManager.setPullAtomCallback(
                 tagId,
                 null, // use default PullAtomMetadata values
                 BackgroundThread.getExecutor(),
@@ -3124,7 +3124,7 @@
 
     private void registerDangerousPermissionStateSampled() {
         int tagId = FrameworkStatsLog.DANGEROUS_PERMISSION_STATE_SAMPLED;
-        mStatsManager.registerPullAtomCallback(
+        mStatsManager.setPullAtomCallback(
                 tagId,
                 null, // use default PullAtomMetadata values
                 BackgroundThread.getExecutor(),
@@ -3134,7 +3134,7 @@
 
     private void registerBatteryLevel() {
         int tagId = FrameworkStatsLog.BATTERY_LEVEL;
-        mStatsManager.registerPullAtomCallback(
+        mStatsManager.setPullAtomCallback(
                 tagId,
                 null, // use default PullAtomMetadata values
                 BackgroundThread.getExecutor(),
@@ -3144,7 +3144,7 @@
 
     private void registerRemainingBatteryCapacity() {
         int tagId = FrameworkStatsLog.REMAINING_BATTERY_CAPACITY;
-        mStatsManager.registerPullAtomCallback(
+        mStatsManager.setPullAtomCallback(
                 tagId,
                 null, // use default PullAtomMetadata values
                 BackgroundThread.getExecutor(),
@@ -3154,7 +3154,7 @@
 
     private void registerFullBatteryCapacity() {
         int tagId = FrameworkStatsLog.FULL_BATTERY_CAPACITY;
-        mStatsManager.registerPullAtomCallback(
+        mStatsManager.setPullAtomCallback(
                 tagId,
                 null, // use default PullAtomMetadata values
                 BackgroundThread.getExecutor(),
@@ -3164,7 +3164,7 @@
 
     private void registerBatteryVoltage() {
         int tagId = FrameworkStatsLog.BATTERY_VOLTAGE;
-        mStatsManager.registerPullAtomCallback(
+        mStatsManager.setPullAtomCallback(
                 tagId,
                 null, // use default PullAtomMetadata values
                 BackgroundThread.getExecutor(),
@@ -3174,7 +3174,7 @@
 
     private void registerBatteryCycleCount() {
         int tagId = FrameworkStatsLog.BATTERY_CYCLE_COUNT;
-        mStatsManager.registerPullAtomCallback(
+        mStatsManager.setPullAtomCallback(
                 tagId,
                 null, // use default PullAtomMetadata values
                 BackgroundThread.getExecutor(),
diff --git a/services/core/java/com/android/server/wm/AccessibilityController.java b/services/core/java/com/android/server/wm/AccessibilityController.java
index 61a33b4..d7a80bf 100644
--- a/services/core/java/com/android/server/wm/AccessibilityController.java
+++ b/services/core/java/com/android/server/wm/AccessibilityController.java
@@ -1392,7 +1392,7 @@
                     tempWindowStatesList.add(w);
                 }
             }, false /* traverseTopToBottom */);
-            // Insert the re-parented windows in another display on top of their parents in
+            // Insert the re-parented windows in another display below their parents in
             // default display.
             mService.mRoot.forAllWindows(w -> {
                 final WindowState parentWindow = findRootDisplayParentWindow(w);
diff --git a/services/core/java/com/android/server/wm/SurfaceAnimator.java b/services/core/java/com/android/server/wm/SurfaceAnimator.java
index 3b3234a..19f8ca9 100644
--- a/services/core/java/com/android/server/wm/SurfaceAnimator.java
+++ b/services/core/java/com/android/server/wm/SurfaceAnimator.java
@@ -379,10 +379,8 @@
         final SurfaceControl.Builder builder = animatable.makeAnimationLeash()
                 .setParent(animatable.getAnimationLeashParent())
                 .setHidden(hidden)
-                .setName(surface + " - animation-leash")
-                .setColorLayer();
+                .setName(surface + " - animation-leash");
         final SurfaceControl leash = builder.build();
-        t.unsetColor(leash);
         t.setWindowCrop(leash, width, height);
         t.setPosition(leash, x, y);
         t.show(leash);
diff --git a/services/core/java/com/android/server/wm/TaskOrganizerController.java b/services/core/java/com/android/server/wm/TaskOrganizerController.java
index 8f5d048..b38c18b 100644
--- a/services/core/java/com/android/server/wm/TaskOrganizerController.java
+++ b/services/core/java/com/android/server/wm/TaskOrganizerController.java
@@ -463,8 +463,9 @@
         int configMask = change.getConfigSetMask();
         int windowMask = change.getWindowSetMask();
         configMask &= ActivityInfo.CONFIG_WINDOW_CONFIGURATION
-                | ActivityInfo.CONFIG_SMALLEST_SCREEN_SIZE;
-        windowMask &= WindowConfiguration.WINDOW_CONFIG_BOUNDS;
+                | ActivityInfo.CONFIG_SMALLEST_SCREEN_SIZE | ActivityInfo.CONFIG_SCREEN_SIZE;
+        windowMask &= (WindowConfiguration.WINDOW_CONFIG_BOUNDS
+                | WindowConfiguration.WINDOW_CONFIG_APP_BOUNDS);
         int effects = 0;
         if (configMask != 0) {
             Configuration c = new Configuration(container.getRequestedOverrideConfiguration());
diff --git a/services/core/java/com/android/server/wm/TaskTile.java b/services/core/java/com/android/server/wm/TaskTile.java
index 74d5c33..205b423 100644
--- a/services/core/java/com/android/server/wm/TaskTile.java
+++ b/services/core/java/com/android/server/wm/TaskTile.java
@@ -147,7 +147,7 @@
      */
     void updateResolvedConfig(Configuration inOutResolvedConfig) {
         Rect resolveBounds = inOutResolvedConfig.windowConfiguration.getBounds();
-        if (resolveBounds == null || resolveBounds.isEmpty()) {
+        if (resolveBounds.isEmpty()) {
             resolveBounds.set(getRequestedOverrideBounds());
         }
         int stackMode = inOutResolvedConfig.windowConfiguration.getWindowingMode();
@@ -162,6 +162,17 @@
             inOutResolvedConfig.smallestScreenWidthDp =
                     getRequestedOverrideConfiguration().smallestScreenWidthDp;
         }
+        if (inOutResolvedConfig.screenWidthDp == Configuration.SCREEN_WIDTH_DP_UNDEFINED) {
+            inOutResolvedConfig.screenWidthDp = getRequestedOverrideConfiguration().screenWidthDp;
+        }
+        if (inOutResolvedConfig.screenHeightDp == Configuration.SCREEN_HEIGHT_DP_UNDEFINED) {
+            inOutResolvedConfig.screenHeightDp = getRequestedOverrideConfiguration().screenHeightDp;
+        }
+        Rect resolveAppBounds = inOutResolvedConfig.windowConfiguration.getAppBounds();
+        if (resolveAppBounds == null || resolveAppBounds.isEmpty()) {
+            inOutResolvedConfig.windowConfiguration.setAppBounds(
+                    getRequestedOverrideConfiguration().windowConfiguration.getAppBounds());
+        }
     }
 
     @Override
@@ -184,7 +195,6 @@
         boolean isResizable = topTask == null || topTask.isResizeable();
         info.resizeMode = isResizable ? RESIZE_MODE_RESIZEABLE : RESIZE_MODE_UNRESIZEABLE;
         info.topActivityType = top == null ? ACTIVITY_TYPE_UNDEFINED : top.getActivityType();
-        info.configuration.setTo(getRequestedOverrideConfiguration());
     }
 
     @Override
diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java
index f140ce8..27f1ca0 100644
--- a/services/core/java/com/android/server/wm/WindowState.java
+++ b/services/core/java/com/android/server/wm/WindowState.java
@@ -657,7 +657,7 @@
     private boolean mIsDimming = false;
 
     private @Nullable InsetsSourceProvider mControllableInsetProvider;
-    private InsetsState mRequestedInsetsState;
+    private final InsetsState mRequestedInsetsState = new InsetsState();
 
     private static final float DEFAULT_DIM_AMOUNT_DEAD_WINDOW = 0.5f;
     private KeyInterceptionInfo mKeyInterceptionInfo;
@@ -816,9 +816,6 @@
         mSeq = seq;
         mPowerManagerWrapper = powerManagerWrapper;
         mForceSeamlesslyRotate = token.mRoundedCornerOverlay;
-        mRequestedInsetsState = new InsetsState(
-                getDisplayContent().getInsetsPolicy().getInsetsForDispatch(this),
-                true /* copySources */);
         if (DEBUG) {
             Slog.v(TAG, "Window " + this + " client=" + c.asBinder()
                             + " token=" + token + " (" + mAttrs.token + ")" + " params=" + a);
diff --git a/services/core/xsd/platform-compat-config.xsd b/services/core/xsd/platform-compat-config.xsd
index a70568f..5a4c682 100644
--- a/services/core/xsd/platform-compat-config.xsd
+++ b/services/core/xsd/platform-compat-config.xsd
@@ -27,6 +27,7 @@
                 <xs:attribute type="xs:long" name="id" use="required"/>
                 <xs:attribute type="xs:string" name="name" use="required"/>
                 <xs:attribute type="xs:boolean" name="disabled"/>
+                <xs:attribute type="xs:boolean" name="loggingOnly"/>
                 <xs:attribute type="xs:int" name="enableAfterTargetSdk"/>
                 <xs:attribute type="xs:string" name="description"/>
             </xs:extension>
diff --git a/services/core/xsd/platform-compat-schema/current.txt b/services/core/xsd/platform-compat-schema/current.txt
index 3a33f63..7def58d 100644
--- a/services/core/xsd/platform-compat-schema/current.txt
+++ b/services/core/xsd/platform-compat-schema/current.txt
@@ -7,12 +7,14 @@
     method public boolean getDisabled();
     method public int getEnableAfterTargetSdk();
     method public long getId();
+    method public boolean getLoggingOnly();
     method public String getName();
     method public String getValue();
     method public void setDescription(String);
     method public void setDisabled(boolean);
     method public void setEnableAfterTargetSdk(int);
     method public void setId(long);
+    method public void setLoggingOnly(boolean);
     method public void setName(String);
     method public void setValue(String);
   }
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
index 1de704d..c58eae1 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
@@ -2691,6 +2691,27 @@
         }
     }
 
+    /**
+     * If the device is in Device Owner mode, apply the restriction on adding
+     * a managed profile.
+     */
+    @GuardedBy("getLockObject()")
+    void applyManagedProfileRestrictionIfDeviceOwnerLocked() {
+        final int doUserId = mOwners.getDeviceOwnerUserId();
+        if (doUserId == UserHandle.USER_NULL) {
+            logIfVerbose("No DO found, skipping application of restriction.");
+            return;
+        }
+
+        final UserHandle doUserHandle = UserHandle.of(doUserId);
+        // Set the restriction if not set.
+        if (!mUserManager.hasUserRestriction(
+                UserManager.DISALLOW_ADD_MANAGED_PROFILE, doUserHandle)) {
+            mUserManager.setUserRestriction(UserManager.DISALLOW_ADD_MANAGED_PROFILE, true,
+                    doUserHandle);
+        }
+    }
+
     /** Apply default restrictions that haven't been applied to profile owners yet. */
     private void maybeSetDefaultProfileOwnerUserRestrictions() {
         synchronized (getLockObject()) {
@@ -3901,6 +3922,7 @@
                 maybeStartSecurityLogMonitorOnActivityManagerReady();
                 synchronized (getLockObject()) {
                     migrateToProfileOnOrganizationOwnedDeviceIfCompLocked();
+                    applyManagedProfileRestrictionIfDeviceOwnerLocked();
                 }
                 final int userId = getManagedUserId(UserHandle.USER_SYSTEM);
                 if (userId >= 0) {
@@ -8764,6 +8786,7 @@
         mOwners.writeProfileOwner(userId);
         deleteTransferOwnershipBundleLocked(userId);
         toggleBackupServiceActive(userId, true);
+        applyManagedProfileRestrictionIfDeviceOwnerLocked();
     }
 
     @Override
diff --git a/services/people/java/com/android/server/people/PeopleService.java b/services/people/java/com/android/server/people/PeopleService.java
index 983a639..37bf664 100644
--- a/services/people/java/com/android/server/people/PeopleService.java
+++ b/services/people/java/com/android/server/people/PeopleService.java
@@ -72,13 +72,13 @@
     }
 
     @Override
-    public void onUserUnlocking(@NonNull TargetUser targetUser) {
-        mDataManager.onUserUnlocked(targetUser.getUserIdentifier());
+    public void onUserUnlocked(@NonNull TargetUser user) {
+        mDataManager.onUserUnlocked(user.getUserIdentifier());
     }
 
     @Override
-    public void onUserStopping(@NonNull TargetUser targetUser) {
-        mDataManager.onUserStopped(targetUser.getUserIdentifier());
+    public void onUserStopping(@NonNull TargetUser user) {
+        mDataManager.onUserStopping(user.getUserIdentifier());
     }
 
     @VisibleForTesting
diff --git a/services/people/java/com/android/server/people/data/DataManager.java b/services/people/java/com/android/server/people/data/DataManager.java
index e4ce6ba..4e0afc5 100644
--- a/services/people/java/com/android/server/people/data/DataManager.java
+++ b/services/people/java/com/android/server/people/data/DataManager.java
@@ -198,13 +198,13 @@
         DataMaintenanceService.scheduleJob(mContext, userId);
     }
 
-    /** This method is called when a user is stopped. */
-    public void onUserStopped(int userId) {
+    /** This method is called when a user is stopping. */
+    public void onUserStopping(int userId) {
         if (mUserDataArray.indexOfKey(userId) >= 0) {
             mUserDataArray.get(userId).setUserStopped();
         }
         if (mUsageStatsQueryFutures.indexOfKey(userId) >= 0) {
-            mUsageStatsQueryFutures.valueAt(userId).cancel(true);
+            mUsageStatsQueryFutures.get(userId).cancel(true);
         }
         if (mBroadcastReceivers.indexOfKey(userId) >= 0) {
             mContext.unregisterReceiver(mBroadcastReceivers.get(userId));
diff --git a/services/tests/servicestests/src/com/android/server/compat/CompatConfigBuilder.java b/services/tests/servicestests/src/com/android/server/compat/CompatConfigBuilder.java
index 328c71d..2cbe7be 100644
--- a/services/tests/servicestests/src/com/android/server/compat/CompatConfigBuilder.java
+++ b/services/tests/servicestests/src/com/android/server/compat/CompatConfigBuilder.java
@@ -40,52 +40,57 @@
     }
 
     CompatConfigBuilder addTargetSdkChangeWithId(int sdk, long id) {
-        mChanges.add(new CompatChange(id, "", sdk, false, ""));
+        mChanges.add(new CompatChange(id, "", sdk, false, false, ""));
         return this;
     }
 
     CompatConfigBuilder addTargetSdkDisabledChangeWithId(int sdk, long id) {
-        mChanges.add(new CompatChange(id, "", sdk, true, ""));
+        mChanges.add(new CompatChange(id, "", sdk, true, false, ""));
         return this;
     }
 
     CompatConfigBuilder addTargetSdkChangeWithIdAndName(int sdk, long id, String name) {
-        mChanges.add(new CompatChange(id, name, sdk, false, ""));
+        mChanges.add(new CompatChange(id, name, sdk, false, false, ""));
         return this;
     }
 
     CompatConfigBuilder addTargetSdkChangeWithIdAndDescription(int sdk, long id,
             String description) {
-        mChanges.add(new CompatChange(id, "", sdk, false, description));
+        mChanges.add(new CompatChange(id, "", sdk, false, false, description));
         return this;
     }
 
     CompatConfigBuilder addEnabledChangeWithId(long id) {
-        mChanges.add(new CompatChange(id, "", -1, false, ""));
+        mChanges.add(new CompatChange(id, "", -1, false, false, ""));
         return this;
     }
 
     CompatConfigBuilder addEnabledChangeWithIdAndName(long id, String name) {
-        mChanges.add(new CompatChange(id, name, -1, false, ""));
+        mChanges.add(new CompatChange(id, name, -1, false, false, ""));
         return this;
     }
     CompatConfigBuilder addEnabledChangeWithIdAndDescription(long id, String description) {
-        mChanges.add(new CompatChange(id, "", -1, false, description));
+        mChanges.add(new CompatChange(id, "", -1, false, false, description));
         return this;
     }
 
     CompatConfigBuilder addDisabledChangeWithId(long id) {
-        mChanges.add(new CompatChange(id, "", -1, true, ""));
+        mChanges.add(new CompatChange(id, "", -1, true, false, ""));
         return this;
     }
 
     CompatConfigBuilder addDisabledChangeWithIdAndName(long id, String name) {
-        mChanges.add(new CompatChange(id, name, -1, true, ""));
+        mChanges.add(new CompatChange(id, name, -1, true, false, ""));
         return this;
     }
 
     CompatConfigBuilder addDisabledChangeWithIdAndDescription(long id, String description) {
-        mChanges.add(new CompatChange(id, "", -1, true, description));
+        mChanges.add(new CompatChange(id, "", -1, true, false, description));
+        return this;
+    }
+
+    CompatConfigBuilder addLoggingOnlyChangeWithId(long id) {
+        mChanges.add(new CompatChange(id, "", -1, false, true, ""));
         return this;
     }
 
diff --git a/services/tests/servicestests/src/com/android/server/compat/CompatConfigTest.java b/services/tests/servicestests/src/com/android/server/compat/CompatConfigTest.java
index 44f4ccf..eb2dd64 100644
--- a/services/tests/servicestests/src/com/android/server/compat/CompatConfigTest.java
+++ b/services/tests/servicestests/src/com/android/server/compat/CompatConfigTest.java
@@ -214,6 +214,17 @@
     }
 
     @Test
+    public void testLoggingOnlyChangePreventAddOverride() throws Exception {
+        CompatConfig compatConfig = CompatConfigBuilder.create(mBuildClassifier, mContext)
+                .addLoggingOnlyChangeWithId(1234L)
+                .build();
+
+        assertThrows(SecurityException.class,
+                () -> compatConfig.addOverride(1234L, "com.some.package", true)
+        );
+    }
+
+    @Test
     public void testPreventRemoveOverride() throws Exception {
         CompatConfig compatConfig = CompatConfigBuilder.create(mBuildClassifier, mContext)
                 .addDisabledChangeWithId(1234L)
diff --git a/services/tests/servicestests/src/com/android/server/compat/OverrideValidatorImplTest.java b/services/tests/servicestests/src/com/android/server/compat/OverrideValidatorImplTest.java
index b14291b..16291b2 100644
--- a/services/tests/servicestests/src/com/android/server/compat/OverrideValidatorImplTest.java
+++ b/services/tests/servicestests/src/com/android/server/compat/OverrideValidatorImplTest.java
@@ -20,6 +20,7 @@
 import static com.android.internal.compat.OverrideAllowedState.DISABLED_NON_TARGET_SDK;
 import static com.android.internal.compat.OverrideAllowedState.DISABLED_NOT_DEBUGGABLE;
 import static com.android.internal.compat.OverrideAllowedState.DISABLED_TARGET_SDK_TOO_HIGH;
+import static com.android.internal.compat.OverrideAllowedState.LOGGING_ONLY_CHANGE;
 
 import static com.google.common.truth.Truth.assertThat;
 
@@ -78,6 +79,7 @@
     @Before
     public void setUp() throws Exception {
         MockitoAnnotations.initMocks(this);
+        android.app.compat.ChangeIdStateCache.disable();
         when(mContext.getPackageManager()).thenReturn(mPackageManager);
     }
 
@@ -89,7 +91,8 @@
                     .addTargetSdkChangeWithId(TARGET_SDK, 2)
                     .addTargetSdkChangeWithId(TARGET_SDK_AFTER, 3)
                     .addEnabledChangeWithId(4)
-                    .addDisabledChangeWithId(5).build();
+                    .addDisabledChangeWithId(5)
+                    .addLoggingOnlyChangeWithId(6).build();
         IOverrideValidator overrideValidator = config.getOverrideValidator();
         when(mPackageManager.getApplicationInfo(eq(PACKAGE_NAME), anyInt()))
                 .thenReturn(ApplicationInfoBuilder.create()
@@ -107,6 +110,8 @@
                 overrideValidator.getOverrideAllowedState(4, PACKAGE_NAME);
         OverrideAllowedState stateDisabledChange =
                 overrideValidator.getOverrideAllowedState(5, PACKAGE_NAME);
+        OverrideAllowedState stateDLoggingOnlyChange =
+                overrideValidator.getOverrideAllowedState(6, PACKAGE_NAME);
 
         assertThat(stateTargetSdkLessChange)
                 .isEqualTo(new OverrideAllowedState(ALLOWED, -1, -1));
@@ -118,6 +123,8 @@
                 .isEqualTo(new OverrideAllowedState(ALLOWED, -1, -1));
         assertThat(stateDisabledChange)
                 .isEqualTo(new OverrideAllowedState(ALLOWED, -1, -1));
+        assertThat(stateDLoggingOnlyChange)
+                .isEqualTo(new OverrideAllowedState(LOGGING_ONLY_CHANGE, -1, -1));
     }
 
     @Test
@@ -128,7 +135,8 @@
                     .addTargetSdkChangeWithId(TARGET_SDK, 2)
                     .addTargetSdkChangeWithId(TARGET_SDK_AFTER, 3)
                     .addEnabledChangeWithId(4)
-                    .addDisabledChangeWithId(5).build();
+                    .addDisabledChangeWithId(5)
+                    .addLoggingOnlyChangeWithId(6).build();
         IOverrideValidator overrideValidator = config.getOverrideValidator();
         when(mPackageManager.getApplicationInfo(eq(PACKAGE_NAME), anyInt()))
                 .thenReturn(ApplicationInfoBuilder.create()
@@ -145,6 +153,8 @@
                 overrideValidator.getOverrideAllowedState(4, PACKAGE_NAME);
         OverrideAllowedState stateDisabledChange =
                 overrideValidator.getOverrideAllowedState(5, PACKAGE_NAME);
+        OverrideAllowedState stateDLoggingOnlyChange =
+                overrideValidator.getOverrideAllowedState(6, PACKAGE_NAME);
 
         assertThat(stateTargetSdkLessChange)
                 .isEqualTo(new OverrideAllowedState(ALLOWED, -1, -1));
@@ -156,6 +166,8 @@
                 .isEqualTo(new OverrideAllowedState(ALLOWED, -1, -1));
         assertThat(stateDisabledChange)
                 .isEqualTo(new OverrideAllowedState(ALLOWED, -1, -1));
+        assertThat(stateDLoggingOnlyChange)
+                .isEqualTo(new OverrideAllowedState(LOGGING_ONLY_CHANGE, -1, -1));
     }
 
     @Test
@@ -232,7 +244,8 @@
                         .addTargetSdkChangeWithId(TARGET_SDK, 2)
                         .addTargetSdkChangeWithId(TARGET_SDK_AFTER, 3)
                         .addEnabledChangeWithId(4)
-                        .addDisabledChangeWithId(5).build();
+                        .addDisabledChangeWithId(5)
+                        .addLoggingOnlyChangeWithId(6).build();
         IOverrideValidator overrideValidator = config.getOverrideValidator();
         when(mPackageManager.getApplicationInfo(eq(PACKAGE_NAME), anyInt()))
                 .thenReturn(ApplicationInfoBuilder.create()
@@ -249,6 +262,8 @@
                 overrideValidator.getOverrideAllowedState(4, PACKAGE_NAME);
         OverrideAllowedState stateDisabledChange =
                 overrideValidator.getOverrideAllowedState(5, PACKAGE_NAME);
+        OverrideAllowedState stateDLoggingOnlyChange =
+                overrideValidator.getOverrideAllowedState(6, PACKAGE_NAME);
 
         assertThat(stateTargetSdkLessChange)
                 .isEqualTo(new OverrideAllowedState(DISABLED_NOT_DEBUGGABLE, -1, -1));
@@ -260,6 +275,8 @@
                 .isEqualTo(new OverrideAllowedState(DISABLED_NOT_DEBUGGABLE, -1, -1));
         assertThat(stateDisabledChange)
                 .isEqualTo(new OverrideAllowedState(DISABLED_NOT_DEBUGGABLE, -1, -1));
+        assertThat(stateDLoggingOnlyChange)
+                .isEqualTo(new OverrideAllowedState(LOGGING_ONLY_CHANGE, -1, -1));
     }
 
     @Test
@@ -351,7 +368,8 @@
                         .addTargetSdkChangeWithId(TARGET_SDK, 2)
                         .addTargetSdkChangeWithId(TARGET_SDK_AFTER, 3)
                         .addEnabledChangeWithId(4)
-                        .addDisabledChangeWithId(5).build();
+                        .addDisabledChangeWithId(5)
+                        .addLoggingOnlyChangeWithId(6).build();
         IOverrideValidator overrideValidator = config.getOverrideValidator();
         when(mPackageManager.getApplicationInfo(eq(PACKAGE_NAME), anyInt()))
                 .thenReturn(ApplicationInfoBuilder.create()
@@ -368,6 +386,8 @@
                 overrideValidator.getOverrideAllowedState(4, PACKAGE_NAME);
         OverrideAllowedState stateDisabledChange =
                 overrideValidator.getOverrideAllowedState(5, PACKAGE_NAME);
+        OverrideAllowedState stateDLoggingOnlyChange =
+                overrideValidator.getOverrideAllowedState(6, PACKAGE_NAME);
 
         assertThat(stateTargetSdkLessChange)
                 .isEqualTo(new OverrideAllowedState(DISABLED_NOT_DEBUGGABLE, -1, -1));
@@ -379,5 +399,7 @@
                 .isEqualTo(new OverrideAllowedState(DISABLED_NOT_DEBUGGABLE, -1, -1));
         assertThat(stateDisabledChange)
                 .isEqualTo(new OverrideAllowedState(DISABLED_NOT_DEBUGGABLE, -1, -1));
+        assertThat(stateDLoggingOnlyChange)
+                .isEqualTo(new OverrideAllowedState(LOGGING_ONLY_CHANGE, -1, -1));
     }
 }
diff --git a/services/tests/servicestests/src/com/android/server/locksettings/LockSettingsServiceTests.java b/services/tests/servicestests/src/com/android/server/locksettings/LockSettingsServiceTests.java
index 2e77c9f..684bbd4 100644
--- a/services/tests/servicestests/src/com/android/server/locksettings/LockSettingsServiceTests.java
+++ b/services/tests/servicestests/src/com/android/server/locksettings/LockSettingsServiceTests.java
@@ -236,6 +236,7 @@
     @Test
     public void testSetLockCredential_forProfileWithSeparateChallenge_updatesCredentials()
             throws Exception {
+        mService.setSeparateProfileChallengeEnabled(MANAGED_PROFILE_USER_ID, true, null);
         initializeStorageWithCredential(
                 MANAGED_PROFILE_USER_ID,
                 newPattern("12345"),
diff --git a/services/tests/servicestests/src/com/android/server/people/data/DataManagerTest.java b/services/tests/servicestests/src/com/android/server/people/data/DataManagerTest.java
index 624b67c..a4d63ac 100644
--- a/services/tests/servicestests/src/com/android/server/people/data/DataManagerTest.java
+++ b/services/tests/servicestests/src/com/android/server/people/data/DataManagerTest.java
@@ -269,7 +269,7 @@
         assertEquals(1, conversations.size());
         assertEquals("sc_1", conversations.get(0).getShortcutId());
 
-        mDataManager.onUserStopped(USER_ID_PRIMARY);
+        mDataManager.onUserStopping(USER_ID_PRIMARY);
         conversations = getConversationsInPrimary();
         assertTrue(conversations.isEmpty());
     }
diff --git a/services/tests/wmtests/src/com/android/server/wm/TaskOrganizerTests.java b/services/tests/wmtests/src/com/android/server/wm/TaskOrganizerTests.java
index e501452..48a583c 100644
--- a/services/tests/wmtests/src/com/android/server/wm/TaskOrganizerTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/TaskOrganizerTests.java
@@ -39,6 +39,7 @@
 
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotEquals;
 import static org.junit.Assert.assertNotNull;
 import static org.junit.Assert.assertTrue;
 import static org.mockito.ArgumentMatchers.any;
@@ -253,6 +254,30 @@
     }
 
     @Test
+    public void testOverrideConfigSize() {
+        removeGlobalMinSizeRestriction();
+        final ActivityStack stack = new ActivityTestsBase.StackBuilder(mWm.mRoot)
+                .setWindowingMode(WINDOWING_MODE_FREEFORM).build();
+        final Task task = stack.getTopMostTask();
+        WindowContainerTransaction t = new WindowContainerTransaction();
+        t.setBounds(task.mRemoteToken, new Rect(10, 10, 100, 100));
+        mWm.mAtmService.mTaskOrganizerController.applyContainerTransaction(t, null);
+        final int origScreenWDp = task.getConfiguration().screenHeightDp;
+        final int origScreenHDp = task.getConfiguration().screenHeightDp;
+        t = new WindowContainerTransaction();
+        // verify that setting config overrides on parent restricts children.
+        t.setScreenSizeDp(stack.mRemoteToken, origScreenWDp, origScreenHDp);
+        t.setBounds(task.mRemoteToken, new Rect(10, 10, 150, 200));
+        mWm.mAtmService.mTaskOrganizerController.applyContainerTransaction(t, null);
+        assertEquals(origScreenHDp, task.getConfiguration().screenHeightDp);
+        t = new WindowContainerTransaction();
+        t.setScreenSizeDp(stack.mRemoteToken, Configuration.SCREEN_WIDTH_DP_UNDEFINED,
+                Configuration.SCREEN_HEIGHT_DP_UNDEFINED);
+        mWm.mAtmService.mTaskOrganizerController.applyContainerTransaction(t, null);
+        assertNotEquals(origScreenHDp, task.getConfiguration().screenHeightDp);
+    }
+
+    @Test
     public void testCreateDeleteRootTasks() {
         RunningTaskInfo info1 = mWm.mAtmService.mTaskOrganizerController.createRootTask(
                 Display.DEFAULT_DISPLAY,
diff --git a/telephony/java/android/telephony/AccessNetworkConstants.java b/telephony/java/android/telephony/AccessNetworkConstants.java
index 01abb26..558f4cd 100644
--- a/telephony/java/android/telephony/AccessNetworkConstants.java
+++ b/telephony/java/android/telephony/AccessNetworkConstants.java
@@ -19,6 +19,10 @@
 import android.annotation.IntDef;
 import android.annotation.SystemApi;
 import android.annotation.TestApi;
+import android.hardware.radio.V1_1.EutranBands;
+import android.hardware.radio.V1_1.GeranBands;
+import android.hardware.radio.V1_5.AccessNetwork;
+import android.hardware.radio.V1_5.UtranBands;
 
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
@@ -84,13 +88,13 @@
     public @interface RadioAccessNetworkType {}
 
     public static final class AccessNetworkType {
-        public static final int UNKNOWN = 0;
-        public static final int GERAN = 1;
-        public static final int UTRAN = 2;
-        public static final int EUTRAN = 3;
-        public static final int CDMA2000 = 4;
-        public static final int IWLAN = 5;
-        public static final int NGRAN = 6;
+        public static final int UNKNOWN = AccessNetwork.UNKNOWN;
+        public static final int GERAN = AccessNetwork.GERAN;
+        public static final int UTRAN = AccessNetwork.UTRAN;
+        public static final int EUTRAN = AccessNetwork.EUTRAN;
+        public static final int CDMA2000 = AccessNetwork.CDMA2000;
+        public static final int IWLAN = AccessNetwork.IWLAN;
+        public static final int NGRAN = AccessNetwork.NGRAN;
 
         /** @hide */
         private AccessNetworkType() {}
@@ -115,20 +119,20 @@
      * http://www.etsi.org/deliver/etsi_ts/145000_145099/145005/14.00.00_60/ts_145005v140000p.pdf
      */
     public static final class GeranBand {
-        public static final int BAND_T380 = 1;
-        public static final int BAND_T410 = 2;
-        public static final int BAND_450 = 3;
-        public static final int BAND_480 = 4;
-        public static final int BAND_710 = 5;
-        public static final int BAND_750 = 6;
-        public static final int BAND_T810 = 7;
-        public static final int BAND_850 = 8;
-        public static final int BAND_P900 = 9;
-        public static final int BAND_E900 = 10;
-        public static final int BAND_R900 = 11;
-        public static final int BAND_DCS1800 = 12;
-        public static final int BAND_PCS1900 = 13;
-        public static final int BAND_ER900 = 14;
+        public static final int BAND_T380 = GeranBands.BAND_T380;
+        public static final int BAND_T410 = GeranBands.BAND_T410;
+        public static final int BAND_450 = GeranBands.BAND_450;
+        public static final int BAND_480 = GeranBands.BAND_480;
+        public static final int BAND_710 = GeranBands.BAND_710;
+        public static final int BAND_750 = GeranBands.BAND_750;
+        public static final int BAND_T810 = GeranBands.BAND_T810;
+        public static final int BAND_850 = GeranBands.BAND_850;
+        public static final int BAND_P900 = GeranBands.BAND_P900;
+        public static final int BAND_E900 = GeranBands.BAND_E900;
+        public static final int BAND_R900 = GeranBands.BAND_R900;
+        public static final int BAND_DCS1800 = GeranBands.BAND_DCS1800;
+        public static final int BAND_PCS1900 = GeranBands.BAND_PCS1900;
+        public static final int BAND_ER900 = GeranBands.BAND_ER900;
 
         /** @hide */
         private GeranBand() {}
@@ -139,28 +143,28 @@
      * http://www.etsi.org/deliver/etsi_ts/125100_125199/125104/13.03.00_60/ts_125104v130p.pdf
      */
     public static final class UtranBand {
-        public static final int BAND_1 = 1;
-        public static final int BAND_2 = 2;
-        public static final int BAND_3 = 3;
-        public static final int BAND_4 = 4;
-        public static final int BAND_5 = 5;
-        public static final int BAND_6 = 6;
-        public static final int BAND_7 = 7;
-        public static final int BAND_8 = 8;
-        public static final int BAND_9 = 9;
-        public static final int BAND_10 = 10;
-        public static final int BAND_11 = 11;
-        public static final int BAND_12 = 12;
-        public static final int BAND_13 = 13;
-        public static final int BAND_14 = 14;
+        public static final int BAND_1 = UtranBands.BAND_1;
+        public static final int BAND_2 = UtranBands.BAND_2;
+        public static final int BAND_3 = UtranBands.BAND_3;
+        public static final int BAND_4 = UtranBands.BAND_4;
+        public static final int BAND_5 = UtranBands.BAND_5;
+        public static final int BAND_6 = UtranBands.BAND_6;
+        public static final int BAND_7 = UtranBands.BAND_7;
+        public static final int BAND_8 = UtranBands.BAND_8;
+        public static final int BAND_9 = UtranBands.BAND_9;
+        public static final int BAND_10 = UtranBands.BAND_10;
+        public static final int BAND_11 = UtranBands.BAND_11;
+        public static final int BAND_12 = UtranBands.BAND_12;
+        public static final int BAND_13 = UtranBands.BAND_13;
+        public static final int BAND_14 = UtranBands.BAND_14;
         // band 15, 16, 17, 18 are reserved
-        public static final int BAND_19 = 19;
-        public static final int BAND_20 = 20;
-        public static final int BAND_21 = 21;
-        public static final int BAND_22 = 22;
+        public static final int BAND_19 = UtranBands.BAND_19;
+        public static final int BAND_20 = UtranBands.BAND_20;
+        public static final int BAND_21 = UtranBands.BAND_21;
+        public static final int BAND_22 = UtranBands.BAND_22;
         // band 23, 24 are reserved
-        public static final int BAND_25 = 25;
-        public static final int BAND_26 = 26;
+        public static final int BAND_25 = UtranBands.BAND_25;
+        public static final int BAND_26 = UtranBands.BAND_26;
 
         // Frequency bands for TD-SCDMA. Defined in 3GPP TS 25.102, Table 5.2.
 
@@ -169,38 +173,38 @@
          * 1900 - 1920 MHz: Uplink and downlink transmission
          * 2010 - 2025 MHz: Uplink and downlink transmission
          */
-        public static final int BAND_A = 101;
+        public static final int BAND_A = UtranBands.BAND_A;
 
         /**
          * Band B
          * 1850 - 1910 MHz: Uplink and downlink transmission
          * 1930 - 1990 MHz: Uplink and downlink transmission
          */
-        public static final int BAND_B = 102;
+        public static final int BAND_B = UtranBands.BAND_B;
 
         /**
          * Band C
          * 1910 - 1930 MHz: Uplink and downlink transmission
          */
-        public static final int BAND_C = 103;
+        public static final int BAND_C = UtranBands.BAND_C;
 
         /**
          * Band D
          * 2570 - 2620 MHz: Uplink and downlink transmission
          */
-        public static final int BAND_D = 104;
+        public static final int BAND_D = UtranBands.BAND_D;
 
         /**
          * Band E
          * 2300—2400 MHz: Uplink and downlink transmission
          */
-        public static final int BAND_E = 105;
+        public static final int BAND_E = UtranBands.BAND_E;
 
         /**
          * Band F
          * 1880 - 1920 MHz: Uplink and downlink transmission
          */
-        public static final int BAND_F = 106;
+        public static final int BAND_F = UtranBands.BAND_F;
 
         /** @hide */
         private UtranBand() {}
@@ -211,54 +215,54 @@
      * http://www.etsi.org/deliver/etsi_ts/136100_136199/136101/14.03.00_60/ts_136101v140p.pdf
      */
     public static final class EutranBand {
-        public static final int BAND_1 = 1;
-        public static final int BAND_2 = 2;
-        public static final int BAND_3 = 3;
-        public static final int BAND_4 = 4;
-        public static final int BAND_5 = 5;
-        public static final int BAND_6 = 6;
-        public static final int BAND_7 = 7;
-        public static final int BAND_8 = 8;
-        public static final int BAND_9 = 9;
-        public static final int BAND_10 = 10;
-        public static final int BAND_11 = 11;
-        public static final int BAND_12 = 12;
-        public static final int BAND_13 = 13;
-        public static final int BAND_14 = 14;
-        public static final int BAND_17 = 17;
-        public static final int BAND_18 = 18;
-        public static final int BAND_19 = 19;
-        public static final int BAND_20 = 20;
-        public static final int BAND_21 = 21;
-        public static final int BAND_22 = 22;
-        public static final int BAND_23 = 23;
-        public static final int BAND_24 = 24;
-        public static final int BAND_25 = 25;
-        public static final int BAND_26 = 26;
-        public static final int BAND_27 = 27;
-        public static final int BAND_28 = 28;
-        public static final int BAND_30 = 30;
-        public static final int BAND_31 = 31;
-        public static final int BAND_33 = 33;
-        public static final int BAND_34 = 34;
-        public static final int BAND_35 = 35;
-        public static final int BAND_36 = 36;
-        public static final int BAND_37 = 37;
-        public static final int BAND_38 = 38;
-        public static final int BAND_39 = 39;
-        public static final int BAND_40 = 40;
-        public static final int BAND_41 = 41;
-        public static final int BAND_42 = 42;
-        public static final int BAND_43 = 43;
-        public static final int BAND_44 = 44;
-        public static final int BAND_45 = 45;
-        public static final int BAND_46 = 46;
-        public static final int BAND_47 = 47;
-        public static final int BAND_48 = 48;
-        public static final int BAND_65 = 65;
-        public static final int BAND_66 = 66;
-        public static final int BAND_68 = 68;
-        public static final int BAND_70 = 70;
+        public static final int BAND_1 = EutranBands.BAND_1;
+        public static final int BAND_2 = EutranBands.BAND_2;
+        public static final int BAND_3 = EutranBands.BAND_3;
+        public static final int BAND_4 = EutranBands.BAND_4;
+        public static final int BAND_5 = EutranBands.BAND_5;
+        public static final int BAND_6 = EutranBands.BAND_6;
+        public static final int BAND_7 = EutranBands.BAND_7;
+        public static final int BAND_8 = EutranBands.BAND_8;
+        public static final int BAND_9 = EutranBands.BAND_9;
+        public static final int BAND_10 = EutranBands.BAND_10;
+        public static final int BAND_11 = EutranBands.BAND_11;
+        public static final int BAND_12 = EutranBands.BAND_12;
+        public static final int BAND_13 = EutranBands.BAND_13;
+        public static final int BAND_14 = EutranBands.BAND_14;
+        public static final int BAND_17 = EutranBands.BAND_17;
+        public static final int BAND_18 = EutranBands.BAND_18;
+        public static final int BAND_19 = EutranBands.BAND_19;
+        public static final int BAND_20 = EutranBands.BAND_20;
+        public static final int BAND_21 = EutranBands.BAND_21;
+        public static final int BAND_22 = EutranBands.BAND_22;
+        public static final int BAND_23 = EutranBands.BAND_23;
+        public static final int BAND_24 = EutranBands.BAND_24;
+        public static final int BAND_25 = EutranBands.BAND_25;
+        public static final int BAND_26 = EutranBands.BAND_26;
+        public static final int BAND_27 = EutranBands.BAND_27;
+        public static final int BAND_28 = EutranBands.BAND_28;
+        public static final int BAND_30 = EutranBands.BAND_30;
+        public static final int BAND_31 = EutranBands.BAND_31;
+        public static final int BAND_33 = EutranBands.BAND_33;
+        public static final int BAND_34 = EutranBands.BAND_34;
+        public static final int BAND_35 = EutranBands.BAND_35;
+        public static final int BAND_36 = EutranBands.BAND_36;
+        public static final int BAND_37 = EutranBands.BAND_37;
+        public static final int BAND_38 = EutranBands.BAND_38;
+        public static final int BAND_39 = EutranBands.BAND_39;
+        public static final int BAND_40 = EutranBands.BAND_40;
+        public static final int BAND_41 = EutranBands.BAND_41;
+        public static final int BAND_42 = EutranBands.BAND_42;
+        public static final int BAND_43 = EutranBands.BAND_43;
+        public static final int BAND_44 = EutranBands.BAND_44;
+        public static final int BAND_45 = EutranBands.BAND_45;
+        public static final int BAND_46 = EutranBands.BAND_46;
+        public static final int BAND_47 = EutranBands.BAND_47;
+        public static final int BAND_48 = EutranBands.BAND_48;
+        public static final int BAND_65 = EutranBands.BAND_65;
+        public static final int BAND_66 = EutranBands.BAND_66;
+        public static final int BAND_68 = EutranBands.BAND_68;
+        public static final int BAND_70 = EutranBands.BAND_70;
 
         /** @hide */
         private EutranBand() {};
@@ -304,51 +308,51 @@
      */
     public static final class NgranBands {
         /** FR1 bands */
-        public static final int BAND_1 = 1;
-        public static final int BAND_2 = 2;
-        public static final int BAND_3 = 3;
-        public static final int BAND_5 = 5;
-        public static final int BAND_7 = 7;
-        public static final int BAND_8 = 8;
-        public static final int BAND_12 = 12;
-        public static final int BAND_14 = 14;
-        public static final int BAND_18 = 18;
-        public static final int BAND_20 = 20;
-        public static final int BAND_25 = 25;
-        public static final int BAND_28 = 28;
-        public static final int BAND_29 = 29;
-        public static final int BAND_30 = 30;
-        public static final int BAND_34 = 34;
-        public static final int BAND_38 = 38;
-        public static final int BAND_39 = 39;
-        public static final int BAND_40 = 40;
-        public static final int BAND_41 = 41;
-        public static final int BAND_48 = 48;
-        public static final int BAND_50 = 50;
-        public static final int BAND_51 = 51;
-        public static final int BAND_65 = 65;
-        public static final int BAND_66 = 66;
-        public static final int BAND_70 = 70;
-        public static final int BAND_71 = 71;
-        public static final int BAND_74 = 74;
-        public static final int BAND_75 = 75;
-        public static final int BAND_76 = 76;
-        public static final int BAND_77 = 77;
-        public static final int BAND_78 = 78;
-        public static final int BAND_79 = 79;
-        public static final int BAND_80 = 80;
-        public static final int BAND_81 = 81;
-        public static final int BAND_82 = 82;
-        public static final int BAND_83 = 83;
-        public static final int BAND_84 = 84;
-        public static final int BAND_86 = 86;
-        public static final int BAND_90 = 90;
+        public static final int BAND_1 = android.hardware.radio.V1_5.NgranBands.BAND_1;
+        public static final int BAND_2 = android.hardware.radio.V1_5.NgranBands.BAND_2;
+        public static final int BAND_3 = android.hardware.radio.V1_5.NgranBands.BAND_3;
+        public static final int BAND_5 = android.hardware.radio.V1_5.NgranBands.BAND_5;
+        public static final int BAND_7 = android.hardware.radio.V1_5.NgranBands.BAND_7;
+        public static final int BAND_8 = android.hardware.radio.V1_5.NgranBands.BAND_8;
+        public static final int BAND_12 = android.hardware.radio.V1_5.NgranBands.BAND_12;
+        public static final int BAND_14 = android.hardware.radio.V1_5.NgranBands.BAND_14;
+        public static final int BAND_18 = android.hardware.radio.V1_5.NgranBands.BAND_18;
+        public static final int BAND_20 = android.hardware.radio.V1_5.NgranBands.BAND_20;
+        public static final int BAND_25 = android.hardware.radio.V1_5.NgranBands.BAND_25;
+        public static final int BAND_28 = android.hardware.radio.V1_5.NgranBands.BAND_28;
+        public static final int BAND_29 = android.hardware.radio.V1_5.NgranBands.BAND_29;
+        public static final int BAND_30 = android.hardware.radio.V1_5.NgranBands.BAND_30;
+        public static final int BAND_34 = android.hardware.radio.V1_5.NgranBands.BAND_34;
+        public static final int BAND_38 = android.hardware.radio.V1_5.NgranBands.BAND_38;
+        public static final int BAND_39 = android.hardware.radio.V1_5.NgranBands.BAND_39;
+        public static final int BAND_40 = android.hardware.radio.V1_5.NgranBands.BAND_40;
+        public static final int BAND_41 = android.hardware.radio.V1_5.NgranBands.BAND_41;
+        public static final int BAND_48 = android.hardware.radio.V1_5.NgranBands.BAND_48;
+        public static final int BAND_50 = android.hardware.radio.V1_5.NgranBands.BAND_50;
+        public static final int BAND_51 = android.hardware.radio.V1_5.NgranBands.BAND_51;
+        public static final int BAND_65 = android.hardware.radio.V1_5.NgranBands.BAND_65;
+        public static final int BAND_66 = android.hardware.radio.V1_5.NgranBands.BAND_66;
+        public static final int BAND_70 = android.hardware.radio.V1_5.NgranBands.BAND_70;
+        public static final int BAND_71 = android.hardware.radio.V1_5.NgranBands.BAND_71;
+        public static final int BAND_74 = android.hardware.radio.V1_5.NgranBands.BAND_74;
+        public static final int BAND_75 = android.hardware.radio.V1_5.NgranBands.BAND_75;
+        public static final int BAND_76 = android.hardware.radio.V1_5.NgranBands.BAND_76;
+        public static final int BAND_77 = android.hardware.radio.V1_5.NgranBands.BAND_77;
+        public static final int BAND_78 = android.hardware.radio.V1_5.NgranBands.BAND_78;
+        public static final int BAND_79 = android.hardware.radio.V1_5.NgranBands.BAND_79;
+        public static final int BAND_80 = android.hardware.radio.V1_5.NgranBands.BAND_80;
+        public static final int BAND_81 = android.hardware.radio.V1_5.NgranBands.BAND_81;
+        public static final int BAND_82 = android.hardware.radio.V1_5.NgranBands.BAND_82;
+        public static final int BAND_83 = android.hardware.radio.V1_5.NgranBands.BAND_83;
+        public static final int BAND_84 = android.hardware.radio.V1_5.NgranBands.BAND_84;
+        public static final int BAND_86 = android.hardware.radio.V1_5.NgranBands.BAND_86;
+        public static final int BAND_90 = android.hardware.radio.V1_5.NgranBands.BAND_90;
 
         /** FR2 bands */
-        public static final int BAND_257 = 257;
-        public static final int BAND_258 = 258;
-        public static final int BAND_260 = 260;
-        public static final int BAND_261 = 261;
+        public static final int BAND_257 = android.hardware.radio.V1_5.NgranBands.BAND_257;
+        public static final int BAND_258 = android.hardware.radio.V1_5.NgranBands.BAND_258;
+        public static final int BAND_260 = android.hardware.radio.V1_5.NgranBands.BAND_260;
+        public static final int BAND_261 = android.hardware.radio.V1_5.NgranBands.BAND_261;
 
         /**
          * NR Bands
diff --git a/telephony/java/android/telephony/ImsManager.java b/telephony/java/android/telephony/ImsManager.java
index d504b38..fe75266 100644
--- a/telephony/java/android/telephony/ImsManager.java
+++ b/telephony/java/android/telephony/ImsManager.java
@@ -74,17 +74,17 @@
             "android.telephony.ims.action.WFC_IMS_REGISTRATION_ERROR";
 
     /**
-     * An extra key corresponding to a String value which contains the carrier specific title to be
-     * displayed as part of the message shown to the user when there is an error registering for
-     * WiFi calling.
+     * An extra key corresponding to a {@link CharSequence} value which contains the carrier
+     * specific title to be displayed as part of the message shown to the user when there is an
+     * error registering for WiFi calling.
      */
     public static final String EXTRA_WFC_REGISTRATION_FAILURE_TITLE =
             "android.telephony.ims.extra.WFC_REGISTRATION_FAILURE_TITLE";
 
     /**
-     * An extra key corresponding to a String value which contains the carrier specific message to
-     * be displayed as part of the message shown to the user when there is an error registering for
-     * WiFi calling.
+     * An extra key corresponding to a {@link CharSequence} value which contains the carrier
+     * specific message to  be displayed as part of the message shown to the user when there is an
+     * error registering for WiFi calling.
      */
     public static final String EXTRA_WFC_REGISTRATION_FAILURE_MESSAGE =
             "android.telephony.ims.extra.WFC_REGISTRATION_FAILURE_MESSAGE";
diff --git a/telephony/java/android/telephony/ServiceState.java b/telephony/java/android/telephony/ServiceState.java
index 08614b9..9b1baef 100644
--- a/telephony/java/android/telephony/ServiceState.java
+++ b/telephony/java/android/telephony/ServiceState.java
@@ -1411,6 +1411,7 @@
             DataSpecificRegistrationInfo dsri = nri.getDataSpecificInfo();
             if (dsri != null) {
                 dsri.setIsUsingCarrierAggregation(ca);
+                addNetworkRegistrationInfo(nri);
             }
         }
     }
diff --git a/telephony/java/android/telephony/TelephonyManager.java b/telephony/java/android/telephony/TelephonyManager.java
index 27bbe68..40def40 100644
--- a/telephony/java/android/telephony/TelephonyManager.java
+++ b/telephony/java/android/telephony/TelephonyManager.java
@@ -333,21 +333,6 @@
     };
 
     /** @hide */
-    @IntDef(prefix = {"MODEM_COUNT_"},
-            value = {
-                    MODEM_COUNT_NO_MODEM,
-                    MODEM_COUNT_SINGLE_MODEM,
-                    MODEM_COUNT_DUAL_MODEM,
-                    MODEM_COUNT_TRI_MODEM
-            })
-    public @interface ModemCount {}
-
-    public static final int MODEM_COUNT_NO_MODEM     = 0;
-    public static final int MODEM_COUNT_SINGLE_MODEM = 1;
-    public static final int MODEM_COUNT_DUAL_MODEM   = 2;
-    public static final int MODEM_COUNT_TRI_MODEM    = 3;
-
-    /** @hide */
     @UnsupportedAppUsage
     public TelephonyManager(Context context) {
       this(context, SubscriptionManager.DEFAULT_SUBSCRIPTION_ID);
@@ -465,22 +450,22 @@
      * Returns 2 for Dual standby mode (Dual SIM functionality).
      * Returns 3 for Tri standby mode (Tri SIM functionality).
      */
-    public @ModemCount int getActiveModemCount() {
+    public int getActiveModemCount() {
         int modemCount = 1;
         switch (getMultiSimConfiguration()) {
             case UNKNOWN:
-                modemCount = MODEM_COUNT_SINGLE_MODEM;
+                modemCount = 1;
                 // check for voice and data support, 0 if not supported
                 if (!isVoiceCapable() && !isSmsCapable() && !isDataCapable()) {
-                    modemCount = MODEM_COUNT_NO_MODEM;
+                    modemCount = 0;
                 }
                 break;
             case DSDS:
             case DSDA:
-                modemCount = MODEM_COUNT_DUAL_MODEM;
+                modemCount = 2;
                 break;
             case TSTS:
-                modemCount = MODEM_COUNT_TRI_MODEM;
+                modemCount = 3;
                 break;
         }
         return modemCount;
@@ -493,7 +478,7 @@
      * dual-SIM capable device operating in single SIM mode (only one logical modem is turned on),
      * {@link #getActiveModemCount} returns 1 while this API returns 2.
      */
-    public @ModemCount int getSupportedModemCount() {
+    public int getSupportedModemCount() {
         return TelephonyProperties.max_active_modems().orElse(getActiveModemCount());
     }
 
@@ -12669,7 +12654,8 @@
      * {@hide}
      */
     @SystemApi
-    public boolean isCurrentSimOperator(@NonNull String mccmnc, @MvnoType int mvnoType,
+    @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
+    public boolean matchesCurrentSimOperator(@NonNull String mccmnc, @MvnoType int mvnoType,
             @Nullable String mvnoMatchData) {
         try {
             if (!mccmnc.equals(getSimOperator())) {
diff --git a/tools/stats_log_api_gen/Collation.cpp b/tools/stats_log_api_gen/Collation.cpp
index aa356f1..66c4b14 100644
--- a/tools/stats_log_api_gen/Collation.cpp
+++ b/tools/stats_log_api_gen/Collation.cpp
@@ -53,8 +53,7 @@
         uidField(that.uidField),
         whitelisted(that.whitelisted),
         binaryFields(that.binaryFields),
-        hasModule(that.hasModule),
-        moduleName(that.moduleName) {}
+        moduleNames(that.moduleNames) {}
 
 AtomDecl::AtomDecl(int c, const string& n, const string& m)
     :code(c),
@@ -442,9 +441,9 @@
         atomDecl.whitelisted = true;
     }
 
-    if (atomField->options().HasExtension(os::statsd::module)) {
-        atomDecl.hasModule = true;
-        atomDecl.moduleName = atomField->options().GetExtension(os::statsd::module);
+    for (int j = 0; j < atomField->options().ExtensionSize(os::statsd::module); ++j) {
+        const string moduleName = atomField->options().GetExtension(os::statsd::module, j);
+        atomDecl.moduleNames.insert(moduleName);
     }
 
     vector<java_type_t> signature;
@@ -453,36 +452,15 @@
         errorCount++;
     }
 
-    // Add the signature if does not already exist.
-    auto signature_to_modules_it = atoms->signatures_to_modules.find(signature);
-    if (signature_to_modules_it == atoms->signatures_to_modules.end()) {
-        set<string> modules;
-        if (atomDecl.hasModule) {
-            modules.insert(atomDecl.moduleName);
-        }
-        atoms->signatures_to_modules[signature] = modules;
-    } else {
-        if (atomDecl.hasModule) {
-            signature_to_modules_it->second.insert(atomDecl.moduleName);
-        }
-    }
+    atoms->signatures_to_modules[signature].insert(
+            atomDecl.moduleNames.begin(), atomDecl.moduleNames.end());
     atoms->decls.insert(atomDecl);
 
     AtomDecl nonChainedAtomDecl(atomField->number(), atomField->name(), atom->name());
     vector<java_type_t> nonChainedSignature;
     if (get_non_chained_node(atom, &nonChainedAtomDecl, &nonChainedSignature)) {
-        auto it = atoms->non_chained_signatures_to_modules.find(nonChainedSignature);
-        if (it == atoms->non_chained_signatures_to_modules.end()) {
-            set<string> modules_non_chained;
-            if (atomDecl.hasModule) {
-                modules_non_chained.insert(atomDecl.moduleName);
-            }
-            atoms->non_chained_signatures_to_modules[nonChainedSignature] = modules_non_chained;
-        } else {
-            if (atomDecl.hasModule) {
-                it->second.insert(atomDecl.moduleName);
-            }
-        }
+        atoms->non_chained_signatures_to_modules[nonChainedSignature].insert(
+            atomDecl.moduleNames.begin(), atomDecl.moduleNames.end());
         atoms->non_chained_decls.insert(nonChainedAtomDecl);
     }
 
diff --git a/tools/stats_log_api_gen/Collation.h b/tools/stats_log_api_gen/Collation.h
index 65d8e3e..ace85e0 100644
--- a/tools/stats_log_api_gen/Collation.h
+++ b/tools/stats_log_api_gen/Collation.h
@@ -98,8 +98,7 @@
 
     vector<int> binaryFields;
 
-    bool hasModule = false;
-    string moduleName;
+    set<string> moduleNames;
 
     AtomDecl();
     AtomDecl(const AtomDecl& that);
diff --git a/tools/stats_log_api_gen/atoms_info_writer.cpp b/tools/stats_log_api_gen/atoms_info_writer.cpp
index 984c929..58f13a4 100644
--- a/tools/stats_log_api_gen/atoms_info_writer.cpp
+++ b/tools/stats_log_api_gen/atoms_info_writer.cpp
@@ -58,19 +58,25 @@
 }
 
 static void write_atoms_info_cpp_body(FILE* out, const Atoms& atoms) {
-    std::set<string> kTruncatingAtomNames = {"mobile_radio_power_state_changed",
-                                                 "audio_state_changed",
-                                                 "call_state_changed",
-                                                 "phone_signal_strength_changed",
-                                                 "mobile_bytes_transfer_by_fg_bg",
-                                                 "mobile_bytes_transfer"};
+    std::set<string> kTruncatingAtomNames = {
+            "mobile_radio_power_state_changed",
+            "audio_state_changed",
+            "call_state_changed",
+            "phone_signal_strength_changed",
+            "mobile_bytes_transfer_by_fg_bg",
+            "mobile_bytes_transfer"
+    };
     fprintf(out,
             "const std::set<int> "
             "AtomsInfo::kTruncatingTimestampAtomBlackList = {\n");
-    for (set<string>::const_iterator blacklistedAtom = kTruncatingAtomNames.begin();
-         blacklistedAtom != kTruncatingAtomNames.end(); blacklistedAtom++) {
-            fprintf(out, " %s,\n", make_constant_name(*blacklistedAtom).c_str());
+    for (set<AtomDecl>::const_iterator atom = atoms.decls.begin();
+         atom != atoms.decls.end(); atom++) {
+        if (kTruncatingAtomNames.find(atom->name) != kTruncatingAtomNames.end()) {
+            const string constant = make_constant_name(atom->name);
+            fprintf(out, "    %d, // %s\n", atom->code, constant.c_str());
+        }
     }
+
     fprintf(out, "};\n");
     fprintf(out, "\n");
 
@@ -81,8 +87,8 @@
         for (vector<AtomField>::const_iterator field = atom->fields.begin();
              field != atom->fields.end(); field++) {
             if (field->javaType == JAVA_TYPE_ATTRIBUTION_CHAIN) {
-                string constant = make_constant_name(atom->name);
-                fprintf(out, " %s,\n", constant.c_str());
+                const string constant = make_constant_name(atom->name);
+                fprintf(out, "    %d, // %s\n", atom->code, constant.c_str());
                 break;
             }
         }
@@ -96,8 +102,8 @@
     for (set<AtomDecl>::const_iterator atom = atoms.decls.begin();
          atom != atoms.decls.end(); atom++) {
         if (atom->whitelisted) {
-            string constant = make_constant_name(atom->name);
-            fprintf(out, " %s,\n", constant.c_str());
+            const string constant = make_constant_name(atom->name);
+            fprintf(out, "    %d, // %s\n", atom->code, constant.c_str());
         }
     }
 
@@ -105,7 +111,7 @@
     fprintf(out, "\n");
 
     fprintf(out, "static std::map<int, int> getAtomUidField() {\n");
-    fprintf(out, "  std::map<int, int> uidField;\n");
+    fprintf(out, "    std::map<int, int> uidField;\n");
     for (set<AtomDecl>::const_iterator atom = atoms.decls.begin();
          atom != atoms.decls.end(); atom++) {
         if (atom->uidField == 0) {
@@ -115,8 +121,8 @@
                 "\n    // Adding uid field for atom "
                 "(%d)%s\n",
                 atom->code, atom->name.c_str());
-        fprintf(out, "    uidField[static_cast<int>(%s)] = %d;\n",
-                make_constant_name(atom->name).c_str(), atom->uidField);
+        fprintf(out, "    uidField[%d /* %s */] = %d;\n",
+                atom->code, make_constant_name(atom->name).c_str(), atom->uidField);
     }
 
     fprintf(out, "    return uidField;\n");
@@ -140,8 +146,8 @@
                 "\n    // Adding primary and exclusive fields for atom "
                 "(%d)%s\n",
                 atom->code, atom->name.c_str());
-        fprintf(out, "    opt = &(options[static_cast<int>(%s)]);\n",
-                make_constant_name(atom->name).c_str());
+        fprintf(out, "    opt = &(options[%d /* %s */]);\n",
+                atom->code, make_constant_name(atom->name).c_str());
         fprintf(out, "    opt->primaryFields.reserve(%lu);\n", atom->primaryFields.size());
         for (const auto& field : atom->primaryFields) {
             fprintf(out, "    opt->primaryFields.push_back(%d);\n", field);
@@ -185,8 +191,8 @@
                 atom->code, atom->name.c_str());
 
         for (const auto& field : atom->binaryFields) {
-            fprintf(out, "    options[static_cast<int>(%s)].push_back(%d);\n",
-                    make_constant_name(atom->name).c_str(), field);
+            fprintf(out, "    options[%d /* %s */].push_back(%d);\n",
+                    atom->code, make_constant_name(atom->name).c_str(), field);
         }
     }
 
@@ -222,12 +228,11 @@
 }
 
 int write_atoms_info_cpp(FILE *out, const Atoms &atoms, const string& namespaceStr,
-        const string& importHeader, const string& statslogHeader) {
+        const string& importHeader) {
     // Print prelude
     fprintf(out, "// This file is autogenerated\n");
     fprintf(out, "\n");
     fprintf(out, "#include <%s>\n", importHeader.c_str());
-    fprintf(out, "#include <%s>\n", statslogHeader.c_str());
     fprintf(out, "\n");
 
     write_namespace(out, namespaceStr);
diff --git a/tools/stats_log_api_gen/atoms_info_writer.h b/tools/stats_log_api_gen/atoms_info_writer.h
index 12ac862..d04e65a 100644
--- a/tools/stats_log_api_gen/atoms_info_writer.h
+++ b/tools/stats_log_api_gen/atoms_info_writer.h
@@ -27,7 +27,7 @@
 using namespace std;
 
 int write_atoms_info_cpp(FILE* out, const Atoms& atoms, const string& namespaceStr,
-        const string& importHeader, const string& statslogHeader);
+        const string& importHeader);
 
 int write_atoms_info_header(FILE* out, const Atoms& atoms, const string& namespaceStr);
 
diff --git a/tools/stats_log_api_gen/main.cpp b/tools/stats_log_api_gen/main.cpp
index 120c2a2..e9723a1 100644
--- a/tools/stats_log_api_gen/main.cpp
+++ b/tools/stats_log_api_gen/main.cpp
@@ -212,7 +212,7 @@
             return 1;
         }
         errorCount = android::stats_log_api_gen::write_atoms_info_cpp(
-            out, atoms, cppNamespace, atomsInfoCppHeaderImport, cppHeaderImport);
+            out, atoms, cppNamespace, atomsInfoCppHeaderImport);
         fclose(out);
     }
 
diff --git a/tools/stats_log_api_gen/test.proto b/tools/stats_log_api_gen/test.proto
index eab622d..f6c89c2 100644
--- a/tools/stats_log_api_gen/test.proto
+++ b/tools/stats_log_api_gen/test.proto
@@ -213,6 +213,10 @@
     optional int32 field = 1;
 }
 
+message ModuleOneAndTwoAtom {
+    optional int32 field = 1;
+}
+
 message NoModuleAtom {
     optional string field = 1;
 }
@@ -221,6 +225,9 @@
     oneof event {
         ModuleOneAtom module_one_atom = 1 [(android.os.statsd.module) = "module1"];
         ModuleTwoAtom module_two_atom = 2 [(android.os.statsd.module) = "module2"];
-        NoModuleAtom no_module_atom = 3;
+        ModuleOneAndTwoAtom module_one_and_two_atom = 3 [
+                (android.os.statsd.module) = "module1", (android.os.statsd.module) = "module2"
+        ];
+        NoModuleAtom no_module_atom = 4;
     }
 }
diff --git a/tools/stats_log_api_gen/test_collation.cpp b/tools/stats_log_api_gen/test_collation.cpp
index a972e23..73abaef 100644
--- a/tools/stats_log_api_gen/test_collation.cpp
+++ b/tools/stats_log_api_gen/test_collation.cpp
@@ -248,23 +248,27 @@
     Atoms atoms;
     int errorCount = collate_atoms(ModuleAtoms::descriptor(), &atoms);
     EXPECT_EQ(errorCount, 0);
-    EXPECT_EQ(atoms.decls.size(), 3ul);
+    EXPECT_EQ(atoms.decls.size(), 4ul);
 }
 
 TEST(CollationTest, RecognizeModuleAtom) {
     Atoms atoms;
     int errorCount = collate_atoms(ModuleAtoms::descriptor(), &atoms);
     EXPECT_EQ(errorCount, 0);
-    EXPECT_EQ(atoms.decls.size(), 3ul);
+    EXPECT_EQ(atoms.decls.size(), 4ul);
     for (const auto& atomDecl: atoms.decls) {
         if (atomDecl.code == 1) {
-            EXPECT_TRUE(atomDecl.hasModule);
-            EXPECT_EQ(atomDecl.moduleName, "module1");
+            EXPECT_EQ(1ul, atomDecl.moduleNames.size());
+            EXPECT_NE(atomDecl.moduleNames.end(), atomDecl.moduleNames.find("module1"));
         } else if (atomDecl.code == 2) {
-            EXPECT_TRUE(atomDecl.hasModule);
-            EXPECT_EQ(atomDecl.moduleName, "module2");
+            EXPECT_EQ(1ul, atomDecl.moduleNames.size());
+            EXPECT_NE(atomDecl.moduleNames.end(), atomDecl.moduleNames.find("module2"));
+        } else if (atomDecl.code == 3) {
+            EXPECT_EQ(2ul, atomDecl.moduleNames.size());
+            EXPECT_NE(atomDecl.moduleNames.end(), atomDecl.moduleNames.find("module1"));
+            EXPECT_NE(atomDecl.moduleNames.end(), atomDecl.moduleNames.find("module2"));
         } else {
-            EXPECT_FALSE(atomDecl.hasModule);
+            EXPECT_TRUE(atomDecl.moduleNames.empty());
         }
     }
 
@@ -286,4 +290,4 @@
 }
 
 }  // namespace stats_log_api_gen
-}  // namespace android
\ No newline at end of file
+}  // namespace android
diff --git a/tools/stats_log_api_gen/utils.cpp b/tools/stats_log_api_gen/utils.cpp
index cd6914b..9dc4ff8 100644
--- a/tools/stats_log_api_gen/utils.cpp
+++ b/tools/stats_log_api_gen/utils.cpp
@@ -102,7 +102,7 @@
     if (moduleName == DEFAULT_MODULE_NAME) {
         return true;
     }
-    return atomDecl.hasModule && (moduleName == atomDecl.moduleName);
+    return atomDecl.moduleNames.find(moduleName) != atomDecl.moduleNames.end();
 }
 
 bool signature_needed_for_module(const set<string>& modules, const string& moduleName) {